Skip to main content
Glama
IM MCP Server on Amazon Bedrock AgentCore

IM MCP Server on Amazon Bedrock AgentCore

by keithyt06

Chinese | English

IM MCP server on Amazon Bedrock AgentCore (Feishu, Lark, DingTalk, WeCom)

One codebase, one config file, and one CDK app deploy a per-user MCP server for one of Feishu, Lark, DingTalk, or WeCom into AWS Global or AWS China regions, running on Amazon Bedrock AgentCore Runtime. AI clients (Kiro, Claude Code, Codex, Cursor, Amazon Quick) then read and write in the IM as the individual signed-in user, not as a shared bot, through the vendor's official CLI (lark-cli, dws, wecom-cli).

IMPORTANT

This is sample code, not production-ready. It is provided for demonstration and learning. It has not been hardened, load-tested, or reviewed for your security, compliance, or availability requirements. Review the security model, test it in a non-production account, and make your own assessment before you use it with real users or data. You are responsible for the AWS charges and for complying with the terms of the IM platforms you connect to.

WARNING

AWS China regions (cn-north-1, cn-northwest-1): public access requires an ICP filing and a custom domain. Without an ICP-filed domain, every request from the internet to the default API Gateway URL returns 403 Forbidden. The stack still deploys and the backend works (verify with npm run e2e:internal), but MCP clients cannot reach it. Set ingress.customDomain to an ICP-filed domain and ingress.certificateArn to an ACM certificate in the same region. Amazon Quick is not available in AWS China; use Kiro, Claude Code, Codex, or Cursor.

What you get

  • One IM per deployment, selected by im: in config/deploy.yaml. The partition (aws or aws-cn) is derived from region; nothing else changes between Global and China.

  • Per-user identity. Each user signs in with their own IM account (OAuth for Feishu/Lark/DingTalk, QR scan for WeCom). Their IM credential is stored in Secrets Manager under a dedicated KMS key, and each user gets their own AgentCore microVM session.

  • Standard MCP OAuth. A self-hosted OAuth 2.1 authorization server (RFC 8414, RFC 9728, RFC 7591 dynamic client registration, PKCE S256) in Lambda. Clients connect with only the URL. No Amazon Cognito (not available in AWS China).

  • Curated tools plus the full CLI. Each IM exposes a tier-1 tool list (26–32 tools) plus <im>_discover and <im>_invoke, which reach the rest of the vendor CLI catalog. Destructive tools require explicit confirmation.

Related MCP server: lark-cli-mcp

Architecture

flowchart LR
  C["MCP client<br/>Kiro / Claude Code / Codex / Cursor / Amazon Quick"]
  subgraph AWS["Your AWS account (Global or China region)"]
    APIGW["API Gateway HTTP API<br/>(+ custom domain; optional CloudFront + WAF on Global)"]
    OA["oauth Lambda<br/>OAuth 2.1 AS: well-known, DCR,<br/>authorize, callback, token"]
    MW["middleware Lambda<br/>verify MCP token, load user credential,<br/>SigV4 InvokeAgentRuntime"]
    RT["AgentCore Runtime (MCP, ARM64)<br/>one microVM per user session<br/>MCP server + vendor CLI"]
    SM[("Secrets Manager + KMS<br/>app secret, root key,<br/>per-user IM credentials")]
    DDB[("DynamoDB<br/>OAuth state, users")]
    RF["refresh Lambda<br/>every 30 min (Feishu/Lark/DingTalk)"]
  end
  IM["IM open platform<br/>Feishu / Lark / DingTalk / WeCom"]
  C -- "HTTPS /mcp, Bearer token" --> APIGW
  C -- "OAuth" --> APIGW
  APIGW --> OA
  APIGW --> MW
  MW -- SigV4 --> RT
  OA -- "WeCom QR control RPC" --> RT
  OA --- SM
  OA --- DDB
  MW --- SM
  RF --- SM
  RT -- "as the user" --> IM
  OA -- "OAuth redirect" --> IM

Plain-text view:

MCP client --HTTPS--> API Gateway --> oauth Lambda      (sign-in, tokens)
                                  \-> middleware Lambda --SigV4--> AgentCore Runtime --> vendor CLI --> IM API
                                         |                          (microVM per user)
                       Secrets Manager (KMS) + DynamoDB

Supported matrix

IM

Auth mode

AWS Global

AWS China

Tested (infra level, no real IM tenant)

Feishu (feishu)

OAuth redirect

Yes

Yes (ICP domain for public access)

Global ap-northeast-1: e2e 8/8. China cn-northwest-1: e2e:internal 7/7 (public URL 403 without ICP, as expected)

Lark (lark)

OAuth redirect

Yes

Yes (cross-border traffic to Lark)

Synth matrix only

DingTalk (dingtalk)

OAuth redirect

Yes

Yes (ICP domain for public access)

Global ap-northeast-1: e2e 8/8. China: synth matrix only

WeCom (wecom)

QR scan in the container

Yes

Yes (ICP domain for public access)

Global ap-northeast-1: e2e 8/8. China: synth matrix only

All 4 IMs × 2 partitions are covered by the synth-matrix unit tests. Real-tenant tests are a manual checklist in docs/en/testing.md. Supported regions: infra/lib/regions.ts.

What you need before deploying

Read docs/en/prerequisites.md (the full table), then the guide for your IM:

In short: an AWS account and credentials for the target partition, Node.js 20.19+ (22 recommended), Docker that can build linux/arm64, the AWS CLI, an IM app (not needed for WeCom), and, for AWS China, an ICP-filed domain with an ACM certificate.

Quick start

# 1. Install
npm ci

# 2. Configure (identifiers only, never secrets)
cp config/deploy.example.yaml config/deploy.yaml
#    edit region, im, slug and the IM block (for example feishu: { appId: cli_... })

# 3. Bootstrap CDK once per account and region
export AWS_PROFILE=<your-profile> AWS_REGION=<region>
npx cdk bootstrap aws://<account-id>/<region>

# 4. AWS China only: mirror the base image once per region
AWS_PROFILE=<your-china-profile> scripts/mirror-base-image.sh <cn-north-1|cn-northwest-1>

# 5. Deploy
npm run deploy -- -c config=config/deploy.yaml

# 6. Feishu / Lark / DingTalk: store the IM app secret (AFTER the deploy, which creates the secret)
npm run secret:set-im-app -- -c config=config/deploy.yaml

# 7. Register the stack output CallbackUrl in the IM developer console (not for WeCom)

# 8. Verify, then give users the stack output McpUrl
npm run e2e -- -c config=config/deploy.yaml

Details, options, and troubleshooting: docs/en/deploy.md.

Verify

npm run e2e -- -c config=config/deploy.yaml            # 8 checks against the public URL
npm run e2e:internal -- -c config=config/deploy.yaml   # AWS China without ICP: invokes the Lambdas directly, 7 checks

The checks cover OAuth metadata, the 401 challenge, dynamic client registration, the redirect to the IM (or the WeCom QR page), tools/list with a test token through the Runtime, the im_not_authorized path, and route throttling. No IM credentials are needed. Wait about 30 seconds between e2e runs; the throttling check drains the rate-limit bucket on purpose. See docs/en/testing.md.

Connect an MCP client

Clients only need the McpUrl stack output (<base>/mcp). They register themselves (DCR), open a browser for sign-in, and refresh tokens on their own.

Claude Code

claude mcp add --transport http feishu https://<your-base>/mcp

Then run /mcp in Claude Code to authenticate.

Kiro (.kiro/settings/mcp.json in the workspace, or ~/.kiro/settings/mcp.json)

{
  "mcpServers": {
    "feishu": { "url": "https://<your-base>/mcp" }
  }
}

Codex (~/.codex/config.toml)

[mcp_servers.feishu]
url = "https://<your-base>/mcp"

Then run codex mcp login feishu to authenticate.

Cursor and other clients that support remote MCP servers with OAuth: add the same URL as a streamable HTTP server.

Amazon Quick (AWS Global only): add an MCP integration with the server URL https://<your-base>/mcp and OAuth with dynamic client registration (verify in console — UI may change). The Quick callback hosts are allowed automatically in AWS Global regions.

Use the IM name you deployed (feishu, lark, dingtalk, wecom) as the server name. Tool names are prefixed with it, for example feishu_im_messages_send, dingtalk_calendar_event_list, wecom_doc_search.

Operations

npm run users -- list                  # users and status: active | pending_approval | revoked | replaced
npm run users -- approve <userId>      # WeCom with wecom.requireApproval: true
npm run users -- revoke <userId>       # disable a user and delete their IM credential
  • Revocation is immediate for new logins and refresh grants. Access tokens already issued stay valid for up to 1 hour; the middleware caches IM credentials for up to 60 seconds.

  • Logs: /aws/lambda/im-mcp-<slug>-{oauth,middleware,refresh}, /aws/apigateway/im-mcp-<slug>-access, and the Runtime log group /aws/bedrock-agentcore/runtimes/<runtime-id>-DEFAULT.

  • Alarms go to the SNS topic in AlarmTopicArn (Lambda errors, API 5xx, token refresh failures, WeCom grant expiry). Set alarm.webhookUrlSsmParam to forward them to an IM bot webhook.

See docs/en/deploy.md.

Cleanup

npm run destroy -- -c config=config/deploy.yaml
npm run teardown:extras -- -c config=config/deploy.yaml

destroy removes the stack. teardown:extras then force-deletes the per-user secrets <slug>/users/* (created at runtime, so CloudFormation does not own them) and schedules deletion of the user-secret KMS key, which the stack keeps (RETAIN, about USD 1 per month until deleted). Still manual: the Runtime log group, CDK asset images in ECR, the China base-image mirror repository, and your DNS record and certificate. See docs/en/deploy.md.

Capability boundaries

IM

Boundaries

All

Acts only as the signed-in user: no bot broadcast, no event subscriptions. Tools that need a local file inside the server (upload from or download to a path) are unavailable, because remote clients cannot pass files into the microVM. Commands that start local processes or daemons are disabled

Feishu / Lark

Scopes must be enabled in the developer console and the app version published; scope changes need a new version. A Feishu app cannot serve a Lark tenant, and vice versa

DingTalk

The org admin must enable CLI access for the organization (and keep it enabled). International DingTalk (dingtalk.io) is not supported

WeCom

Each capability grant expires after 7 days and the user must renew it manually in the WeCom client (platform policy, accepted for this sample; the service returns im_grant_expired and raises an alarm). Chat history is unavailable in organizations with more than 10 members. The bot does not inherit the user's document permissions. 50 calls per minute per bot. The QR flow has no tenant boundary, so turn on wecom.requireApproval

Security

  • Secrets never go in the config file; the validator rejects secret-looking keys. The IM app secret is written by npm run secret:set-im-app.

  • The container is reachable only through SigV4 InvokeAgentRuntime from the stack's Lambdas. Its execution role has no bedrock:InvokeModel.

  • Per-user IM credentials are encrypted with a dedicated KMS key. MCP access tokens are HMAC-signed and expire after 1 hour.

  • Destructive tools require _confirm: true. The LLM sets this flag itself, so use a client that shows tool calls for approval.

  • WeCom: anyone with a WeCom account can complete the QR flow. Set wecom.requireApproval: true so new users wait for npm run users -- approve.

Full model, IAM summary, and known limitations: docs/en/security.md. To report a security issue, see CONTRIBUTING.md.

Repository layout

Path

Content

infra/

CDK app (bin/app.ts), typed config (lib/config.ts), constructs

lambda/

oauth, middleware, refresh, alarm Lambdas and IM OAuth adapters

container/

MCP server (src/), Dockerfile, CLI installer, tool catalogs (tools/<cli>/)

config/

deploy.example.yaml, generated Feishu/Lark scope list

scripts/

Operator scripts: secrets, users, e2e, base-image mirror, catalog generator, teardown

shared/

Names and versions shared by all parts

test/

vitest suites and fixtures

docs/en/, docs/zh-CN/

Documentation

container/tools/*/catalog.json is generated by npm run gen:catalog from the pinned vendor CLIs' help output. It is kept in the vendors' original language (the DingTalk and WeCom CLIs ship Chinese help text) and remains under the vendors' licenses; see THIRD-PARTY-LICENSES and NOTICE.

Development

npm run build          # TypeScript type check
npm test               # unit, synth-matrix, and container tests
npm run gen:catalog    # regenerate tool catalogs after a CLI version bump

License

This sample is licensed under the MIT-0 License. See LICENSE. Third-party components and ported code are listed in THIRD-PARTY-LICENSES and NOTICE.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI agents to securely read from and interact with Matrix and Microsoft Teams chat under scoped, expiring, human-approved grants, with per-operation approval for sending and editing messages and no free access to room content.
    GPL 3.0
  • A
    license
    Not graded
    quality
    C
    maintenance
    Connects MCP clients such as ChatGPT and Claude to a user's Feishu tenant through OAuth, offering 91 read and write tools covering documents, wiki nodes, spreadsheets, Base records, calendar events, tasks, chats, and cloud files. Per-user authorization, isolated read/write scopes, and token rotation keep actions scoped to the consenting account.
    283 npm
    1
    MIT