Skip to content

Bundled MCP servers silently fail to spawn on pull_request events (mcp_servers empty despite correct config build) #1245

@PengyuKevinChen

Description

@PengyuKevinChen

Summary

On pull_request events with anthropics/claude-code-action@v1 (SHA 4e5d8b13ca281a6d163cdb287d8917b216e00d6f), the action's bundled MCP servers — specifically github_comment and github_inline_comment — never spawn in the Claude CLI subprocess. Claude Code's session init message reports "mcp_servers": [] on every run. The action correctly builds --mcp-config '{…}' via src/mcp/install-mcp-server.ts (verified by reading the source), but the spawned Claude CLI either doesn't receive or doesn't consume it. No startup error is logged — just silent absence.

This is reproducible across 10+ iterations with varying config (documented below).

Environment

  • Runner: GitHub-hosted ubuntu-24.04
  • Bun 1.3.6 (installed by action)
  • Claude CLI: /home/runner/.local/bin/claude (installed by action)
  • Auth: claude_code_oauth_token (subscription OAuth)
  • Event: pull_request (synchronize, same-repo branch, not a fork)
  • Repo: private

Reproduction

Minimal workflow that triggers the bug:

jobs:
  claude_review:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    permissions:
      contents: read
      pull-requests: write
      issues: write
      id-token: write
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: anthropics/claude-code-action@v1
        with:
          claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
          track_progress: true
          prompt: |
            <custom senior-dev review instructions>

Expected behavior

  • Action detects tag mode (✅ confirmed in logs: Auto-detected mode: tag for event: pull_request)
  • prepareMcpConfig builds JSON config containing github_comment server (✅ code path verified in src/mcp/install-mcp-server.ts)
  • tag/index.ts appends --mcp-config '{…}' to claudeArgs (✅ confirmed)
  • parse-sdk-options.ts keeps mcp-config in extraArgs for forwarding to the CLI (✅ confirmed)
  • Claude CLI session init includes the server in mcp_servers
  • Claude can call mcp__github_comment__update_claude_comment to update the tracking comment

Actual behavior

  • Auto-detected mode: tag for event: pull_request
  • SDK options allowedTools contains mcp__github_comment__update_claude_comment
  • Claude Code's init message:
    {
      "type": "system",
      "subtype": "init",
      "tools": [ "Task", "Bash", "Edit", "Read", ... ],
      "mcp_servers": []
    }
  • Claude attempts mcp__github_comment__update_claude_commentError: No such tool available: mcp__github_comment__update_claude_comment
  • Claude falls back to trying gh api / gh pr comment — all denied (not in allowlist)
  • Final sticky comment never updates from the action's "I'll analyze this..." placeholder

Full SDK output (show_full_output: true) confirms Claude repeatedly attempts the advertised MCP tool and gets No such tool available. The tool name is in allowedTools but the backing server isn't registered.

What we tried (none fixed it)

  • track_progress: true (forces tag mode — confirmed active)
  • Explicit MCP tool names in claude_args --allowed-tools
  • Adding actions: read permission (fixed unrelated github_ci warning; github_comment still missing)
  • settings: "{}" override (made it worse — permission_denials_count went from 2 → 13)
  • claude_args: "--setting-sources user" to bypass the project's .claude/settings.json (also made it worse)
  • Custom prompt removed vs kept (no difference to MCP state)
  • Various combinations of the above

In every configuration, "mcp_servers": [] persists.

Suspicion

The disconnect seems to sit between how the action builds claudeArgs and how @anthropic-ai/claude-agent-sdk's query() forwards extraArgs to the spawned Claude CLI subprocess. The --mcp-config flag appears to be dropped or not consumed somewhere in that chain.

From src/modes/tag/index.ts:

const ourMcpConfig = await prepareMcpConfig({, mode: "tag",});
claudeArgs = `--mcp-config '${escapedOurConfig}'`;
claudeArgs += ` --permission-mode acceptEdits --allowedTools "${tagModeTools.join(",")}"`;
if (userClaudeArgs) { claudeArgs += ` ${userClaudeArgs}`; }

From base-action/src/parse-sdk-options.ts:

// Pass through claudeArgs as extraArgs - CLI handles --mcp-config, --json-schema, etc.
extraArgs,

The code path is correct; the runtime outcome isn't.

Workaround (for anyone finding this)

We shipped a wrapper script instead. Claude writes /tmp/claude-review.json via the Write tool (path-scoped), and a separate workflow step runs a bash script that validates the JSON and posts via POST /repos/{owner}/{repo}/pulls/{n}/reviews. Happy to share the workflow as a gist if useful.

Asks

  1. Can a maintainer confirm whether --mcp-config from extraArgs is supposed to reach the spawned Claude CLI when using @anthropic-ai/claude-agent-sdk's query()?
  2. If yes, any known environment where it silently drops (e.g., specific Bun version, specific settings file shape, OAuth vs API-key auth path)?
  3. If no, what's the intended mechanism for the bundled MCP servers to be registered in the session?

Happy to provide full run logs (multiple, with show_full_output: true enabled) on request. I've redacted nothing that's sensitive but didn't want to paste hundreds of kB inline.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingmcpp2Non-showstopper bug or popular feature request

    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