Skip to content

fix(mcp): tell ChatGPT the tools need OAuth and which scopes to request - #21

Merged
willynikes2 merged 1 commit into
masterfrom
fix/chatgpt-oauth-signals
Oct 13, 2026
Merged

willynikes2 merged 1 commit into
masterfrom
fix/chatgpt-oauth-signals

Conversation

@willynikes2

Copy link
Copy Markdown
Owner

Problem

A ChatGPT plugin pointed at https://brain.cutdacord.app/mcp installs with no Connect button, so there is no way to sign in.

What was wrong

The OAuth flow itself works. Checked against production (read-only) and end to end against a local copy:

  • discovery endpoints return valid JSON, the resource is exactly <base>/mcp, the issuer is consistent, PKCE S256 is supported
  • unauthenticated POST /mcp returns 401 with WWW-Authenticate: Bearer resource_metadata=…
  • dynamic client registration returns 201
  • sign-in → consent → code → token → initialize → tools/list → kb_search all pass

Since the 2026-10-05 migration the production auth DB has 0 registered OAuth clients, so ChatGPT never started the flow. The signals ChatGPT reads before offering sign-in were missing:

  1. No tool declared securitySchemes (0 of 12).
  2. The 401 challenge and the protected resource metadata named no scopes. The mcp plugin drops identity and refresh scopes from scopes_supported, and those are the only scopes this server has.
  3. The plugin's mcp.json has no extensions["com.openai"].auth block (outside this repo; the README now documents it).

Change

  • tools/list carries securitySchemes: [{ type: "oauth2", scopes: ["openid", "offline_access"] }] on every tool, top-level and in _meta (the SDK only passes _meta through).
  • The 401 challenge adds scope="openid offline_access".
  • /.well-known/oauth-protected-resource[/mcp] adds scopes_supported.
  • README: the plugin mcp.json auth block (oauth + dcr).

Nothing is exposed anonymously. Every MCP request still needs an API key or a token bound to the MCP resource. API-key clients are untouched.

Tests

  • New: tests/mcp-http.test.js (3 tests) and 3 tests in tests/auth-oauth.test.js. All 6 failed before the change.
  • Full suite with an isolated HOME: 146 pass, 0 fail.
  • Tool list before vs after: the same 12 tools, identical apart from the new fields.
  • ChatGPT-style HTTP run against a local copy of this branch (register, sign in, consent, PKCE exchange, initialize, tools/list, kb_search, kb_context, kb_read, refresh, bad-token and code-replay rejection): passes both when the client requests every scope and when it requests only the advertised ones.
  • A client that omits the resource parameter gets an unbound token and is refused with 401. That is intended.

Deploy

Merge, then sudo systemctl restart kb-server. No schema or data change.

🤖 Generated with Claude Code

A ChatGPT plugin pointed at /mcp installed with no Connect button. The
OAuth flow itself works (registration, sign-in, consent, token, search);
what was missing is everything ChatGPT reads to decide to offer sign-in:

- tools/list now carries securitySchemes (oauth2) on every tool, as a
  top-level field and in _meta (the SDK only passes _meta through)
- the 401 challenge names the scopes to request
- the protected resource metadata lists scopes_supported; the mcp plugin
  leaves identity and refresh scopes out, so a client had no hint to ask
  for offline_access

README documents the plugin mcp.json auth block (oauth + dcr), which the
plugin package needs for the button to appear.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@willynikes2
willynikes2 merged commit 7ff8a0b into master Oct 13, 2026
8 of 9 checks passed
@willynikes2
willynikes2 deleted the fix/chatgpt-oauth-signals branch October 13, 2026 12:16
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