Skip to content

feat(mcp): add no-OAuth docs-only endpoint at ?category=docs#230

Open
andrelandgraf wants to merge 2 commits intomainfrom
feat/docs-only-mcp-no-oauth
Open

feat(mcp): add no-OAuth docs-only endpoint at ?category=docs#230
andrelandgraf wants to merge 2 commits intomainfrom
feat/docs-only-mcp-no-oauth

Conversation

@andrelandgraf
Copy link
Copy Markdown
Collaborator

Summary

  • Adds a strict docs-only mode (?category=docs with no other category and no projectId) that bypasses OAuth entirely on /api/mcp and /api/sse, exposing only list_docs_resources and get_doc_resource.
  • Lets clients embed the Neon docs MCP tools anonymously (e.g. via mcp.neon.tech/mcp?category=docs) with no account, no OAuth flow, and no WWW-Authenticate 401 challenge.
  • Any other category combination, or the presence of projectId, keeps the existing authenticated flow unchanged.

Why it's safe

The two docs handlers (landing/mcp-src/tools/tools.ts) only call fetch(NEON_DOCS_INDEX_URL) / fetch(\${NEON_DOCS_BASE_URL}/${slug}`)and never touchneonClientorextra.account. validateDocSlug` already blocks path traversal and absolute URLs.

Implementation

  • isDocsOnlyRequest(params) helper in landing/mcp-src/utils/grant-context.ts.
  • New createDocsOnlyMcpHandler() in landing/app/api/[transport]/route.ts. It builds a mcp-handler instance without withMcpAuth, registers only docs-scoped tools, and overrides tools/list to surface only that subset. Telemetry uses a fixed anonymous-docs anonymousId.
  • handleRequest branches to the lazily-initialized docs-only handler before falling through to authHandler.
  • We deliberately don't go through getAvailableTools / grant-filter for docs-only so the always-available search / fetch tools (which need API auth) are not surfaced anonymously.

Test plan

  • pnpm run lint
  • pnpm run typecheck
  • pnpm run fmt:check
  • pnpm run knip
  • pnpm run test:unit (135/135 pass, includes 9 new cases for isDocsOnlyRequest)
  • pnpm run test:e2e:web (22/22 pass, includes 5 new cases in e2e/docs-only-mcp.spec.ts covering: initialize without auth, tools/list returns only docs tools, tools/call list_docs_resources succeeds, mixed categories still 401, and category=docs + projectId still 401)
  • Manual smoke after deploy-preview: curl -X POST 'https://preview-mcp.neon.tech/mcp?category=docs' -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2025-03-26\",\"capabilities\":{},\"clientInfo\":{\"name\":\"smoke\",\"version\":\"1.0.0\"}}}' → expect 200 with no WWW-Authenticate header.
  • Verify same request without ?category=docs still returns 401 with OAuth challenge.

Risk / follow-ups

  • Anonymous traffic is unbounded; the docs handlers proxy to neon.com. If abuse is a concern, add a per-IP rate limit (out of scope here).
  • /.well-known/oauth-protected-resource keeps advertising OAuth; clients only act on it after a 401, which we no longer return for docs-only requests, so this is a no-op for them.
  • If a future docs-scoped tool ever needs the Neon API client, this assumption breaks. Keep the docs scope handler set explicit.

Strict docs-only mode (?category=docs with no other category and no
projectId) bypasses withMcpAuth entirely so the documentation tools
(list_docs_resources, get_doc_resource) can be embedded anonymously
without an OAuth flow. These handlers only fetch from neon.com and
never touch the Neon API client, so anonymous access is safe.

Any other category combination, or the presence of a projectId,
keeps today's authenticated flow.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 4, 2026

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
mcp-server-neon Ignored Ignored Preview May 4, 2026 4:25pm

Request Review

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 4, 2026

🚀 Deployed to https://preview-mcp.neon.tech

This PR now owns the preview environment. OAuth flow is available for testing.

Keep anonymous docs mode independent from the authenticated tool handler map by sharing small docs fetch helpers and registering the two docs callbacks directly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant