openclaw - 💡(How to fix) Fix MCP server tools missing from agent's request body in 2026.4.26 (gmail/outlook configured but not exposed to model) [6 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#74844Fetched 2026-05-01 05:40:49
View on GitHub
Comments
6
Participants
3
Timeline
13
Reactions
2
Timeline (top)
commented ×6cross-referenced ×4closed ×1mentioned ×1

Configured MCP servers (gmail, outlook) spawn correctly and respond to direct stdio JSON-RPC probes with their full tool catalog, but their tools never appear in the tools[] array of the request body that the gateway sends to the LLM provider. Only the bundled OpenClaw tools (read, write, exec, sessions_*, web_search, web_fetch, etc.) are present. Result: the agent reports "I don't have access to those tools" while the underlying MCP servers are healthy and serving tools on stdio.

This worked in 2026.4.15 and broke at some point between then and 2026.4.26 (we upgraded straight from 4.15 to 4.26, so we cannot identify the specific intermediate release).

Root Cause

Configured MCP servers (gmail, outlook) spawn correctly and respond to direct stdio JSON-RPC probes with their full tool catalog, but their tools never appear in the tools[] array of the request body that the gateway sends to the LLM provider. Only the bundled OpenClaw tools (read, write, exec, sessions_*, web_search, web_fetch, etc.) are present. Result: the agent reports "I don't have access to those tools" while the underlying MCP servers are healthy and serving tools on stdio.

This worked in 2026.4.15 and broke at some point between then and 2026.4.26 (we upgraded straight from 4.15 to 4.26, so we cannot identify the specific intermediate release).

Fix Action

Fix / Workaround

Workarounds

  1. Downgrade to 2026.4.15 (last known working version on this stack).
  2. Wait for an upstream fix.

Code Example

"mcp": {
  "sessionIdleTtlMs": 0,
  "servers": {
    "gmail": {
      "command": "/opt/homebrew/bin/gmail-mcp",
      "args": []
    },
    "outlook": {
      "command": "/Users/<user>/.local/bin/uv",
      "args": ["--directory", "/Users/<user>/ClaudeCode/outlook-mcp", "run", "outlook-mcp"]
    }
  }
}

---

MCP servers (/Users/<user>/.openclaw/openclaw.json):
- gmail
- outlook

---

echo '{"jsonrpc":"2.0","id":1,"method":"initialize",...}' \
     | <command from mcp.servers.<id>.command>

---

edit, exec, image, process, read, session_status,
sessions_history, sessions_list, sessions_send, sessions_spawn,
sessions_yield, subagents, web_fetch, web_search, write

---

{
  "jsonrpc": "2.0", "id": 2,
  "result": {
    "content": [{"type": "text", "text": "{\"display_name\": ..., \"email\": ..., ...}"}],
    "isError": false
  }
}

---

openclaw proxy start --port 18790

---

OPENCLAW_DEBUG_PROXY_ENABLED=1
   OPENCLAW_DEBUG_PROXY_URL=http://127.0.0.1:18790

---

SELECT id, host, path, length(data_text), data_blob_id
   FROM capture_events
   WHERE host LIKE '%openrouter%' AND direction='outbound' AND kind='request'
   ORDER BY ts DESC LIMIT 1;

---

{
  "_note": "Redacted snapshot of OpenRouter chat-completions request captured via openclaw 2026.4.26 debug proxy. messages[] removed; tools[] preserved verbatim (the bug is the absence of MCP-server tools from this array).",
  "_messages_redacted": {
    "count": 91,
    "role_counts": {
      "system": 1,
      "user": 31,
      "assistant": 37,
      "tool": 22
    }
  },
  "model": "google/gemini-2.5-pro",
  "stream": true,
  "max_completion_tokens": 32000,
  "reasoning": {
    "effort": "minimal"
  },
  "tools_count": 15,
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "edit",
        "description": "Edit a single file using exact text replacement. Every edits[].oldText must match a unique, non-overlapping region of the original file. If two changes affect the same block or nearby lines, merge them into one edit instead of emitting overlapping edits. Do not include large unchanged regions just to connect distant changes.",
        "parameters": {
          "type": "object",
          "required": [
            "path",
            "edits"
          ],
          "properties": {
            "path": {
              "type": "string",
              "description": "Path to the file to edit (relative or absolute)"
            },
            "edits": {
              "type": "array",
              "items": {
                "type": "object",
                "required": [
                  "oldText",
                  "newText"
                ],
                "properties": {
                  "oldText": {
                    "type": "string",
                    "description": "Exact text for one targeted replacement. It must be unique in the original file and must not overlap with any other edits[].oldText in the same call."
                  },
                  "newText": {
                    "type": "string",
                    "description": "Replacement text for this targeted edit."
                  }
                },
                "additionalProperties": false
              },
              "description": "One or more targeted replacements. Each edit is matched against the original file, not incrementally. Do not include overlapping or nested edits. If two changes touch the same block or nearby lines, merge them into one edit instead."
            }
          },
          "additionalProperties": false
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "exec",
        "description": "Execute shell commands with background continuation for work that starts now. Use yieldMs/background to continue later via process tool. For long-running work started now, rely on automatic completion wake when it is enabled and the command emits output or fails; otherwise use process to confirm completion. Use process whenever you need logs, status, input, or intervention. Use pty=true for TTY-required commands (terminal UIs, coding agents).",
        "parameters": {
          "type": "object",
          "required": [
            "command"
          ],
          "properties": {
            "command": {
              "type": "string",
              "description": "Shell command to execute"
            },
            "workdir": {
              "type": "string",
              "description": "Working directory (defaults to cwd)"
            },
            "env": {
              "type": "object",
              "patternProperties": {
                "^.*$": {
                  "type": "string"
                }
              }
            },
            "yieldMs": {
              "type": "number",
              "description": "Milliseconds to wait before backgrounding (default 10000)"
            },
            "background": {
              "type": "boolean",
              "description": "Run in background immediately"
            },
            "timeout": {
              "type": "number",
              "description": "Timeout in seconds (optional, kills process on expiry)"
            },
            "pty": {
              "type": "boolean",
              "description": "Run in a pseudo-terminal (PTY) when available (TTY-required CLIs, coding agents)"
            },
            "elevated": {
              "type": "boolean",
              "description": "Run on the host with elevated permissions (if allowed)"
            },
            "host": {
              "type": "string",
              "description": "Exec host/target (auto|sandbox|gateway|node)."
            },
            "security": {
              "type": "string",
              "description": "Exec security mode (deny|allowlist|full)."
            },
            "ask": {
              "type": "string",
              "description": "Exec ask mode (off|on-miss|always)."
            },
            "node": {
              "type": "string",
              "description": "Node id/name for host=node."
            }
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "image",
        "description": "Analyze one or more images with a vision model. Use image for a single path/URL, or images for multiple (up to 20). Only use this tool when images were NOT already provided in the user's message. Images mentioned in the prompt are automatically visible to you.",
        "parameters": {
          "type": "object",
          "properties": {
            "prompt": {
              "type": "string"
            },
            "image": {
              "type": "string",
              "description": "Single image path or URL."
            },
            "images": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Multiple image paths or URLs (up to maxImages, default 20)."
            },
            "model": {
              "type": "string"
            },
            "maxBytesMb": {
              "type": "number"
            },
            "maxImages": {
              "type": "number"
            }
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "process",
        "description": "Manage running exec sessions for commands already started: list, poll, log, write, send-keys, submit, paste, kill. Use poll/log when you need status, logs, quiet-success confirmation, or completion confirmation when automatic completion wake is unavailable. Use write/send-keys/submit/paste/kill for input or intervention.",
        "parameters": {
          "type": "object",
          "required": [
            "action"
          ],
          "properties": {
            "action": {
              "type": "string",
              "description": "Process action"
            },
            "sessionId": {
              "type": "string",
              "description": "Session id for actions other than list"
            },
            "data": {
              "type": "string",
              "description": "Data to write for write"
            },
            "keys": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Key tokens to send for send-keys"
            },
            "hex": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Hex bytes to send for send-keys"
            },
            "literal": {
              "type": "string",
              "description": "Literal string for send-keys"
            },
            "text": {
              "type": "string",
              "description": "Text to paste for paste"
            },
            "bracketed": {
              "type": "boolean",
              "description": "Wrap paste in bracketed mode"
            },
            "eof": {
              "type": "boolean",
              "description": "Close stdin after write"
            },
            "offset": {
              "type": "number",
              "description": "Log offset"
            },
            "limit": {
              "type": "number",
              "description": "Log length"
            },
            "timeout": {
              "type": "number",
              "description": "For poll: wait up to this many milliseconds before returning",
              "minimum": 0
            }
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "read",
        "description": "Read the contents of a file. Supports text files and images (jpg, png, gif, webp). Images are sent as attachments. For text files, output is truncated to 2000 lines or 50KB (whichever is hit first). Use offset/limit for large files. When you need the full file, continue with offset until complete.",
        "parameters": {
          "type": "object",
          "required": [
            "path"
          ],
          "properties": {
            "path": {
              "type": "string",
              "description": "Path to the file to read (relative or absolute)"
            },
            "offset": {
              "type": "number",
              "description": "Line number to start reading from (1-indexed)"
            },
            "limit": {
              "type": "number",
              "description": "Maximum number of lines to read"
            }
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "session_status",
        "description": "Show a /status-equivalent session status card for the current or another visible session, including usage, time, cost when available, and linked background task context. Use `sessionKey=\"current\"` for the current session; do not use UI/client labels such as `openclaw-tui` as session keys. Optional `model` sets a per-session model override; `model=default` resets overrides. Use this for questions like what model is active or how a session is configured.",
        "parameters": {
          "type": "object",
          "properties": {
            "sessionKey": {
              "type": "string"
            },
            "model": {
              "type": "string"
            }
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "sessions_history",
        "description": "Fetch sanitized message history for a visible session. Supports limits and optional tool messages; use this to inspect another session before replying, debugging, or resuming work.",
        "parameters": {
          "type": "object",
          "required": [
            "sessionKey"
          ],
          "properties": {
            "sessionKey": {
              "type": "string"
            },
            "limit": {
              "type": "number",
              "minimum": 1
            },
            "includeTools": {
              "type": "boolean"
            }
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "sessions_list",
        "description": "List visible sessions with optional filters for kind, label, agentId, search, recent activity, derived titles, and last-message previews. Use this to discover a target session before calling sessions_history or sessions_send.",
        "parameters": {
          "type": "object",
          "properties": {
            "kinds": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "limit": {
              "type": "number",
              "minimum": 1
            },
            "activeMinutes": {
              "type": "number",
              "minimum": 1
            },
            "messageLimit": {
              "type": "number",
              "minimum": 0
            },
            "label": {
              "type": "string",
              "minLength": 1
            },
            "agentId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "search": {
              "type": "string",
              "minLength": 1
            },
            "includeDerivedTitles": {
              "type": "boolean"
            },
            "includeLastMessage": {
              "type": "boolean"
            }
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "sessions_send",
        "description": "Send a message into another visible session by sessionKey or label. Use this to delegate follow-up work to an existing session; waits for the target run and returns the updated assistant reply when available.",
        "parameters": {
          "type": "object",
          "required": [
            "message"
          ],
          "properties": {
            "sessionKey": {
              "type": "string"
            },
            "label": {
              "type": "string",
              "minLength": 1,
              "maxLength": 512
            },
            "agentId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "message": {
              "type": "string"
            },
            "timeoutSeconds": {
              "type": "number",
              "minimum": 0
            }
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "sessions_spawn",
        "description": "Spawn a clean isolated session by default with the native subagent runtime. `mode=\"run\"` is one-shot and `mode=\"session\"` is persistent or thread-bound. Subagents inherit the parent workspace directory automatically. For native subagents only, set `context=\"fork\"` when the child needs the current transcript context; otherwise omit it or use `context=\"isolated\"`. Use this when the work should happen in a fresh child session instead of the current one.",
        "parameters": {
          "type": "object",
          "required": [
            "task"
          ],
          "properties": {
            "task": {
              "type": "string"
            },
            "label": {
              "type": "string"
            },
            "runtime": {
              "type": "string",
              "enum": [
                "subagent"
              ]
            },
            "agentId": {
              "type": "string"
            },
            "model": {
              "type": "string"
            },
            "thinking": {
              "type": "string"
            },
            "cwd": {
              "type": "string"
            },
            "runTimeoutSeconds": {
              "type": "number",
              "minimum": 0
            },
            "timeoutSeconds": {
              "type": "number",
              "minimum": 0
            },
            "thread": {
              "type": "boolean"
            },
            "mode": {
              "type": "string",
              "enum": [
                "run",
                "session"
              ]
            },
            "cleanup": {
              "type": "string",
              "enum": [
                "delete",
                "keep"
              ]
            },
            "sandbox": {
              "type": "string",
              "enum": [
                "inherit",
                "require"
              ]
            },
            "context": {
              "type": "string",
              "enum": [
                "isolated",
                "fork"
              ],
              "description": "Native subagent context mode. Omit or use \"isolated\" for a clean child session; use \"fork\" only when the child needs the requester transcript context."
            },
            "lightContext": {
              "type": "boolean",
              "description": "When true, spawned subagent runs use lightweight bootstrap context. Only applies to runtime='subagent'."
            },
            "attachments": {
              "type": "array",
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "content"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "content": {
                    "type": "string"
                  },
                  "encoding": {
                    "type": "string",
                    "enum": [
                      "utf8",
                      "base64"
                    ]
                  },
                  "mimeType": {
                    "type": "string"
                  }
                }
              },
              "maxItems": 50
            },
            "attachAs": {
              "type": "object",
              "properties": {
                "mountPath": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "sessions_yield",
        "description": "End your current turn. Use after spawning subagents to receive their results as the next message.",
        "parameters": {
          "type": "object",
          "properties": {
            "message": {
              "type": "string"
            }
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "subagents",
        "description": "List, kill, or steer spawned sub-agents for this requester session. Use this for sub-agent orchestration.",
        "parameters": {
          "type": "object",
          "properties": {
            "action": {
              "type": "string",
              "enum": [
                "list",
                "kill",
                "steer"
              ]
            },
            "target": {
              "type": "string"
            },
            "message": {
              "type": "string"
            },
            "recentMinutes": {
              "type": "number",
              "minimum": 1
            }
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "web_fetch",
        "description": "Fetch and extract readable content from a URL (HTML \u2192 markdown/text). Use for lightweight page access without browser automation.",
        "parameters": {
          "type": "object",
          "required": [
            "url"
          ],
          "properties": {
            "url": {
              "type": "string",
              "description": "HTTP or HTTPS URL to fetch."
            },
            "extractMode": {
              "type": "string",
              "enum": [
                "markdown",
                "text"
              ],
              "description": "Extraction mode (\"markdown\" or \"text\").",
              "default": "markdown"
            },
            "maxChars": {
              "type": "number",
              "description": "Maximum characters to return (truncates when exceeded).",
              "minimum": 100
            }
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "web_search",
        "description": "Search the web using DuckDuckGo. Returns titles, URLs, and snippets with no API key required.",
        "parameters": {
          "type": "object",
          "properties": {
            "query": {
              "type": "string",
              "description": "Search query string."
            },
            "count": {
              "type": "number",
              "description": "Number of results to return (1-10).",
              "minimum": 1,
              "maximum": 10
            },
            "region": {
              "type": "string",
              "description": "Optional DuckDuckGo region code such as us-en, uk-en, or de-de."
            },
            "safeSearch": {
              "type": "string",
              "description": "SafeSearch level: strict, moderate, or off."
            }
          },
          "additionalProperties": false
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "write",
        "description": "Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.",
        "parameters": {
          "type": "object",
          "required": [
            "path",
            "content"
          ],
          "properties": {
            "path": {
              "type": "string",
              "description": "Path to the file to write (relative or absolute)"
            },
            "content": {
              "type": "string",
              "description": "Content to write to the file"
            }
          }
        }
      }
    }
  ]
}
RAW_BUFFERClick to expand / collapse

MCP server tools missing from agent's request body in 2026.4.26

Summary

Configured MCP servers (gmail, outlook) spawn correctly and respond to direct stdio JSON-RPC probes with their full tool catalog, but their tools never appear in the tools[] array of the request body that the gateway sends to the LLM provider. Only the bundled OpenClaw tools (read, write, exec, sessions_*, web_search, web_fetch, etc.) are present. Result: the agent reports "I don't have access to those tools" while the underlying MCP servers are healthy and serving tools on stdio.

This worked in 2026.4.15 and broke at some point between then and 2026.4.26 (we upgraded straight from 4.15 to 4.26, so we cannot identify the specific intermediate release).

Environment

  • OpenClaw: 2026.4.26 (be8c246)
  • Node.js: v22.22.2
  • macOS: 26.4.1
  • Install method: npm i -g openclaw
  • Agent runtime: embedded (Pi)

Configuration

Relevant ~/.openclaw/openclaw.json excerpt:

"mcp": {
  "sessionIdleTtlMs": 0,
  "servers": {
    "gmail": {
      "command": "/opt/homebrew/bin/gmail-mcp",
      "args": []
    },
    "outlook": {
      "command": "/Users/<user>/.local/bin/uv",
      "args": ["--directory", "/Users/<user>/ClaudeCode/outlook-mcp", "run", "outlook-mcp"]
    }
  }
}

openclaw mcp list confirms both are registered:

MCP servers (/Users/<user>/.openclaw/openclaw.json):
- gmail
- outlook

Tool profile: coding. Configured tools.alsoAllow: ["web_search", "web_fetch"] (these DO get through to the agent — confirming alsoAllow works in general; just not for MCP tools).

Expected behavior

The agent's outbound request to the LLM provider (here, OpenRouter) should include all bundled tools plus the tools advertised by configured MCP servers (outlook__*, gmail__*).

Actual behavior

The outbound request body's tools[] array contains exactly 15 entries — all of them OpenClaw bundled tools. No MCP tools. The agent then reports the MCP-backed capability as unavailable.

Reproduction steps

  1. Configure two MCP servers in mcp.servers (any working stdio MCP server will do).
  2. Verify the servers spawn and respond by probing them directly:
    echo '{"jsonrpc":"2.0","id":1,"method":"initialize",...}' \
      | <command from mcp.servers.<id>.command>
    They return their full tools/list cleanly.
  3. Restart the gateway.
  4. Send the agent a message that requires one of those MCP tools (e.g. "search my Outlook for X").
  5. Capture the outbound LLM request via the built-in debug proxy (see "Diagnostic data" below). Inspect body.tools[] — MCP tools are absent.

Captured evidence

The 15 tool names that actually appeared in body.tools[]:

edit, exec, image, process, read, session_status,
sessions_history, sessions_list, sessions_send, sessions_spawn,
sessions_yield, subagents, web_fetch, web_search, write

No outlook__*, no gmail__*.

The full redacted request body (messages[] stripped, all other request-shape preserved) is inlined at the bottom of this issue under "Redacted request body" if you want to feed it to a unit test or compare against your own capture.

For comparison, a direct stdio probe of the same outlook MCP server returns 50+ tools (outlook_list_inbox, outlook_search_mail, outlook_read_message, outlook_send_message, outlook_list_events, etc.) and successful tools/call invocations:

{
  "jsonrpc": "2.0", "id": 2,
  "result": {
    "content": [{"type": "text", "text": "{\"display_name\": ..., \"email\": ..., ...}"}],
    "isError": false
  }
}

So the MCP server is healthy and serving tools; the gateway just isn't including them in the request to the model.

What I ruled out

Confirmed via testing that none of these are the cause:

KnobTestedEffect on bug
tools.profileTried coding, messaging, fullNone
tools.alsoAllow: ["outlook__*", "gmail__*"]Added at root and under tools.sandbox.toolsNone
plugins.allow containing "outlook", "gmail", "mcp"Added; logged as "plugin not found: <name> (stale config entry ignored)"None — these aren't recognized as plugin IDs
mcp.sessionIdleTtlMs: 0 (prevent idle eviction)MCP processes stay resident; tools still missingNone
Multiple gateway restartsn/aNone
openclaw doctorDid not flag MCP at alln/a — invisible to doctor

openclaw doctor reports the gateway, plugins (7 loaded, 0 errors), and channel as healthy. The bug is invisible to its checks.

Last known working version

2026.4.15 — pre-upgrade gateway logs show outlook__* and gmail__* tool names being registered and exposed to the agent. We upgraded directly from 2026.4.15 to 2026.4.26, so the specific regressing release is somewhere in 4.16…4.26. Candidate suspects from the changelog:

  • 4.24 — "Plugin SDK/tool-result transforms: remove the Pi-only api.registerEmbeddedExtensionFactory(...) compatibility path." (Note: our two custom non-bundled plugins do NOT use that API; bundled-MCP loading might.)
  • 4.25 — "Plugin startup and install paths move to the cold persisted registry."
  • 4.26 — "Plugins/config: deprecate direct plugin config load/write helpers in favor of passed runtime snapshots."

Diagnostic data — how I captured the evidence

For maintainers reproducing on their end:

  1. Start the built-in debug proxy in another terminal:
    openclaw proxy start --port 18790
  2. Add to the gateway plist (or otherwise inject into the gateway process env):
    OPENCLAW_DEBUG_PROXY_ENABLED=1
    OPENCLAW_DEBUG_PROXY_URL=http://127.0.0.1:18790
  3. Restart gateway, fire one agent turn.
  4. Read the captured request body from ~/.openclaw/debug-proxy/blobs/<blob_id>.bin.gz (gunzip → JSON), or query ~/.openclaw/debug-proxy/capture.sqlite:
    SELECT id, host, path, length(data_text), data_blob_id
    FROM capture_events
    WHERE host LIKE '%openrouter%' AND direction='outbound' AND kind='request'
    ORDER BY ts DESC LIMIT 1;

OPENCLAW_CACHE_TRACE=1 OPENCLAW_CACHE_TRACE_PROMPT=1 writes pipeline-stage snapshots to ~/.openclaw/logs/cache-trace.jsonl but does not capture the final outbound request body — the debug proxy is the right tool for this.

Impact

For users who rely on configured MCP servers to extend agent capability (Outlook/Gmail/etc.), the agent appears unable to use those capabilities even though every other layer (config, server process, openclaw mcp list) reports healthy. The failure mode is silent — no warnings or errors in gateway.log or gateway.err.log, and openclaw doctor reports the system clean.

Workarounds

None we found. Options for affected users:

  1. Downgrade to 2026.4.15 (last known working version on this stack).
  2. Wait for an upstream fix.

<details> <summary><b>Redacted request body</b> (click to expand — full <code>tools[]</code> array, messages stripped)</summary>
{
  "_note": "Redacted snapshot of OpenRouter chat-completions request captured via openclaw 2026.4.26 debug proxy. messages[] removed; tools[] preserved verbatim (the bug is the absence of MCP-server tools from this array).",
  "_messages_redacted": {
    "count": 91,
    "role_counts": {
      "system": 1,
      "user": 31,
      "assistant": 37,
      "tool": 22
    }
  },
  "model": "google/gemini-2.5-pro",
  "stream": true,
  "max_completion_tokens": 32000,
  "reasoning": {
    "effort": "minimal"
  },
  "tools_count": 15,
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "edit",
        "description": "Edit a single file using exact text replacement. Every edits[].oldText must match a unique, non-overlapping region of the original file. If two changes affect the same block or nearby lines, merge them into one edit instead of emitting overlapping edits. Do not include large unchanged regions just to connect distant changes.",
        "parameters": {
          "type": "object",
          "required": [
            "path",
            "edits"
          ],
          "properties": {
            "path": {
              "type": "string",
              "description": "Path to the file to edit (relative or absolute)"
            },
            "edits": {
              "type": "array",
              "items": {
                "type": "object",
                "required": [
                  "oldText",
                  "newText"
                ],
                "properties": {
                  "oldText": {
                    "type": "string",
                    "description": "Exact text for one targeted replacement. It must be unique in the original file and must not overlap with any other edits[].oldText in the same call."
                  },
                  "newText": {
                    "type": "string",
                    "description": "Replacement text for this targeted edit."
                  }
                },
                "additionalProperties": false
              },
              "description": "One or more targeted replacements. Each edit is matched against the original file, not incrementally. Do not include overlapping or nested edits. If two changes touch the same block or nearby lines, merge them into one edit instead."
            }
          },
          "additionalProperties": false
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "exec",
        "description": "Execute shell commands with background continuation for work that starts now. Use yieldMs/background to continue later via process tool. For long-running work started now, rely on automatic completion wake when it is enabled and the command emits output or fails; otherwise use process to confirm completion. Use process whenever you need logs, status, input, or intervention. Use pty=true for TTY-required commands (terminal UIs, coding agents).",
        "parameters": {
          "type": "object",
          "required": [
            "command"
          ],
          "properties": {
            "command": {
              "type": "string",
              "description": "Shell command to execute"
            },
            "workdir": {
              "type": "string",
              "description": "Working directory (defaults to cwd)"
            },
            "env": {
              "type": "object",
              "patternProperties": {
                "^.*$": {
                  "type": "string"
                }
              }
            },
            "yieldMs": {
              "type": "number",
              "description": "Milliseconds to wait before backgrounding (default 10000)"
            },
            "background": {
              "type": "boolean",
              "description": "Run in background immediately"
            },
            "timeout": {
              "type": "number",
              "description": "Timeout in seconds (optional, kills process on expiry)"
            },
            "pty": {
              "type": "boolean",
              "description": "Run in a pseudo-terminal (PTY) when available (TTY-required CLIs, coding agents)"
            },
            "elevated": {
              "type": "boolean",
              "description": "Run on the host with elevated permissions (if allowed)"
            },
            "host": {
              "type": "string",
              "description": "Exec host/target (auto|sandbox|gateway|node)."
            },
            "security": {
              "type": "string",
              "description": "Exec security mode (deny|allowlist|full)."
            },
            "ask": {
              "type": "string",
              "description": "Exec ask mode (off|on-miss|always)."
            },
            "node": {
              "type": "string",
              "description": "Node id/name for host=node."
            }
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "image",
        "description": "Analyze one or more images with a vision model. Use image for a single path/URL, or images for multiple (up to 20). Only use this tool when images were NOT already provided in the user's message. Images mentioned in the prompt are automatically visible to you.",
        "parameters": {
          "type": "object",
          "properties": {
            "prompt": {
              "type": "string"
            },
            "image": {
              "type": "string",
              "description": "Single image path or URL."
            },
            "images": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Multiple image paths or URLs (up to maxImages, default 20)."
            },
            "model": {
              "type": "string"
            },
            "maxBytesMb": {
              "type": "number"
            },
            "maxImages": {
              "type": "number"
            }
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "process",
        "description": "Manage running exec sessions for commands already started: list, poll, log, write, send-keys, submit, paste, kill. Use poll/log when you need status, logs, quiet-success confirmation, or completion confirmation when automatic completion wake is unavailable. Use write/send-keys/submit/paste/kill for input or intervention.",
        "parameters": {
          "type": "object",
          "required": [
            "action"
          ],
          "properties": {
            "action": {
              "type": "string",
              "description": "Process action"
            },
            "sessionId": {
              "type": "string",
              "description": "Session id for actions other than list"
            },
            "data": {
              "type": "string",
              "description": "Data to write for write"
            },
            "keys": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Key tokens to send for send-keys"
            },
            "hex": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Hex bytes to send for send-keys"
            },
            "literal": {
              "type": "string",
              "description": "Literal string for send-keys"
            },
            "text": {
              "type": "string",
              "description": "Text to paste for paste"
            },
            "bracketed": {
              "type": "boolean",
              "description": "Wrap paste in bracketed mode"
            },
            "eof": {
              "type": "boolean",
              "description": "Close stdin after write"
            },
            "offset": {
              "type": "number",
              "description": "Log offset"
            },
            "limit": {
              "type": "number",
              "description": "Log length"
            },
            "timeout": {
              "type": "number",
              "description": "For poll: wait up to this many milliseconds before returning",
              "minimum": 0
            }
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "read",
        "description": "Read the contents of a file. Supports text files and images (jpg, png, gif, webp). Images are sent as attachments. For text files, output is truncated to 2000 lines or 50KB (whichever is hit first). Use offset/limit for large files. When you need the full file, continue with offset until complete.",
        "parameters": {
          "type": "object",
          "required": [
            "path"
          ],
          "properties": {
            "path": {
              "type": "string",
              "description": "Path to the file to read (relative or absolute)"
            },
            "offset": {
              "type": "number",
              "description": "Line number to start reading from (1-indexed)"
            },
            "limit": {
              "type": "number",
              "description": "Maximum number of lines to read"
            }
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "session_status",
        "description": "Show a /status-equivalent session status card for the current or another visible session, including usage, time, cost when available, and linked background task context. Use `sessionKey=\"current\"` for the current session; do not use UI/client labels such as `openclaw-tui` as session keys. Optional `model` sets a per-session model override; `model=default` resets overrides. Use this for questions like what model is active or how a session is configured.",
        "parameters": {
          "type": "object",
          "properties": {
            "sessionKey": {
              "type": "string"
            },
            "model": {
              "type": "string"
            }
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "sessions_history",
        "description": "Fetch sanitized message history for a visible session. Supports limits and optional tool messages; use this to inspect another session before replying, debugging, or resuming work.",
        "parameters": {
          "type": "object",
          "required": [
            "sessionKey"
          ],
          "properties": {
            "sessionKey": {
              "type": "string"
            },
            "limit": {
              "type": "number",
              "minimum": 1
            },
            "includeTools": {
              "type": "boolean"
            }
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "sessions_list",
        "description": "List visible sessions with optional filters for kind, label, agentId, search, recent activity, derived titles, and last-message previews. Use this to discover a target session before calling sessions_history or sessions_send.",
        "parameters": {
          "type": "object",
          "properties": {
            "kinds": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "limit": {
              "type": "number",
              "minimum": 1
            },
            "activeMinutes": {
              "type": "number",
              "minimum": 1
            },
            "messageLimit": {
              "type": "number",
              "minimum": 0
            },
            "label": {
              "type": "string",
              "minLength": 1
            },
            "agentId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "search": {
              "type": "string",
              "minLength": 1
            },
            "includeDerivedTitles": {
              "type": "boolean"
            },
            "includeLastMessage": {
              "type": "boolean"
            }
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "sessions_send",
        "description": "Send a message into another visible session by sessionKey or label. Use this to delegate follow-up work to an existing session; waits for the target run and returns the updated assistant reply when available.",
        "parameters": {
          "type": "object",
          "required": [
            "message"
          ],
          "properties": {
            "sessionKey": {
              "type": "string"
            },
            "label": {
              "type": "string",
              "minLength": 1,
              "maxLength": 512
            },
            "agentId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "message": {
              "type": "string"
            },
            "timeoutSeconds": {
              "type": "number",
              "minimum": 0
            }
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "sessions_spawn",
        "description": "Spawn a clean isolated session by default with the native subagent runtime. `mode=\"run\"` is one-shot and `mode=\"session\"` is persistent or thread-bound. Subagents inherit the parent workspace directory automatically. For native subagents only, set `context=\"fork\"` when the child needs the current transcript context; otherwise omit it or use `context=\"isolated\"`. Use this when the work should happen in a fresh child session instead of the current one.",
        "parameters": {
          "type": "object",
          "required": [
            "task"
          ],
          "properties": {
            "task": {
              "type": "string"
            },
            "label": {
              "type": "string"
            },
            "runtime": {
              "type": "string",
              "enum": [
                "subagent"
              ]
            },
            "agentId": {
              "type": "string"
            },
            "model": {
              "type": "string"
            },
            "thinking": {
              "type": "string"
            },
            "cwd": {
              "type": "string"
            },
            "runTimeoutSeconds": {
              "type": "number",
              "minimum": 0
            },
            "timeoutSeconds": {
              "type": "number",
              "minimum": 0
            },
            "thread": {
              "type": "boolean"
            },
            "mode": {
              "type": "string",
              "enum": [
                "run",
                "session"
              ]
            },
            "cleanup": {
              "type": "string",
              "enum": [
                "delete",
                "keep"
              ]
            },
            "sandbox": {
              "type": "string",
              "enum": [
                "inherit",
                "require"
              ]
            },
            "context": {
              "type": "string",
              "enum": [
                "isolated",
                "fork"
              ],
              "description": "Native subagent context mode. Omit or use \"isolated\" for a clean child session; use \"fork\" only when the child needs the requester transcript context."
            },
            "lightContext": {
              "type": "boolean",
              "description": "When true, spawned subagent runs use lightweight bootstrap context. Only applies to runtime='subagent'."
            },
            "attachments": {
              "type": "array",
              "items": {
                "type": "object",
                "required": [
                  "name",
                  "content"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "content": {
                    "type": "string"
                  },
                  "encoding": {
                    "type": "string",
                    "enum": [
                      "utf8",
                      "base64"
                    ]
                  },
                  "mimeType": {
                    "type": "string"
                  }
                }
              },
              "maxItems": 50
            },
            "attachAs": {
              "type": "object",
              "properties": {
                "mountPath": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "sessions_yield",
        "description": "End your current turn. Use after spawning subagents to receive their results as the next message.",
        "parameters": {
          "type": "object",
          "properties": {
            "message": {
              "type": "string"
            }
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "subagents",
        "description": "List, kill, or steer spawned sub-agents for this requester session. Use this for sub-agent orchestration.",
        "parameters": {
          "type": "object",
          "properties": {
            "action": {
              "type": "string",
              "enum": [
                "list",
                "kill",
                "steer"
              ]
            },
            "target": {
              "type": "string"
            },
            "message": {
              "type": "string"
            },
            "recentMinutes": {
              "type": "number",
              "minimum": 1
            }
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "web_fetch",
        "description": "Fetch and extract readable content from a URL (HTML \u2192 markdown/text). Use for lightweight page access without browser automation.",
        "parameters": {
          "type": "object",
          "required": [
            "url"
          ],
          "properties": {
            "url": {
              "type": "string",
              "description": "HTTP or HTTPS URL to fetch."
            },
            "extractMode": {
              "type": "string",
              "enum": [
                "markdown",
                "text"
              ],
              "description": "Extraction mode (\"markdown\" or \"text\").",
              "default": "markdown"
            },
            "maxChars": {
              "type": "number",
              "description": "Maximum characters to return (truncates when exceeded).",
              "minimum": 100
            }
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "web_search",
        "description": "Search the web using DuckDuckGo. Returns titles, URLs, and snippets with no API key required.",
        "parameters": {
          "type": "object",
          "properties": {
            "query": {
              "type": "string",
              "description": "Search query string."
            },
            "count": {
              "type": "number",
              "description": "Number of results to return (1-10).",
              "minimum": 1,
              "maximum": 10
            },
            "region": {
              "type": "string",
              "description": "Optional DuckDuckGo region code such as us-en, uk-en, or de-de."
            },
            "safeSearch": {
              "type": "string",
              "description": "SafeSearch level: strict, moderate, or off."
            }
          },
          "additionalProperties": false
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "write",
        "description": "Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.",
        "parameters": {
          "type": "object",
          "required": [
            "path",
            "content"
          ],
          "properties": {
            "path": {
              "type": "string",
              "description": "Path to the file to write (relative or absolute)"
            },
            "content": {
              "type": "string",
              "description": "Content to write to the file"
            }
          }
        }
      }
    }
  ]
}```

</details>

extent analysis

TL;DR

The issue can likely be fixed by downgrading to version 2026.4.15 or waiting for an upstream fix, as the problem seems to be related to changes introduced between versions 2026.4.15 and 2026.4.26.

Guidance

  1. Verify MCP server configuration: Ensure that the MCP servers (gmail and outlook) are correctly configured in the ~/.openclaw/openclaw.json file.
  2. Check the changelog: Review the changelog for versions 2026.4.16 to 2026.4.26 to identify potential changes that may have caused the issue.
  3. Test with a previous version: Try downgrading to version 2026.4.15 to confirm if the issue is indeed related to the version change.
  4. Wait for an upstream fix: If downgrading is not feasible, wait for an upstream fix, as the issue may be addressed in a future release.

Example

No code snippet is provided, as the issue seems to be related to a version change rather than a code-specific problem.

Notes

The issue may be related to changes in the plugin loading mechanism or the handling of MCP servers between versions 2026.4.15 and 2026.4.26. Further investigation is needed to identify the root cause.

Recommendation

Downgrade to version 2026.4.15 if possible, as it is the last known working version. If downgrading is not feasible, wait for an upstream fix.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

The agent's outbound request to the LLM provider (here, OpenRouter) should include all bundled tools plus the tools advertised by configured MCP servers (outlook__*, gmail__*).

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING