|
|
vor 2 Wochen | |
|---|---|---|
| services | vor 2 Wochen | |
| tests | vor 2 Wochen | |
| tools | vor 2 Wochen | |
| utils | vor 2 Wochen | |
| .coveragerc | vor 2 Wochen | |
| .env.example | vor 2 Wochen | |
| .gitignore | vor 2 Wochen | |
| COVERAGE_GUIDE.md | vor 2 Wochen | |
| README.md | vor 2 Wochen | |
| app.py | vor 2 Wochen | |
| config.py | vor 2 Wochen | |
| constants.py | vor 2 Wochen | |
| mcp_protocol.py | vor 2 Wochen | |
| public_gateway.py | vor 2 Wochen | |
| public_server.py | vor 2 Wochen | |
| requirements.txt | vor 2 Wochen | |
| run_coverage.py | vor 2 Wochen |
# Python MCP Gateway
这是物流系统给 Workbuddy 使用的轻量 MCP Gateway。它负责接收 MCP 请求、管理员工授权会话,并把工具调用转发到现有 ThinkPHP 项目的 MCP 接口。
Gateway 保持“薄网关”边界:
mcp_token、员工状态、公司、工具白名单和业务数据权限的最终校验。.env 优先的配置加载。serve-stdio。serve-public。bind_auth_code 授权绑定工具。query_order 订单查询工具。query_track 轨迹查询工具。initialize、tools/list、tools/call。gateway_session_id 请求级隔离、Redis Gateway session、审计日志和基础限流。适合员工本机 Workbuddy 通过命令方式拉起 Gateway。
python \\192.168.1.241\chenjiacheng\mcp\app.py serve-stdio
Workbuddy 配置示例:
{
"mcpServers": {
"fms": {
"command": "python",
"args": [
"\\\\192.168.1.241\\chenjiacheng\\mcp\\app.py",
"serve-stdio"
]
}
}
}
不要把 Y:\mcp\app.py 写进员工 Workbuddy 配置;Y: 只是开发机映射盘视角,员工机器未必存在。
本地模式下,员工流程为:
serve-stdio。bind_auth_code,输入授权码完成绑定。/mcp/auth/exchange,并带上本机生成的 session_key。query_order、query_track 等工具。适合把 Gateway 部署成公网共享服务,由多个员工的 Workbuddy 远程访问同一个 Gateway。
启动命令:
python app.py serve-public --host 0.0.0.0 --port 8765
生产部署必须满足:
.mcp_token.json 保存公网用户 token。FMS_SESSION_KEY 表示公网用户。gateway_session_id。公网模式当前支持三种 session 传递方式,优先级如下:
X-Gateway-Session: GWS_xxxAuthorization: Bearer GWS_xxxgateway_session_id=GWS_xxx如果 Workbuddy 远程 MCP 无法稳定传递 header、Bearer 或 cookie 中任意一种会话身份,公网共享 Gateway 不能生产放量。
客户端首次使用时生成高熵会话 ID:
import secrets
gateway_session_id = 'GWS_' + secrets.token_urlsafe(32)
客户端需要保存这个 ID,并在后续每次请求中复用。
员工从后台复制授权码后,Workbuddy 调用 bind_auth_code:
POST /mcp
X-Gateway-Session: GWS_xxx
Content-Type: application/json
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "bind_auth_code",
"arguments": {
"auth_code": "AC_xxx"
}
}
}
Gateway 会调用 base 项目的 /mcp/auth/exchange,并把返回的 mcp_token 存入 Redis:
fms:mcp:gateway:session:{sha256(gateway_session_id)}
Redis value 中保存 mcp_token、admin_id、company_id、client_type、expire_time 等信息。Redis key 不保存明文 gateway_session_id。
后续工具调用必须继续带同一个 gateway_session_id:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "query_order",
"arguments": {
"keyword": "USC26070371955",
"page": 1,
"limit": 20
}
}
}
Gateway 根据 gateway_session_id 从 Redis 读取当前员工的 mcp_token,再把请求转发到 fmsoperate 的 /mcp/tools/queryOrder。
mcp_token 失效。FMS_GATEWAY_SESSION_TTL_SECONDS 调整。查看工具列表:
python app.py list-tools
开发/排障时手动绑定授权码:
python app.py bind --auth-code AUTH123
直接调用订单查询:
python app.py call --tool query_order --keyword USC26070371955 --page 1 --limit 20
直接调用轨迹查询:
python app.py call --tool query_track --order-number USC26070371955
运行全部测试:
python -m unittest discover -s tests -p "test_*.py"
基础配置:
FMS_AUTH_BASE=http://chenjiacheng.base.dahuo.fudingri.com
FMS_TOOLS_BASE=http://chenjiacheng.fmsoperate.dahuo.fudingri.com
FMS_CLIENT_TYPE=workbuddy
FMS_TIMEOUT_SECONDS=10
FMS_REFRESH_SKEW_SECONDS=120
FMS_LOG_LEVEL=info
本地 stdio 推荐 Redis token store:
FMS_TOKEN_STORE=redis
FMS_REDIS_HOST=192.168.1.241
FMS_REDIS_PORT=6379
FMS_REDIS_DB=20
FMS_REDIS_PASSWORD=
FMS_REDIS_PREFIX=fms:mcp:workbuddy:
公网模式推荐配置:
FMS_GATEWAY_MODE=public
FMS_GATEWAY_PUBLIC_BASE=https://mcp.example.com
FMS_GATEWAY_SESSION_TTL_SECONDS=2592000
FMS_TOKEN_STORE=redis
FMS_REDIS_HOST=127.0.0.1
FMS_REDIS_PORT=6379
FMS_REDIS_DB=20
FMS_REDIS_PASSWORD=change-me
FMS_REDIS_PREFIX=fms:mcp:gateway:
兼容旧配置键:
MCP_AUTH_BASE_URLMCP_TOOLS_BASE_URLMCP_CLIENT_TYPEMCP_TIMEOUT_SECONDSMCP_REFRESH_SKEW_SECONDSMCP_LOG_LEVELMCP_TOKEN_STOREMCP_TOKEN_STORE_PATHMCP_REDIS_HOSTMCP_REDIS_PORTMCP_REDIS_DBMCP_REDIS_PASSWORDMCP_REDIS_PREFIXMCP_SESSION_KEY说明:
config.py 会自动读取 mcp/.env。.env 优先,系统环境变量只作为兜底。FMS_API_BASE,会同时作为 auth 和 tools 的基础地址。FMS_AUTH_BASE 和 FMS_TOOLS_BASE。本地 stdio 模式:
fms:mcp:workbuddy:{session_key}。session_key 默认由员工本机 COMPUTERNAME / USERNAME 生成。.env 中不要写死 FMS_SESSION_KEY。公网 HTTP 模式:
fms:mcp:gateway:session:{sha256(gateway_session_id)}。gateway_session_id。mcp_token 返回给 Workbuddy 展示层。gateway_session_id、mcp_token 或授权码。文件存储仅用于开发排障:
FMS_TOKEN_STORE=file
FMS_TOKEN_STORE_PATH=C:/fms-mcp/.mcp_token.json
如果使用网络共享 app.py,不要把文件 token store 指向 \\192.168.1.241\chenjiacheng\mcp\ 共享目录。
ThinkPHP MCP 路由位于各后端项目的 route/mcp/mcp_route.php。
Gateway 会追加以下路径:
/mcp/auth/exchange、/mcp/auth/refresh、/mcp/auth/revoke/mcp/tools/queryOrder、/mcp/tools/queryTrackFMS_AUTH_BASE 和 FMS_TOOLS_BASE 只配置域名或基础地址,不要包含 /admin/mcp。
如果 Workbuddy 提示:
Unexpected UTF-8 BOM (decode using utf-8-sig)
说明后端工具接口返回的 JSON 前面带了 UTF-8 BOM。当前 Gateway 已在 HTTP JSON 解码层使用 utf-8-sig 兼容。先运行全量测试确认当前文件是否已包含修复:
python -m unittest discover -s tests -p "test_*.py"
Windows 下 Python 标准输出可能使用本机控制台编码。当前 mcp_protocol.py 已将 stdio JSON-RPC 响应改为 ensure_ascii=True,传输行只包含 ASCII JSON 转义,客户端解析后仍是正常中文。
如果仍然乱码,优先确认 Workbuddy 启动的是最新的 \\192.168.1.241\chenjiacheng\mcp\app.py。
gateway_session_id。