Skip to content

OAuth fails with invalid_target: ?utm_source=plugin in MCP URL breaks RFC 8707 resource matching #334

Description

@GraceChingChingYeh

Summary

The ?utm_source=plugin query string appended to the MCP server URL breaks the OAuth flow in Claude Code. Authorization fails with:

Error
Authentication failed
Close this tab and try again from Claude Code.

invalid_target: The resource parameter does not match this authorization server

The plugin installs fine and its skills load, but the MCP server can never be authenticated, so none of its tools are usable.

Root cause

https://mcp.sentry.dev publishes this protected-resource metadata:

$ curl -s https://mcp.sentry.dev/.well-known/oauth-protected-resource/mcp
{
  "resource": "https://mcp.sentry.dev/mcp",
  "authorization_servers": ["https://mcp.sentry.dev"],
  "scopes_supported": ["org:read", "project:write", "team:write", "event:write"],
  "bearer_methods_supported": ["header"]
}

The canonical resource identifier is https://mcp.sentry.dev/mcp — no query component.

Claude Code derives the RFC 8707 resource parameter from the configured server URL, so it sends
resource=https://mcp.sentry.dev/mcp?utm_source=plugin. RFC 8707 requires the resource indicator to
match the protected resource identifier, and the authorization server correctly rejects the
mismatch with invalid_target.

Evidence

Two OAuth entries accumulated in the macOS keychain under Claude Code-credentialsmcpOAuth,
one per URL variant (the key is derived from the server URL):

entry serverUrl state
plugin:sentry:sentry|800cb29a… https://mcp.sentry.dev/mcp dynamic client registration completed (clientId + full scopes present), no token
plugin:sentry:sentry|b328196b… https://mcp.sentry.dev/mcp?utm_source=plugin never got a clientId

The clean URL gets through client registration; the utm_source variant fails before it.

Affected files

?utm_source=plugin appears in three distribution configs, so this affects more than the Claude Code plugin:

  • src/plugins/claude/plugin.json
  • src/plugins/agent-plugin/mcp.json
  • mcp.json

Reproduction

  1. Install the Sentry plugin in Claude Code (sentry@claude-plugins-official, v1.3.2)
  2. Enable it and run /mcpsentry → Authenticate
  3. Browser tab shows the invalid_target error above

Workaround

Edit the installed plugin manifest and strip the query string:

   "mcpServers": {
     "sentry": {
       "type": "http",
-      "url": "https://mcp.sentry.dev/mcp?utm_source=plugin"
+      "url": "https://mcp.sentry.dev/mcp"
     }
   }

on macOS at
~/.claude/plugins/cache/claude-plugins-official/sentry/<version>/.claude-plugin/plugin.json.
This is overwritten on the next plugin update.

Suggested fix

TELEMETRY.md documents that ?utm_source=plugin exists so distributed MCP configs are attributed
on spans, so simply deleting it would lose that signal. Two options that keep attribution intact:

  1. Move attribution out of the URL — carry it in a request header (e.g. X-Sentry-Client or a
    User-Agent suffix) rather than the resource URI. The URL is load-bearing for OAuth; the header
    is not.
  2. Canonicalize resource server-side — have the authorization server strip the query component
    before comparing resource indicators. This fixes existing installs without a plugin release, but
    only helps clients talking to mcp.sentry.dev.

Option 1 seems preferable — it keeps the resource identifier spec-compliant for every client, not
just ones that happen to hit a lenient server.

Environment

  • Claude Code 2.1.197
  • Sentry plugin 1.3.2 (sentry@claude-plugins-official)
  • macOS 26.5.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions