sanxiao-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@sanxiao-mcplist my recent reimbursements"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
sanxiao-mcp — Kingdee Cloud·Xingchen "Sanxiao Project Management" MCP Server
GC032 Financial Agent · Sanxiao endpoint. App identifier bdi_projectmanagement,
subscription URL https://cloud.kingdee.com/kae/#/market/detail?sid=1285.
Implemented per the official 《Sanxiao Project Management API_2025》 documentation + 《Kingdee Sanxiao Project Management API Development Framework》. Phase 1 read-only: all query operations enabled; write operations are in place in code but rejected by guards by default.
The shape of the Sanxiao API (understand this first, the rest is easy)
Sanxiao is not "one endpoint per business" — it is generic Bill CRUD:
all bills — project profiles, loans, reimbursements, payments, working-hour entries, purchase requests — go through the same set of interfaces,
driven by formId + field identifiers.
POST https://bj1-api.kingdee.com/bdiprojectapi/common/{action}
后端 openapi/ierp/kapi/app/bdi_projectmanagement/{action}
action ∈ { listQuery, getById, saveOrUpdate, submit, unSubmit,
audit, unAudit, delete, push, operation }So this service's structure is also "one gateway + two layers of wrapping", rather than dozens of endpoint constants.
Related MCP server: mcp-timely
Table of Contents
sanxiao/
├── config.py 环境与鉴权四要素;url() / headers() 在这里定形
├── forms.py formId 登记表 + 中文别名解析(项目档案 → bdi_projectfile)
├── query.py qParams 结构化查询 DSL:构造、校验、还原成类 SQL 可读串
├── models.py saveOrUpdate 字段模型(8 种 fType + 分录 + 下推 + 附件)
├── guards.py 白名单 + 默认拒绝 + 审计
├── client.py 唯一 HTTP 出口 _post(),读写方法都从这里过
└── server.py 28 个 MCP 工具(通用层 + 语义层)
test_connection.py L1 配置 → L2 网络 → L3 鉴权 → L4 只读 → L5 守卫
tests/ pytest:query / models / guards / clientAuthentication: four request headers, no signature
Unlike kingdee-star-mcp (jdy open gateway) — Sanxiao requires no HMAC signature,
just four headers, all obtained in advance via the standard Xingchen API:
Header | Source of value |
| Product account-set-level token, obtained via Xingchen standard API authentication |
| IDC domain = the |
| Authorization info, pushed by the open platform to the sandbox message receiving address |
| Same as above |
Pitfall warning: The official docs explicitly state "when debugging in the cloud platform API marketplace,
X-GW-Router-Addrcan be ignored". So many people get it working in the marketplace, then hit 404 as soon as they write code — because code calls must include this header.config.headers()already handles this; don't delete it.
Once you have the four elements, fill them into .env (template in .env.example).
Quick Start
pip install -r requirements.txt
cp .env.example .env # 填入四要素
pytest -q # 69 项单测应全绿
python test_connection.py # 分层联调,结果写入 connection_test_result.txtOn Windows, just double-click run_test.bat.
MCP Tools (28)
Meta Information
Tool | Purpose |
| Gateway address, read-only switch, readiness status of the four elements and what's missing |
| Registered formIds, Chinese names, default fields |
| Available actions, read-only operation whitelist, currently permitted write actions |
Generic Layer — Full Mapping of Official Interfaces
Tool | Official Interface |
|
|
|
|
|
|
| Local tool: translates simplified conditions into |
Semantic Layer — No Need to Memorize formIds
sx_list_projects / sx_list_reimbursements / sx_list_loans /
sx_list_payments / sx_list_working_hours / sx_get_bill
sx_query_cost_budget / sx_query_material_budget / sx_query_working_hour_budget
sx_get_user_permission / sx_get_form_config / sx_workflow_status / sx_get_app_parameter
Write Layer — Rejected by Default
sx_build_bill_payload (only assembles, does not send; usable in phase 1 for manual review of the payload)
sx_save_or_update / sx_submit / sx_un_submit / sx_audit / sx_un_audit
/ sx_delete / sx_push
How to Write Query Conditions
The official qParams is an array of conditions: top-level items are joined by and, and within a condition group items are joined by joinKey.
[
{ "childGroup": false, "qKey": "number", "qCp": "like", "qValue": "ew" },
{ "childGroup": true, "joinKey": "or", "childCondition": [
{ "childGroup": false, "qKey": "number", "qCp": "=", "qValue": "new5" },
{ "childGroup": false, "qKey": "number", "qCp": "=", "qValue": "New" }
]}
]
// 等价于 number like '%ew%' and (number='new5' or number='New')Comparison operators: = > >= < <= != like likeLeft. There is no in — use query.any_of()
or the or-group in sx_build_query to simulate it. Entry fields are written as "entry identifier.field identifier",
e.g. projectfileteam.teamstaff.
Security Model
The guard is a whitelist + default-deny three-layer design:
Action classification —
listQuery/getById/operationare reads; the other seven are writes.operationKey whitelist —
operationlooks like a read interface, butoperationKeyis a free-form string, so the nine methods in doc sections 10.1–10.9 get a second whitelist pass.Funds-related operations permanently write-blocked — writes and workflow actions on payment bills (
bdi_ex_pay*), evenSX_ALLOW_WRITE_ACTIONS=*will not bypass this.
Order for enabling writes in phase 2: SX_READONLY=false → add actions one by one in SX_ALLOW_WRITE_ACTIONS
for gray rollout. Do not jump straight to *.
All calls and blocks are logged to the sanxiao.audit logger.
Real Payloads Overturn What the Docs Suggest
The official 《Sanxiao-API Reference Code》 is a complete bdi_projectfile bill payload
(saved as tests/fixtures/projectfile_reference.json). It is more trustworthy than the doc examples,
and overturns four assumptions taken for granted — each one is pinned down in tests/test_reference_payload.py,
and reverting any of them will fail immediately:
What the doc examples suggest | What the real payload shows |
Every field has | Empty-value fields omit the |
|
|
| Native |
|
|
The third one is the most dangerous: an earlier str(d["fValue"]) in field_from_dict,
when hitting {"fType":"enum","fValue":true}, would produce Python-style "True" —
a string with a capital T, which the server does not recognize, and the error message will not tell you this is the cause.
Now fValue is passed through as-is.
The benefit is that getById responses can be fed straight back into saveOrUpdate (change one or two fields and save again),
lossless round-trip, and this path is guarded by test_roundtrip_is_lossless.
Additionally, eight base-data formIds were extracted from the bd field of the payload and registered in forms.py:
bd_employee, bd_department, bd_customer, bdi_bd_customer_fork,
bdi_projecttypes, bdi_projectarea, bdi_projectstauts, bdi_projectroles.
bdi_projectstautsis not a typo — the vendor spelled status as stauts, and both the formId and field names use that spelling. Don't "fix it" out of habit.
Where Field Identifiers Come From
Don't guess. The authoritative method is in the Xingchen UI: Bill list → More → Import Data → Template Management → New Template.
Once running, you can also look it up in reverse: sx_get_form_config(form_id) calls
operation.getUserconfig and returns that bill's field configuration.
forms.py registers 15 formIds: seven from the official docs
(bdi_projectfile, bdi_ex_loan, bdi_ex_bx, bdi_ex_pay,
bdi_fillinworkinghours, pur_bill_request, bd_auxinfo),
and eight base-data references from the reference-code payload. For other bills, just pass the formId
directly to sx_list_query — no need to register first.
Same for field names — only bdi_projectfile's fields have been verified against the real payload
(note it uses status/enable, not billstatus; that belongs to business bills).
The default fields for other bills are still inferred by convention; after getting them working, please verify with sx_get_form_config.
Relationship with kingdee-star-mcp
The two are two open capabilities of the same Xingchen account set, each deployed independently:
kingdee-star-mcp | sanxiao-mcp | |
Gateway |
|
|
Auth | HMAC signature + app-token two-layer credentials | Four headers, no signature |
Endpoints |
|
|
Coverage | Finance (vouchers, reimbursements, receivables/payables) | Project management (projects, working hours, budgets, reimbursements) |
Sanxiao's Token must first be obtained via the Xingchen standard API — if you've already
gotten the authorization chain working in kingdee-star-mcp, you can fill the token you obtained
along with the domain/groupname/accountid from the authorization push directly into this project's .env.
Known Gaps
The official docs do not provide a unified response body schema;
client._unwrap()does a loose unwrap: if it can recognizeerrcode/success/datait normalizes, otherwise it returns as-is — better to return extra data than to swallow data by guessing the structure wrong. It can be tightened once real responses are available.Bill status codes are not fully documented. In the reference code, project profile
status="A",enable="1", but what A/B/C each mean, and the value domain ofbillstatusfor business bills, still lack authoritative explanation. The semantic layer'sstatusparameter currently passes through the raw identifier.In the reference code, a few fields have contradictory
fTypevalues —phaseplanenddate,phaseenddateare declared asnumyet are clearly dates. This is an inconsistency in the vendor's own payload; the model layer accepts it as-is without correction, so as not to "help in the wrong direction".Attachment upload goes through base64; large files need evaluation against the gateway size limit, which the docs do not specify.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- FlicenseNot gradedqualityBmaintenanceExposes enterprise WeChat approval, report, and check-in data reading capabilities through the MCP protocol, enabling WorkBuddy and CodeBuddy to read historical business data.7
- AlicenseAqualityBmaintenanceA read-only MCP server for querying Timely time tracking data, providing tools for project overviews, time spent summaries, and work log entries.3MIT
- FlicenseAqualityBmaintenanceRead-only MCP connector for querying the Protheus (TOTVS) system, exposing 10 GET endpoints as MCP tools with OAuth2 authentication and friendly error handling.10
- AlicenseBqualityCmaintenanceMCP server for Kingdee Cloud (K3Cloud) ERP that enables AI assistants to query and operate ERP data through natural language, supporting bills, metadata, and read/write operations.81Apache 2.0
Related MCP Connectors
A paid remote MCP for AI SDK data query MCP, built to return verdicts, receipts, usage logs, and aud
Log, query, and edit expenses, budgets, and accounts in Ledgy from any MCP-compatible AI assistant.
Read-only MCP server for ClassQuill, a tutoring-business-management platform.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/adambbhe/kingdee-sanxiao-MCP'
If you have feedback or need assistance with the MCP directory API, please join our Discord server