Skip to content

Rewrite Notion MCP guide for Kubernetes remote proxy support#1004

Merged
danbarr merged 6 commits into
mainfrom
notion-remote-mcp-guide
Jul 8, 2026
Merged

Rewrite Notion MCP guide for Kubernetes remote proxy support#1004
danbarr merged 6 commits into
mainfrom
notion-remote-mcp-guide

Conversation

@danbarr

@danbarr danbarr commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Description

The Kubernetes tab claimed the ToolHive operator doesn't support remote MCP servers with OAuth, which hasn't been true for a long time. Replaced the static-integration-key workaround with a verified MCPRemoteProxy + embedded authorization server setup.

Notion's remote MCP server only supports Dynamic Client Registration for third-party OAuth clients, so the guide walks through minting persistent credentials via DCR instead of a dashboard app. Two callouts cover gotchas found while verifying this end to end against a real cluster and a real Notion account: the issuer field must stay path-free, and the upstream redirectUri default computed from resourceUrl breaks once resourceUrl has a path.

Also updated the Overview, Recommended Practices, and Troubleshooting sections to reflect the embedded-auth-server session model instead of a bare pass-through, and pointed the "expose the proxy externally" reference at the more complete connect-clients.mdx guide instead of a thinner duplicate section.

Type of change

  • Documentation update
  • Bug fix (typo, broken link, etc.)

Related issues/PRs

N/A

Screenshots

N/A - no visual or sidebar changes.

Submitter checklist

Content and formatting

  • I have reviewed the content for technical accuracy
  • I have reviewed the content for spelling, grammar, and style

Reviewer checklist

Content

  • I have reviewed the content for technical accuracy
  • I have reviewed the content for spelling, grammar, and style

The K8s tab claimed the operator doesn't support remote MCP servers
with OAuth, which hasn't been true for a long time. Replace the
static-integration-key workaround with a verified MCPRemoteProxy +
embedded authorization server setup.

Notion's remote MCP server only supports Dynamic Client Registration
for third-party OAuth clients, so the guide walks through minting
persistent credentials via DCR instead of a dashboard app. Callouts
cover two gotchas found while verifying this end to end: the issuer
field must stay path-free, and the upstream redirectUri default
computed from resourceUrl breaks once resourceUrl has a path.
Copilot AI review requested due to automatic review settings July 1, 2026 17:03
@vercel

vercel Bot commented Jul 1, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
docs-website Ready Ready Preview, Comment Jul 8, 2026 12:54pm

Request Review

Copilot AI left a comment

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.

Pull request overview

Updates the Notion remote MCP server guide to correct Kubernetes guidance and document a working remote-proxy + embedded authorization server flow, including Dynamic Client Registration (DCR) for Notion’s OAuth client credentials.

Changes:

  • Replaces the prior “static integration key” Kubernetes workaround with an MCPRemoteProxy + MCPExternalAuthConfig (embedded auth server) setup.
  • Adds a DCR-based “mint persistent client credentials” step and expands Kubernetes-specific operational/troubleshooting guidance around sessions and OAuth flow debugging.
  • Updates recommended practices/troubleshooting to reflect the embedded-auth-server session model and points external exposure guidance at connect-clients.mdx.

Comment thread docs/toolhive/guides-mcp/notion-remote.mdx
Comment thread docs/toolhive/guides-mcp/notion-remote.mdx Outdated
Rephrase four spaced-hyphen sentence separators per the style guide.

Clarify why this guide sets redirectUri explicitly instead of relying
on the documented {resourceUrl}/oauth/callback default: that default
only works for a bare-host resourceUrl, and breaks once resourceUrl
has a path (as it does here), since the callback route is only ever
served at the host root. Cross-references the relevant auth-k8s.mdx
section instead of leaving the divergence unexplained.
danbarr added a commit that referenced this pull request Jul 6, 2026
Split the 1,492-line guides-k8s/auth-k8s.mdx into a scenario-first
entry point plus two focused pages: embedded-auth-server-k8s.mdx and
authorization-k8s.mdx. Remove the front-loaded five-approach picker
and the vestigial legacy ConfigMap section, pointing instead to the
existing migrate-to-v1beta1.mdx guidance for that upgrade path.

Add the issuer-must-be-path-free and redirectUri callouts learned
from PR #1004 to the new embedded auth server page and to
concepts/embedded-auth-server.mdx.

Trim the duplicate backend-pattern decision table out of
embedded-auth-server.mdx, and note that vMCP's incoming/outgoing
terminology maps to MCPServer's frontend/backend in auth-framework.mdx.

Tighten the header-forwarding wording in remote-mcp-proxy.mdx to list
the full disallowed-header set and clarify User-Agent isn't blocked.

Correct the OIDC prerequisites partial and the CLI auth examples:
only the issuer is required, JWKS is auto-discovered, and client ID
only matters for introspection-based providers.

Update sidebars.ts and cross-references across the files that linked
to anchors which moved.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@danbarr danbarr changed the title Reform Notion MCP guide for Kubernetes remote proxy support Rewrite Notion MCP guide for Kubernetes remote proxy support Jul 6, 2026
danbarr added a commit that referenced this pull request Jul 7, 2026
)

* Restructure K8s auth guide, dedup concept docs

Split the 1,492-line guides-k8s/auth-k8s.mdx into a scenario-first
entry point plus two focused pages: embedded-auth-server-k8s.mdx and
authorization-k8s.mdx. Remove the front-loaded five-approach picker
and the vestigial legacy ConfigMap section, pointing instead to the
existing migrate-to-v1beta1.mdx guidance for that upgrade path.

Add the issuer-must-be-path-free and redirectUri callouts learned
from PR #1004 to the new embedded auth server page and to
concepts/embedded-auth-server.mdx.

Trim the duplicate backend-pattern decision table out of
embedded-auth-server.mdx, and note that vMCP's incoming/outgoing
terminology maps to MCPServer's frontend/backend in auth-framework.mdx.

Tighten the header-forwarding wording in remote-mcp-proxy.mdx to list
the full disallowed-header set and clarify User-Agent isn't blocked.

Correct the OIDC prerequisites partial and the CLI auth examples:
only the issuer is required, JWKS is auto-discovered, and client ID
only matters for introspection-based providers.

Update sidebars.ts and cross-references across the files that linked
to anchors which moved.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Trim boilerplate, nest auth pages under a category

Remove the "authentication is emerging" admonition from the K8s and
CLI auth guides; the spec has had a stable dated release for a while,
and client-support caveats belong closer to where they matter, not a
blanket disclaimer up top.

Trim the Prerequisites sections on the three K8s auth pages down to
what's actually specific to each page, dropping the boilerplate
cluster/kubectl/operator bullets already established earlier in the
section.

Reorder the K8s sidebar so token-exchange-k8s sits with the other
auth-adjacent pages instead of after Redis/rate-limiting, and nest
all four under a new "Authentication and authorization" category
(auth-k8s.mdx as the landing page), matching the existing
"Permissions and security" and "Deploy the Registry Server" category
patterns elsewhere in the sidebar. Add short sidebar_label overrides
to the two new pages so their labels match their neighbors.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Fix client ID/secret framing in OIDC prerequisites

Client ID isn't operator-invented like audience is; when it's
needed, the provider issues it on app registration. Reframe around
whether it's required, not where it comes from, and pair it with
client secret since both travel together for introspection-based
providers.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Trim token exchange prereqs, note Entra OBO is Enterprise

Drop the same cluster/kubectl/operator boilerplate from the
Prerequisites section as the other auth pages.

Add an enterprise callout: Entra ID doesn't implement RFC 8693 token
exchange, only its own RFC 7523-based on-behalf-of flow, which
Stacklok Enterprise supports via a dedicated obo auth type.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Extract IdP token exchange setup into a shared partial

The "Configure your identity provider" steps (register a client,
define audience/scopes, create an access policy) were duplicated
between the CLI and K8s token exchange guides, with K8s punting to
the CLI page for the actual steps. Since it's pure IdP-side
configuration with nothing CLI-specific in it, extract it to
_configure-token-exchange-idp.mdx and embed it directly in both,
matching the existing pattern for shared auth content.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Add diagrams showing CRD relationships

Signed-off-by: Dan Barr <6922515+danbarr@users.noreply.github.com>

* Cross-link backend federation options from each other

auth-k8s.mdx never mentioned AWS STS, so a reader starting at the
entry point had no way to discover it short of clicking into a child
page. Add it alongside token exchange in Next steps.

token-exchange-k8s.mdx didn't point to the "combine with embedded
auth server" pattern that already existed on the embedded-auth-server
page, so that combination was undiscoverable from the token exchange
side. Add the missing link back.

The combine section itself only showed AWS STS in its worked example
even though the same authServerRef + externalAuthConfigRef pattern
works identically for plain RFC 8693 token exchange. Generalize the
wording and YAML, and link both paths.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Cut vestigial section, fix mismatched heading framing

"Benefits of MCPOIDCConfig" was written as a comparison against
inline oidcConfig, which no longer exists as an option since v0.21.0.
Its still-accurate bullets (validation, status tracking, lifecycle)
were retrospective justification for a resource the reader already
created, not something that helps them do anything next. Cut it.

"Run an embedded OAuth server for spec-compliant clients" mismatched
the section's own body text, which correctly frames the reason as no
federation relationship with the IdP, not client compliance. Drop the
qualifier and match the plain action-phrase style of its sibling
headings.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Move CIMD/DCR config into the how-to, promote CIMD ordering

The concept doc's CIMD and baseline-scopes sections carried the
actual YAML config, field defaults, and document validation rules,
while the how-to guide only had a one-row table summary that bounced
readers out to concepts for the mechanics. Move the real
configuration (YAML blocks, cache defaults, validation rules) into
embedded-auth-server-k8s.mdx as two proper subsections, and trim the
concept doc back to the why (registration friction, the two-layer
trust architecture) with forward links into the how-to.

Also promote CIMD above DCR/baseline-scopes in both files' section
ordering, matching the MCP spec's stated preference (CIMD preferred,
DCR is the backward-compatibility fallback) and the ordering already
used everywhere else in the concept doc that lists both side by side.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Surface backend auth decision on the main K8s auth page

auth-k8s.mdx only discussed frontend (client-to-proxy) auth; backend
auth (MCP server/proxy-to-backend) wasn't mentioned until a single
Next steps bullet at the bottom. Add a "Choose a backend
authentication pattern" section mirroring the decision table in
concepts/backend-auth.mdx, giving both axes equal up-front billing.

Static credentials route to the actual common path (spec.secrets env
vars, Vault) plus the narrower MCPRemoteProxy header-forwarding case,
rather than only the proxy-level option. The MCPExternalAuthConfig
headerInjection/bearerToken gap for MCPServer is tracked in #1013.

Also add a CRD reference cross-link to embedded-auth-server-k8s.mdx,
closing out the last open item from #866.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Fix issues found by independent editorial review

Fix a broken sentence in the "First consent only" Google callout.

Trim the concept doc's new "issuer must be a bare host" section down
to a pointer into the how-to guide, which already carries the same
explanation almost verbatim - the one place this diff grew new
duplication instead of removing it.

Import the shared auth-troubleshooting partial into
authorization-k8s.mdx so the 403 guidance auth-k8s.mdx points readers
to is actually there.

Note the entities_json/entitiesJson casing difference between the
ConfigMap and inline authzConfig contexts, and reword an ambiguous
"always required" claim about oidcConfigRef.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Address Copilot review findings

Fix placeholder inconsistency in guides-cli/auth.mdx: embedded full
URLs and lowercase names inside angle brackets, unlike the <YOUR_X>
convention used everywhere else.

Scope the OIDC prerequisites partial: the issuer-lookup guidance only
applies to external IdPs, not Kubernetes service account auth, where
there's nothing to look up.

Set redirectUri explicitly in embedded-auth-server-k8s.mdx's two main
upstream-provider examples. Both omitted it while resourceUrl (set in
Step 5) includes a path, which is exactly the broken combination the
page's own later warning describes - the primary walkthrough wasn't
actually copy-paste-safe.

Fix the real source of the MCPAuthzConfig walkthrough link:
scripts/lib/crd-intros.mjs, not just the generated .mdx, which would
have reverted on the next CRD doc regeneration.

Use conventional header casing (TE, HTTP2-Settings, X-Real-IP) in the
disallowed-header list; HTTP header names are case-insensitive so
this doesn't change behavior, just readability.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Signed-off-by: Dan Barr <6922515+danbarr@users.noreply.github.com>
Co-authored-by: Dan Barr <6922515+danbarr@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Comment thread docs/toolhive/guides-mcp/notion-remote.mdx Outdated
jhrozek
jhrozek previously approved these changes Jul 8, 2026
Replace the manual client registration curl step and static client
secret with the embedded auth server's dcrConfig field, which
registers a client with Notion automatically at startup. Verified
end to end against a real cluster: the proxy performed live DCR
registration against Notion and a real client connected through it.

Also flag that DCR credentials share the session store, so a pod
restart without Redis-backed storage re-registers a new client with
Notion instead of just re-authenticating.
Signed-off-by: Dan Barr <6922515+danbarr@users.noreply.github.com>
Drop the "only supports DCR... unlike classic API integrations"
framing and shorten the issuer path-free note, which repeated the
same reasoning twice.
@danbarr danbarr merged commit 9d04523 into main Jul 8, 2026
3 checks passed
@danbarr danbarr deleted the notion-remote-mcp-guide branch July 8, 2026 14:31
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.

3 participants