Skip to content

G2/G3/G4 MCP tools missing from mcp_serve.list_tools() despite create_mcp_server() registration #88

@PowerCreek

Description

@PowerCreek

9th cascade bug, follow-up to #82/#83/#85/#86 + #79.

Observed

Worker (post-autowire) reports asyncio.run(srv.list_tools()) returns only canvas/conversation/messages/channels tools — missing all 6 G2/G3/G4 tools: silo_query, confer_run, file_issue, lane_h_list, lane_h_fetch, grafted_context_fetch.

Investigation

Direct invocation in dev workspace:

from mcp_serve import create_mcp_server
mcp = create_mcp_server()
import asyncio
[t.name for t in asyncio.run(mcp.list_tools())]  # → 32 tools including all 6

The G2/G3/G4 registrars (_register_devagentic_mutation_tools, _register_github_tools, _register_lane_h_tools) exist in mcp_serve.py:1447/1569/1659 AND are called from create_mcp_server at lines 877-879. Each uses @mcp.tool() decorators unconditionally — they don't gate on plugin availability (only the tool bodies check via _resolve_*_client).

So in dev, registration works. The deployment-side discrepancy is one of:

  1. Deployed wheel has mcp_serve.py from a commit predating the registrar additions (b05444c / 7059267 / c0f017b)
  2. A silent exception in one of the registrars during create_mcp_server (currently no try/except — would crash the server entirely, inconsistent with "some tools registered")
  3. FastMCP version mismatch / list_tools visibility behavior change

Fix (defensive hardening — addresses all 3 possibilities)

  1. Wrap each registrar call in create_mcp_server with try/except + WARN log. If one registrar fails (e.g., import error), the others still register + the failure is visible in stderr, instead of silently killing the server.
  2. Boot-time log line: MCP server: registered N tools: [silo_query, confer_run, ...]. Visible in MCP subprocess stderr → worker logs. Tells us EXACTLY what's registered on each deploy.
  3. Contract test: assert create_mcp_server() registers all 6 required G2/G3/G4 tools by name. Catches future regressions where a registrar is removed or its decorator path breaks.

Out of scope

A bigger refactor to make plugin register(ctx) own its MCP tool surface (delegating to plugin-side register_mcp_tools(mcp) functions called by an mcp_serve loader) is appealing but a larger change. File separately if desired.

Acceptance

  • Deployed worker logs MCP server: registered N tools: [...] on subprocess spawn, exposing exactly which tools are present in that wheel.
  • Contract test catches any future drop of a G2/G3/G4 registrar.
  • One failing registrar no longer takes down peer registrars.

Severity

Final integration gap for poly-explorer end-to-end tool surface.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions