[BUG] plugin:github:github MCP fails with HTTP 400 — malformed JSON-RPC payload missing version tag

Status Open
Reported on v2.1.150
Maintainer reply None cached
Activity 20 comments · opened Jun 2, 2026

Preflight Checklist

  • [ ] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Bug Description

The GitHub MCP plugin (plugin:github:github) fails to connect with HTTP 400 from https://api.githubcopilot.com/mcp/.

Environment

  • Claude Code version: 2.1.150
  • OS: macOS
  • Auth: gh CLI with copilot, gist, read:org, repo, workflow scopes

Error

Failed to reconnect to plugin:github:github: HTTP 400 at https://api.githubcopilot.com/mcp/

Root Cause (diagnosed)

Manually curling the endpoint with an empty payload returns:

malformed payload: invalid message version tag ""; expected "2.0"

The plugin appears to be sending a request without the required "jsonrpc": "2.0" field.
A correct JSON-RPC 2.0 initialize request to the same endpoint returns HTTP 200 successfully,
confirming the endpoint and account are fine — the bug is in the plugin's request construction.

Steps to Reproduce

  1. Enable GitHub MCP plugin in Claude Code settings
  2. Authenticate with gh auth login --scopes copilot,gist,read:org,repo,workflow
  3. Run /mcp — plugin fails with HTTP 400

What Should Happen?

The plugin appears to be sending a request without the required "jsonrpc": "2.0" field.
A correct JSON-RPC 2.0 initialize request to the same endpoint returns HTTP 200 successfully,
confirming the endpoint and account are fine — the bug is in the plugin's request construction.

Error Messages/Logs

Failed to reconnect to plugin:github:github: HTTP 400 at https://api.githubcopilot.com/mcp/

Steps to Reproduce

  1. Enable GitHub MCP plugin in Claude Code settings
  2. Authenticate with gh auth login --scopes copilot,gist,read:org,repo,workflow
  3. Run /mcp — plugin fails with HTTP 400

Claude Model

None

Is this a regression?

Yes, this worked in a previous version

Last Working Version

_No response_

Claude Code Version

2.1.150

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Terminal.app (macOS)

Additional Information

_No response_

View original on GitHub ↗

20 Comments

kpkrr · 2 months ago

up pls

brunotiyoda · 2 months ago

up

aaronjhall-tech · 2 months ago

up

samuelpatro · 2 months ago

did you solved it?

whyvrafvr · 2 months ago

Up

MollTonNRW · 2 months ago

up

vcscroll · 2 months ago

up

HendrikKoelbel · 2 months ago

up

1stvamp · 2 months ago

up

1stvamp · 2 months ago

also happens on linux

bertinma · 2 months ago

up

swaowf · 1 month ago

up

TizianoCoroneo · 1 month ago

@claude fix this, open a PR referencing this issue, review it, merge it, and tag a new release. Top priority, no mistakes

ph7jack · 1 month ago

I was able to fix my GitHub MCP by adding GITHUB_PERSONAL_ACCESS_TOKEN on my Claude global config

edit ~/.claude/settings.json

{
   "env": {
      "GITHUB_PERSONAL_ACCESS_TOKEN": "token"
   }
}

It can also be fixed by adding EXPORT GITHUB_PERSONAL_ACCESS_TOKEN=token in your shell profile, like ~/.zshrc

tomasf10 · 1 month ago
I was able to fix my GitHub MCP by adding GITHUB_PERSONAL_ACCESS_TOKEN on my Claude global config edit ~/.claude/settings.json { "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "token" } } It can also be fixed by adding EXPORT GITHUB_PERSONAL_ACCESS_TOKEN=token in your shell profile, like ~/.zshrc

I can confirm it works.

For some reason this doesn't

fnur32 · 1 month ago
I was able to fix my GitHub MCP by adding GITHUB_PERSONAL_ACCESS_TOKEN on my Claude global config edit ~/.claude/settings.json { "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "token" } } It can also be fixed by adding EXPORT GITHUB_PERSONAL_ACCESS_TOKEN=token in your shell profile, like ~/.zshrc

i was try this, but still not work

Arkhamk · 1 month ago
I was able to fix my GitHub MCP by adding GITHUB_PERSONAL_ACCESS_TOKEN on my Claude global config edit ~/.claude/settings.json { "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "token" } } It can also be fixed by adding EXPORT GITHUB_PERSONAL_ACCESS_TOKEN=token in your shell profile, like ~/.zshrc

this works for me, thanks

gblikas · 1 month ago

Make sure to follow these instructions:

🔗 https://github.com/github/github-mcp-server/blob/main/docs/installation-guides/install-claude.md

From your terminal

⚠️ NOT in Claude Code CLI
export GITHUB_PAT=<YOUR_PAT_HERE>
claude mcp add-json github '{"type":"http","url":"https://api.githubcopilot.com/mcp","headers":{"Authorization":"Bearer $GITHUB_PAT"}}'

Troubleshooting

You may need to remove your local Github MCP configuration if was improperly configured before:

claude mcp list  #shows all servers availabe 
claude remove github
n3kuri · 25 days ago

This issue has also occurred for me whilst, being on windows. So the macos label is false.

keithwithAI · 11 days ago

Adding a reproduction for what looks like a second, distinct cause of this same 400. The original report diagnoses a malformed JSON-RPC payload missing the "jsonrpc": "2.0" tag. On my machine the payload is fine and the auth header is the problem, so anyone landing here should check which error their debug log actually names before trying a fix.

Claude Code 2.1.235, macOS 26.5.2, plugin:github:github from the official marketplace.

The error

From ~/.claude/debug/<session>.txt:

[ERROR] MCP server "plugin:github:github" Connection failed (400):
Streamable HTTP error: Error POSTing to endpoint:
bad request: Authorization header is badly formatted

Note this is not malformed payload: invalid message version tag, which is what the OP saw.

Cause

The plugin's .mcp.json sets:

"headers": { "Authorization": "Bearer ${GITHUB_PERSONAL_ACCESS_TOKEN}" }

Claude Code expands that from its own process environment. Exporting the variable in .zshenv or .zshrc does not reach it, so the header goes out empty (or as the literal ${...}) and GitHub rejects it.

Isolating which side is broken

Four requests to the same endpoint, same account:

| Request | Result |
|---|---|
| Valid token + valid initialize | 200 |
| Valid token + empty body | 400 POST requires a non-empty body |
| Empty token + valid initialize | 400 bad request: Authorization header is badly formatted |
| Literal ${GITHUB_PERSONAL_ACCESS_TOKEN} + valid initialize | 400 bad request: Authorization header is badly formatted |

Rows 3 and 4 reproduce the logged error exactly. Row 2 is the OP's failure mode. Row 1 confirms the endpoint, token and account are fine.

Reproduction

You cannot reproduce this from a shell that already exports the token, because the child claude process inherits it. That cost me a wrong conclusion, so unset it explicitly:

# with no env key in settings.json
env -u GITHUB_PERSONAL_ACCESS_TOKEN claude --debug -p "say ok"
# -> plugin:github:github ... Authorization header is badly formatted

Add the token to env in ~/.claude/settings.json:

{ "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_xxx" } }
# same command, variable still unset in the environment
env -u GITHUB_PERSONAL_ACCESS_TOKEN claude --debug -p "say ok"
# -> plugin:github:github: Successfully connected (transport: http) in 440ms

This is the workaround @ph7jack posted, and the A/B above may explain why the shell-export half of it works for some people and not others: only the settings.json entry is guaranteed to land in the process that expands the header. Whether the export works depends on how that particular Claude Code process was launched.

Two things that cost time

claude mcp list reported ✔ Connected for this server the whole time it was failing, and a direct initialize and tools/list against the endpoint both returned 200. The only accurate signal was ~/.claude/debug/*.txt.

It may also be worth failing loudly when a referenced variable is unset at expansion time, rather than sending Bearer and surfacing a generic remote 400 that points at the wrong layer.