lazy-auth-server: support mounting under a base path#683
Open
ochafik wants to merge 2 commits into
Open
Conversation
createApp() previously built every advertised URL (AS metadata
endpoints, PRM resource, WWW-Authenticate resource_metadata, consent
approve link, elicitation callbacks) from the bare origin, so mounting
the app inside another Express app — app.use("/lazy-auth",
createApp()) — advertised URLs that pointed at the host's root and
collided with the host's own OAuth endpoints.
Derive the public base URL from Express's req.baseUrl instead (empty
when standalone, so standalone behavior is unchanged), and treat
PUBLIC_URL as including any mount path. Document the mounting pattern,
including the root well-known rewrite hosts must add for RFC 8414/9728
path-insertion discovery.
import.meta.filename and import.meta.dirname are undefined in some module-VM contexts (e.g. importing this package from jest), which made createApp() throw at import time. import.meta.url is defined everywhere; derive the dist directory from it instead.
@modelcontextprotocol/ext-apps
@modelcontextprotocol/server-basic-preact
@modelcontextprotocol/server-basic-react
@modelcontextprotocol/server-basic-solid
@modelcontextprotocol/server-basic-svelte
@modelcontextprotocol/server-basic-vanillajs
@modelcontextprotocol/server-basic-vue
@modelcontextprotocol/server-budget-allocator
@modelcontextprotocol/server-cohort-heatmap
@modelcontextprotocol/server-customer-segmentation
@modelcontextprotocol/server-debug
@modelcontextprotocol/server-lazy-auth
@modelcontextprotocol/server-map
@modelcontextprotocol/server-pdf
@modelcontextprotocol/server-scenario-modeler
@modelcontextprotocol/server-shadertoy
@modelcontextprotocol/server-sheet-music
@modelcontextprotocol/server-system-monitor
@modelcontextprotocol/server-threejs
@modelcontextprotocol/server-transcript
@modelcontextprotocol/server-video-resource
@modelcontextprotocol/server-wiki-explorer
commit: |
5ab6589 to
9110c2c
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this does
Makes the lazy-auth example mountable inside another Express app (
hostApp.use("/lazy-auth", createApp())), so an existing MCP server can host it at a sub-path of its own origin. Motivation: serving this example from example-remote-server alongside the other examples at/:slug/mcp, on its existing single-origin deployment (a follow-up PR there consumes this).Why
createApp()built every advertised URL (AS metadata endpoints, PRMresource,WWW-Authenticateresource_metadata, consent approve link, elicitation callbacks) from the bare origin. Mounted under a sub-path, those URLs point at the host's root — colliding with the host's own OAuth endpoints. The observed failure is nasty: the 401 advertiseshttps://host/auth/prm, which 404s, so SDK clients fall back to treating the host origin as the authorization server and users complete the wrong OAuth flow, ending in a 401 loop.What changed
resolvePublicUrl()now appends Express'sreq.baseUrl(empty when standalone, so standalone behavior is unchanged).PUBLIC_URL, when set, must include the mount path.publicBaseHref()helper replaces all${base.origin}joins.DIST_DIRis now derived fromimport.meta.urlinstead ofimport.meta.filename/import.meta.dirname, which are undefined in some module-VM contexts (importing the package from jest threw at import time)./.well-known/oauth-authorization-server/lazy-auth) live at the origin root, outside the mount, and the TS SDK only tries that insertion form foroauth-authorization-server.How it was verified
npm run --workspace examples/lazy-auth-server build(includestsc --noEmit) and prettier pass.http://localhost:3097— URLs identical to before (back-compat);/lazy-authinside a host app with colliding root/authorize+/.well-known/oauth-authorization-serverroutes — full 401 → PRM → AS discovery (insertion form) → PKCE → token → authedget_secretflow, TTL-scoped PRM, host routes untouched;PUBLIC_URL=https://example.test/lazy-auth— advertised URLs use the configured base.req.baseUrl, and double body-parsing all behave.After merge
Publish as 1.7.4 so example-remote-server can pick it up. Note:
@modelcontextprotocol/server-transcript@1.7.3appears to have been skipped by the 1.7.3 publish (npm has up to 1.7.2) — worth checking the publish workflow at the same time.