Skip to content

fix(mcp): use dynamic client registration for OAuth instead of hardcoded client ID#1313

Merged
Kitenite merged 1 commit into
mainfrom
kitenite/mcp-install
Feb 8, 2026
Merged

fix(mcp): use dynamic client registration for OAuth instead of hardcoded client ID#1313
Kitenite merged 1 commit into
mainfrom
kitenite/mcp-install

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented Feb 8, 2026

Summary

  • MCP OAuth authentication from Claude Code was failing with invalid_client because the hardcoded clientId: "claude-code" in .mcp.json was never registered in the oauth_applications database table
  • Removed the hardcoded OAuth config so Claude Code uses the standard MCP OAuth discovery + dynamic client registration flow (which the API already supports via better-auth's MCP plugin)
  • Updated the consent page to look up the application's registered name from the database, so dynamically registered clients display their proper name

Changes

  • .mcp.json: Removed oauth block (clientId, authorizationUrl, tokenUrl, scopes) — Claude Code will auto-discover these via /.well-known/oauth-authorization-server
  • apps/web/src/app/oauth/consent/page.tsx: Query oauth_applications table for the client's name field and pass it as clientName prop
  • apps/web/src/app/oauth/consent/components/ConsentForm/ConsentForm.tsx: Accept clientName prop and prefer it over the hardcoded knownClients fallback map

Test Plan

  • From Claude Code, run /mcp and authenticate the Superset MCP server — should complete OAuth flow without invalid_client error
  • Verify the consent screen shows the application name correctly
  • Verify existing knownClients fallback still works for clients without a DB name

Summary by CodeRabbit

  • New Features

    • OAuth consent form now displays the actual application name in the authorization request, providing clearer identification of the service requesting access.
  • Chores

    • Updated OAuth server configuration settings.

…ded client ID

The hardcoded clientId "claude-code" in .mcp.json was never registered
in the oauth_applications table, causing invalid_client errors. Remove
the oauth config to let Claude Code use the standard MCP OAuth discovery
and dynamic client registration flow. Also resolve the consent form to
show the registered application name from the database.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 8, 2026

📝 Walkthrough

Walkthrough

The changes add client name fetching and display to the OAuth consent flow while removing OAuth configuration from the superset MCP server. The ConsentForm component now accepts an optional clientName prop, and the consent page queries the database for the OAuth application name to pass to the form.

Changes

Cohort / File(s) Summary
MCP Configuration
.mcp.json
Removed OAuth configuration block (clientId, authorizationUrl, tokenUrl, scopes) from superset MCP server, retaining only the URL endpoint.
OAuth Consent Flow
apps/web/src/app/oauth/consent/components/ConsentForm/ConsentForm.tsx, apps/web/src/app/oauth/consent/page.tsx
Added optional clientName prop to ConsentForm; updated consent page to fetch OAuth application name from database and pass it to the form component.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Poem

🐰 A rabbit hopped through OAuth's gate,
Adding names to make things great!
The consent form now knows the way,
Which app is asking, come what may! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: moving from hardcoded client ID configuration to dynamic client registration for OAuth.
Description check ✅ Passed The description covers the issue, changes made, and test plan; however, it lacks the structured template sections (Type of Change, Related Issues, Screenshots).

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch kitenite/mcp-install

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@apps/web/src/app/oauth/consent/components/ConsentForm/ConsentForm.tsx`:
- Around line 145-150: The consent screen currently renders the
attacker-controlled displayName in ConsentForm; update ConsentForm (where
displayName is used) to show the raw clientId alongside displayName and/or a
visual "verified" badge for trusted clients: fetch or accept a isVerified flag
for the client and render a small badge component next to displayName when true,
and render clientId in muted text under or beside the name when not verified;
ensure displayName/clientId are output as plain text (React JSX escaping) or
explicitly sanitize them before rendering to avoid any HTML injection.
🧹 Nitpick comments (1)
apps/web/src/app/oauth/consent/page.tsx (1)

67-70: Direct db access bypasses the tRPC layer used elsewhere in this file.

Line 65 fetches userOrganizations through tRPC, but the new oauthApplications lookup goes straight to the DB client. This is a minor inconsistency — consider wrapping this in a tRPC procedure (or a shared query helper) so all data access in this page follows the same pattern. Not blocking given the query's simplicity.

Comment on lines +145 to 150
Authorize {displayName}
</h1>
<p className="text-muted-foreground text-sm">
<span className="font-medium text-foreground">{clientName}</span> is
<span className="font-medium text-foreground">{displayName}</span> is
requesting access to your Superset account
</p>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Consider whether displaying an attacker-controlled name needs sanitization or a visual trust indicator.

With dynamic client registration, any caller can register an application with an arbitrary name (e.g., "Superset Desktop" or "Google"). The consent screen currently renders that name without any trust differentiation. This could be used to impersonate a known/trusted application.

Consider either:

  • Showing the raw clientId alongside the display name so users can distinguish dynamically registered apps.
  • Adding a "verified" badge for known/trusted clients only.
🤖 Prompt for AI Agents
In `@apps/web/src/app/oauth/consent/components/ConsentForm/ConsentForm.tsx` around
lines 145 - 150, The consent screen currently renders the attacker-controlled
displayName in ConsentForm; update ConsentForm (where displayName is used) to
show the raw clientId alongside displayName and/or a visual "verified" badge for
trusted clients: fetch or accept a isVerified flag for the client and render a
small badge component next to displayName when true, and render clientId in
muted text under or beside the name when not verified; ensure
displayName/clientId are output as plain text (React JSX escaping) or explicitly
sanitize them before rendering to avoid any HTML injection.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 8, 2026

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch
  • ✅ Electric Fly.io app

Thank you for your contribution! 🎉

@Kitenite Kitenite merged commit 94587b0 into main Feb 8, 2026
14 checks passed
@Kitenite Kitenite deleted the kitenite/mcp-install branch February 8, 2026 20:05
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