Chinese services: what the agent can reach without a screen
The ladder puts the phone's screen last. For that to mean anything, the first rung has to be real: the services a Chinese day runs on need a CLI or an MCP server the agent can actually call. This page is the list (what has been run, what has not, what we will not recommend) and the rule that keeps it honest:
Nothing enters the showcase until it has run inside the phone's root file system and left a trace. A package that installs is not a service that works. "Runs" means the tool was called and answered; the transcript is at the bottom of this page.
The root file system on the phone today is the Alpine Linux 3.21 minirootfs the Android app unpacks under proot (android.md; android/scripts/prepare_android_sandbox.sh fetches it at build time). It ships bare: the agent installs Node and Python inside it with apk add the first time a task needs them. The transcript at the bottom of this page was recorded on 2026-09-24 in the Python line's image of the same Alpine base, which had Node 22 and Python 3.12 preinstalled (local-runtime.md is that line's record), on an arm64 emulator (QEMU user-mode on the build machine); the current app's rootfs has no run of its own recorded here yet. PRoot itself and the phone's network are the two things the emulator does not exercise, and the checklist keeps a line for them. The skills named below are the Python runtime's built-in ones under nanomuse/skills/builtin/.
Tier 1: verified
Run inside the rootfs, answered, in the showcase.
| Service | Through | Verified | Needs from the user | Skill |
|---|---|---|---|---|
| 12306 (trains) | 12306-mcp, a community MCP server over 12306's public timetable: npx -y 12306-mcp, stdio | Installed in the rootfs; a live query for Beijing → Shanghai the next morning came back in 1.0 s with trains, seats and prices. Query only: the server cannot book | Nothing: no key, no login | train-tickets (searches here; books on the phone only when told to) |
| Feishu / Lark | lark-cli, the official CLI: npm i -g @larksuite/cli | Installed and runs in the rootfs (1.0.96); on the build machine a configured install answers lark-cli auth status with its identities. Login is the owner's step: lark-cli config init --new once, then lark-cli auth login, both through a link in a browser | A Feishu account; the two login steps, once | feishu |
| Amap (maps, weather) | Amap MCP Server, official: hosted at https://mcp.amap.com/mcp?key=…, or npx -y @amap/amap-maps-mcp-server | The package runs in the rootfs and lists its twelve tools; live calls go through the hosted URL with a key. No key was available on the build machine, so the live geocode and route calls are the owner's line in the checklist | A free Web key from console.amap.com, in the vault as AMAP_KEY | amap |
| Tencent Meeting | tmeet, Tencent's official CLI (a Go binary, npm i -g @tencentcloud/tmeet) | Installed and runs in the rootfs (v1.0.18); tmeet auth status and tmeet meeting create --help answer. Login is an OAuth device flow the owner clicks through once (tmeet auth login --no-browser prints the link on the phone) | A Tencent Meeting account; the login, once | tencent-meeting |
The device MCP server (the phone's own clipboard, calendar, contacts, alarms, location, notifications, photos; device.md) is not a third-party service and is not listed; it is verified with the Android app.
Tier 2: to be run one by one
A server exists; it has not run inside the rootfs with a real key, or it has no skill yet. In the order we would try them.
| Service | Through | State | Why not yet |
|---|---|---|---|
| (parcels) | MCP Server, official: hosted (https://api.kuaidi100.com/mcp/streamable?key=…) or npx -y @kuaidi100-mcp/kuaidi100-mcp-server | The package runs in the rootfs and lists its four tools (query_trace, estimate_time, estimate_time_with_logistic, estimate_price); the kuaidi100 skill is written against them. A live query needs an account: paid per tracking number, free trial on sign-up | No key on the build machine. Moves to tier 1 with one traced query_trace |
| Baidu | @baidumap/mcp-server-baidu-map, official (1.0.5 on npm) | Not run. Same shape as Amap; a second map only matters where one of them is wrong | Needs a key; Amap covers the showcase |
Official MCP Server, hosted (https://mcp.map.qq.com/sse?key=…, also Streamable HTTP): geocoder, place search, routes, IP location, weather | Not run | Needs a key with WebServiceAPI enabled; same reason as Baidu | |
Community servers over the QWeather API (hefeng-weather-mcp on PyPI, others); no official server found | Not run. Amap's maps_weather gives the showcase its forecast; is for people who want hourly or air-quality data | Needs a project, a key id and an Ed25519 private key, a heavier setup than the others | |
| DingTalk | dingtalk-mcp-server (community, messages / todos / calendar); DingTalk's own agent platform is not an MCP server | Not run | Enterprise account and app registration; no showcase case needs it |
yuque-mcp-server (community) over the open API | Not run | Personal token; would slot into the feishu-style skill pattern in an afternoon | |
| Baidu | Announced MCP support; no package or endpoint we could confirm | Not run | Nothing to run yet |
| **Ctrip / / ** | Servers in the Alibaba Cloud Bailian MCP market, hosted behind a Bailian account | Not run. The showcase's hotel-budget case browses Ctrip in the in-app browser instead (the third rung) because that works for anyone without an account with Bailian | Requires a Bailian account and the market's per-call billing; worth it for a hosted demo, not for the personal build |
Tier 3: not recommended
Listed so nobody asks.
| Service | Why |
|---|---|
| WeChat: any automation of it, including community "wechat MCP" servers | Against the terms of use; accounts get restricted. The agent reads and replies to WeChat on the phone's screen only when the user asks for exactly that, and none of it appears in public material |
| Xiaohongshu MCP servers | Community servers scrape a logged-in session; Xiaohongshu bans the account. The screen does the same job when asked |
| Alipay / WeChat MCP servers | They exist for merchants (payments, refunds), not for a person's own account. Paying is the user's; the agent stops before it |
| Anything that needs the user's password in a config file | The vault holds keys and tokens; a login the tool cannot do itself with a device flow or a QR code is not a login the agent should hold |
Adding one
An MCP server: a [[mcp.servers]] block in config.toml (or Connections → MCP servers in the app), key in the vault as {{vault:NAME}}, risk and egress set honestly, reads_private_data = true when the arguments carry the user's data (a tracking number, a phone number). A CLI: install it in the rootfs or share it with the sandbox on a computer (sandbox.share_read_only for the program, share for its login), then a skill that says which commands to run and what to ask before writes. config/config.example.toml has the blocks for Amap, 12306 and ; configuration.md explains the fields.
When it has run inside the rootfs and answered once, add the transcript below and move it up a tier.
Verification log
Inside nanomuse-rootfs:aarch64, the Python line's image (Alpine 3.21.8, Node 22.23.2, npm 10.9.1, Python 3.12.14, nanomuse 0.1.0), QEMU user-mode on x86_64, 2026-09-24. Mirrors were switched with that image's nanomuse-mirror cn; the app today measures its package mirrors itself on first start. The probe is a 60-line Python script over the mcp client the agent itself uses: connect, tools/list, a few tools/call.
$ npm i -g 12306-mcp @larksuite/cli @tencentcloud/tmeet @amap/amap-maps-mcp-server @kuaidi100-mcp/kuaidi100-mcp-server
added 386 packages in 2m (136 s under emulation; a phone is faster)
/usr/local/bin: 12306-mcp kuaidi100-mcp lark-cli mcp-amap tmeet …
== 12306-mcp (stdio)
connected in 15.5s · 8 tools
get-current-date, get-stations-code-in-city, get-station-code-of-citys, get-station-code-by-names,
get-station-by-telecode, get-tickets, get-interline-tickets, get-train-route-stations
$ get-current-date {} (0.1s) → 2026-09-24
$ get-station-code-of-citys {"citys": "Beijing|Shanghai"} (0.1s) → {"Beijing":{"station_code":"BJP",…},"Shanghai":{"station_code":"SHH",…}}
$ get-tickets {"date":"2026-09-25","fromStation":"Beijing","toStation":"Shanghai","trainFilterFlags":"G",
"earliestStartTime":7,"latestStartTime":9,"sortFlag":"startTime","limitedNum":3} (1.0s)
G565 Beijing -> Shanghai 07:07 -> 13:12 :05 : 2156 · : 967 · : 576
G549 Beijing -> Shanghai 07:13 -> 13:03 :50 : 2315 · : 967 · : 598
G5 Beijing -> Shanghai 07:40 -> 12:32 :52 : 2350 · : 1075 · : 672 · :
== lark-cli
lark-cli version 1.0.96
$ lark-cli auth status → {"ok": false, "error": {"type": "config", "subtype": "not_configured",
"hint": "run `lark-cli config init --new` … open it in a browser to complete setup."}} (the owner's step)
== tmeet
tmeet version v1.0.18
$ tmeet auth status → Not logged in. Please use 'tmeet auth login' to authenticate. (the owner's step)
$ tmeet meeting create --help → --subject, --start, --end (ISO 8601), --invitees, --password, --waiting-room,
--meeting-type / --recurring-type / --until-type / --until-count / --until-date, --join-type, --auto-record-type, --auto-asr …
== @amap/amap-maps-mcp-server (stdio, AMAP_MAPS_API_KEY set to a placeholder — tools only)
connected · 12 tools: maps_regeocode, maps_geo, maps_ip_location, maps_weather, maps_search_detail, maps_bicycling,
maps_direction_walking, maps_direction_driving, maps_direction_transit_integrated, maps_distance, maps_text_search, maps_around_search
== @kuaidi100-mcp/kuaidi100-mcp-server (stdio, KUAIDI100_API_KEY set to a placeholder — tools only)
connected in 4.1s · 4 tools: query_trace, estimate_time, estimate_time_with_logistic, estimate_price
(the server prints one non-JSON line, "MCP server is running…", on stdout first; the client logs it and carries on)On the build machine itself (x86_64, Node 20) the same 12306 query answered in 3.5 s including npx start-up, and lark-cli auth status on the configured install reported the bot identity ready and the user identity due for a refresh, which is what the feishu skill checks for before doing anything in the user's name.
