mcs v0.18
Table of contents

Documentation

End-user documentation. Each section covers "when to use, how to use, a proper example". For the full parameter list, run mcs <cmd> --help.

[00]Concepts: profile, semantic package, business scenario

Learn these three terms before using mcs — every command revolves around them.

You configure profile mcs produces semantic package agent reads it to write SQL

[A]profile
  • identityAK / passwordless
  • scenariodescription
  • tablessources × N
[B]semantic package
  • contentstables / columns / JOINs / UDFs
  • locationlocal directory

Business scenario = [A] + [B] + accumulated semantic annotations / memory

"Data warehouse A monthly analysis" = 12 tables from dwd / dws + GMV formula notes

  • profile — a configuration that answers two questions: who am I (AK or passwordless, which RAM principal it resolves to) + which tables do I see (one or more sources, each source being a set of project.schema.tables). A single machine can have any number of profiles.
  • semantic packagemcs build scans all tables covered by the profile, samples a few rows, infers JOIN relationships, discovers UDFs, and writes them to a local directory. The agent reads this package before writing SQL, so it does not need to query MaxCompute metadata every time.
  • business scenario — not an entity in mcs, but a usage convention: one business domain maps to one profile (one for data warehouse A, one for marketing B, another for cross-domain metrics). The semantic annotations (written via the proposal queue) and memory (verified SQL) accumulated under one profile all belong to that business line.
Purpose of authentication mcs uses your RAM permissions to list tables, run SQL, and scan metadata — it does not use a shared account. So the semantic package produced by mcs build only covers the tables you can see; building with a different AK will produce a different package. This is why the wizard's first step asks about auth: it determines the scope of everything that follows.
Next steps [01] Quick Start gets you running in 5 minutes; for a deep dive into profile resolution chains / cwd bindings / versioning, see [02] Profile.

[01]Quick Start

5 minutes, from zero to your first SQL.

1.Install mcs

Letting the agent install it is the fastest path — it will also set up the skill. Send this message to your agent:

agent> Install mcs for me, read this guide fully then follow step by step: curl -fsSL https://raw.githubusercontent.com/aliyun/maxcompute-semantic/main/scripts/install.md

Or install it yourself:

$ uv tool install maxcompute-semantic

After installation, run mcs --version to verify. If ~/.local/bin is not in your PATH, you need to add it (see README).

2.Create a profile

One business scenario maps to one profile, answering "who am I + which tables do I see". See [00] Concepts for details.
$ mcs profile create

The wizard will ask: profile name, target MaxCompute project, AK or passwordless auth, endpoint region. All fields can be changed later (mcs profile update).

For AK auth, prefer environment-variable references or ProcessAuth/ncs. For non-interactive literal-AK setup, pass --ak-literal with --ak-id and pipe one secret line with --ak-secret-stdin; avoid --ak-secret unless shell-history exposure is acceptable.

Once bound, mcs commands in this directory will default to this profile — the agent will too — no need to pass --profile every time.
$ cd ~/work/my-data-project
$ mcs link bind <profile-name>

Check / unbind: mcs link status, mcs link unlink.

4.Run a build (generate the semantic package)

Scans all tables covered by the profile and generates the local knowledge base the agent reads before writing SQL — table schemas, sample data, JOIN relationships, and UDFs are all included. Takes a few minutes; afterwards the agent does not need to query MaxCompute metadata on every request.
$ mcs build

After it finishes, run mcs status --tables to see the number of tables / columns / JOINs collected. If table schemas changed, mcs build --refresh only updates modified tables. Not a required step: you can skip it — without a semantic package the agent uses cold-start mode (mcs meta list-tables / describe-table) to query metadata live — it works but is slower each time.

5.Start asking

The agent reads the semantic package from the previous step to write SQL, then runs mcs sql cost for cost estimation and mcs sql execute for execution. mcs build is a one-time onboarding step and does not appear in the query flow.
agent> Use mcs to query last month's GMV from the orders table

The agent will automatically call mcs sql cost for cost estimation, mcs sql execute for execution, and summarize the results in plain language. If you want to verify, you can run mcs sql execute "..." directly in the terminal.

Next steps To understand the profile resolution mechanism (multi-profile / cwd binding / which environment variable takes precedence), see [02] Profile. To jump straight to running SQL accurately and cost-effectively, go to [03] Core Queries.

[02]Profile: Identity, Organization, and Versioning

A profile is mcs's single abstraction for "who am I, where do I connect". One profile contains: a MaxCompute compute project, an endpoint, an auth method (AK / passwordless), a list of sources to scan (each source is a set of project.schema.tables), and cost thresholds.

profile ──build──▶ semantic package ──reads──▶ agent writes SQL
   │
   └─ scopes a business scenario (a set of sources + an identity + associated annotations/memory)

2.1Resolution chain: which profile is active?

Every mcs command resolves the profile in this order, using the first match:

  1. Explicit --profile X flag
  2. Environment variable MCS_PROFILE
  3. Current directory's mcs link bind binding
  4. Standard ODPS environment variable quartet (ALIBABA_CLOUD_ACCESS_KEY_ID, etc.) — constructs an in-memory temporary profile

To see which profile is currently active: mcs profile show.

2.2Create: wizard and multi-source DataSource

$ mcs profile create

The interactive wizard walks you through: name, compute project, endpoint, auth, and sources to include in the semantic package. A profile can have multiple sources (e.g., scanning both dwd and ads from the data warehouse, or spanning two projects) — mcs build processes all sources in a single pass. In the agent flow, the wizard first asks what scenario this semantic package should address (business questions, domain, metrics of interest) and stores it as the profile's description; when selecting tables, the agent recommends candidates from mcs meta list-tables results based on this scenario description — you add or remove from those candidates instead of picking blindly from hundreds of tables. mcs build writes this description into the semantic package's _overview.md.

For AK auth, prefer environment-variable references or ProcessAuth/ncs. For non-interactive literal-AK setup, pass --ak-literal with --ak-id and pipe one secret line with --ak-secret-stdin; avoid --ak-secret unless shell-history exposure is acceptable.

To reuse maxc / odpscmd configuration, run mcs profile import-creds. If the external configuration uses a non-ncs ProcessAuth helper, the CLI will display the full command and require explicit trust; after confirming the local command is safe, import with --trust-process-command.

Already created a profile and want to change fields:

$ mcs profile update <name>

Opens a multi-level picker: compute_project / endpoint / auth / cost_thresholds / tags / sources — select a row to edit it.

Bind a directory to a profile so that mcs commands in that directory default to that profile:

$ cd ~/work/biz-A
$ mcs link bind biz-A-prod
# All mcs commands in this directory now default to the biz-A-prod profile

Check / unbind: mcs link status, mcs link unlink. The binding maps the current directory to a profile name, follows the working directory, and persists across shell restarts.

2.4Inspect and switch: show / whoami

CommandWhat it shows
mcs profile listNames of all profiles on this machine
mcs profile show [name]Static config (compute project / sources / thresholds / version) — no network call
mcs profile whoami [name]Live ODPS query for "which RAM principal am I right now" — hits the server every time

Use whoami to debug "which principal does my AK resolve to"; use show to just view the config.

2.5Versioning: log / diff / fork / reset

Each profile's data directory is an independent git repository. Every write from mcs build / package apply/reject / memory / udf / profile import is auto-committed.

$ mcs profile log -n 10           # last 10 writes
$ mcs profile diff HEAD~1 HEAD     # what changed in the last write
$ mcs profile reset --to HEAD~1    # rollback a mistake
$ mcs profile fork exp --from HEAD # branch off for A/B testing

To disable auto-versioning (e.g., in CI batch runs), set the environment variable MCS_NO_VERSIONING=1 — writes still happen but are not committed.

2.6Export and share: profile export

Package a profile's semantic package into a single file for sharing with colleagues or migrating machines. The default output is mcs's own tar.gz archive, which can be restored as-is with mcs profile import.

$ mcs profile export <name>                  # defaults to ./<name>.tar.gz
$ mcs profile export <name> --osi            # emit OSI YAML instead

With --osi, the same command emits OSI (Open Semantic Interchange) YAML instead of a tar.gz archive — useful for feeding the profile's semantic model into external OSI-aware tooling. Output conforms to OSI core schema v0.2.0.dev0. The mcs-native tar.gz export is still the default; --osi opts into the YAML path.

[03]Core Queries: build · package · sql

The main workflow in mcs: first build a semantic package; semantic suggestions generated during build enter the package proposal queue for review then apply; finally use sql to execute, estimate costs, and view execution plans.

3.1mcs build: when to run, --refresh / --fresh / --parallel

Scans all tables covered by the profile's sources list, samples a few rows, infers JOIN relationships, discovers UDFs, and writes them to the local semantic package. The agent reads this package before writing SQL to avoid unnecessary detours.

$ mcs build                  # full build on first run; resumes from where it left off if interrupted
$ mcs build --fresh          # force a full rebuild from scratch, ignoring resume state
$ mcs build --refresh        # incremental: rebuild tables whose schema or data changed (also catches up interrupted tables)
$ mcs build --refresh --refresh-min-age-hours 6  # throttle data-change resampling: only resample if last sample is older than N hours (default 24, 0 = no throttle)
$ mcs build --parallel 8     # sample 8 tables concurrently (default auto = min(table_count, 32))
When to run Run once after creating a profile; if interrupted mid-build, just run mcs build again to resume; run --refresh after upstream table schemas or data change (resamples tables with modified data; --refresh-min-age-hours controls resampling frequency); use --fresh to start a full rebuild from scratch ignoring resume state. mcs status --tables shows data_modified_at / last_sampled_at to see which tables lag behind their source. Day-to-day queries do not require repeated builds.
Review semantic suggestions after build mcs build generates explainable semantic suggestions but does not directly modify the semantic layer by default. When the agent runs post-build enrichment, it first converts these suggestions into mcs package proposals for you to review the evidence before applying or rejecting.

3.2mcs package: review semantic suggestions from build

After build / refresh, the agent can place high-confidence suggestions derived from samples, historical SQL, and column distributions into the proposal queue. It can also submit reviewed ai_context, column descriptions, and column role corrections as YAML proposals. A proposal is a "pending patch": you can see the target columns, suggested content, evidence, and confidence; only after apply does it write to the semantic package, and reject records the decision too.

$ mcs package propose --from-suggestions
$ mcs package propose --from-stdin      # create ai_context / column_description / column_semantics proposals from YAML
$ mcs package list-proposals
$ mcs package show-proposal <id>
$ mcs package apply <id>
$ mcs package reject <id> --reason "not correct for this domain"

This is the default path for generative semantic suggestions: first propose --from-suggestions, then use propose --from-stdin to add agent-reviewed table semantics, column descriptions, or role corrections; if a previously rejected agent YAML proposal needs correcting in the same enrichment round, --from-stdin puts it back into the suggested queue. Then review each one with show-proposal to see the evidence, apply the correct ones, and reject those that do not match business definitions with a reason. The agent's enrich runtime skill also follows this path.

Why use a proposal queue Automated suggestions are often "plausible" but may be off by an enum value, a granularity level, or a time field in business terms. Proposals add a review gate between generating suggestions and writing to the semantic layer, and the profile's auto git history also records the apply / reject decisions.

3.3Semantic annotations: all via the proposal queue

All semantic annotation writes go through mcs package propose → review → mcs package apply; there is no direct-write entry point. The business semantics you can annotate include:

  • ai_context — what this table is for (a natural language description)
  • dimensions / measures / identifiers — role classification for columns
  • Per-column semantic_description — what this column means (a semantic explanation, not a restatement of the column name)
$ mcs package propose --from-stdin # submit a semantic annotation proposal for review
$ mcs package list-proposals # view the review queue
$ mcs package apply <id> # write after approval

See which tables are annotated: mcs status --tables — the last column shows Annotated: yes/no/partial.

3.4mcs metric: top-down named business metrics

Explicitly register algorithms like "total paid order amount per user per month" that have a business name and are used repeatedly, so they can be reused directly next time without re-composing the SQL. A metric is profile-global with UNIQUE(name) — even across sources there can be only one total_revenue.

$ mcs metric add total_revenue --expression "SUM(orders.amount)"
$ mcs metric list
$ mcs metric show total_revenue
$ mcs metric edit total_revenue --description "..."
$ mcs metric remove total_revenue
measure vs metric --role measure is a column-level attribute ("this column can be SUMmed"); mcs metric add is a top-level entity ("this number has a business name"). The two do not conflict: measures are tagged on columns, metrics are registered at the profile level.

Bulk import is also supported: mcs package propose --from-stdin accepts a top-level metrics: list (alongside tables:) and writes them via the proposal queue after review.

OSI export (mcs profile export --osi) writes these metrics to semantic_model.metrics[], so downstream OSI tools can read them directly.

3.5mcs sql: review / execute / async / cost / explain

These verbs cover every "run SQL" scenario:

CommandPurposeWhen to use
sql reviewLocal static SQL review (no MaxCompute round-trip)Scan before execute to avoid wasting a round-trip on basic errors
sql executeSynchronous execution with resultsProbes, small result sets, queries with clearly low cost
sql submit/status/wait/result/cancelAsync submit and poll MaxCompute instancesProduction analysis, large table JOINs/aggregations, queries that need cost confirmation or may time out
sql costCost estimate + pass/fail verdictCheck before running large-table queries
sql explainExecution planWhen optimizing SQL
$ mcs sql review  "SELECT IIF(x > 0, 1, 0) FROM orders"
# → issues[0].rule = dialect.sqlite-iif · suggests rewriting to CASE WHEN
$ mcs sql execute "SELECT COUNT(*) FROM orders WHERE ds = '20260520'"
$ mcs sql submit -y "SELECT * FROM big_a JOIN big_b ON big_a.id = big_b.id"
$ mcs sql wait <instance_id>   # check lifecycle_state / successful
$ mcs sql result <instance_id> # fetch rows after lifecycle_state == "success"
$ mcs sql result --offset 10000 <instance_id> # fetch next page when has_more=true
$ mcs sql cost    "SELECT * FROM orders"
# → verdict: confirm · cost 12.4 CNY · full scan on large table, consider adding partition filter
$ mcs sql explain "SELECT ds, SUM(amount) FROM orders GROUP BY ds"
review outputs two layers issues (error / warning — dialect incompatibilities, missing tables/columns, and other hard errors) and hints (info — undeclared JOINs, dimensions used in aggregations, and other "possible misuse" notes). The agent workflow is: first review and fix all issues, check hints to decide whether to proceed, then run execute; this step does not consume MaxCompute quota.
review works without a semantic package An un-built profile returns review_mode: syntax_only and semantic_checks_skipped: true, still checking SQLite dialect issues, unsupported functions, bare table names in 3-level projects, and other checks that do not depend on the semantic package; table/column existence, JOIN/aggregation, and other semantic checks are skipped. Do not run mcs build mid-query just to complete the review.
cost verdict has three levels ok (below confirm_cny threshold, safe) / confirm (between confirm and blocked — the agent will ask the user to confirm) / blocked (above blocked_cny — the agent will not execute by default). Defaults: confirm=10 CNY, blocked=100 CNY; change thresholds via mcs profile update under cost_thresholds.
execute / submit are read-only by default mcs sql execute and mcs sql submit reject DML/DDL, SET session mutations, and statements that cannot be identified as read queries by default; pass --allow-write only when the user explicitly requests a write, and the cost gate still applies.
Choose execution method by verdict and SQL shape Do not let the agent guess "short query": blocked is not executed; for confirm, ask the user first, then prefer submit / wait / result after confirmation; for ok, also check the SQL shape — only use execute for probes, small results, explicit small LIMIT, or tight partition lookup/aggregation. Production analysis, large table scans/JOINs/aggregations, SQL without tight partitions or LIMIT, and previously timed-out SQL should use async even with ok. For async results, check lifecycle_state, successful, and task_statuses; confirm lifecycle_state == "success" before fetching rows.
Results default to a maximum of 10,000 rows sql execute and sql result do not rewrite the submitted SQL or automatically add LIMIT; they only paginate on the reader output side. JSON responses include result_max_rows, result_offset, has_more, truncated, and next_offset. Pass --offset <next_offset> for the next page, --max-rows N to adjust page size, or --max-rows 0 to disable the limit.

Note: mcs sql cost returns exit code 0 even when blocked — the verdict is in the verdict field of the JSON output. Scripts should read the field, not the exit code.

3.6--project / --schema / --profile usage

These three flags have completely different meanings and are easy to confuse:

FlagMeaningWhen to pass
--profile XWhich local profile config to useWhen cwd is not bound / when you want to temporarily switch profiles
--project PTarget MaxCompute projectWhen the profile spans multiple projects and you want to specify one
--schema SSchema name for 3-level projectsAlmost never — mcs auto-detects and caches; only as a fallback when detection is wrong

The difference between 2-level projects (no schema) and 3-level projects is handled automatically by mcs — you write orders and it becomes my_proj.orders or my_proj.default.orders as appropriate.

[04]Advanced: memory · udf · meta

This section is for users who have completed the main workflow and want mcs to get more accurate over time.

4.1memory: verify / fail / note / recall

Memory is the query experience store. Every question asked and every mistake made can be recorded, providing reference for similar questions next time. Three write verbs + one read verb:

VerbPurpose
memory verify --question Q --sql S --tables T1,T2Record a "question → correct SQL" entry
memory fail --question Q --sql S --error-msg MRecord a "this SQL failed + error message" entry — the agent will avoid similar patterns next time
memory note '<TEXT>'Record free-form domain knowledge (not necessarily SQL)
memory recall '<keyword>'BM25 + vector hybrid search across all three entry types
$ mcs memory verify \
    --question "last month's GMV" \
    --sql "SELECT SUM(amount) FROM orders WHERE ds BETWEEN '20260401' AND '20260430'" \
    --tables orders
$ mcs memory recall "GMV"

Management: memory list to view all, memory show <id> to view one, memory remove <id> to delete one, memory clear to clear all (by default only clears user-written entries, not auto-generated ones).

Disable during benchmarks When running benchmarks (e.g., Bird NL2SQL), set MCS_NO_HISTORY=1 to prevent historical experience from leaking answers — mcs build's history miner phase will be skipped.

4.2udf: list / show / search / create / test / remove

Read side (anyone can run):

$ mcs udf list
$ mcs udf show parse_user_agent
$ mcs udf search "json"

Write side (requires confirmation / write permissions):

$ mcs udf create my_fn --inline-python my_fn.py --description "parse order number prefix"
$ mcs udf test   my_fn --args '1, "abc"'
$ mcs udf remove my_fn --delete-resources

udf test --args only accepts literals: numbers, NULL, TRUE/FALSE, and quoted strings; it will not splice bare identifiers, expressions, or semicolon fragments into SQL. Currently create only supports inline Python; for jar / resource-based UDFs, use mcs sql execute --allow-write 'CREATE FUNCTION ...', which still requires user confirmation and goes through the cost gate.

4.3meta: list-tables / describe-table

A "raw" interface that queries MaxCompute metadata directly without depending on the semantic package. Use during cold start (no build yet) or to inspect tables not in the sources list:

$ mcs meta list-tables --project my_proj
$ mcs meta describe-table --project my_proj orders

For tables that have already been built, mcs show --table orders is better — it includes sample SQL, JOIN relationships, and annotations, representing the "crystallized" version from the semantic package.

[05]Operations and Troubleshooting

Refer to this section when something goes wrong, when setting up on a new machine, or when you need to check the environment state.

5.1mcs doctor: one-command diagnostics + JSON output

A single command that checks everything — profile / auth / network / semantic package / skill installation:

$ mcs doctor                # full check, including network
$ mcs doctor --offline      # skip ODPS probe, check local config / package / skill only
$ mcs -f json doctor        # JSON output for agent parsing, includes per-check remediation

Typical usage: run mcs doctor after installation to see all green; when something breaks, run mcs -f json doctor first to see which check is red. The agent will use the remediation field in the JSON to guide you through the fix step by step.

5.2skill install: 55 platforms, --all / --detect

Symlinks SKILL.md into your agent tool's skills directory. A symlink rather than a copy, so when mcs is upgraded the skill auto-syncs with no version drift.

$ mcs skill install                       # default: project-level .agents/skills/
$ mcs skill install -g                    # global (~/.agents/skills/)
$ mcs skill install -p claude-code -g     # Claude Code global
$ mcs skill install --all                 # install to all 55+ platforms
$ mcs skill install --detect              # install only to detected agents on this machine

Common platform mappings:

Agent-p name
Universalagents (default)
Claude Codeclaude-code
Cursorcursor
OpenAI Codexcodex
Gemini CLIgemini-cli
Qwen Codeqwen-code
OpenCodeopencode
Windsurfwindsurf
Traetrae

Full 55+ platform list: mcs skill list. Other operations: mcs skill update / uninstall / path / diff.

Runtime skill is served by the CLI The SKILL.md installed to the agent is now a thin discovery stub; the actual workflow is output by mcs skill get query / build / enrich commands matching the current mcs version. When answering data questions, only the query skill is loaded; the build skill is only loaded when explicitly building or refreshing the semantic package, to prevent the query flow from mistakenly running mcs build.
$ mcs skill catalog
$ mcs skill get query
$ mcs skill get query --full
$ mcs skill get build

5.32-level vs 3-level tier auto-detection

MaxCompute projects have two addressing modes: 2-level (project.table) and 3-level (project.schema.table). The first time mcs accesses a project, it auto-detects the tier and caches the result in tier_cache/<project> — no need for SET odps.namespace.schema or --schema afterwards.

If detection was wrong and you want to force re-detection: delete the one-byte file at ~/.local/share/maxcompute-semantic/data/<profile>/tier_cache/<project>. As an extreme fallback: all mcs commands accept --schema S for explicit override.

5.4Common environment variables

VariablePurpose
MCS_PROFILEResolution chain tier 2: specifies a profile when cwd is not bound and --profile is not passed
MCS_NO_HISTORY=1Skip mcs build's history mining — required when running benchmarks
MCS_NO_VERSIONING=1Disable profile auto git commit — useful for CI batch runs
MCS_DATA_DIROverride the local data directory (default ~/.local/share/maxcompute-semantic/)
ALIBABA_CLOUD_ACCESS_KEY_ID and the other threeResolution chain tier 4: fallback when not using profiles at all

Truthy values are case-insensitive: 1 / true / yes / on.

[06]Agent Conversation Scripts

Once mcs has the skill installed, talking to your agent is all you need — the agent will automatically invoke mcs commands. This section provides templates for "what to say".

6.1Triggering the skill

Most agents auto-load the maxcompute-semantic skill when they see keywords like these:

  • Mention the brand name: "use mcs", "use maxcompute", "use ODPS"
  • Explicitly invoke the skill: "/maxcompute-semantic ..." (agents that support slash commands like Claude Code / Codex)
  • Verb triggers: "query", "create table", "calculate", "get stats on" + one of your MaxCompute table names

If the agent does not load the skill (and generates non-runnable SQL instead), the most reliable fallback is to say explicitly: "Please load the maxcompute-semantic skill and then answer."

6.2Common task examples

agent> Use mcs to query last month's GMV from the orders table
agent> What is the products table on ODPS for? What do the fields mean?
agent> Do you remember the DAU formula I asked about last time? Re-run that SQL
agent> Estimate how much this SQL will cost: <paste SQL>
agent> Save the SQL that just worked to mcs memory, with the question "monthly active users"

The agent will call sql cost for cost estimation, use sql execute for probes and small-result queries, or use sql submit / sql wait / sql result for production analysis, cost confirmation, and queries that may time out; it will also use show --table to inspect structure, memory recall to find history, and memory verify to save new experience.

6.3Have the agent report bugs / run diagnostics

agent> Report an mcs bug for me: <describe the symptom>
agent> Run an mcs environment check

When reporting a bug, the skill follows the Aone work-item convention — it auto-adds the [maxcompute-semantic] prefix, sets the related project to 2155299, and attaches the version number and doctor output. An environment check runs mcs -f json doctor and explains any red items in plain language.