mcp服务

jackson e8671a85ea mcp пре 2 недеља
services 8f2bebf87b mcp пре 2 недеља
tests 0fbd342225 mcp пре 2 недеља
tools 0fbd342225 mcp пре 2 недеља
.env.example f0ff40881c mcp服务 пре 2 недеља
.gitignore f0ff40881c mcp服务 пре 2 недеља
README.md e8671a85ea mcp пре 2 недеља
app.py 0fbd342225 mcp пре 2 недеља
config.py f0ff40881c mcp服务 пре 2 недеља
mcp_protocol.py 0fbd342225 mcp пре 2 недеља
requirements.txt f0ff40881c mcp服务 пре 2 недеља

README.md

Python MCP Gateway

这是一个轻量的 Python MCP Gateway,用来把 Workbuddy 的 MCP 工具调用转发到现有 ThinkPHP 授权接口和工具接口。

当前状态

当前仓库已经具备一个可运行的 stdio MCP 入口,以及一套经过测试的核心模块,覆盖:

  • .env 优先的配置加载
  • Redis token 存储,按员工本机 session_key 隔离
  • 文件型 token 存储兜底
  • auth_code 换票、续期、失效的认证客户端
  • bind_auth_code 授权绑定工具
  • 工具 HTTP 转发客户端
  • query_order 工具注册
  • Gateway 运行时会话管理
  • MCP initialize / tools/list / tools/call 请求处理
  • 本地命令模式下的 stdio MCP 启动入口

当前实现仍然保持“薄网关”原则:

  • 业务认证和权限判断仍然留在 ThinkPHP 项目中
  • Gateway 只负责协议适配、会话管理和 HTTP 转发
  • 第一阶段只开放查询型工具,当前从 query_order 开始

Workbuddy 配置

员工侧 Workbuddy 使用网络 UNC 路径启动 Gateway:

{
  "mcpServers": {
    "fms": {
      "command": "python",
      "args": [
        "\\\\192.168.1.241\\mcp\\app.py",
        "serve-stdio"
      ]
    }
  }
}

不要把 Y:\mcp\app.py 写进 Workbuddy 配置;那只是开发机映射盘视角。

常用命令

以下命令在 mcp/ 目录下执行。

查看工具列表

python app.py list-tools

绑定授权码(开发/排障)

python app.py bind --auth-code AUTH123

员工正式使用时不需要执行这条命令。Workbuddy 拉起 serve-stdio 后,员工应在 Workbuddy 中调用 bind_auth_code 工具完成绑定。

直接调用 query_order(开发/排障)

python app.py call --tool query_order --keyword SO20260706001 --page 1 --limit 20

启动 MCP stdio 服务

python \\192.168.1.241\chenjiacheng\mcp\app.py serve-stdio

这个命令可作为 Workbuddy 本地命令模式下的 MCP 服务入口,由 Workbuddy 自动拉起,不要求员工手动执行。

环境变量

当前代码直接支持以下文档口径的配置键:

  • FMS_API_BASE
  • FMS_AUTH_BASE
  • FMS_TOOLS_BASE
  • FMS_CLIENT_TYPE
  • FMS_TIMEOUT_MS
  • FMS_TIMEOUT_SECONDS
  • FMS_REFRESH_SKEW_SECONDS
  • FMS_LOG_LEVEL
  • FMS_TOKEN_STORE
  • FMS_TOKEN_STORE_PATH
  • FMS_REDIS_HOST
  • FMS_REDIS_PORT
  • FMS_REDIS_DB
  • FMS_REDIS_PASSWORD
  • FMS_REDIS_PREFIX
  • FMS_SESSION_KEY

同时兼容早期实现中的这些键名:

  • MCP_AUTH_BASE_URL
  • MCP_TOOLS_BASE_URL
  • MCP_CLIENT_TYPE
  • MCP_TIMEOUT_SECONDS
  • MCP_REFRESH_SKEW_SECONDS
  • MCP_LOG_LEVEL
  • MCP_TOKEN_STORE
  • MCP_TOKEN_STORE_PATH
  • MCP_REDIS_HOST
  • MCP_REDIS_PORT
  • MCP_REDIS_DB
  • MCP_REDIS_PASSWORD
  • MCP_REDIS_PREFIX
  • MCP_SESSION_KEY

说明:

  • config.py 会自动尝试读取 mcp/.env
  • 同名配置以 .env 优先,系统环境变量只在 .env 缺少该配置时兜底。
  • 如果只提供 FMS_API_BASE,当前实现会同时把它作为 auth 和 tools 的基础地址。
  • 如果 basefmsoperate 部署在不同域名,应分别提供 FMS_AUTH_BASEFMS_TOOLS_BASE

.env 文件

当前 mcp/ 目录建议使用 .env 保存共享 Gateway 配置。

推荐配置如下:

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

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:

不要在共享 .env 中写死 FMS_SESSION_KEY。默认情况下 Gateway 会用员工本机的 COMPUTERNAME / USERNAME 自动生成稳定 session_key,Redis key 形如:

fms:mcp:workbuddy:{session_key}

这样多个员工通过同一个 \\192.168.1.241\chenjiacheng\mcp\app.py 启动时,也不会共用同一个 token。

Token 存储

当前推荐使用 Redis:

FMS_TOKEN_STORE=redis

Redis 存储行为:

  • bind_auth_code 成功后把 mcp_token 写入 Redis
  • Redis key 使用 FMS_REDIS_PREFIX + session_key
  • session_key 优先读取 FMS_SESSION_KEY,未配置时自动从员工本机信息生成
  • token 过期时间会同步设置为 Redis TTL
  • revoke 成功后会删除当前 session 的 Redis key

文件存储仍保留为兜底方式:

FMS_TOKEN_STORE=file
FMS_TOKEN_STORE_PATH=C:/fms-mcp/.mcp_token.json

如果使用网络共享 app.py,不要把 FMS_TOKEN_STORE_PATH 指向 \\192.168.1.241\chenjiacheng\mcp\ 共享目录。

本地接入建议

当前员工正式使用路径是:

  1. 员工在后台获取一次性 auth_code
  2. Workbuddy 自动通过 python \\192.168.1.241\chenjiacheng\mcp\app.py serve-stdio 拉起 Gateway
  3. 员工在 Workbuddy 中调用 bind_auth_code,输入授权码完成绑定
  4. Gateway 调用 exchange 时带上 session_key
  5. token 保存到 Redis 当前员工对应的 key
  6. 后续直接使用 query_order 等工具

python app.py bind --auth-code ... 仅保留给开发、联调和排障使用。

测试命令

python -m unittest discover -s tests -p "test_*.py"

当前边界

当前 Gateway 已可作为本地 stdio MCP 进程使用,但仍保持最小边界:

  • 不在 Python 中沉淀额外业务规则
  • 不直接连接业务数据库
  • 不做动态插件加载
  • 第一阶段不开放写入型工具

    query_order BOM 排障

如果 Workbuddy 调用 query_order 时提示:

Unexpected UTF-8 BOM (decode using utf-8-sig)

说明后端工具接口返回的 JSON 前面带了 UTF-8 BOM。当前 Gateway 已在 HTTP JSON 解码层使用 utf-8-sig 做兼容。排查时先在 mcp/ 目录运行:

python -m unittest discover -s tests -p "test_*.py"

若全量测试通过但 Workbuddy 仍报同样错误,优先确认 Workbuddy 启动的 app.py 是否为 \\192.168.1.241\chenjiacheng\mcp\app.py 的最新文件。

2026-07-07 ThinkPHP MCP route path

ThinkPHP MCP routes now live in each backend project's route/mcp/mcp_route.php. The Gateway appends these paths to FMS_AUTH_BASE and FMS_TOOLS_BASE:

  • Auth: /mcp/auth/exchange, /mcp/auth/refresh, /mcp/auth/revoke
  • Tools: /mcp/tools/queryOrder

Keep FMS_AUTH_BASE and FMS_TOOLS_BASE as host/base-domain values. Do not include /admin/mcp in these environment variables.

query_track / stdio 中文乱码排障

如果后端 HTTP 返回、保存到 UTF-8 文件都正常,但 Workbuddy/AI 调 MCP 工具时中文显示成乱码,优先检查 Python Gateway 的 serve-stdio 输出层。

本次踩坑原因:Windows 下 Python 标准输出可能使用本机控制台编码,而 MCP stdio 客户端按 JSON/UTF-8 读取时会出现中文乱码。当前 mcp_protocol.py 已将 JSON-RPC stdio 响应改为 json.dumps(..., ensure_ascii=True),传输行只包含 ASCII JSON 转义;客户端解析 JSON 后仍是正常中文。

排查顺序:

  • 先确认 HTTP 层 ApiClient 能用 utf-8-sig 正常解析后端 JSON。
  • 再确认 serve-stdio 输出不是直接吐本机编码中文。
  • 修改后需要重启 Workbuddy 拉起的 MCP Gateway 进程。

验证命令:

python -m unittest discover -s tests -p "test_*.py"