Customs operations as MCP tools — drop into any AI agent.
14 production-grade customs / trade capabilities (declarations, ship info, tariff, dual-use screening, AI-powered declaration generation, ...) exposed as standard Model Context Protocol tools for Claude Desktop, Claude Code, Cursor, Windsurf, Trae and any other MCP-compatible AI client.
- 14 MCP tools — every customs-skill capability exposed as a typed tool with zod-validated input
- Universal client support — Claude Desktop / Claude Code / Cursor / Windsurf / Trae / Codex / any MCP client
- Production auth —
/session/exchange→ 5-minagentToken→ action-code whitelist → tenant isolation - Per-call identity override — server-level env default + optional
_identityfield per tool call (multi-user / multi-tenant friendly) - AI document maker — multipart upload, no-wait mode,
decIdpolling pattern - Error translation — backend
NEED_BIND/NEED_TENANT/ etc. rendered as actionable English guidance - Tiered timeouts — 15 s reads / 180 s upload / 660 s dual-use AI query
- Zero runtime deps —
@modelcontextprotocol/sdk+zod+dotenvonly; Node 18+ built-infetch+FormData - Dual transport — stdio (Claude Desktop) and Streamable HTTP (remote / self-hosted)
Ask your customs system admin to insert one row into agent_identity_binding
mapping your chosen (platform, externalUserId) to an existing sys_user_id.
Full SQL in docs/identity-binding.md.
Pick a ready-made config from examples/:
Or use the generic snippet:
{
"mcpServers": {
"customs": {
"command": "npx",
"args": ["-y", "@dearmrzhang/customs-mcp-server", "--transport", "stdio"],
"env": {
"CUSTOMS_API_BASE_URL": "http://your-backend-host:port",
"CUSTOMS_ACCESS_KEY": "your-access-key",
"CUSTOMS_SECRET_KEY": "your-secret-key",
"CUSTOMS_DEFAULT_PLATFORM": "mcp",
"CUSTOMS_DEFAULT_EXTERNAL_USER_ID": "your-bound-username",
"CUSTOMS_DEFAULT_EXTERNAL_CORP_ID": "mcp-prod"
}
}
}
}
"Use
customs_query_tariffto look up HS code 8471300000."
That's it. The AI agent picks the tool, the MCP server signs the request, exchanges a grant, and returns structured tariff data.
┌────────────────────────────────┐
│ AI client (Claude / Cursor / │
│ Windsurf / Trae / ...) │
└───────────────┬────────────────┘
│ MCP protocol (stdio | HTTP)
┌───────────────▼────────────────┐
│ customs-mcp-server │
│ │
│ • 14 tool handlers │
│ • Identity resolver │
│ • Signer + GrantBroker │
│ (5-min agentToken cache) │
│ • Error translator │
└───────────────┬────────────────┘
│ HTTPS + signed headers
┌───────────────▼────────────────┐
│ Customs backend │
│ /open-api/agent/v1/... │
└─────────────────────────────────┘
| Document | What's inside |
|---|---|
| CHANGELOG.md | All version changes, including v0.1.2 → v1.0.0 breaking changes, v1.1.0 declaration-list enhancements |
| docs/tool-reference.md | Complete schema and usage for all 14 tools |
| docs/identity-binding.md | Backend SQL setup, multi-tenant patterns, troubleshooting |
| examples/ | Ready-to-paste config snippets for 5 AI clients |
| Variable | Required | Default | Description |
|---|---|---|---|
CUSTOMS_API_BASE_URL |
✅ | — | Customs backend root URL |
CUSTOMS_ACCESS_KEY |
✅ | — | Static signature access key |
CUSTOMS_SECRET_KEY |
✅ | — | Static signature secret key |
CUSTOMS_DEFAULT_PLATFORM |
✅ | — | Identity platform (e.g. mcp / cursor) |
CUSTOMS_DEFAULT_EXTERNAL_USER_ID |
✅ | — | Bound external user identifier |
CUSTOMS_DEFAULT_EXTERNAL_CORP_ID |
✅ | — | Bound external corp identifier |
CUSTOMS_API_PREFIX |
/open-api/agent |
API path prefix | |
CUSTOMS_TIMEOUT_MS |
15000 |
Default request timeout (ms) | |
CUSTOMS_UPLOAD_TIMEOUT_MS |
180000 |
AI-maker upload timeout (ms) | |
CUSTOMS_DUAL_USE_TIMEOUT_MS |
660000 |
Dual-use slow query timeout (ms) | |
CUSTOMS_TIMESTAMP_TIMEZONE |
Asia/Shanghai |
Timestamp tz (must match backend) | |
CUSTOMS_DEFAULT_CHANNEL |
${PLATFORM} |
Channel field for /session/exchange |
|
MCP_HTTP_HOST |
0.0.0.0 |
HTTP transport bind host | |
MCP_HTTP_PORT |
8787 |
HTTP transport port | |
MCP_HTTP_PATH |
/mcp |
HTTP transport endpoint | |
CUSTOMS_DEBUG |
0 |
Set 1 for verbose stderr debug logs |
14 tools across 7 domains. Full schema and examples in tool-reference.md.
| Domain | Tools |
|---|---|
| Declaration | customs_get_declaration_status · customs_query_declaration_list · customs_get_declaration_detail · customs_get_import_export_status · customs_get_full_process_tracking |
| Ship | customs_query_ship_info (with auto I→E fallback) · customs_query_ship_plan |
| Manifest | customs_query_manifest_info · customs_query_ship_manifest_info |
| Tariff | customs_query_tariff |
| Compliance | customs_query_dual_use_item (slow AI query) |
| Orders | customs_create_order_draft (pre-check only) |
| AI Maker | customs_submit_ai_maker · customs_get_ai_maker_status |
v1.0.0 is a breaking release with mandatory new env vars. See CHANGELOG.md → 1.0.0 for the full list. TL;DR:
- Add three identity env vars (
CUSTOMS_DEFAULT_PLATFORM/CUSTOMS_DEFAULT_EXTERNAL_USER_ID/CUSTOMS_DEFAULT_EXTERNAL_CORP_ID) - Have your admin insert the matching
agent_identity_bindingrow - Rename
customs_query_tariff_info→customs_query_tariff - Switch
customs_get_declaration_detailcallers fromcusCiqNotoentryId(ordecIdwhen known)
CUSTOMS_SECRET_KEYand cachedagentTokens never leave server memory- Per-call
_identityoverrides should not embed PII — they appear in MCP structured responses - All write tools route through action-code whitelist on the backend
- Cross-tenant
ai-makerstatus access is blocked at the backend layer
Issues and PRs welcome at github.com/yak33/customs-mcp-server.
git clone https://github.com/yak33/customs-mcp-server.git
cd customs-mcp-server
pnpm install
pnpm build
pnpm dev:stdio # or dev:http
- customs-skill — the same 13 customs capabilities as an OpenClaw skill for Feishu/Lark integration