tech-specs.md 5.4 KB

技术规格

技术栈与边界

  • Gateway:Python 3,核心运行模块只使用标准库;stdio 使用逐行 JSON-RPC,公网使用 ThreadingHTTPServer
  • 后端:ThinkPHP 6.0 + PHP 7.1+,按 Controller / Logic / Model / Validate 分层实现业务工具。
  • 存储:Redis 保存本地 token 或公网 Gateway session;MySQL、MongoDB 和文件存储只由所属业务系统访问。
  • Gateway 不连接业务数据库;跨仓调用只通过明确的 HTTP 路由和服务端会话进行。

组件

组件 职责
app.py 本地 GatewayApp、stdio/CLI 入口、11 个工具注册与参数转发
public_gateway.py 公网 PublicGatewayApp、设备会话解析后的 scoped 调用、同组 11 个工具注册
public_server.py /mcp HTTP JSON-RPC、可信追踪号、审计上下文、限流和 /health
mcp_protocol.py MCP 握手、tools/listtools/call、旧/新结果分流和协议错误
services/api_client.py 本地 token 上下文下的 ThinkPHP 工具请求与动态列表请求
services/scoped_api_client.py 公网请求级 mcp_token 转发,避免进程级身份串用
services/gateway_session_store.py GWS_xxx 到服务端员工会话的 Redis 映射
services/output_presenter.py 10 个安全工具的白名单 DTO、错误映射和文本渲染
tools/*.py 工具名称、说明、输入 Schema、路由和调用封装

本地与公网会话

本地 stdio 流程:

  1. GatewayApp 从 Redis 或开发用文件 store 读取本机 session。
  2. token 临近过期时通过 base 刷新。
  3. tools/listtools/call 携带该 token 请求 fmsoperate。

公网流程:

  1. Workbuddy 通过 Header、Bearer 或 Cookie 提交 GWS_xxx
  2. RequestContextParser 提取设备凭据,GatewaySessionStore 从 Redis 获取服务端 mcp_token
  3. PublicGatewayApp 为单次请求创建 scoped API 调用上下文,不把 token 放进进程全局状态。
  4. fmsoperate 再校验 token、员工状态、公司、工具权限和业务数据范围。

会话缺失、过期或后端动态列表不可用时关闭访问。公网不得使用文件 token store、固定 FMS_SESSION_KEY 或共享进程级员工 token。

动态工具可见性

  • GatewayAppPublicGatewayApp 的候选注册顺序和名称必须完全一致,当前各为 11 个。
  • tools/list 调用 /mcp/tools/listEnabledTools,只返回本地注册与后端启用代码的交集。
  • tools/call 重新读取启用集合,避免工具被禁用后继续调用。
  • MCP 返回 tools.listChanged=false,因此工具或 Schema 变更必须通过 Gateway 重启和客户端重连刷新。

Presenter 分类

query_order 走旧协议分支,保留 columns/records/meta 和既有文本行为。OutputPresenter.SAFE_TOOLS 显式处理其余 10 个工具:

类型 工具 DTO
表格 query_order_exactquery_trackquery_customs_declaration_filesquery_outbound_list headers + rows + pagination
排舱详情 query_outbound_detail summary + details,分页位于 details.pagination
筛选项 list_order_filter_optionslist_outbound_filter_optionslist_pending_outbound_export_filter_options value + label + code 三列
导出 export_pending_outbound_ordersexport_out_of_province_port_data files[].label + files[].url

Presenter 对列定义、记录类型、详情汇总、附件结构和导出 URL 做白名单校验。未知工具、未允许列、畸形响应或未知异常返回安全 isError=true;真实异常仅记录在服务端日志。后端业务错误映射为固定消息,不透传原始 msg/data

追踪、日志与限流

  • stdio 自动生成 rq_*;公网入口始终生成可信 rq_http_*,不采信调用方 X-Request-Id
  • 调用方 X-Request-Id 只记录 SHA-256 短哈希 client_request_id_hash,用于关联客户端反馈。
  • 追踪号贯穿动态工具列表、工具调用、MCP _meta 和结构化日志。
  • 审计日志只记录必要的 request/jsonrpc ID、协议方法、工具代码、员工/公司标识和脱敏客户端标识;禁止记录凭据与原始响应。
  • initializetools/list 不进入限流器;tools/call 使用进程内 SimpleRateLimiter,已知工具按 gateway_session_id + tool_name 分桶。
  • 限流配置为 FMS_RATE_LIMIT_ENABLEDFMS_RATE_LIMIT_MAX_REQUESTSFMS_RATE_LIMIT_WINDOW_SECONDS;生产环境还应在反向代理层限流。

关键业务参数

  • query_outbound_list.outbound_status 必填,只暴露后台业务阶段;shipping_method 无默认值,未传表示全部运输方式。
  • query_outbound_list.warehouse_id 接受正整数或 -1(客户仓),拒绝 0 与其他负数。
  • list_outbound_filter_options.filter_type 使用七个中文枚举;仓库分支由 fmsoperate 复用 OrderModel::getSortWarehouse(),所有分支先校验 admin/Outbound/index
  • 排舱筛选响应保留 value/label/code 供跨工具传参,面向用户只展示中文标签。

验证基线

python -m unittest discover -s tests -p "test_*.py"
python -m coverage run -m unittest discover -s tests -p "test_*.py"
python -m coverage report -m --fail-under=100
git diff --check

运行 coverage 会更新本地 .coverage 文件;只做文档治理时使用已有只读报告,不应制造覆盖率产物变更。