跳转至

MCP 能力与接口

本页汇总当前已实现的 MCP(Model Context Protocol)出站能力。

范围

  • ✅ 已实现:Agent 作为 MCP Client 调用外部 MCP Server(出站)。
  • ✅ 已实现:stdiohttp_sse 两种出站传输。
  • ✅ 已实现:http_sse 下的 URL Import 模式,可将普通 HTTP URL 映射为 MCP 工具。
  • ❌ 未实现:Chameleon 作为 MCP Server 对外提供入站能力。

功能清单

  • MCP Server 注册与健康检查
  • MCP Server 在线测试调用(控制面 tools/list / tools/call
  • MCP 凭据管理(加密存储 + 轮换)
  • Agent 级 MCP 挂载(优先级、allowlist、capability、超时、调用预算)
  • Agent 级 MCP 响应控制面(direct-response rules + quick-match rules + intent-gate rules)
  • Agent 级 MCP 真实预览与字段目录提取
  • 对话编排中的受控工具调用回路
  • 单次真实调用下的 MCP direct-response / raw JSON 直返
  • MCP 调用审计查询(按会话/按 Agent)

传输配置约束

stdio

  • 必填:connection_config.command
  • 可选:connection_config.args(字符串或字符串数组)

示例:

{
  "transport_type": "stdio",
  "connection_config": {
    "command": "uv",
    "args": ["run", "python", "scripts/mock_mcp_stdio.py"]
  }
}

部署注意:

  • 在线上部署环境中,stdio 命令是在 ai-service 运行容器内执行,不是在 Dokploy 宿主机或开发机上执行。
  • 因此脚本路径必须填写容器内路径,例如 /app/scripts/dewell_tracking_stdio.py,不要填写开发机路径 /home/atahang/codes/aibot/...
  • 当前 ai-service 镜像构建时会复制仓库内 scripts/ 到容器中的 /app/scripts/

Dokploy / 生产环境示例:

{
  "transport_type": "stdio",
  "connection_config": {
    "command": "uv",
    "args": ["run", "python", "/app/scripts/dewell_tracking_stdio.py"]
  }
}

http_sse

  • 必填:connection_config.url(必须是 http://https://
  • 可选:connection_config.headers(JSON 对象)
  • 可选:connection_config.import_modemcpurl
  • mcp:远端按 MCP action 处理请求
  • url:将 URL 映射为单工具模式(用于快速导入 GET/POST 接口)
  • import_mode=url 时可选:
  • connection_config.http_methodGET/POST(默认 GET
  • connection_config.tool_name:默认 imported_http_tool

示例:

{
  "transport_type": "http_sse",
  "connection_config": {
    "url": "https://api.example.com/tracking",
    "headers": {
      "Authorization": "Bearer {{token}}"
    },
    "import_mode": "url",
    "http_method": "GET",
    "tool_name": "tracking_lookup"
  }
}

接口入口

MCP Server 在线测试调用

新增端点:POST /mcp-servers/{mcp_server_id}/test-call

  • 用途:在 Admin Frontend 直接验证 MCP Server 返回结果,无需先挂载到 Agent。
  • 支持动作:
  • tools/list:返回工具列表和原始响应
  • tools/call:按 tool_name + arguments 执行一次工具调用
  • 可选参数:
  • credential_id:指定凭据
  • timeout_ms:覆盖默认超时

Agent 级 MCP 响应预览

新增端点:POST /agents/{agent_id}/mcp-response-preview

  • 用途:在 Agent 设置页里直接基于当前已挂载 MCP 执行一次真实调用,拿到字段目录,再配置 direct-response rule。
  • 请求体:
  • mcp_server_id
  • tool_name
  • arguments
  • 响应体:
  • status
  • latency_ms
  • raw_response_payload
  • business_response_payload
  • field_catalog[]
  • error_message
  • 限制:
  • chat Agent 支持
  • 仅允许当前 Agent 已挂载且 active 的 MCP Server
  • 若挂载配置了 allowed_tools_json,预览也必须遵守该 allowlist

tools/list 推荐返回结构

为提升参数生成稳定性,建议 MCP Server 在工具定义中返回 input_schema(JSON Schema)。 编排器会将该 schema 交给模型生成参数,并在本地做 required 字段预检。 如果 tools/list 返回多个工具,编排器会先过滤空名称工具并应用 Agent 挂载 allowlist。运行时会先走确定性选择(例如追踪意图优先 tracking tool),再在需要时使用有界上下文工具选择;如果当前消息并不明确需要任何工具,编排器会返回 no_tool,而不是盲用返回列表里的第一个工具。

当前运行时会把 query_trackingquery_tracking9 视为同一个 tracking capability,用于:

  • 确定性工具选择
  • allowlist 匹配
  • Agent direct-response rule 匹配
  • legacy raw passthrough key 匹配
  • pre/post gate user guidance
  • quick-match usage guidance

这些 capability 级判定与 guidance 文本现在由 ai_service/services/mcp_tool_capabilities.py 中的 capability registry 持有;ai_service/services/mcp_tool_runtime_strategies.py 负责把 capability 解析到对应的 runtime strategy;ai_service/services/mcp_tool_runtime_models.py 提供 capability-generic 的 runtime result shape;tracking 的具体运行时解析与门控逻辑则位于 ai_service/services/mcp_tool_tracking_runtime.pyMCPToolAdapterService 统一消费这几层能力资产,orchestrator/stream API 只消费抽象后的能力接口,不再直接分支判断 tracking tool,也不再直接 import 某个 concrete tracking runtime 常量。缺参/歧义 guidance payload 也统一使用 capability-generic key:missing_identifierscandidate_identifier_arguments,不再把 tracking-specific key shape 暴露到外层。

除内建 tracking capability 外,管理员现在还可以在 Agent 的某个 MCP 挂载上声明任意 tool_capability 标签,例如 shipment_etabooking_status。这类自定义 capability 当前不会自动获得 identifier 解析、歧义澄清、上下文续问等 runtime strategy;它们只用于把挂载接入 Agent mcp_response_config.intent_gate_rules[] 的挂载级前门禁。

另外:

  • 当唯一 eligible 工具就是 tracking tool 且当前消息没有任何追踪信号时,运行时会确定性跳过,不再额外跑一次 LLM 工具选择;但若最近可信 user 历史已建立 tracking 上下文,则像 SSHAS0172993 这样的纯标识回复仍可被识别为安全的补参回合。
  • mcp-tool-selectionmcp-argument-generation 都优先使用 structured output;其中工具选择会一次返回 selected_tool_name + should_call_now + missing_required_arguments + reason,仅在模型/网关不支持时回退到 JSON 文本解析。
  • 若工具来自 AI selector,运行时会直接复用这份结构化执行决策进入 mcp-pre-generation-gate,避免再做一次松耦合的“先选工具、再猜能否立即执行”判断。
  • 若命中 legacy mcp.raw_passthrough_tool_keys 且未命中 Agent direct-response rule,可通过 mcp.raw_passthrough_wrap_json_code_block=true(或环境变量 MCP_RAW_PASSTHROUGH_WRAP_JSON_CODE_BLOCK=true)让默认 raw JSON 直返包成 ```json fenced block。

示例:

{
  "tools": [
    {
      "name": "query_tracking9",
      "description": "Query De Well tracking by selectNo",
      "input_schema": {
        "type": "object",
        "properties": {
          "selectNo": {"type": "string"},
          "query": {"type": "string"},
          "round": {"type": "integer"}
        },
        "required": ["selectNo"]
      }
    }
  ]
}

query_tracking9 请求示例

{
  "action": "tools/call",
  "tool_name": "query_tracking9",
  "arguments": {
    "selectNo": "S55ES0000134"
  },
  "timeout_ms": 30000
}

query_tracking9 响应结构

query_tracking9 的返回分为两层:

  • 顶层:工具调用元信息
  • response:业务响应体

当前响应是“部分投影”而不是完整透传,规则如下:

  • 顶层 selectNo:本次实际用于查询的单号
  • response.selectNo:与顶层相同,便于消费方在业务层直接读取
  • response.tracking:保留 tracking 数组
  • tracking[].trackingSub[]:仅保留以下字段
  • equipment
  • currentStatus
  • shipmentType
  • containerNumberListMap
  • containerNumberListMap[]:仅保留以下字段
  • currentNewStatus
  • currentTime
  • currentLocation
  • curricon
  • currList
  • currList[]:返回完整事件列表,但每个事件只保留以下字段
  • tile
  • time
  • des
  • addtype

换句话说:

  • currList 是完整列表
  • containerNumberListMap 不是完整原始对象,而是裁剪后的对象列表
  • curricon 取自 currList 最后一条事件

示例响应:

{
  "tool": "query_tracking9",
  "selectNo": "S55ES0000134",
  "response": {
    "selectNo": "S55ES0000134",
    "tracking": [
      {
        "trackingSub": [
          {
            "equipment": "CONT-1",
            "currentStatus": "In Transit",
            "shipmentType": "FCL",
            "containerNumberListMap": [
              {
                "currentNewStatus": "Departed",
                "currentTime": "2026-03-09 09:30:00",
                "currentLocation": "Shanghai",
                "curricon": "ship",
                "currList": [
                  {
                    "tile": "Loaded",
                    "time": "2026-03-08 08:00:00",
                    "des": "Container loaded",
                    "addtype": "system"
                  },
                  {
                    "tile": "Departed",
                    "time": "2026-03-09 09:30:00",
                    "des": "Vessel departed",
                    "addtype": "system"
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
  }
}

消费建议

  • 如果消费的是 MCP 服务器工具原始返回,查询单号读取 response.selectNo
  • 如果消费的是聊天接口在 Agent direct-response raw_json 模式下的最终 response_content,查询单号直接读取 selectNo
  • 如果需要运输状态,读取 tracking[].trackingSub[].currentStatus
  • 如果需要整段轨迹事件,读取 tracking[].trackingSub[].containerNumberListMap[].currList
  • 如果需要 containerNumberListMap 的其他原始字段,当前脚本不会返回,需要额外扩展

配置入口

  • 配置说明:见 使用指南 / 配置
  • Agent 级 mcp_response_config.direct_response_rules[] 支持 wrap_json_code_block
  • 适用于 raw_json
  • 适用于 json_subset
  • 也适用于 text/json_subset 无法渲染字段时回退到 raw_json 的场景
  • 开启后返回形态为 Markdown ```json fenced block,便于下游直接按代码块展示原始 JSON
  • 关键项:[mcp] section、MCP_SECRET_KEY 等环境变量

Agent 级 Direct Return、Quick Match 与 Intent Gate(2026-03-18)

当前 MCP 控制面以 Agent 配置 mcp_response_config 为主,支持三类规则。查询前门禁关键词匹配的主入口是 Agent settings,而不是全局 ai_service/utils/settings.py

  • direct_response_rules[]
  • 绑定 mcp_server_id + tool_name
  • 在“单次真实 MCP 调用”的回合里决定是否绕过最终 LLM 总结
  • 输出模式支持:
    • raw_json
    • json_subset
    • text
  • quick_match_rules[]
  • 仅在 POST /streammessage_type=user_chat 上生效
  • 通过显式前缀命令直接映射到一个 MCP 工具,例如 #get_tracking123556
  • 这是 API 层快路径:命中后直接返回 SSE,不进入 orchestrator / 最终 LLM 总结
  • 可通过 suffix_parameter_name 把后缀文本映射到 MCP 参数
  • 在真正调用前仍执行 MCP 挂载/allowlist 校验、预门控/后门控、required 字段校验与审批 checkpoint;任一步阻断都不会发起 invoke_tool(...)
  • 若命中 quick-match 但 suffix_parameter_name 后缀为空,或工具 schema 仍缺少 required 字段,则直接返回确定性的 usage guidance,而不是回退到普通聊天;例如:Quick-match '#get_tracking' requires one cargo number after the prefix. Use HBL No., FBA No., CTN No., or PO No.
  • 可选 response_rule_key 复用 direct-response rule;若该字段未配置、留空或为空字符串,则 quick-match 不会自动套用同工具的 direct-response rule,而是直接返回 raw JSON
  • intent_gate_rules[]
  • tool_capability 允许管理员填写任意非空 capability 标签
  • tracking,用于配置 tracking/query 前门禁关键词与 Python regex 匹配
  • 对自定义 capability,运行时会在 discover_tools() 之前用该 rule 的 keywords[] / regex_patterns[] 对当前用户消息做一次挂载级过滤
  • match_source_mode 支持 defaultappendreplace
  • allow_contextual_follow_up=true 时,像“帮我查一下 / 那个呢”这类省略式续问可复用最近唯一可信标识;当前该逻辑仍只对 tracking 生效
  • 自定义 capability 若未配置 enabled rule,则运行时继续保持旧行为,不会额外拦截该挂载
  • 自定义 capability 目前没有内建默认 matcher,因此实际匹配来源就是管理员在 rule 中填写的关键词和 regex

direct-response 的运行语义:

  • 触发条件:
  • 本轮真实进入 invoke_tool(...) 的 MCP 调用次数恰好为 1
  • 命中了该 Agent 的某个 enabled direct-response rule
  • 返回方式:
  • raw_json:返回业务 payload 的 JSON 序列化结果
  • json_subset:只保留 selected_fields[]
  • text:按 prefix_text + selected_fields + suffix_text 渲染文本
  • 兜底行为:
  • json_subset / text 因字段缺失或全空无法渲染,运行时会回退为 raw JSON
  • 只要本轮真实 MCP 调用次数大于 1,就退回默认“聚合后总结”路径

产品约束说明:

  • direct-response、quick-match 与 intent-gate 的产品入口统一是 Agent 级 mcp_response_config
  • 挂载级 capability 的产品入口是 Agent MCP mount 的 tool_capability
  • [mcp] 配置仍负责运行时总开关、轮次数、超时和加密等底层能力,但不再作为业务关键词匹配或直返产品语义的主控制面

Agent 级 MCP Runtime Strategy(2026-03-31)

在不改变现有 mcp_response_config 语义的前提下,聊天 Agent 现在额外支持 mcp_runtime_config,用于覆盖 MCP 运行时策略:

  • history_user_message_window
  • 覆盖全局 [mcp].history_user_message_window
  • 控制 MCP 前门禁与参数生成可引用的最近用户消息条数
  • 0 表示禁用最近历史补全,只看当前消息
  • tool_selection_prompt_guidance
  • 追加到 Chameleon runtime 的 MCP 工具选择提示词末尾
  • 适合放管理员自定义的门禁偏好、优先级或保守策略
  • tool_argument_prompt_guidance
  • 追加到 Chameleon runtime 的 MCP 参数生成提示词末尾
  • 适合放参数抽取约束,例如“不要猜测缺失单号”

兼容性约束:

  • intent_gate_rules[] 仍然保留在 mcp_response_config
  • mcp_runtime_config 不重复存储 gate 规则,只负责 prompt/context 这类运行时覆盖
  • history_user_message_window 同时影响 chameleon_chat_v1langgraph_react_agent_v1
  • 两个 prompt guidance 字段当前仅影响 chameleon_chat_v1,因为只有它显式构造 MCP tool-selection / argument-generation helper prompt

失败时的最小 raw JSON payload 如下:

{
  "server_name": "tracking-server",
  "tool_name": "query_tracking9",
  "status": "error",
  "error_message": "upstream failed"
}

相关观测字段:

  • response_source
  • llm_generatedmcp_rawmcp_direct_responsemcp_quick_match
  • mcp_raw_passthrough
  • 布尔值,兼容标记当前响应是否来自 MCP 直返链路
  • mcp_direct_response
  • 当前响应是否命中 Agent direct-response 或 quick-match 直返
  • mcp_invocation_count
  • 当前轮次真实进入 invoke_tool(...) 的次数
  • mcp_output_mode
  • 当前直返输出模式,例如 raw_jsonjson_subsettext
  • mcp_response_rule_key
  • 命中的 direct-response rule key;若 quick-match 未绑定 formatter,则为 null
  • mcp_quick_match_prefix
  • 命中的 quick-match prefix
  • mcp_format_fallback_used
  • 字段格式化失败后是否回退为 raw JSON

query_tracking9 调用门控与参数生成(2026-04)

为避免”无号也查”与 AI 幻觉参数,tracking tool(query_tracking / query_tracking9)在每次 MCP 循环内按以下 6 个阶段顺序执行:

阶段一:mcp-tool-selection-decision

确定本轮是否选定 tracking tool,以及是否需要进入参数生成阶段。

  • 若当前消息包含可识别的追踪标识(单号、提单号、PO 号等),确定性选工具,并可跳过 AI 参数生成。
  • 若当前消息没有追踪标识但有追踪意图(含关键词/正则),选工具但进入参数生成。
  • 若消息属于闲聊或普通问答,静默跳过整条工具路径,不返回补参提示。
  • 若 AI 选择器返回 no_tool,同样跳过。

阶段二:mcp-pre-generation-gate(参数生成前门控)

进一步校验是否满足触发 AI 参数生成的条件。判断依据:

  • 当前消息含非歧义追踪标识should_attempt=true,允许进入生成。
  • 历史中含唯一追踪标识,且当前消息是省略式续问(如”查一下”、”继续”、”那个呢”)→ should_attempt=true,允许进入生成。
  • 历史中存在多个竞争标识should_attempt=false,返回歧义澄清提示,break。
  • 追踪意图但当前消息与历史均无标识should_attempt=false,返回结构化补参提示,break。
  • 非追踪内容should_attempt=false,静默跳过,不返回补参提示,break。
  • message_type=rule/form/other 且无显式追踪标识should_attempt=false,break。

注意:此阶段”历史标识”仅用于判断是否值得进入参数生成,不会直接填入工具参数。

阶段三:mcp-argument-generation(AI 参数生成)

调用 tool_call_model 生成工具参数。

  • 模型接收当前消息、工具 Schema、最近 user 历史(窗口大小由 history_user_message_window 控制,默认 3 条)作为上下文。
  • 优先使用 structured output,不支持时回退到 JSON 文本解析。
  • AI 的输出是权威信号:AI 输出了哪些字段,就代表它在上下文中找到了哪些信息。若 AI 未输出某个 required 字段(如 selectNo),说明当前上下文不足以提供该参数,不应强行填充。

阶段四:build_tool_arguments(参数组装,非独立 span)

将 AI 生成的参数与当前消息的确定性提取结果合并,得到最终工具调用 payload。

此阶段分两个来源,优先级明确

来源 A — AI 生成参数(主要来源)

  • AI 输出的参数先经过 canonicalize(别名归一化)。
  • 对追踪标识字段做可追溯性校验:只有能从当前消息(或允许历史复用时从最近 user 历史)确定性回溯到的值才保留,无法追溯的视为幻觉丢弃。
  • 通过校验的字段直接写入 payload。

来源 B — 当前消息确定性提取(兜底来源)

  • 仅对当前消息(resolution_source=current_user_message)做规则提取。
  • 典型场景:用户在上一轮被询问后,当前轮直接回复了单号(如 S55ES0000134),此时当前消息就是单号本身,直接提取补入。
  • 不从历史消息中自动填充:历史中的旧单号不会在此阶段注入 payload。这是故意的设计——若 AI 已经看到历史却没有生成该字段,说明它判断当前上下文不足,不应由规则层覆盖这一判断。

最终 payload 还包含两个固定字段:query(原始用户消息)和 round(当前执行轮次)。

阶段五:mcp-tool-attempt-gate(参数生成后门控)

对已组装的参数做二次追踪标识校验。

  • 若 payload 中的追踪标识字段可从用户消息确定性回溯 → should_attempt=true
  • 若无可用标识 → should_attempt=false,返回补参提示,break。
  • 若存在歧义 → should_attempt=false,返回歧义澄清提示,break。

阶段六:mcp-required-argument-check(必填字段校验)

对照工具 Schema 的 input_schema.required 数组,逐一检查 payload 中每个必填字段是否有有效值。

  • 若全部必填字段均有值 → 放行,进入 mcp-call。
  • 若存在缺失字段 → 记录审计(status=blocked),返回结构化缺参提示,break。

总结:门控触发条件

场景 在哪个阶段拦截 是否返回补参提示
非追踪内容(闲聊、问答) pre-generation-gate 否,静默跳过
追踪意图但无标识 pre-generation-gate
历史中标识歧义 pre-generation-gate / tool-attempt-gate 是(歧义澄清)
AI 未生成 required 字段,且当前消息无单号 required-argument-check
AI 生成了幻觉字段(无法从消息追溯) build_tool_arguments 丢弃,若由此导致必填缺失 由 required-argument-check 处理
省略式续问(”查一下”)+ 历史唯一标识 允许通过至 mcp-call
用户直接回复单号(当前消息即单号) 由来源 B 兜底补入,允许通过

其他约束

  • 工具选择与参数生成读取最近 3user 历史(可通过 mcp_runtime_config.history_user_message_window 覆盖);assistant 历史不参与标识提取。
  • 解析层兼容多种标识格式:selectNo=...BLcontainerbooking、纯数字单号、混合字母数字单号(如 555E898665)、常见 typo(如 traking 212234566)。
  • message_type=rule/form/other 默认不触发参数生成;仅在消息含显式追踪标识时允许调用。
  • 参数生成提示词可通过 mcp_runtime_config.tool_argument_prompt_guidance 追加自定义约束。

MCP 审计状态语义(2026-03)

  • blocked:表示系统本来打算进入该工具路径,但被策略、歧义或缺参阻断。
  • skipped:表示系统根据当前上下文决定不进入该工具路径。
  • 当当前消息上下文没有明确匹配任何工具时,审计会以 tool_name="_tool_selection" 记录一次 skipped 决策,而不是把普通聊天错误挂到某个业务工具名上。

本地 Mock MCP 脚本测试

项目内提供了一个最小可用脚本:/home/atahang/codes/aibot/scripts/mock_mcp_stdio.py

执行方式

echo '{"action":"tools/call","tool_name":"echo_time"}' | uv run python /home/atahang/codes/aibot/scripts/mock_mcp_stdio.py

示例输出

{"tool": "echo_time", "utc_time": "2026-02-10T03:16:48.411520+00:00", "arguments": {}}

说明:utc_time 为实时时间,每次执行都会不同。

其他常用测试

# Health check
echo '{"action":"health/check"}' | uv run python /home/atahang/codes/aibot/scripts/mock_mcp_stdio.py

# List tools
echo '{"action":"tools/list"}' | uv run python /home/atahang/codes/aibot/scripts/mock_mcp_stdio.py

部署平台添加本地 stdio MCP

若你是在 Dokploy 或其他部署平台上通过 Admin Frontend 添加 MCP Server,需注意:

  • CommandArgs 是两个独立表单字段。
  • Args 输入框不是 JSON 数组输入框,而是普通文本框;前端会按空格拆分参数。
  • 因此在 UI 中应填写:
  • Command: uv
  • Args: run python /app/scripts/dewell_tracking_stdio.py
  • 不要在 Args 中填写 ["run", "python", "/app/scripts/dewell_tracking_stdio.py"] 这种 JSON 数组字符串,否则后端会把整串当成一个参数,出现类似 No such file or directory: '[\"run\", ...]' 的错误。

推荐上线后立即执行两步验证:

  • Health Check
  • Test Call -> tools/list

常见工具测试示例:

{
  "action": "tools/list"
}
{
  "action": "tools/call",
  "tool_name": "query_tracking9",
  "arguments": {
    "selectNo": "S55ES0000134"
  }
}