MCP OAuth: unhandled TypeError "Cannot read properties of undefined (reading 'map')" when a DCR response omits grant_types/response_types

Status Open
Reported on v2.1.220
Maintainer reply None cached
Activity 0 comments · opened Jul 27, 2026

Summary

When an OAuth authorization server's Dynamic Client Registration response omits grant_types /
response_types, the MCP OAuth client throws

Cannot read properties of undefined (reading 'map')

instead of falling back to the RFC 6749 / RFC 7591 defaults. The affected MCP server is left
permanently unauthenticated, and because the crash happens after registration succeeds, every retry
mints another orphaned client registration on the provider side.

RFC 7591 §3.2.1 does say the server should return the full registered metadata — so the provider is
also at fault, and I've reported it there (supabase-community/supabase-plugin#51). But a missing
optional field in a third-party response should degrade, not throw an unhandled TypeError with no
actionable message.

Reproduction

Any server whose DCR response is short of those fields. A live one:

  1. /plugin install supabase@claude-plugins-official (v0.1.12), which registers an HTTP MCP server

at https://mcp.supabase.com/mcp

  1. Invoke its authenticate tool
  2. Observe: {"message":"Cannot read properties of undefined (reading 'map')","errorEventId":"..."}

The provider's DCR endpoint returns HTTP 201 with only:

client_id, client_secret, client_secret_expires_at, id, redirect_uris

even when the registration request explicitly sends grant_types, response_types, and scope:

curl -s -X POST https://api.supabase.com/platform/oauth/apps/register \
  -H 'Content-Type: application/json' \
  -d '{"client_name":"dcr-probe","redirect_uris":["http://localhost:57999/callback"],
       "grant_types":["authorization_code","refresh_token"],"response_types":["code"],
       "token_endpoint_auth_method":"client_secret_post","scope":"organizations:read projects:read"}'

Discovery is not implicated — I verified both metadata documents are complete
(response_types_supported, grant_types_supported, code_challenge_methods_supported,
scopes_supported all present), the protected-resource document is complete, and the MCP endpoint
returns a correct www-authenticate challenge. The DCR response is the only place in the flow where
an expected array is undefined.

Expected

  • Treat grant_types / response_types as absent-with-defaults per RFC 7591 §2

(["authorization_code"] and ["code"]) rather than dereferencing them.

  • If the response is genuinely unusable, fail with a message naming the server and the missing field,

not a raw TypeError.

  • Do not persist / re-register a new dynamic client on a failure path that has already registered one

successfully — see "orphan churn" below.

Note on the error message

The user-visible output is just the TypeError plus an errorEventId. No stack trace is written
locally
— I searched the whole ~/.claude tree, and the only local occurrences of the string were
the user's own pasted copy in history.jsonl and the session transcript. Since the errorEventId
resolves only server-side, there is nothing a user or a support thread can act on. Logging the
failing server name + field locally would make this self-diagnosable.

Orphan client churn (overlaps #80422)

Because the throw happens post-registration, retrying re-registers. This machine's credential store
accumulated three distinct client registrations for this one server (30369d14…, d6474d66…,
a7bb9b2a…), one half-completed with an empty access token and no expiresAt. Providers have no way
to distinguish these from real clients, and the register endpoint has no unauthenticated delete.

Separately, and consistent with #80422: the live credential store currently holds 62 mcpOAuth
entries of which all 62 have an empty accessToken and zero have a refreshToken, while
same-day backups hold 65 entries including 2 with live tokens. I've added that data as a comment on
#80422 rather than duplicating it here.

Environment

  • Claude Code 2.1.220, macOS 26.6, Node v22.14.0
  • HTTP transport, plugin-provided MCP server, no static --client-id configured

Workaround

Skip DCR entirely with a pre-issued token:

claude mcp add --transport http --scope user <name> <url> --header "Authorization: Bearer <token>"

Verified working against the same server — initialize 200, tools/list 200 with all 29 tools,
claude mcp list✔ Connected.

Possibly related

  • #80422 — MCP OAuth storage wiped mid-session; silent re-registration, orphan churn
  • #79505 — no re-registration when a cached DCR client is rejected; no per-server clear-auth
  • #67258 / #26675 — DCR attempted even when static client credentials are configured

View original on GitHub ↗