Skip to content

Add Tembo TAS and MCP OAuth Integration - #379

Merged
ryw merged 1 commit into
mainfrom
tembo/tas-mcp-integration-web-connector-section-msng9szr
Aug 10, 2026
Merged

Add Tembo TAS and MCP OAuth Integration#379
ryw merged 1 commit into
mainfrom
tembo/tas-mcp-integration-web-connector-section-msng9szr

Conversation

@ryw

@ryw ryw commented Aug 10, 2026

Copy link
Copy Markdown
Member

Summary

Added per-user OAuth 2.1 support for the TAS MCP server enabling hosted clients like Claude Web to authenticate via OAuth with dynamic client registration, PKCE, and workspace selection. Updated MCP docs to include a new section for connecting Claude Web before Claude Code. Enhanced MCP server to accept OAuth tokens with scope checks and live workspace role enforcement. Added OAuth consent UI for workspace selection. Added OAuth metadata endpoints under /.well-known for MCP clients. Updated API auth to authorize OAuth claims with workspace binding and scopes. Added database migration for OAuth 2.1 authorization server tables and workspace selection binding. Added tests for OAuth MCP claims authorization and MCP server write scope enforcement. Updated changelog and docs to reflect these changes.

  • Added OAuth 2.1 support for MCP server with dynamic client registration and PKCE.
  • Updated MCP docs with new Claude Web connection instructions.
  • MCP server POST handler supports OAuth tokens and API keys.
  • OAuth consent page and workspace selection API.
  • OAuth metadata endpoints for MCP discovery.
  • API auth supports OAuth claims with workspace binding and scope checks.
  • Added database migration for OAuth tables.
  • Added tests for OAuth MCP claims and MCP server write scope enforcement.
  • Updated changelog and docs content.
  • Added @better-auth/oauth-provider dependency.

Want tembo to make any changes? Add a comment with @tembo and i'll get back to work!

View on Tembo  Review in Tembo  View Agent Settings

Co-authored-by: Ry <4283+ryw@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings August 10, 2026 16:32
@tembo tembo Bot added the tembo Pull request created by Tembo label Aug 10, 2026
Comment thread web/src/lib/auth.ts
consentReferenceId: async ({ user, session, scopes }) => {
if (!hasMcpOAuthScope(scopes)) return undefined;
return (
(await getMcpOAuthWorkspaceSelection(session.id, user.id)) ??

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.

A returning user can already have an oauthConsent for this client but no selection in their new session. In that case this returns undefined; the provider's consent lookup omits the referenceId filter, reuses the old consent, and issues a code without a workspace, which customAccessTokenClaims then rejects. Ensure authorization cannot reuse consent until this session has a valid workspace selection.

Comment thread web/src/lib/auth.ts
validAudiences: [mcpOAuthResource()],
grantTypes: ["authorization_code", "refresh_token"],
allowDynamicClientRegistration: true,
allowUnauthenticatedClientRegistration: true,

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.

This exposes dynamic registration to the public internet, while the provider only rate-limits authorize/token/introspect; every registration can insert an oauthClient row. Add registration-specific rate limiting or quotas/cleanup so anonymous traffic cannot grow this table indefinitely.

{selectedWorkspace ? (
<div className="text-foreground-weak space-y-2 text-sm">
<p>
The MCP client will act as you in the workspace you select.

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.

This screen doesn't identify the requesting client or show its exact requested scopes. With unauthenticated DCR, a phishing authorization URL looks the same as Claude and can request mcp:write. Surface the registered client name/redirect origin and requested scopes before the user allows access.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR adds per-user OAuth 2.1 authentication to the TAS MCP server so hosted MCP clients (notably Claude Web) can connect via Dynamic Client Registration + PKCE, select a workspace during consent, and receive scoped tokens that still enforce live workspace RBAC.

Changes:

  • Added Better Auth OAuth Authorization Server support (JWT + oauth-provider) with workspace-binding claims and consent UI.
  • Updated MCP endpoint/auth boundary to accept either tas_ API keys or OAuth access tokens, enforcing mcp:write for write tools.
  • Published OAuth discovery metadata under /.well-known/* and updated docs/changelogs accordingly.

Reviewed changes

Copilot reviewed 25 out of 27 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
web/src/proxy.ts Marks /.well-known/* as public so OAuth discovery metadata is reachable without a session.
web/src/lib/mcp/server.ts Enforces mcp:write scope for OAuth-based write/admin MCP tools while keeping API keys working.
web/src/lib/mcp/server.test.ts Adds coverage for rejecting write-tool calls when OAuth lacks mcp:write.
web/src/lib/mcp-oauth.ts Defines MCP OAuth scopes, issuer/resource helpers, and the workspace claim name.
web/src/lib/mcp-oauth-selection.ts Persists and validates the user’s workspace choice for the OAuth consent flow.
web/src/lib/mcp-oauth-metadata.ts Implements OAuth Protected Resource Metadata response for MCP discovery.
web/src/lib/mcp-oauth-metadata.test.ts Tests the advertised resource + issuer metadata values.
web/src/lib/docs-content.ts Regenerates in-app docs bundle to include updated API/MCP content and changelog entry.
web/src/lib/auth.ts Wires Better Auth JWT + oauth-provider (DCR, PKCE, refresh tokens) and binds tokens to a selected workspace.
web/src/lib/auth.test.ts Expands auth wiring tests to cover oauth-provider config and workspace-bound token claims.
web/src/lib/auth-client.ts Adds oauth-provider client plugin so OAuth query params survive login/consent transitions.
web/src/lib/api-auth.ts Adds OAuth-claims authorization path for MCP, binding claims to workspace + live role + scopes.
web/src/lib/api-auth.test.ts Adds tests for OAuth-claims authorization (happy path, missing scope/claim, lost membership).
web/src/app/oauth/consent/page.tsx New server-rendered consent page that lists the user’s workspaces for selection.
web/src/app/oauth/consent/consent-card.tsx New client consent UI that stores workspace selection then completes oauth-provider consent.
web/src/app/mcp/route.ts MCP endpoint now supports OAuth tokens via mcpHandler in addition to tas_ API keys.
web/src/app/api/mcp/oauth/select-workspace/route.ts API route to persist a chosen workspace into the selection table for the current session.
web/src/app/.well-known/oauth-protected-resource/route.ts Exposes protected-resource metadata at the standard well-known path.
web/src/app/.well-known/oauth-protected-resource/mcp/route.ts Exposes protected-resource metadata at the resource-specific well-known subpath.
web/src/app/.well-known/oauth-authorization-server/api/auth/route.ts Serves OAuth Authorization Server metadata for the Better Auth issuer under /.well-known.
web/pnpm-lock.yaml Locks the new @better-auth/oauth-provider dependency.
web/package.json Adds @better-auth/oauth-provider dependency.
docs/src/content/docs/mcp.md Updates MCP docs with Claude Web connector setup and OAuth vs API-key auth model.
docs/src/content/docs/changelog.md Adds an Unreleased changelog entry for per-user MCP OAuth.
docs/src/content/docs/api.md Clarifies REST API uses API keys while MCP also supports OAuth for hosted clients.
CHANGELOG.md Adds an Unreleased changelog entry for per-user MCP OAuth (repo root).
api/migrations/0072_mcp_oauth.sql Adds OAuth provider storage tables plus a TAS-owned workspace-selection binding table.
Files not reviewed (1)
  • web/pnpm-lock.yaml: Generated file
Suppressed comments (1)

web/src/app/mcp/route.ts:67

  • With handleAuthorizedMcpRequest accepting Request, the OAuth path no longer needs to cast request to NextRequest. Keeping the cast hides type mismatches and can mask runtime differences between Request and NextRequest.
      );
    }
    return handleAuthorizedMcpRequest(request as NextRequest, auth);
  },

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread web/src/app/mcp/route.ts
Comment on lines +35 to +38
async function handleAuthorizedMcpRequest(
request: NextRequest,
auth: AuthorizeApiSuccess,
): Promise<Response> {
@ryw
ryw merged commit b465e67 into main Aug 10, 2026
6 checks passed
@ryw
ryw deleted the tembo/tas-mcp-integration-web-connector-section-msng9szr branch August 10, 2026 16:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tembo Pull request created by Tembo

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants