diff --git a/mcp_servers.json b/mcp_servers.json index 854d3cb..0093882 100644 --- a/mcp_servers.json +++ b/mcp_servers.json @@ -26,7 +26,7 @@ "list_pending_changes" ] }, - "instructions": "MANDATORY for profiles that expose gnexus-book tools: Before answering any question about infrastructure, servers, services, networks, documentation, or system inventory, call gnexus-book tools first.\n\nUse only gnexus-book tool names that are present in the current tool schema. In Navi they are exposed with the mcp_gnexus-book_ prefix, but each profile may expose only some groups. Do not invent or call gnexus-book tools that are not in the current tool list.\n\nQuery mapping by capability:\n- Status or facts about a server/service → search docs first, then read a specific doc or inventory item if those tools are available.\n- Service placement or topology → list inventory and relationships if available.\n- Documentation changes → read the target doc first, then propose a doc or inventory change if write tools are available.\n- Freshness questions → use freshness checks if available.\n- Repository validation/status → use repository tools only if they are available in the current tool schema; otherwise skip this step and continue with available read/write tools.\n\nDo not rely on memory for infrastructure facts. Memory is only for personal user facts and preferences. Always pull infrastructure state from gnexus-book when these tools are available to the active profile.\n\nDo not store raw secrets in documentation.\n\nABSOLUTE RULE — NEVER bypass MCP tools:\nYou MUST NOT use filesystem, terminal, code_exec, or any direct file access to read or write gnexus-book files. The MCP tools are the ONLY valid interface to this knowledge base. Violating this rule bypasses validation, corrupts repository state, and breaks consistency guarantees.\n- To read: use mcp_gnexus-book_search_docs, mcp_gnexus-book_read_doc, mcp_gnexus-book_list_inventory, mcp_gnexus-book_get_inventory_item.\n- To write: use mcp_gnexus-book_propose_doc_change, mcp_gnexus-book_propose_inventory_item_change, mcp_gnexus-book_apply_pending_change, mcp_gnexus-book_commit_changes.\n- NEVER call filesystem write, filesystem smart_edit, terminal, or code_exec on gnexus-book paths.\n\nBefore the final response, decide whether tool execution revealed stable reusable infrastructure facts, service configurations, or relationships. If yes and gnexus-book write tools are available, persist them before answering. If write tools are not available, report the facts that should be persisted. If the fact is user-specific rather than infrastructure documentation, use the memory tool instead. Choose the target based on scope, not habit." + "instructions": "MANDATORY for profiles that expose gnexus-book tools: Before answering any question about infrastructure, servers, services, networks, documentation, or system inventory, call gnexus-book tools first.\n\nUse only gnexus-book tool names that are present in the current tool schema. In Navi they are exposed with the mcp:gnexus-book: prefix (example: mcp:gnexus-book:search_docs), but each profile may expose only some groups. Do not invent or call gnexus-book tools that are not in the current tool list.\n\nQuery mapping by capability:\n- Status or facts about a server/service → search docs first, then read a specific doc or inventory item if those tools are available.\n- Service placement or topology → list inventory and relationships if available.\n- Documentation changes → read the target doc first, then propose a doc or inventory change if write tools are available.\n- Freshness questions → use freshness checks if available.\n- Repository validation/status → use repository tools only if they are available in the current tool schema; otherwise skip this step and continue with available read/write tools.\n\nDo not rely on memory for infrastructure facts. Memory is only for personal user facts and preferences. Always pull infrastructure state from gnexus-book when these tools are available to the active profile.\n\nDo not store raw secrets in documentation.\n\nABSOLUTE RULE — NEVER bypass MCP tools:\nYou MUST NOT use filesystem, terminal, code_exec, or any direct file access to read or write gnexus-book files. The MCP tools are the ONLY valid interface to this knowledge base. Violating this rule bypasses validation, corrupts repository state, and breaks consistency guarantees.\n- To read: use mcp:gnexus-book:search_docs, mcp:gnexus-book:read_doc, mcp:gnexus-book:list_inventory, mcp:gnexus-book:get_inventory_item.\n- To write: use mcp:gnexus-book:propose_doc_change, mcp:gnexus-book:propose_inventory_item_change, mcp:gnexus-book:apply_pending_change, mcp:gnexus-book:commit_changes.\n- NEVER call filesystem write, filesystem smart_edit, terminal, or code_exec on gnexus-book paths.\n\nBefore the final response, decide whether tool execution revealed stable reusable infrastructure facts, service configurations, or relationships. If yes and gnexus-book write tools are available, persist them before answering. If write tools are not available, report the facts that should be persisted. If the fact is user-specific rather than infrastructure documentation, use the memory tool instead. Choose the target based on scope, not habit." }, "navi-3d": { "transport": "stdio", diff --git a/navi/core/tool_executor.py b/navi/core/tool_executor.py index 33a51c9..d116862 100644 --- a/navi/core/tool_executor.py +++ b/navi/core/tool_executor.py @@ -38,6 +38,16 @@ if len(normalized_matches) == 1: return normalized_matches[0] + # Fallback: old underscore format like mcp_server_tool → mcp:server:tool + old_format_matches = [ + (candidate_name, candidate) + for candidate_name, candidate in tool_map.items() + if candidate_name.startswith("mcp:") and name.startswith("mcp_") + and candidate_name.replace(":", "_") == name + ] + if len(old_format_matches) == 1: + return old_format_matches[0] + return name, None diff --git a/tests/unit/core/test_tool_executor.py b/tests/unit/core/test_tool_executor.py index aa5e180..f2ed782 100644 --- a/tests/unit/core/test_tool_executor.py +++ b/tests/unit/core/test_tool_executor.py @@ -36,3 +36,18 @@ assert images == [] assert messages[0].name == "mcp:gnexus-book:search_docs" assert messages[0].content == "executed mcp:gnexus-book:search_docs" + + async def test_executes_old_underscore_format_fallback(self): + registry = ToolRegistry() + tool = FakeTool("mcp:gnexus-book:search_docs") + registry.register(tool, builtin=True) + executor = ToolExecutor(registry) + + messages, images = await executor._execute_tool_calls( + [ToolCallRequest(id="1", name="mcp_gnexus-book_search_docs", arguments={"query": "git"})], + [tool], + ) + + assert images == [] + assert messages[0].name == "mcp:gnexus-book:search_docs" + assert messages[0].content == "executed mcp:gnexus-book:search_docs"