Operate, O&M, and Manage Alibaba Cloud
Observability (MUST follow for every aliyun command)
Before any cloud API invocation, read references/manifest.json from this skill's root and use only its top-level non-empty string version as {skill-version}. If missing or invalid, STOP. NEVER invent, guess, or reuse a version from another skill.
Bind version and session to the current skill name and skill root. Before this skill's first cloud API invocation in a conversation, generate a fresh random 32-character lowercase hexadecimal session ID. Reuse that session ID for this skill throughout the conversation; each skill MUST use a distinct session ID. NEVER copy one from documentation, examples, another skill, or a previous conversation, and NEVER send the literal {session-id} placeholder. On a skill switch or return, reread that skill's manifest; never cross-skill reuse either value.
Rule: Every aliyun CLI command that calls a cloud API MUST include the --user-agent flag.
Markdown examples may omit the flag for brevity. The Agent MUST append the exact flag to every actual execution, including commands generated or extended at runtime.
Attach the User-Agent at the remote cloud-call boundary:
CallCLI: put--user-agent "..."inside the JSONcommandfield, as part of its Alibaba Cloud CLI string. NEVER pass--user-agentas an argument tomcpx.py; that is a local usage error (exit code 2).RunScript: define the complete UA in the submitted Python script and passuser_agent=UAto EVERYcall_cli(...)invocation. Environment variables supplied to the localmcpx.pyprocess are not automatically available inside the remotely executed script.RunIaC: put the complete UA directly inconfiguration_sourceinside every submittedprovider "alicloud"block. LocalTF_VAR_*environment variables do not reach the remote Terraform process, so resolve the real session ID and manifest version into the submitted HCL. AnapplyordestroyusingpreviousProcessIdreuses that planned code.
Local utility commands (e.g. configure, plugin, version) do not support this flag
and should be excluded.
--user-agent "AlibabaCloud-Agent-Skills/alibabacloud-mcp-connector/{session-id} skill-version/{skill-version}"
Runtime templates:
mcpx call CallCLI '{"command":"aliyun ecs describe-regions --region cn-hangzhou --user-agent \"AlibabaCloud-Agent-Skills/alibabacloud-mcp-connector/{session-id} skill-version/{skill-version}\""}'
UA = "AlibabaCloud-Agent-Skills/alibabacloud-mcp-connector/{session-id} skill-version/{skill-version}"
result = await call_cli(product="Ecs", action="DescribeRegions", params={}, user_agent=UA)
provider "alicloud" {
region = "cn-hangzhou"
configuration_source = "AlibabaCloud-Agent-Skills/alibabacloud-mcp-connector/{session-id} skill-version/{skill-version}"
}
SKILL_SESSION_ID={session-id} SKILL_VERSION={skill-version} uv run --python 3.11 scripts/mcpx.py doctor
Confirm with the user before changing anything
Read-only work needs no permission: queries, doc lookups and API discovery run straight away. But before any call that creates, modifies, deletes or costs money, state in plain language what is about to change — product, region, resource identifiers, action — and wait for the user's explicit go-ahead. A general request such as "clean up the idle machines" is not approval for a specific deletion; RunIaC apply / destroy and every mutating CallCLI or RunScript still need one. If the user has not answered yet, do not proceed.
When to use
Use this whenever you need to do anything with Alibaba Cloud. The 15 tools cover the full path from "figure out how" to "verify it is done":
| Goal | Main tools | What they do |
|---|---|---|
| Operate — perform a concrete action | CallCLI | First choice. Run Alibaba Cloud CLI/API commands to create, read, update, delete resources of any product |
| O&M — batch and multi-step | RunScript + GetTask | One Python script handles many resources / multi-step flows; poll async tasks to a terminal state |
| Manage — infrastructure orchestration | RunIaC + GetTask | Terraform HCL, plan → apply → destroy, with state management |
| Find the right API | SearchApis ListApis GetApiDefinition GenerateCLICommand ListProducts ListProductRegions | Unsure which API, how to pass parameters, which regions are available |
| Look up authoritative docs | SearchDocuments GetDocument GetDocumentTree GrepDocuments | Official doc search, per-product retrieval, full text |
| Transfer files | GetPresignedUrl | OSS presigned URL, to pass large files into RunScript / RunIaC |
What "best-practice path" means:
- If unsure, confirm parameters with
GetApiDefinitionor the docs first, then runCallCLI— do not guess-and-try - Do batch operations in one
RunScriptrun, not by loopingCallCLI - Do infrastructure changes via
RunIaCplan-then-apply (see the diff before landing), not scattered commands - Read calls carry
x_output_jmespath_filterby default; do not push a 50KB raw response into context - For Alibaba Cloud official documentation, use
SearchDocuments/GetDocument/GetDocumentTree/GrepDocuments— neverweb_search, and never scrapehelp.aliyun.comviaweb_fetch. These tools query the official Alibaba Cloud doc corpus directly, scoped by product, and are authoritative and current; web searching/scraping is unscoped, slower, and may return outdated or third-party content. This holds even for a pure "search the docs" request with no resource operation involved.
The capability comes from alibabacloud.mcp-proxy, exposed as local commands by scripts/mcpx.py, covering all Alibaba Cloud product lines.
No MCP configuration is needed — so it also works in environments where mcpServers cannot be injected into the agent client. It keeps no resident process; each call is reclaimed when done.
Mandatory: route every cloud operation through mcpx
When this skill is active, every Alibaba Cloud operation goes through mcpx call <Tool> (tool mapping: see "When to use" and "Selection order"). Do not bypass it with direct tools — even when a direct tool seems simpler and would also work. Bypassing skips the proxy's authentication, transport, validation, cost preview, and observability, and is out of scope for this skill:
- No direct
aliyunCLI in the shell. Wrap it:mcpx call CallCLI '{"command":"aliyun ..."}'. (The onlyaliyunyou run directly is none —mcpx login/mcpx doctoralready wrap it.) - No cloud SDKs and no hand-rolled request signing — that includes Alibaba Cloud SDK packages (
oss2,alibabacloud-*,aliyun-python-sdk-*) and any code that computes a signature itself. For a presigned URL usemcpx call GetPresignedUrl; for custom logic usemcpx call RunScript. - No local
terraform. Usemcpx call RunIaC(plan → apply → destroy) +mcpx call GetTask. - No
web_search/web_fetchfor Alibaba Cloud docs. Usemcpx call SearchDocuments/GetDocument/GetDocumentTree/GrepDocuments.
If a task seems doable with a direct CLI/SDK/terraform/web call, it is still in scope here — do it through the matching mcpx call <Tool> instead.
Prerequisites
| Dependency | Purpose | Required to call tools | Required to set up credentials first time |
|---|---|---|---|
| uv / uvx | Starts the service and provides the Python runtime (no system Python needed) | Yes | Yes |
| Alibaba Cloud identity | Authentication | Yes | — |
| Network egress | Downloads dependencies on first run | First run | Yes |
| aliyun CLI | Configures credentials | No | Yes |
The aliyun CLI row is easy to misread: calling tools does not need it (calls execute remotely), but login hard-depends on it. So in an environment with no credentials yet, it is required to get started; the real dependency chain is:
doctor (no credentials) → install aliyun CLI → login → doctor passes
Only when credentials are already in place (~/.aliyun/config.json exists, or on ECS via the metadata service) is it truly optional.
doctor tells you what is missing. In an environment where uv is absent and there is no network egress, it cannot run — do not retry repeatedly; state the situation directly.
Step 1: mandatory self-check
uv run --python 3.11 scripts/mcpx.py doctor
Do not attempt any tool call before the self-check passes. Credential problems surface at the handshake stage; forcing a tool call only yields a meaningless error.
doctor checks in order: MCP server command availability → Python runtime → credential source → handshake connectivity → current identity (AccountId / Arn / IdentityType).
First-time setup
Step 1: run doctor to see what is missing
Step 2: install uv if missing
curl -LsSf https://astral.sh/uv/install.sh | sh
Step 3: install the aliyun CLI if missing
Most environments do not have it.
macOS / Linux (auto-detects architecture):
/bin/bash -c "$(curl -fsSL --connect-timeout 10 --max-time 120 https://aliyuncli.alicdn.com/setup.sh)"
Windows (PowerShell; writing the Machine-level PATH needs admin rights):
# Download
Invoke-WebRequest -Uri "https://aliyuncli.alicdn.com/aliyun-cli-windows-latest-amd64.zip" -OutFile "aliyun-cli.zip"
# Extract
Expand-Archive -Path aliyun-cli.zip -DestinationPath C:\aliyun-cli
# Add to PATH: read the Machine scope, then append
$machinePath = [Environment]::GetEnvironmentVariable("Path", "Machine")
[Environment]::SetEnvironmentVariable("Path", "$machinePath;C:\aliyun-cli", "Machine")
# Verify in a new terminal
aliyun version
On Windows, do not use
$env:Path += ...and then write the whole$env:Pathback to the Machine scope. In PowerShell$env:Pathis the merged Machine+User value, so writing it back permanently copies user-level entries into the machine level, bloating it on every run. The form above reads Machine only and appends, avoiding this.
After installing, confirm aliyun version is >= 3.3.3. On Windows you must open a new terminal to see the PATH change.
This modifies the system. Get the user's explicit consent before running it on their behalf. If they decline, give them the command to run themselves.
The aliyun CLI is only needed to configure credentials — it is not a runtime dependency; tool calls execute remotely.
Step 4: log in (only if doctor reports no usable credential)
Skip this when doctor already passed — a passing handshake means a working credential (AK/SK, OAuth token, STS, or an ECS RAM role) is already in place and in use; do not re-login. Only log in when doctor reports no credential, or an invalid/expired one. (A 403 at the handshake is a missing RAM permission, not a credential problem — re-login does not fix it; see Troubleshooting.)
uv run --python 3.11 scripts/mcpx.py login --region cn-hangzhou
Run this in the background. It waits for a human to click authorize in a browser, so the duration is unpredictable: about 5s when the browser already has an authorized session, or it waits until timeout when nobody authorizes. A foreground blocking call will hang.
It overwrites credentials. Without
--profile,loginconfigures the currently active aliyun profile, replacing its existing credentials. Before starting,loginprints即将配置 aliyun profile: X— relay this line to the user and get confirmation that overwriting is OK. To write elsewhere, use--profile NAME.
login auto-answers all terminal prompts and prints the authorization URL immediately. As soon as you read the URL from the output, relay it to the user and ask them to complete authorization in the browser. The user clicks once; everything else is automatic.
Also remind the user: whichever identity is logged into the browser is the identity that gets authorized. If the browser is logged into the primary account, the resulting credentials are the primary account's — which conflicts with the "use a least-privilege RAM user" principle. After login, check IdentityType with doctor.
Optional flags: --profile (defaults to overwriting the active profile), --region (default cn-hangzhou), --site cn|intl (default cn), --timeout (default 180s). Use --site intl for the international site.
Step 5: verify
uv run --python 3.11 scripts/mcpx.py doctor
When the [5] identity line prints real account info, you can start calling tools.
Servers without a browser
The OAuth callback address is 127.0.0.1:12345 on the machine running the command. On a remote server, copying the URL to a local browser cannot reach the callback. Two options:
- SSH port forwarding:
ssh -L 12345:127.0.0.1:12345 user@host, then runlogin - Skip OAuth: on ECS, bind a RAM role to the instance (no keys or files needed), or have the user run
aliyun configure --mode AKin their own terminal
Credential security baseline
Every tool call (CallCLI / RunScript / RunIaC) authenticates server-side through the proxy's credential chain (the ~/.aliyun/config.json / env / ECS-metadata source that doctor reports). You never need to read, set, pass, inspect, or debug credentials yourself — and you must never expose them. These five are non-negotiable:
- Never ask the user to paste AK/SK into the conversation. Once pasted, the secret enters the session record and logs. To configure a key, output a command and let the user run it in their own terminal.
- Never print, echo, log, or dump credential values — including the credential env vars
ALIBABA_CLOUD_ACCESS_KEY_ID/ALIBABA_CLOUD_ACCESS_KEY_SECRET/ALIBABA_CLOUD_SECURITY_TOKEN: do notenv/printenv/os.environthem, and do not write code that reads or prints them. Do not turn on verbose/debug logging that surfaces auth headers (TF_LOG=debugfor Terraform, HTTP-client debug,aliyun --debug) — these print the livex-acs-security-token/Authorizationvalue into the transcript. When diagnosing, report only "set / not set", plus the identity returned byaliyun sts get-caller-identity. - Never write credentials to any file. Not into this skill directory, not into files you create, not into logs. When the user needs to create
~/.aliyun/config.jsonby hand, the user does it. - Never put credentials into any tool argument — not the
commandstring ofCallCLI, not thecode(HCL) ofRunIaC, not thescriptofRunScript. All of them are sent to the remote gateway and may be logged. ForRunIaCspecifically, do not putaccess_key/secret_keyin theprovider "alicloud"block — credentials are injected automatically server-side; the provider block only needsregion(plus the UAconfiguration_source). - Use a least-privilege RAM user, not the primary account's AK.
Two more prohibitions:
- Do not run
aliyun configure set --access-key-secret <value>: command-line args are visible to other processes on the same machine (ps) and land in shell history. - Do not put
export ALIBABA_CLOUD_ACCESS_KEY_SECRET=...into~/.zshrc: a long-term key in plaintext on disk is worse than a~/.aliyun/config.jsonwith 600 permissions.
How the credential chain resolves (and its trap)
Priority is environment variables → ~/.aliyun/config.json → ECS metadata service. Two consequences:
- An
exportthe user ran in some other terminal never reaches this script: the script is started by the agent, in a different process tree, inheriting the agent's own environment. Explain this, then guide them tologin. - But any
ALIBABA_CLOUD_*var that is present in the agent's own environment outranksconfig.json. If that set is incomplete — for instance an STS identity whoseALIBABA_CLOUD_SECURITY_TOKENis set but empty — the proxy still signs with it and the gateway rejects the signature, even thoughconfig.jsonholds a valid credential that is never reached. Telltale sign: the gateway's echoedCanonicalRequestcarries nox-acs-security-tokenheader.
Fix: unset ALIBABA_CLOUD_ACCESS_KEY_ID ALIBABA_CLOUD_ACCESS_KEY_SECRET ALIBABA_CLOUD_SECURITY_TOKEN so the chain falls back to config.json, or set them to valid values. Then re-run doctor.
On any signature or authentication failure, diagnose with mcpx doctor — never print or dump the credential env vars. doctor reports set / not set, without exposing any value.
Three invocation commands
Below, mcpx stands for uv run --python 3.11 scripts/mcpx.py; see references/examples.md for how to define it as a shell function.
# List all tools
mcpx list
# Print a tool's input schema
mcpx schema CallCLI
# Call a tool
mcpx call CallCLI '{"command":"aliyun ecs describe-regions --region cn-hangzhou"}'
# When the argument contains double quotes, pass it via - from stdin to avoid escaping
echo '{"command":"aliyun ossutil ls oss://my-bucket --include \"*.log\""}' \
| mcpx call CallCLI -
# Tools with no required parameter can omit the argument
mcpx call ListProducts
Use the short tool name (CallCLI); the script auto-prepends the AlibabaCloud___ prefix. The full name is also accepted.
stdout carries only the tool's returned payload, so it pipes cleanly to | jq. All diagnostics go to stderr.
Tool reference
The verbatim original description of all 15 tools and their parameters is in references/tool-reference.md. For the meaning and constraints of any parameter, that file is authoritative — consult it before calling a tool.
Verified examples
Copy-pasteable, run-verified examples for every tool — CallCLI, RunScript, RunIaC, the API discovery tools and the documentation tools, in both bash and PowerShell — are in references/examples.md.
Key behaviors of this script
These are behaviors of mcpx.py itself; the MCP tool descriptions do not cover them:
-
processIDis valid across processes. This script is one process per call. AprocessIDfromRunScript/RunIaCcan be picked up byGetTaskin any later new process — task state lives server-side. -
Save the
RunScriptreturn to disk before readingprocessID. It is at the start of the returned JSON; viewing withtailtruncates it, and losing the handle means re-running the whole task:mcpx call RunScript '{"script":"result = await call_cli(product=\"Ecs\", action=\"DescribeRegions\", params={})"}' > /tmp/start.json PID=$(python3 -c 'import json;print(json.load(open("/tmp/start.json"))["processID"])') echo "processID = $PID"PowerShell equivalent (reads the key with
ConvertFrom-Json, no systempython3):mcpx call RunScript '{"script":"result = await call_cli(product=\"Ecs\", action=\"DescribeRegions\", params={})"}' > $env:TEMP\start.json $PID_ = ($(Get-Content $env:TEMP\start.json -Raw | ConvertFrom-Json)).processID "processID = $PID_" -
--timeoutworks before or after the subcommand.mcpx --timeout 600 listequalsmcpx list --timeout 600. -
The script warns when a filter returns empty. See empirical finding 1 below. When you see the warning, actually re-check by calling bare; do not skip it as noise.
-
stdout is only the tool payload; all diagnostics go to stderr. So
| jqis always clean; to troubleshoot, read stderr.
Empirical findings not covered by the official descriptions
The verbatim descriptions are already complete — how to pass parameters, OpenMeta being the single source of truth, checking the definition first for an unfamiliar API, all nextAction states including the three approval states, how to write costManifest: the original text covers all of it; just follow it.
The following are not in the original text; all are empirically verified behaviors:
-
A wrong jmespath path silently returns
null, with no error. It is indistinguishable from "genuinely no data". Example:ListProductRegionsfor SLS with[].regionIdyieldsnull, while the response top level is an object and the correct path isdata.endpoints[].regionId. Treating thatnullas "this product has no region data" leads to borrowing another product's (e.g. ECS's) region list — the result: 7 regions never scanned, yet coverage reported as complete.The script warns, but the re-check must actually be done:
mcpx call ListProductRegions '{"product":"Sls"}' # remove the filter to see the real structure -
XML responses do not support filter. OSS's
ossutil api list-bucketsreturns XML; forcing a filter reproduces the silentnullabove. Save to disk and parse locally; judge pagination withgrep -E 'IsTruncated|NextMarker':mcpx call CallCLI '{"command":"aliyun ossutil api list-buckets --region cn-hangzhou --max-keys 1000"}' > /tmp/oss.xml uv run --python 3.11 python -c " import xml.etree.ElementTree as ET for b in ET.parse('/tmp/oss.xml').getroot().iter('Bucket'): print(b.findtext('Region'), b.findtext('Name')) " -
A jmespath key with non-ASCII or other non-identifier characters must be double-quoted.
{"总数": TotalCount}works,{总数: TotalCount}errors. -
The
CallCLIcommand form varies by product. ECS/VPC/RDS are OpenAPI-style; SLS and OSS are plugin-style kebab-case subcommands. Using the wrong form yields a misleading error that points at the version number and "contact support", even though the version is correct — the real cause is the command form. Get the authoritative command withGenerateCLICommandand use it verbatim; in the response preferunifiedCli, orcliif it is empty:mcpx call GenerateCLICommand '{"product":"Oss","apiName":"ListBuckets","apiVersion":"2019-05-17","regionId":"cn-hangzhou"}' # → aliyun ossutil api list-buckets --region cn-hangzhou (ossutil, not the deprecated oss command) -
Determine resource scope empirically; "no RegionId" does not imply "global". SLS and OSS both lack a RegionId parameter, yet their scopes are opposite:
| Product / API | Scope | Observed | |---|---|---| | SLS
ListProject| region-level | Hangzhou returns 55, Beijing returns 4, no overlap | | OSSListBuckets| account-global | one call returns 17 buckets across 4 regions |Test: call the same API in two regions. Results that vary by region and do not overlap ⇒ region-level; one call returning cross-region data ⇒ global.
-
Iterate regions with that product's own
ListProductRegions; do not borrow ECS's. SLS has 33 regions, ECS has 32; they do not coincide. -
The
RunScriptsandbox forbids dunder attribute access.type(exc).__name__is rejected (attribute not allowed: __name__); usestr(exc)for the error message. Wrappingcall_cliitself intry/exceptworks. -
paramsmust be passed explicitly as{}even when empty. Omitting it is rejected withBLK-4001(call_cli is missing required kwarg(s): ['params']). -
Pure Python logic (no
call_clicall) is rejected by the safety check, returningBLK-4002. Merely defining acall_clicall in the function body does not count as "reachable". -
Read a bulk job's errors one by one, distinguishing two classes:
| Error | Meaning | Data gap? | |---|---|---| |
endpoint not configured for product 'x' in region 'y'| no service endpoint in that region | No — there cannot be resources | |Forbidden/AccessDenied| permission problem | Yes — there may be resources you cannot see; must declare |So keep the full error text rather than recording only
True/False:errs[rid] = str(exc)[:200]
Selection order
- Known exact command →
CallCLI - Unsure of the API →
SearchApis→ListApis→GetApiDefinition - Looking up Alibaba Cloud official docs →
SearchDocuments/GetDocument/GetDocumentTree/GrepDocuments(notweb_search/web_fetch) - Batch or multi-step →
RunScript+GetTask - Infrastructure orchestration →
RunIaC
Full workflow for an unfamiliar product
The findings above are scattered rules. To query a product you have never touched (not ECS/VPC/RDS), follow the six steps in references/unfamiliar-product-checklist.md: read the parameter table → get the authoritative command → determine resource scope → use that product's own region list → run a probe → scale to the full set. That checklist also includes the "before drawing a conclusion" checks.
Troubleshooting
Exit codes
| Code | Meaning | Action |
|---|---|---|
| 0 | Success | — |
| 1 | Tool returned isError | Read the payload in stderr; usually a parameter or permission problem |
| 2 | Usage error | Misspelled tool name, invalid JSON. stderr lists the available tool names |
| 3 | Transport-layer or precondition failure | See below |
Cases of exit code 3
The stderr signatures below are quoted verbatim from what mcpx.py actually prints.
| stderr signature | Cause | Action |
|---|---|---|
| 找不到可执行文件 'uvx' | uv not installed | Setup step 2 |
| 未检测到可用的阿里云凭证 | No credentials and not on ECS | Setup step 4 (login) |
| 阿里云凭证无效 | Credentials expired or wrong | Re-run login |
| 凭证可用但被拒绝 | Missing RAM permission, see below | Request AliyunOpenAPIMCPServerStaticCredentialAccess |
| MCP 服务未响应即退出 | Unknown failure | Read the server's original text; also suspect RAM permission first, see below |
| 等待 MCP 服务响应超时 | First-run dependency download too slow | Increase --timeout; it works before or after the subcommand: mcpx call CallCLI '{...}' --timeout 600 or mcpx --timeout 600 call CallCLI '{...}' |
A sub-account must pass two independent gates
For a sub-account to use this skill, two unrelated things must both be in place. Confusing them sends you troubleshooting in the wrong direction:
| # | Gate | Decides | Who configures | Failure symptom |
|---|---|---|---|---|
| 1 | The official-cli third-party app is installed in the primary account, and the sub-account is added to its visitor list | Whether OAuth login works | Primary account / RAM admin only | The authorization page rejects directly, no terminal error, login waits until timeout (exit 3) |
| 2 | The sub-account has the AliyunOpenAPIMCPServerStaticCredentialAccess RAM permission | Whether it can connect to MCP after login | Primary account / RAM admin | login succeeds, but the handshake reports code: 403, You are not authorized to perform this action |
To tell which gate is stuck:
loginreports授权未在时限内完成→ go back and look at the browser page. Gate 1's error is only on the page; the terminal gets nothing.loginsucceeds but thedoctorhandshake fails → gate 2, see below.
Gate 1 page text (verbatim)
Accessing the authorization link with a sub-account that is not assigned to the app, the browser page shows:
账号未允许当前身份访问该应用。
将以下信息发送给 RAM 访问控制管理员,请管理员将当前访问身份添加至应用的访问者列表中。
访问身份
<子账号名>@<主账号UID>.onaliyun.com
应用管理地址
https://ram.console.aliyun.com/applications/4038181954557748008?appType=ThirdPartyApp
管理员配置后请刷新页面或重新访问应用。
At this point the terminal shows no error at all — you cannot click authorize, the callback never comes, and mcpx login can only wait until timeout. Do not assume it is a slow network and raise --timeout; that does not fix it.
Ask the user which situation applies. Both fixes need a primary-account / RAM administrator; the sub-account cannot do either itself.
Situation A — the primary account has never installed the official-cli app. The administrator installs it first:
- Open https://ram.console.aliyun.com/applications?activeTab=ThirdParty
- Click "安装官方应用" (install official application) → "官方 CLI" (official CLI)
- Select
alibabacloud-cli@app.1263926834388048.onaliyun.com
Situation B — the app is installed but the current sub-account is not in its visitor list. The administrator assigns it:
- Open https://ram.console.aliyun.com/applications/4038181954557748008?appType=ThirdPartyApp&activeTab=Assignments
- Click "添加用户或角色" (add user or role)
- Select the current sub-account user
After the administrator finishes, refresh the authorization page or re-run mcpx login. The appId 4038181954557748008 on the page is the same as the client_id in the authorization link.
Logged in but cannot connect: check RAM permission first
A successful aliyun CLI login does not mean you have permission to use this MCP service; the two are separate. This is the most typical cause of "login clearly succeeded but cannot connect".
The MCP service requires the account to have this RAM permission point to issue credentials for the caller:
AliyunOpenAPIMCPServerStaticCredentialAccess
Symptom: login succeeds, aliyun sts get-caller-identity returns the identity, but doctor fails at the handshake step.
Server's original text:
凭证可用但被拒绝, MCP 服务在握手前已退出。
服务端原始信息:
Error: Failed to discover MCP server URL: code: 403, You are not authorized to perform this action. request id: ...
Note the difference from "invalid credentials" — the two look similar but differ in status code and wording:
| Error | Meaning |
|---|---|
| code: 403, You are not authorized to perform this action | Credentials valid, but missing the RAM permission |
| code: 404, Specified access key is not found | Credentials themselves invalid; re-run login |
When you see the 403 one, do not re-login — login is not the problem; go add the permission.
The wording may change in future, so the script also attaches this hint on unknown failures it cannot classify. The criterion is "credentials are fine but the handshake fails"; do not fixate on the exact text.
Action: request or add this RAM permission point for the identity currently logged in, then re-run doctor. First confirm which identity you are using:
mcpx call CallCLI '{"command":"aliyun sts get-caller-identity"}'
A sub-account and the primary account are different identities — adding the permission to the primary account does not grant the sub-account. Do not repeatedly re-run login in this case; login is not the problem. The permission is declared in references/ram-policies.md.
When a description disagrees with the server
The tool reference is authoritative; copy it for normal calls. Only when you suspect the server version changed, or need a deeply nested structure not expanded there, use these two commands to get the server's truth:
uv run --python 3.11 scripts/mcpx.py list
uv run --python 3.11 scripts/mcpx.py schema GetPresignedUrl
For example, the array-element structure of GetPresignedUrl.requests or the full shape of RunScript.costManifest do not fit in a table; use schema.
Running tests
uv run --python 3.11 --with pytest -m pytest tests/ -q
No network or Alibaba Cloud account needed; runs fully offline.
微信扫一扫