ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

FinceptTerminal AI Chat 中 MCP 工具报 “Tool not found“ 怎么检查注册?

FinceptTerminal AI Chat 中 MCP 工具报 “Tool not found“ 怎么检查注册? FinceptTerminal AI Chat 中 MCP 工具报 Tool not found 怎么检查注册【免费下载链接】FinceptTerminalFinceptTerminal is a modern finance application offering advanced market analytics, investment research, and economic data tools, designed for interactive exploration and>项目地址: https://gitcode.com/GitHub_Trending/fi/FinceptTerminal在 FinceptTerminal 的 AI Chat 里让模型调用某个 MCP 工具时如果返回Tool not found说明这个工具名在运行时注册表里根本不存在。排查的落点只有一个工具是否被注册进了McpProvider的内部工具注册表。本文按“先看运行时注册表再查源码与构建配置”的顺序给出可执行的检查路径涉及 AI Chat、McpInit.cpp、CMakeLists.txt这几处。先理解注册发生在哪个环节内部 MCP 工具从工厂到调用链路上是这样走的LlmService (HTTP / streaming) │ via ToolDispatcher ▼ ToolDispatcher (multi-round loop, parallel tool fan-out) ▼ McpService::execute_*_async ← 统一入口 ▼ 内部工具: McpProvider ← 注册表 分发 权限门 外部工具: McpManager → McpClient (JSON-RPC over stdio)见 MCP_TOOLS_GUIDE.md 第 1 节的架构说明。注册发生在启动阶段McpInit.cpp 里的initialize_all_tools()逐个调用各模块的工厂函数并注册例如void initialize_all_tools() { auto provider McpProvider::instance(); // navigation provider.register_tools(tools::get_navigation_tools()); // ... provider.register_tools(tools::get_meta_tools()); // ... LOG_INFO(TAG, QString(Registered %1 internal MCP tools).arg(provider.tool_count()));之后每一次工具调用都经过McpProvider::call_tool_async它先解析名字再查注册表// Phase 6.10: try canonical name first, then any registered alias. QString resolved name; if (!tools_.contains(resolved)) { for (auto it tools_.constBegin(); it ! tools_.constEnd(); it) { if (it.value().legacy_aliases.contains(name)) { LOG_INFO(TAG, QString(Tool called by legacy name %1 — canonical %2).arg(name, it.key())); resolved it.key(); break; } } } if (!tools_.contains(resolved)) return fail_now(Tool not found: name); if (disabled_tools_.contains(resolved)) return fail_now(Tool is disabled: resolved);摘自 McpProvider.cpp。两个要点Tool not found是“规范名和所有 legacy alias 都没命中注册表”的结果。按 MCP_TOOLS_GUIDE.md 的说法它意味着工厂没返回这个工具、工厂没在McpInit.cpp里被注册或模块的.cpp没进构建三种情况之一。名字解析顺序是先规范名、后legacy_aliases命中别名时会打一条 INFO 日志Tool called by legacy name ... — canonical ...日志里会给出当前规范名可直接用来纠正调用。用 AI Chat 里的 meta 工具检查注册表不需要改代码AI Chat 自身注册了 meta 工具tool_list、tool_describe、mcp_health见 MetaTools.cpp可以直接用来核对运行时状态。第一步跑mcp_health看整体数量与分类计数在 AI Chat 中让模型调用mcp_health。它的 handler 返回的内容包括internal段tool_count当前启用的工具数、all_count注册表总数、disabled_count以及按category分组的计数无分类的归入(uncategorising)实际键为(uncategorised)external段每个外部 MCP 服务器的id、name、status、enabled、auto_startdatahub段topic 数、订阅者总数、发布总数tool_rag段tool_list/tool_describe的调用计数与 top 曝光工具timestampISO 日期。判断方式如果你要查的工具所属分类计数为 0说明这一整个模块的工厂没被调用或没被编译如果分类计数正常但缺个例问题通常出在工厂函数自己没把这个工具push_back进去。第二步tool_describe点名核对或用tool_list找正确名字tool_describe的入参是name必填长度 1–128工具名不带 server 前缀命中时返回{name, category, description, input_schema, server_id}未命中时它自己也会返回Tool not found: nameMetaTools.cpp所以它可以直接当“点名探针”用。tool_list按自然语言查询检索目录BM25 排序入参query必填1–256 字符、可选category、top_k1–20默认 5。当不确定规范名是什么时用它按功能描述搜再从返回的name字段拿准确名字。注意核对时请使用规范名。命名约定是点分式area.verb例如markets.get_quote而不是get_quote见 MCP_TOOLS_GUIDE.md 第 5 节的 Naming convention。旧名如果配了legacy_aliases也能解析没配的话调用旧名就会得到Tool not found——这是重命名后最常见的一种“假性”未注册。新加的工具报 Tool not found三个检查点如果工具是你刚加的按 MCP_TOOLS_GUIDE.md 第 6 节 Diagnosis 给出的顺序逐项核对工厂是否返回了它。模块工厂函数如get_markets_tools()返回std::vectorToolDef确认定义完的ToolDef在函数末尾有tools.push_back(std::move(t));工厂是否在McpInit.cpp里被注册。McpInit.cpp 的initialize_all_tools()里要有一行对应的provider.register_tools(tools::get_xxx_tools())。新建了MyAreaTools.{h,cpp}这类新分类文件时这一步最容易漏。模块的.cpp是否进了构建。CMakeLists.txt 中的MCP_SOURCES列表列出了所有要编译的 MCP 源文件# MCP — Model Context Protocol system set(MCP_SOURCES # Core src/mcp/McpProvider.cpp src/mcp/McpService.cpp ... # Tool modules src/mcp/tools/JobTools.cpp src/mcp/tools/NavigationTools.cpp src/mcp/tools/MarketsTools.cpp ...新建工具文件时文档要求同时更新MCP_SOURCES和SKIP_UNITY_BUILD_INCLUSION列表。漏掉这一项的后果正是编译产物里根本没有这个模块运行时注册表里自然查不到表现就是Tool not found。改完后重新构建启动时看日志。initialize_all_tools()注册完会打一条 INFORegistered N internal MCP toolsN是当次运行实际注册的数量随工具总数变化不是固定值。用它和上一次启动的计数对比可以快速判断新模块有没有被计入配合mcp_health的all_count二次确认。区分 Tool not found 与 Tool is disabled注册表里“存在但被禁用”是另一种失败报错文案不同不要混为一谈tools_.contains(resolved)不通过 →Tool not found: name工具在disabled_tools_集合里 →Tool is disabled: name由set_tool_enabled(name, false)标记见 McpProvider.cpp。mcp_health的internal段同时给出tool_count、all_count和disabled_count三者相等说明没有工具被禁用all_count明显大于tool_count时则存在被禁用的工具。另外即使工具已经注册调用仍可能在后续环节失败——参数 schema 校验validate_args在 handler 之前执行拒绝时会打Tool %1 rejected: ...日志和授权门auth_required/is_destructive。这些失败各有各的报错不属于Tool not found的排查范围出现时再按日志文案分别处理。小结Tool not found的检查路径就是mcp_health看分类计数和all_count→tool_describe/tool_list点名或搜索确认注册名 → 新工具场景按“工厂push_back、McpInit.cpp注册、CMakeLists.txt的MCP_SOURCES/SKIP_UNITY_BUILD_INCLUSION”三点核对 → 重新构建后用启动日志的Registered N internal MCP tools与mcp_health复核。凡是命中 legacy alias 的调用日志里会打印规范名优先改用规范名调用。【免费下载链接】FinceptTerminalFinceptTerminal is a modern finance application offering advanced market analytics, investment research, and economic data tools, designed for interactive exploration and>项目地址: https://gitcode.com/GitHub_Trending/fi/FinceptTerminal创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进