Skip to content

MCP server tools never reach outbound tools[] across 4.26 → 5.7 (cluster previously closed + locked as 'resolved') #80909

@mpalermiti

Description

@mpalermiti

MCP server tools never reach outbound tools[] across 4.26 → 5.7 (cluster previously closed + locked as "resolved")

Summary

Configured mcp.servers entries do not appear in the agent's outbound LLM request body's tools[] array, on every stable release tested from 2026.4.26 through 2026.5.7 (latest at filing). The MCP servers themselves are healthy — they spawn, register, and respond to direct stdio tools/list and tools/call cleanly with real results. Only the path from "openclaw materializes the catalog" to "OpenAI-format chat-completions request body" fails.

This issue exists because the predecessor cluster (#74387, #74726, #74844) was closed three times — twice as "already implemented" by automated review, then locked as resolved — despite wire-level evidence to the contrary posted by two independent users including at least one additional environment beyond a single-machine repro.

Why a fresh issue

All three predecessor issues are now closed + locked with lock_reason: "resolved":

Each was auto-closed by clawsweeper after static-analysis review citing the same code paths that ship with the bug intact. Locking eliminated the only feedback channel into the cluster. The bug is still present; opening a fresh canonical issue is the only available path.

Environment

  • OpenClaw: 2026.5.7 (eeef486)
  • Node.js: v22.22.2
  • macOS: 26.4.1
  • Install method: npm i -g openclaw@2026.5.7
  • Agent runtime: embedded (Pi)
  • MCP servers configured: two stdio servers, both verified healthy
  • tools.profile: coding
  • plugins.allow: contains explicit plugin ids; allow list verified loaded via openclaw plugins list

Reproduction

  1. Configure two stdio MCP servers under mcp.servers.
  2. Verify each starts and responds:
    echo '{"jsonrpc":"2.0","id":1,"method":"initialize",...}' | <command from mcp.servers.<id>.command>
    Returns full tools/list (50+ tools across the two servers in our case).
  3. openclaw mcp list confirms both servers configured.
  4. openclaw plugins inspect <pluginId> shows Status: loaded for each configured MCP server.
  5. Start the gateway and trigger one agent turn (any normal channel — iMessage/BlueBubbles in our case).
  6. Capture the outbound https://openrouter.ai/api/v1/chat/completions request body via the built-in debug proxy (OPENCLAW_DEBUG_PROXY_ENABLED=1 + OPENCLAW_DEBUG_PROXY_URL=...).
  7. Inspect body.tools[]no server__* entries, only bundled openclaw tools (read, write, exec, sessions_*, web_search, web_fetch, etc.).

Longitudinal data (7 stable releases)

Each row is an independently verified test run, configuration unchanged, MCP servers verified healthy each time:

Version Tested tools[] contains server__* Agent behavior
2026.4.26 yes "I don't have access to outlook tools" (honest failure)
2026.4.27 (cited as "fixed", cbc2ba0) yes Silent confabulation — fabricates plausible-sounding email lists with no overlap to reality
2026.5.2 (cited as "fixed", 8b2a6e5) yes Silent confabulation
2026.5.7 (current, eeef486) yes Reverts to honest admission — tries shell exec workaround, hits "openclaw: not found"

Cost-tracker confirms one LLM call per agent turn in every test (no tool round-trip occurred). Input token count stable at ~48–72k across versions — consistent with no MCP tool definitions in the prompt (which would add ~20–30k for the configured server count).

Wire evidence

The captured outbound request body from 2026.4.26 (redacted, messages[] stripped) is inlined in #74844 (it's locked but still readable). The tools[] array contains exactly 15 entries — all bundled OpenClaw tools. Zero server__* entries.

I can re-capture on 5.7 if it would help maintainers — we observed event-loop stalls with the debug proxy attached on some recent releases, so we've been using cost-tracker telemetry as the cleaner signal in subsequent tests. Same evidence shape either way.

What works at every layer

Every layer between config and provider serialization passes its own test:

  • mcp.servers populated, valid JSON, dmPolicy and credential resolution working
  • openclaw mcp list lists both servers
  • MCP server child processes spawn (visible in ps aux)
  • Direct stdio probe of each server returns full tools/list (verified each test)
  • Direct stdio probe of tools/call outlook_list_inbox returns real inbox data (verified each test)
  • openclaw plugins inspect <id> reports Status: loaded for every configured MCP plugin
  • Built-in OpenClaw tools (read/write/exec/sessions_*/web_search/web_fetch) DO appear in outbound tools[] — so the serializer works, just not for MCP tools
  • Gateway log shows BlueBubbles (or whichever channel) catchup, webhook, and inbound delivery all working

The failure is silent: no warning in gateway.log, no error in gateway.err.log, openclaw doctor reports the system clean.

Code paths cited by previous closures

The clawsweeper static review of each predecessor cited these as the implementation:

  • src/agents/bundle-mcp-config.ts:49loadMergedBundleMcpConfig
  • src/agents/command/attempt-execution.ts:457runEmbeddedPiAgent
  • src/agents/pi-embedded-runner/run/attempt.ts:908 — embedded attempt materializing bundle-MCP tools and appending to effectiveTools
  • src/agents/pi-embedded-runner/run/attempt.ts:1358 — converting effectiveTools into Pi customTools and session allowlist
  • src/agents/pi-bundle-mcp-materialize.ts:64materializeBundleMcpToolsForRun
  • src/agents/tool-catalog.ts:316coding/messaging profile includes bundle-mcp

These code paths likely exist and run, but something between materialization and the final OpenAI-format serialization drops the MCP tools. The cost-tracker single-LLM-call-per-turn pattern across 7 versions rules out "tool was attempted but execution failed."

Things I have ruled out (tested each)

  • tools.profile — tried coding, messaging, full. Same result on all.
  • tools.alsoAllow: ["outlook__*","gmail__*"] at root and under tools.sandbox.tools. No effect.
  • plugins.allow containing outlook, gmail, mcp — flagged as stale-not-a-plugin and ignored.
  • mcp.sessionIdleTtlMs: 0 (prevent idle eviction). MCP processes stay resident; tools still missing.
  • Multiple gateway restarts.
  • openclaw doctor, openclaw doctor --fix. No MCP-related findings.
  • Bundled vs external plugin: the BlueBubbles plugin moved from bundled to npm in 5.x; reinstalling and reconnecting did not affect MCP tool exposure.

Ask

@steipete @vincentkocclawsweeper named both of you as the owners of the embedded Pi MCP exposure path across the closure comments on #74387 and #74844. This bug has now persisted through seven stable releases with two automated "already implemented" closures and a lock as "resolved" despite consistent wire-level falsifying evidence from at least two independent users (myself and @luuq2026).

A human pair of eyes on this would be valuable. Concrete options:

  1. Quick check: add an integration test that asserts body.tools[] includes configured server__* entries when mcp.servers is populated. If such a test already exists and is passing, the test does not exercise the same code path users hit.
  2. Diagnostic ask: what specific config shape or environment is the existing integration coverage exercising? My setup uses iMessage/BlueBubbles inbound, Gemini 2.5 Pro via OpenRouter, tools.profile: coding, two stdio MCP servers. If yours uses something different, that's the clue.
  3. Reproduce: I'm happy to capture a fresh debug-proxy wire capture on 5.7, or any other artifact you'd like. Just say what's most useful.

The three locked predecessors should ideally be unlocked and linked back to this issue once a human triage decision is made — but that's an optional cleanup.

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