Talk to DingTalk as yourself — from Amazon Quick Desktop and any other MCP host.
An MCP server that wraps DingTalk's official CLI (dws) so an AI assistant can send and read DingTalk messages with your real user identity — your avatar, your name in the group — instead of posting as a bot.
English · 中文
DingTalk's own MCP server (open-dingtalk/dingtalk-mcp) only speaks as a bot — your teammates see a robot talking in the group, not you. That's wrong for a personal assistant.
This project takes the opposite route. It wraps dws, DingTalk's official CLI, which authenticates over user-identity OAuth. So when you tell your assistant "post 'meeting moved to 3pm' in the project group", the message lands authored by you — exactly as if you'd typed it.
dws is itself a thin client to DingTalk's MCP gateway (mcp-gw.dingtalk.com), meaning DingTalk's backend is already MCP-native. This project exposes that capability in two ways:
| Local MCP | Remote MCP | |
|---|---|---|
| Who it's for | Just you, on your own machine | A whole team, shared |
| Runs where | dws on your laptop, stdio to the host |
AWS Bedrock AgentCore + Lambda, HTTPS |
| Setup | npm install + dws auth login (~5 min) |
Admin deploys once; each teammate self-authorizes |
| Identity | Your own logged-in dws session |
Per-user OAuth, isolated per teammate |
| Best when | Personal use, fastest start | Many users, central audit, no local install |
Both expose the same 38 tools (see Tools) backed by the same shared command catalog.
Run it on your own machine and wire it into Amazon Quick Desktop (or Claude Desktop, Cursor) over stdio.
You type Amazon Quick Desktop quick-dingtalk-mcp dws CLI DingTalk
"post in X group" ──→ (MCP host) ──stdio──→ node packages/local/server.mjs ──exec──→ dws chat ... ──HTTPS──→ mcp-gw.dingtalk.com
npm install -g dingtalk-workspace-cliYour DingTalk org must have CLI access enabled. Admins: open-dev.dingtalk.com → "CLI 访问管理" → enable (once, org-wide). Members hitting a not-enabled wall get a one-click request prompt at login.
git clone https://github.com/keithyt06/quick-dingtalk-mcp.git
cd quick-dingtalk-mcp
npm installdws auth login --device # device flow — works over SSH / headless tooScan the code with your DingTalk app to authorize. This is the step that makes messages post as you.
First grab two absolute paths (Quick Desktop's child process doesn't inherit your full PATH, so absolute paths are the reliable choice — and no spaces in the path):
which node # e.g. /opt/homebrew/bin/node
echo "$(pwd)/packages/local/server.mjs" # the server entrypointThen in Amazon Quick Desktop → Settings → Capabilities → MCP → + Add MCP:
| Field | Value |
|---|---|
| Connection type | Local |
| ID | quick-dingtalk-mcp |
| Name | quick-dingtalk-mcp |
| Command | the which node path |
| Arguments | the server.mjs absolute path |
Save. You should see quick-dingtalk-mcp · 38 tools · Connected ✅.
Once connected, asking it to look you up returns your real DingTalk identity — proof the chain works end to end:
In a Quick Desktop chat:
List my recent DingTalk chats, then post a markdown message titled "test"
with body "hello from quick-dingtalk-mcp" to chat_id=cidXXXX.
Full walkthrough (incl. Claude Desktop / Cursor, troubleshooting, the "is it really me?" verification) → packages/local/docs/setup.md
A shared, multi-user deployment on AWS Bedrock AgentCore. One deploy serves any number of teammates — onboarding a new person is self-service, with zero code changes and no redeploy.
Each teammate Amazon Quick Desktop AWS
authorizes once ──→ (MCP host, HTTPS + Bearer) ──→ CloudFront → API GW → mcp-middleware (Lambda)
│ verify HMAC token, load *this user's* DingTalk token
▼
AgentCore Runtime (container running dws, per-user config)
│
▼
DingTalk (authored by that teammate)
Each teammate's DingTalk token is stored, KMS-encrypted, per userId in Secrets Manager; the container gives each user an isolated dws config. DingTalk tokens auto-refresh on a schedule, and your connection stays valid as long as you keep using it — the backend tracks a per-user activity window (90 days idle before re-auth is needed), so a one-time setup just keeps working.
curl -fsSL https://raw.githubusercontent.com/keithyt06/quick-dingtalk-mcp/main/packages/remote/scripts/install.sh | bash
~/.quick-dingtalk-mcp/packages/remote/scripts/deploy.shdeploy.sh provisions everything (CloudFront, API Gateway, Lambdas, DynamoDB, Secrets Manager, the AgentCore Runtime container) and prints:
- the authorize URL to hand to teammates
- the MCP endpoint (
https://<domain>/mcp) they paste into Amazon Quick Desktop
Prereqs: a DingTalk app (AppKey/AppSecret) with
<domain>/callbackregistered as its redirect URL, AWS credentials (pick any AgentCore-supported region viaAWS_REGION, defaultus-east-1), Docker, and Node ≥ 22.6. Chicken-and-egg (you don't know the domain before deploying)? Rundeploy.sh --only-oauthfirst — it deploys just the gateway, prints the CloudFront domain to register with DingTalk, then re-run the full deploy. Updating later? Just re-rundeploy.sh— it's idempotent (the signing key and stored secrets are preserved). Full deployment guide (prereqs, two-phase first deploy, updates, smoke tests, teardown) → docs/remote-deploy.md · day-2 operations → docs/remote-operations.md.
The gateway is a standard OAuth 2.1 Authorization Server, so your client can connect in one of two modes. They differ only in how your client obtains the credential — both reach the same backend (which runs dws under your DingTalk identity) and behave identically once connected. Pick by what your client supports:
| Mode A — OAuth wizard (recommended) | Mode B — manual Bearer (fallback) | |
|---|---|---|
| Use when | your client has an OAuth login (Amazon Quick does) | your client only lets you set a fixed header |
| What you do | fill a few URLs, click Approve once | open a URL, copy a Bearer token into a header |
| Token upkeep | client auto-refreshes — you never touch a token | paste once; stays valid while in use (re-auth after 90 days idle) |
In Amazon Quick: Connectors → Add connector → MCP (not Settings → MCP), choose User authentication, and fill:
| Field | Value |
|---|---|
| MCP endpoint | https://<domain>/mcp |
| Authorization URL | https://<domain>/authorize |
| Token URL | https://<domain>/token |
| Client ID | quick |
| Client Secret | placeholder (any non-empty value) |
| Scope | openid |
Save → Quick pops a login button → approve with your DingTalk account → it wires up the token and shows 38 tools. You authorize once; Quick auto-refreshes the token from then on.
Client IDmust be exactlyquick— the gateway pre-registers this client (Quick's form requires an ID and doesn't self-register via DCR). The secret isn't checked (PKCE is). Make sure the domain is identical in all three URLs — one mistyped character breaks the login page.
For clients without an OAuth wizard: open https://<domain>/authorize in a browser, approve with your DingTalk account, and copy the Bearer … it returns. In your client set Connection type: Remote / HTTP, transport: streamable-http, URL = https://<domain>/mcp, and header Authorization: Bearer <that value>.
Then verify (either mode): ask "use dingtalk to look up my own profile" — it returns your real org/department. You never touch the DingTalk developer console; the app is the admin's, you just authorize with your own account.
Step-by-step onboarding (recommended OAuth path, beginner-friendly) → docs/remote-新人首配-oauth.md · technical reference (transport, troubleshooting matrix, admin setup) → docs/remote-quick-desktop.md
38 tools, identical across Local and Remote, backed by a shared catalog that covers all 261 dws commands:
| Group | Count | What |
|---|---|---|
| Named tools | 30 | The common ones, exposed directly: dingtalk_chat_message_send / _list / _search / _recall / _reply / _forward, dingtalk_contact_user_search / _get_self, dingtalk_calendar_event_create, dingtalk_doc_create / _read, dingtalk_todo_task_create, dingtalk_ding_message_send, … |
| Discover + invoke | 2 | dingtalk_discover (keyword-search the full catalog) + dingtalk_invoke (run anything it returns) — reaches all 261 commands without bloating the tool list |
| Aliases | 6 | Older names kept working, marked [deprecated, use …] |
Covers IM, contacts, calendar, docs/drive, todo, DING, attendance, OA approval, AI table, minutes, mail, and more. Every DingTalk message requires a title (unlike Feishu) — the catalog enforces it.
| This project | open-dingtalk/dingtalk-mcp |
Custom robot webhook | |
|---|---|---|---|
| Posts as | You (real user) | A bot | A robot |
| Auth | User OAuth (dws) |
App credentials | Webhook URL |
| Read history / search | ✅ | ❌ / limited | ❌ |
| Group display | Your avatar + name | Bot | Robot name |
Want the assistant to be you? Use this. Want clearly-labelled automation? Use the bot/webhook routes.
Full index (by audience): docs/README.md
- Local: setup · identity verification
- Remote: AWS deployment guide (中文) · first-time setup · OAuth wizard, recommended (中文) · connect help · manual (中文) · Quick Desktop onboarding · security · operations · observability · FAQ · cost
Issues and pull requests are welcome — bug reports, new region availability notes, doc fixes, and tool-catalog improvements are all fair game. Before sending a PR:
npm run test:all # 125 tests must stay green (Node ≥ 22.6)A few house rules: packages/shared/catalog.json is generated (npm run build:catalog), never hand-edited; changes in packages/shared/ affect both Local and Remote, so run the full suite; never commit real AppKeys, tokens, account IDs, or live domains.
dws— DingTalk-Real-AI/dingtalk-workspace-cli — does the heavy lifting; this project is a thin shim over it.@modelcontextprotocol/sdk
MIT © Keith Yu
