Skip to content

Add lazy-auth example server (mounted at /lazy-auth)#45

Closed
ochafik wants to merge 2 commits into
modelcontextprotocol:mainfrom
ochafik:deps/ext-apps-1.7.3-lazy-auth
Closed

Add lazy-auth example server (mounted at /lazy-auth)#45
ochafik wants to merge 2 commits into
modelcontextprotocol:mainfrom
ochafik:deps/ext-apps-1.7.3-lazy-auth

Conversation

@ochafik
Copy link
Copy Markdown
Contributor

@ochafik ochafik commented Jun 5, 2026

What this does

Adds the @modelcontextprotocol/server-lazy-auth example, served at /lazy-auth/mcp alongside the other example MCP App servers, and bumps the ext-apps example family to 1.7.3.

Unlike the other examples (plain createServer() factories behind the stateless handler), lazy-auth's value is its HTTP layer — public tools work unauthenticated; protected tools answer 401 + WWW-Authenticate; a built-in mock OAuth authorization server completes the flow. So it mounts its full Express app (createApp()) under /lazy-auth.

Why now / what's blocked without it

The mobile clauditor e2e specs are blocked on reaching lazy-auth at https://example-server.modelcontextprotocol.io/lazy-auth/ttl/3600/mcp (TTL-scoped path → 1-hour tokens, so 30s defaults don't expire mid-test on slow mobile runs).

What changed

  • src/modules/example-apps/lazy-auth.ts — mounts the app before the host middleware, and adds the RFC 8414/9728 path-insertion well-known rewrite (/.well-known/oauth-authorization-server/lazy-auth → into the mount). MCP SDK clients only try the insertion form for oauth-authorization-server, so this rewrite is required for discovery under a base path.
  • src/index.ts / example-apps/index.ts — early mount (so the example's CORS/body handling stay self-contained), splash + console listings.
  • No new deploy config: PUBLIC_URL for the example is derived from this server's own BASE_URI (already the source of truth for the host's OAuth issuer). An explicit PUBLIC_URL still wins (e.g. a tunnel). Tests on an ephemeral port fall back to the package's per-request Host resolution.
  • Integration test covering the full flow: public initialize/tools/list, 401 on the protected tool, mount-prefixed discovery metadata, TTL-path PRM, and the PKCE → token → authed get_secret round trip.

How we know it works

  • npm run build, npm run lint, npm test all green (7 suites / 85 tests, lazy-auth integration included), verified in a linux container matching CI.
  • Driven additionally with the real @modelcontextprotocol/sdk@1.29.0 client discovery machinery (extractResourceMetadataUrl → PRM → buildDiscoveryUrlsauth() with PKCE) — full discovery + auth + silent refresh pass, on both /lazy-auth/mcp and /lazy-auth/ttl/3600/mcp.
  • Prod-like boot (BASE_URI=https://example-server.modelcontextprotocol.io/, no PUBLIC_URL) advertises correct mount-prefixed OAuth URLs, trailing slash normalized.

⚠️ Draft: blocked on a release

The base-path mount support is not yet in a published release of server-lazy-auth. This branch temporarily pins the dependency to the merged-PR preview build (pkg.pr.new, from modelcontextprotocol/ext-apps#683) so CI runs against the real code. Before merge, the finishing commit flips both server-lazy-auth and ext-apps to the registry ^<release> and regenerates the lockfile against npmjs.

Depends on: ext-apps#683 (merged) → next ext-apps release.

ochafik added 2 commits June 2, 2026 13:17
server-transcript stays at 1.7.2 — no 1.7.3 was published for it.
Mounts @modelcontextprotocol/server-lazy-auth as an additional example,
served at /lazy-auth/mcp alongside the other example MCP App servers.

Unlike the other examples (plain createServer() factories behind the
stateless handler), lazy-auth's value is its HTTP layer: public tools
work unauthenticated, protected tools answer 401 + WWW-Authenticate, and
a built-in mock OAuth authorization server completes the flow. So it
mounts its full Express app (createApp()) under /lazy-auth.

- New src/modules/example-apps/lazy-auth.ts mounts the app before the
  host middleware and adds the RFC 8414/9728 path-insertion well-known
  rewrite (/.well-known/oauth-authorization-server/lazy-auth -> into the
  mount) that SDK clients require for discovery under a base path.
- PUBLIC_URL for the example is derived from this server's own BASE_URI,
  so no extra deploy-time configuration is needed; an explicit PUBLIC_URL
  still wins (e.g. a tunnel).
- Integration test covers the full flow: public initialize/tools/list,
  401 on the protected tool, mount-prefixed discovery metadata, and the
  PKCE -> token -> authed get_secret round trip.

The dependency is temporarily pinned to the merged-PR preview build
(pkg.pr.new) because the base-path mount support is not yet in a
published release; it will be flipped to the registry version once that
release ships.
@ochafik
Copy link
Copy Markdown
Contributor Author

ochafik commented Jun 5, 2026

Superseded by #46 — reopened from an upstream branch now that repo write access is restored (modelcontextprotocol/access#116). Closing this fork-based PR.

@ochafik ochafik closed this Jun 5, 2026
@ochafik ochafik deleted the deps/ext-apps-1.7.3-lazy-auth branch June 5, 2026 18:45
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.

1 participant