Skip to content

feat(api): declare oauth2 security scheme for MCP per-user auth#2961

Merged
tofikwest merged 1 commit into
mainfrom
feat/openapi-oauth2-mcp
May 29, 2026
Merged

feat(api): declare oauth2 security scheme for MCP per-user auth#2961
tofikwest merged 1 commit into
mainfrom
feat/openapi-oauth2-mcp

Conversation

@tofikwest
Copy link
Copy Markdown
Contributor

@tofikwest tofikwest commented May 29, 2026

Why

This unblocks keyless, per-user auth for the hosted MCP (Speakeasy Gram).

I traced Gram's source: it picks the credential it sends to our backend from the spec's security scheme. With only the X-API-Key scheme, Gram would call our API with one shared key for every MCP user — bypassing the per-user/per-org RBAC the API already enforces. Gram also only shows the customer-facing OAuth wizard when the spec advertises an oauth2 scheme (oauth2SecurityCount > 0); until then it offers only "Gram OAuth" (internal Gram-org members).

What

  • Adds an oauth2 (authorization code) security scheme pointed at the better-auth MCP authorization server (/api/auth/mcp/authorize + /token).
  • Offers it alongside the API key on every authenticated operation (OR semantics — either credential satisfies a request, so existing API-key integrations and the SDK are unaffected).
  • Centralized in applyPublicOpenApiMetadata so all three spec-generation paths (main.ts, gen-openapi.spec.ts, openapi-docs.spec.ts) stay consistent.
  • Regenerated the committed openapi.jsonverified byte-identical to a real GEN_OPENAPI=1 run (935 insertions, 0 deletions; 306/306 API-key ops now also offer oauth2).

How it fits the rollout

Once merged, the existing gram-sync CI pushes the updated spec → oauth2SecurityCount flips above 0 → the External/Proxy OAuth wizard unlocks in Gram. Next steps (Gram-side): set the MCP server Public, run the OAuth wizard pointed at better-auth, set the staging GRAM_OAUTH_* env vars.

Tests

  • New openapi-docs.spec.ts cases: asserts the oauth2 scheme exists with the right endpoints, every API-key op also offers oauth2, and oauth2 is never on a non-API-key (public) op.
  • Full openapi-docs.spec.ts green (5/5).

Heads-up

Speakeasy SDK generation consumes this spec; it'll see the new oauth2 scheme (additive). The authorization-code flow is for interactive/MCP clients — existing API-key SDK usage is unchanged.

🤖 Generated with Claude Code


Summary by cubic

Enables per-user OAuth for hosted MCP (Speakeasy Gram) by declaring an oauth2 authorization-code security scheme in the public OpenAPI spec, alongside the existing API key. This unlocks Gram’s OAuth wizard and keeps current API-key integrations working.

  • New Features
    • Added oauth2 authorization code scheme pointing to /api/auth/mcp/authorize and /api/auth/mcp/token.
    • Offered oauth2 on all API-key–gated operations (OR semantics: API key or OAuth token).
    • Centralized in applyPublicOpenApiMetadata to keep all spec-generation paths consistent.
    • Regenerated packages/docs/openapi.json.

Written for commit e906b6d. Summary will update on new commits.

Review in cubic

Hosted MCP (Speakeasy Gram) only surfaces a customer-facing 'Sign in with Comp AI' flow and forwards each user's bearer token to the API when the OpenAPI spec declares an oauth2 scheme. With only the X-API-Key scheme, Gram would call the API with one shared key for every user, bypassing the per-user/per-org RBAC the API already enforces.

Adds an oauth2 (authorization code) scheme pointed at the better-auth MCP authorization server and offers it alongside the API key on every authenticated operation (OR semantics — either credential satisfies a request, so existing API-key integrations are unaffected). Centralized in applyPublicOpenApiMetadata so all three spec-generation paths stay consistent; committed openapi.json regenerated (verified byte-identical to a GEN_OPENAPI=1 run). Once synced to Gram, oauth2SecurityCount>0 unlocks the External/Proxy OAuth wizard.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel vercel Bot temporarily deployed to Preview – portal May 29, 2026 01:44 Inactive
@vercel
Copy link
Copy Markdown

vercel Bot commented May 29, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
comp-framework-editor Ready Ready Preview, Comment May 29, 2026 1:45am
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
app Skipped Skipped May 29, 2026 1:45am
portal Skipped Skipped May 29, 2026 1:45am

Request Review

@vercel vercel Bot temporarily deployed to Preview – app May 29, 2026 01:44 Inactive
@mintlify
Copy link
Copy Markdown
Contributor

mintlify Bot commented May 29, 2026

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
CompAI 🟢 Ready View Preview May 29, 2026, 1:45 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

No issues found across 3 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Re-trigger cubic

@tofikwest tofikwest merged commit 2bd0de6 into main May 29, 2026
13 checks passed
@tofikwest tofikwest deleted the feat/openapi-oauth2-mcp branch May 29, 2026 01:48
@claudfuen
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 3.66.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

claudfuen pushed a commit that referenced this pull request Jun 4, 2026
## [3.70.3](v3.70.2...v3.70.3) (2026-06-04)

### Bug Fixes

* **api:** revert oauth2 spec scheme to restore the MCP generator ([64978f5](64978f5)), closes [#2961](#2961) [#2961](#2961) [pre-#2961](https://github.com/pre-/issues/2961) [#2955](#2955) [hi#value](https://github.com/hi/issues/value)
yerramasu pushed a commit to iagentic/compliance-ai that referenced this pull request Jun 5, 2026
Reverts the oauth2 security scheme that trycompai#2961 added to the public OpenAPI
spec. That change put two auth methods (apikey + oauth2) on every endpoint,
which made Speakeasy's mcp-typescript generator drop ~300 of ~335 MCP tools
on every nightly run — it cannot emit a tool when an operation declares more
than one security scheme. The nightly regen kept opening "Update SDK" PRs
that would gut the published @trycompai/mcp-server if merged.

This removes ONLY the oauth2 scheme + the per-op oauth2 entries; the
packages/docs/openapi.json diff is a pure inverse of trycompai#2961 (936 deletions,
no other endpoint touched). public-docs-metadata.ts is restored byte-for-byte
to its pre-trycompai#2961 state.

All the actual OAuth work (better-auth provider, guards, McpOrgBinding, org
picker from trycompai#2955) is UNTOUCHED and stays intact. Keyless OAuth will be wired
at the hosting layer (self-host or Speakeasy Enterprise), never in the base
spec.

Adds a guardrail test in openapi-docs.spec.ts that fails if any operation
ever declares more than one security scheme again, so this regression cannot
silently recur.

Note: an unrelated, pre-existing test ("curates high-value API pages" /
expects "SOC 2" in the /v1/policies description) fails on main too — that
description changed and the SEO assertion is stale. Left as-is to keep this
revert surgical.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants