Skip to content

CL-6456: GitHub MCP preset with a token connect and honest connect guidance - #184

Merged
TheGreatAxios merged 7 commits into
mainfrom
cl-6456-github-mcp
Aug 21, 2026
Merged

TheGreatAxios merged 7 commits into
mainfrom
cl-6456-github-mcp

Conversation

@TheGreatAxios

Copy link
Copy Markdown
Contributor

Adds GitHub's official remote MCP server as a one-click preset, in the mold of the existing nine.

What the preset looks like

slug: "github-mcp"        displayName: "GitHub MCP"
url:  "https://api.githubcopilot.com/mcp/"
connectionMode: "token"   docsUrl: "https://github.com/settings/tokens"

Slug and display name deliberately avoid github / "GitHub": the native GitHub REST connector (PAT/OAuth-App, feeding @corbits/github-tools) keeps its own card, and mcpPresetByName("github") still resolves to it rather than here. No nativeConnectorId, so the REST connector is never hidden from the galleries.

Why token and not OAuth

Verified live against the server rather than assumed:

  • GET /.well-known/oauth-protected-resource/mcp advertises authorization_servers: ["https://github.com/login/oauth"], and that server's RFC 8414 metadata advertises PKCE (S256) — so far so good.
  • But it publishes no registration_endpoint, and POST https://github.com/login/oauth/register answers 422 with an HTML error page. GitHub has no dynamic client registration.

Our MCP OAuth flow is the official SDK's auth() orchestrator, which relies on RFC 7591 dynamic registration to obtain a client for a server we have no pre-registered app with. Against GitHub that dance cannot complete — it would fail mid-redirect after sending the person to GitHub. GitHub does officially accept a personal access token as the bearer, which the existing preset connect route already stores, so PAT-bearer is the honest mode here. No second auth path was built: connectionMode: "token" is a new value on the existing enum, and the connect rides the same POST /mcp-servers presetSlug + token path every other preset uses.

Two guards keep that honest rather than silently degrading:

  • GET /mcp-servers/oauth/:slug/start now refuses any non-OAuth preset up front (400) instead of failing mid-dance at the provider.
  • A token preset submitted without a token is a 400 that never probes.

What each guidance state renders

  • Plugins preset card, closed — one row, one Connect button, same as every other preset.
  • Plugins preset card, opened — a numbered walkthrough (open github.com/settings/tokens and generate a token → give it the repo scope → paste it below, stored encrypted, only your agents use it, disconnect any time), a live link to the token settings page, a password field, and Connect / Cancel. Opening the form is not a connect: no request goes out until a token is pasted.
  • Chat connect card (ConnectServiceBlockView) — a token preset resolves to the key-paste affordance carrying the preset's docs URL, and the submitted key rides the preset connect route rather than the fixed-registry credential route.
  • Chat connect card, OAuth arm — the helper now narrates what actually happens ("You'll be sent to X to approve access, then land right back here connected") instead of "two clicks".
  • connect-github card (the REST connector) — dropped its claim to install a Workbench GitHub app, which this repo has no hosted sign-in for; it now leads with the same honest three-step PAT walkthrough and says plainly that the token is stored encrypted, used only by your agents, and removable any time.

Read-only classification

Unchanged and deliberately so: mcp_call's allowance classifier trusts only the target server's own live tools/list. A GitHub MCP tool rides a standing grant when GitHub marks it readOnlyHint: true (search, get file contents, list pull requests) and stays parked otherwise — writes (create_issue) and unannotated tools (merge_pull_request) never classify read-only. The preset promises nothing beyond that live check, so it cannot over-promise; tests pin both directions.

Tests

Red/green at the layers the other presets use: preset registry shape and the no-collision rule, the preset connect route (token stored as the bearer; missing token 400s without probing), the OAuth start refusal, the card's walkthrough + paste + POST body, the chat host's affordance mapping, and the GitHub read/write classification list.

Also carried: @corbits/mcp-tools bumped 0.0.7 → 0.0.8 (the tenant-seed freshness gate refuses a changed src/ under an unchanged version) with the three workflow definition pins rippled, and the assistant's connections roster fixture now lists GitHub MCP among the not-connected services.

Fixes CL-6456

GitHub's remote MCP server (api.githubcopilot.com/mcp/) advertises OAuth
discovery and PKCE but no dynamic client registration, so the SDK-driven
OAuth dance cannot complete against it. It does accept a personal access
token as a bearer, and the preset connect route already stores one — this
adds a 'token' connection mode expressing that: the preset card opens a
step-by-step token walkthrough and posts the pasted token through the
same POST /mcp-servers preset path every other connect uses.

The preset is slugged github-mcp and displayed 'GitHub MCP' (GitHub's own
product name) so it never shadows the native github REST connector in
preset-by-name resolution or the galleries. The OAuth start route now
refuses non-OAuth presets up front instead of failing mid-dance, and a
token preset without a token is a 400 that never probes.
…s helper

The GitHub connect card no longer claims an app install it cannot do —
it leads with a numbered personal-access-token walkthrough (create at
github.com/settings/tokens, give it the repo scope, paste it here) and
says plainly what happens to the token: stored encrypted, used only by
your agents, removable any time. The generic connect card's OAuth helper
now walks through the dance too: you're sent to the service to approve,
then land back here connected.
The tenant seeding freshness gate keys tool packages on name@version and
refuses a changed src/ under an unchanged version.
Workflow definitions pin tool packages by exact version, and the
assistant's connections roster lists every preset — both follow the
preset addition and the mcp-tools version bump.
@TheGreatAxios
TheGreatAxios merged commit a1205d7 into main Aug 21, 2026
0 of 2 checks passed
@TheGreatAxios
TheGreatAxios deleted the cl-6456-github-mcp branch August 25, 2026 15:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant