Commit graph example-remote-server/src
Author SHA1 Message Date
Olivier Chafik
2476540fab
Add lazy-auth example server mounted at /lazy-auth
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.
2026-06-05 20:15:08 +01:00
Olivier Chafik
e83d4207a6
chore: bump ext-apps + example servers to 1.7.1, sdk to 1.29.0
ext-apps@1.7.x peers on @modelcontextprotocol/sdk ^1.29.0, which
required bumping the pinned sdk from 1.24.2 and adapting to its
StreamableHTTPServerTransport refactor:

- redisTransport: sessionId is now a readonly getter on the Node
  wrapper; inject it (and _initialized) on the underlying web-standard
  transport so resumed sessions validate. Also guard message.id which
  is now optional on JSONRPCMessage.
- shttp.integration.test: handleRequest now routes through
  @hono/node-server, so the mock IncomingMessage needs url/host/
  rawHeaders/on/off/resume, and the session-id header now arrives via
  writeHead instead of setHeader.
2026-04-27 16:35:26 +01:00
Olivier Chafik
811a78f310
fix: close per-request server and transport in example-apps handler
The stateless /:slug/mcp handler creates a fresh McpServer and
StreamableHTTPServerTransport on every request but never closed them,
leaking memory under load. Register a 'close' listener (fires on both
normal completion and client abort mid-SSE) to release them.
2026-04-23 14:15:47 +01:00
guro
67ffeb0b93
Increase rate limits across server endpoints
Raise request limits to better accommodate legitimate traffic patterns:
- Splash page: 50 -> 200 req/min
- Auth endpoints: 20 -> 200 req/min
- Static assets (auth & mcp): 100 -> 500 req/min
- OAuth metadata: 100 -> 300 req/5s
- Client registration: 10 -> 60 req/min
2026-03-17 14:52:21 +00:00
guro
43f1f61019
fix: enable trust proxy for correct rate limiting behind reverse proxy
Without this, rate limiting uses the proxy's IP instead of actual client IPs,
causing all requests through Cloudflare to be rate limited together.
2026-03-17 14:46:52 +00:00
Claude
4597f7453b
bump ext-apps and server packages to 1.1.1, add debug-server
- Bump @modelcontextprotocol/ext-apps from ^1.1.0 to ^1.1.1
- Bump all @modelcontextprotocol/server-* packages from ^1.1.0 to ^1.1.1
- Add new @modelcontextprotocol/server-debug package at ^1.1.1
- Wire up debug server in example-apps module at /debug/mcp
2026-02-24 14:15:15 +00:00
Claude
12cacce7e9
Make example app MCP endpoints unauthenticated
Remove bearer auth middleware from all /:slug/mcp routes (pdf, map, etc.)
so they are publicly accessible without an OAuth token. The root /mcp
endpoint retains its existing bearer auth requirement.

https://claude.ai/code/session_019bG1wzY84JA7LbpkybddP9
2026-02-12 11:24:28 +00:00
Jerome Swannack
22d60f9e5a logging full init body 2026-01-26 16:33:16 +00:00
Jerome Swannack
94ffb7922c Log client capabilities and extensions on initialize requests
Add INFO-level logging to both the stateful SHTTP handler and the
stateless example-apps handler to show the full client capabilities
sent during MCP initialization, including any extensions like
io.modelcontextprotocol/ui.

This helps verify that clients are correctly sending UI extension
capabilities during the initialization handshake.
2026-01-26 15:47:44 +00:00
Jerome Swannack
5772183ae8 Fix double slash in example server URLs
Remove trailing slash from baseUri before constructing example server
URLs to avoid URLs like "example.com//budget-allocator/mcp".

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 17:03:00 +00:00
Jerome Swannack
c8e22b8b00 feat: add copy buttons to example server URLs on splash page
Each MCP App example server now has a copy button that copies the
full URL (including domain) to clipboard for easy pasting into Claude.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 16:43:27 +00:00
Jerome Swannack
015a9d9d91 refactor: make example servers stateless
Address PR feedback:
- Remove session store and session management
- Use stateless mode (sessionIdGenerator: undefined)
- Each request creates a fresh server instance
- Remove user-controlled format string in error message
- Simplify handler logic significantly

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 16:24:20 +00:00
Jerome Swannack
56a0835fd4 feat: add MCP Apps example servers module
Wire up 13 MCP Apps servers from the @modelcontextprotocol/server-* packages:
- budget-allocator: Interactive budget allocation UI
- cohort-heatmap: Customer retention heatmap
- customer-segmentation: Scatter chart with clustering
- map: Interactive 3D globe viewer (CesiumJS)
- pdf: Interactive PDF viewer
- scenario-modeler: SaaS business projections dashboard
- shadertoy: Real-time GLSL shader renderer
- sheet-music: ABC notation to sheet music visualizer
- system-monitor: Real-time OS metrics display
- threejs: 3D scene renderer
- transcript: Live speech transcription
- video-resource: Binary video streaming via MCP resources
- wiki-explorer: Wikipedia link graph visualization

Each server is mounted at /{slug}/mcp and shares the same OAuth
authentication as the main MCP server.

Also updates the splash page to dynamically list all available
example servers.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 16:24:20 +00:00
Anton Pidkuiko MacBook
2903c3a023
fix: update MCP Apps to use new _meta.ui.resourceUri format
- Update @modelcontextprotocol/ext-apps to 0.4.0
- Use new nested format `_meta.ui.resourceUri` in tool definition
- Remove resourceUri from tool result (only needed in tool definition)
- Add example structuredContent and _meta in tool result for demo
2026-01-14 20:10:41 +00:00
Jerome Swannack
50f135dace
Add UI resource to ListResources response
Include the MCP Apps UI resource in the resources list so clients
can discover it via resources/list.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 18:21:10 +00:00
Jerome Swannack
730d8559e0
Update MCP Apps tool result message for clarity 2025-12-07 18:10:56 +00:00
Jerome Swannack
c872ecd224
Add MCP Apps hello world demo tool
Implements a simple MCP Apps tool that returns an interactive React UI:

- Add `mcp_apps_hello_world` tool with `_meta.ui/resourceUri` metadata
- Add resource handler for `ui://hello-world/app.html` returning HTML
- Create React app using `@modelcontextprotocol/ext-apps/react` hooks
- Add Vite build tooling to bundle React apps into single HTML files

The tool demonstrates the MCP Apps extension (SEP-1865) which allows
MCP servers to return interactive UI that runs in the client.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 18:06:38 +00:00
Jerome Swannack
07300e8453
Add dev scripts for mitmproxy debugging and fix JSON-RPC error responses
- Add dev-with-mitm.sh for TUI-based traffic inspection
- Add dev-with-mitmweb.sh for web UI-based traffic inspection
- Fix missing 'id' field in JSON-RPC error responses (required by spec)
- Migrate from zod-to-json-schema to Zod v4's native z.toJSONSchema()

The mitmproxy scripts help developers debug MCP traffic by running
the server through a reverse proxy that intercepts all client requests.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 13:35:29 +00:00
Basil Hosmer
33e7827dbd
Update splash page to reflect elicitation tool
Updated demo tools count from 7 to 8 and added elicitations to the feature list

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-16 19:00:39 -04:00
Olivier Chafik
1547891443
fix elicitation 2025-10-15 20:35:55 +01:00
Olivier Chafik
79b2444701
fix elicitation 2025-10-15 20:33:49 +01:00
Olivier Chafik
b6e39748aa
Merge branch 'main' into ochafik/add-elicitation-tool 2025-10-15 20:25:42 +01:00
Basil Hosmer
38c30a4e70
Fix security vulnerabilities, package-lock.json, misc other changes
- Add rate limiting to prevent DoS attacks on vulnerable routes
- Update package-lock.json to use public npm registry
- Document intentionally permissive CORS for public test server
- Remove health endpoints to match original codebase (no health checks)
- Fix auth server splash page to list all OAuth endpoints
- Update test scripts to check server availability via splash page
2025-10-14 17:41:32 -04:00
Basil Hosmer
bc3619c73c
Unify auth and MCP servers into single modular codebase
- Merge auth-server and mcp-server into unified architecture under src/modules/
- Add configurable auth modes: internal (single process) and external (separate processes)
- Update example scripts to support OAuth discovery and both auth modes
- Consolidate OAuth documentation into comprehensive implementation guide
- Add configuration options for development vs production deployments
- Support both Redis-backed and in-memory session storage
2025-10-14 13:53:03 -04:00
Basil Hosmer
112997d352
refactor, improve docs 2025-10-05 23:51:06 -04:00
Basil Hosmer
a735b9810c
Add comprehensive token validation to ExternalAuthVerifier
Enhance token validation in separate mode to fully comply with MCP specification:
- Validate audience (aud) claim to ensure tokens are issued for this specific MCP server
- Validate temporal claims (nbf, iat) with appropriate clock skew tolerance
- Add configurable canonical URI for audience validation
- Improve logging for validation failures

These changes prevent token passthrough attacks and ensure tokens are
properly scoped to the intended resource server, as required by the
MCP OAuth 2.0 specification.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-23 16:33:02 -04:00
Basil Hosmer
dbd3e9a853
Revert OAuth metadata change for backwards compatibility
Keep serving .well-known/oauth-authorization-server from MCP server
in separate mode as some clients may expect to find it there
2025-09-23 16:19:47 -04:00
Basil Hosmer
e393cb2129
Add OAuth protected resource metadata endpoint for separate mode
Fixes MCP Inspector connection by providing OAuth discovery endpoint
that points to the external auth server at http://localhost:3001
2025-09-15 02:57:56 -04:00
Basil Hosmer
34fe20efc4
Implement Redis namespace isolation for auth and MCP keys 2025-09-15 02:33:59 -04:00
Basil Hosmer
4fe137426b
Add debug logging for OAuth flow troubleshooting
Add logging to track authorization flow steps and token introspection
to help diagnose issues with separate mode authentication.
2025-09-15 02:11:07 -04:00
Basil Hosmer
56a43ac67f
Fix OAuth metadata endpoint in separate mode
Remove incorrect mcpAuthMetadataRouter call when running in separate mode.
The resource server should not serve OAuth metadata endpoints - only the
auth server should provide these endpoints.
2025-09-15 02:10:36 -04:00
Basil Hosmer
890beed75a
Add rate limiting and improve e2e testing workflow
- Add express-rate-limit to custom endpoints for security:
  - /introspect: 100 requests per 5 minutes
  - /fakeupstreamauth/*: 20 requests per minute
  - Static files: 25 requests per 10 minutes
- Add automated e2e testing npm scripts using concurrently:
  - npm run test:e2e:integrated: Auto-starts server and runs test
  - npm run test:e2e:separate: Auto-starts both servers and runs test
- Update README with automated testing approach documentation
- Update docs/streamable-http-design.md with current file structure
- Remove redundancy in README e2e testing documentation
- Verified: All tests, linting, and e2e scripts pass with rate limiting
2025-09-12 00:27:07 -04:00
Basil Hosmer
40773bd051
Add end-to-end verification scripts and fix server issues
- Fix server hanging issue: incomplete HTTP responses in shttp.ts
- Add proper JSON-RPC error responses per MCP specification
- Fix PKCE challenge encoding: use base64url not standard base64
- Add comprehensive e2e scripts with OAuth flow and feature testing:
  - scripts/test-integrated-e2e.sh: Tests integrated mode
  - scripts/test-separate-e2e.sh: Tests separate mode
- Scripts verify all README claims: 7 tools, 100 resources (paginated), 3 prompts
- Add environment variable support and prerequisite checking
- Add TODO documentation for Streamable HTTP implementation choices
- Update README with table of contents and scripts documentation
- Update project structure to include scripts directory

Scripts successfully verify:
✅ Complete OAuth 2.0 + PKCE flows in both modes
✅ Token introspection and cross-server session management
✅ All MCP features working correctly
✅ README accuracy (tool/resource counts verified programmatically)
2025-09-11 23:52:39 -04:00
Basil Hosmer
9ffe376932
Fix endpoint consistency and documentation accuracy
- Remove /oauth prefix from introspect endpoint to match SDK pattern
- Fix auth-server endpoints: /introspect not /oauth/introspect
- Update external-verifier to call correct introspect endpoint
- Add 30-day expiry to client registration (REDIS_EXPIRY_TIMES.CLIENT_REGISTRATION)
- Remove inaccurate scratch/ directory references from README
- Add backlinks from auth-server/README.md to main README sections
- Verified all implementation details against running servers and Redis data
2025-09-11 21:08:29 -04:00
Basil Hosmer
4771c6eb34
Add retry logic and token caching
- Implemented retry logic (5 attempts, 3 second delay) for auth server connection
- Added token validation caching with 60-second default TTL
- Cache respects token expiration time if provided
- Cache invalidation on 401/403 responses
- Automatic cache cleanup every minute
- Debug logging for cache hits and misses
2025-09-04 19:29:54 -04:00
Basil Hosmer
03deb88ea0
Fix build and lint issues
- Corrected imports in external-verifier.ts (OAuthTokenVerifier from provider.js)
- Fixed InvalidTokenError import from errors.js
- Changed logger.warn to logger.info (warn method doesn't exist)
- Removed unused OAuthTokens import from services/auth.ts
2025-09-04 19:15:45 -04:00
Basil Hosmer
0135abd62a
Phase 3: Implement MCP server mode switching
- Created ExternalAuthVerifier for token validation with external auth server
- Added mode switching logic to src/index.ts
- Integrated mode uses mcpAuthRouter (current behavior)
- Separate mode uses mcpAuthMetadataRouter and external verifier
- Fake upstream auth routes only available in integrated mode
- Added auth server metadata fetching with error handling
2025-09-03 23:50:32 -04:00
Basil Hosmer
98cec052e4
Phase 2: Extract shared auth logic
- Created shared/types.ts with well-documented type definitions
- Created shared/auth-core.ts with core auth functions (PKCE, tokens, encryption)
- Created shared/redis-auth.ts with Redis operations for auth data
- Updated src/services/auth.ts to use shared modules
- Added TokenIntrospectionResponse interface for Mode 2
2025-09-03 23:48:27 -04:00
Basil Hosmer
1bcb85bb4f
Phase 1: Add configuration for integrated/separate auth modes
- Updated config.ts with AUTH_MODE, AUTH_SERVER_URL, AUTH_SERVER_PORT
- Added validation for port consistency between URL and PORT variables
- Added comprehensive JSDoc comments for all config variables
- Created .env.integrated and .env.separate config files
- Updated redis.ts to use REDIS_URL from config
- Added .claude/ to .gitignore
2025-09-03 22:54:27 -04:00
Jerome
72fcc292f4
Fix splash page styling issues
- Moved inline CSS to external stylesheet to comply with CSP
- Added black background to logo area for visibility of white MCP logo
- Updated specification link to point to dated version (2025-06-18)
- Changed "MCP Everything Server" to "MCP Example Server"
- Added route to serve styles.css file

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-27 23:46:11 +01:00
Jerome
3e81ec45a8
Add splash page for MCP Everything Server
Implemented a clean, informative splash page at the root endpoint that showcases:
- Server features and capabilities
- API endpoints documentation
- Links to GitHub repository and MCP documentation
- Black and white theme matching MCP branding
- Responsive design for mobile and desktop

The splash page provides users with an immediate overview of the server's functionality
and serves as a landing page for the MCP Everything Server.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-19 20:07:19 +01:00
Paul Carleton
1160524a70
types 2025-07-17 14:20:50 +01:00
Paul Carleton
077fed19b9
Add PRM metadata to www-authenticate 2025-07-17 13:54:28 +01:00
Jerome
927d34c0d1
Fix 'stream is not readable' error in SSE message handler
- Replace getRawBody with direct req.body usage since express.json() middleware already parses it
- Add debugging support with --inspect flag for dev scripts
- Add VS Code launch configurations for debugging

The issue was that getRawBody tried to read an already-consumed stream. Since express.json()
middleware is applied globally, we can directly use req.body instead.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-15 13:41:34 +01:00
Jerome
2f1aa9c93b
Merge pull request #2 from modelcontextprotocol/feature/streamable-http-transport
Implement streamable HTTP transport with Redis-based session management
2025-07-10 17:30:46 +01:00
Jerome
36f86c2657
Fix TypeScript errors with proper typing
- Add MCPInitResponse interface for test responses
- Replace 'any' types with proper interface
- Remove unused JSONRPCResponse import
- Maintain type safety while fixing build errors

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-10 17:29:42 +01:00
Jerome
c6f3f40937
Fix all ESLint errors
- Remove unused imports and variables
- Replace 'any' types with proper type guards
- Add comments to empty catch blocks
- Fix Response/Request type imports in logger
- Use 'unknown' instead of 'any' for generic types
- Remove unused createMcpServer and setSessionOwner imports

All ESLint checks now pass.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-10 16:52:32 +01:00
Jerome
46c71a9857
Tidying up static files 2025-07-10 11:17:11 +01:00
Jerome
d67ef14ad6
Add comprehensive structured logging to streamable HTTP
- Remove sensitive data (auth tokens, cookies) from request logging
- Add detailed logging throughout streamable HTTP request lifecycle:
  - Session creation/reuse
  - Session ownership validation
  - Transport initialization
  - Message flow through Redis channels
  - Session shutdown and cleanup
- Add logging for inactivity timeouts and control messages
- Use appropriate log levels (info for lifecycle, debug for details, error for failures)

All logs now include contextual information like sessionId, userId, and channel names
for easier debugging and monitoring.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-10 11:05:50 +01:00
Jerome
f4aed937f0
Replace console.log with structured logging for Cloud Run
- Add structured logger utility with Cloud Run trace context support
- Uses AsyncLocalStorage for request context propagation
- Replace all console.log/error/warn statements with structured logger
- Add logging middleware to capture request/response metadata
- Support Google Cloud Logging severity levels and trace correlation

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-10 10:55:57 +01:00