diff --git a/README.md b/README.md index cce94c1..513ed1d 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ A comprehensive example implementation of a scalable Model Context Protocol (MCP The Everything Server is an open-source reference implementation that showcases: - **Complete [MCP Protocol](https://modelcontextprotocol.io/specification) Support**: All MCP features including tools, resources, prompts, sampling, completions, and logging - **Multiple [Transport Methods](https://modelcontextprotocol.io/docs/concepts/transports)**: Streamable HTTP (SHTTP) and Server-Sent Events (SSE) -- **Comprehensive Auth**: OAuth 2.0 with fake upstream provider for testing +- **Dual Authentication Modes**: Integrated and separate authorization server support - **Horizontal Scalability**: Redis-backed session management for multi-instance deployments This server serves as both primarily as a learning resource, and an example implementation of a scalable remote MCP server. @@ -40,162 +40,6 @@ This server serves as both primarily as a learning resource, and an example impl - **Security Headers**: CSP, HSTS, X-Frame-Options, and more - **Bearer Token Auth**: Middleware for protected endpoints -## Authentication Modes - -The Everything Server supports two authentication modes to demonstrate different MCP deployment patterns: - -### Integrated Mode (Default) -The MCP server acts as its own OAuth 2.0 authorization server. This is simpler to deploy and suitable for standalone MCP servers. - -```bash -npm run dev:integrated -``` - -### Separate Mode -The MCP server delegates authentication to a standalone authorization server. This demonstrates how MCP servers can integrate with existing OAuth infrastructure. See [auth-server/README.md](auth-server/README.md) for more details about the standalone auth server. - -```bash -# Start both the auth server and MCP server -npm run dev:with-separate-auth - -# Or run them separately: -# Terminal 1: Start the authorization server -npm run dev:auth-server - -# Terminal 2: Start the MCP server in separate mode -npm run dev:separate -``` - -In production, the separate authorization server would typically be replaced with: -- Corporate SSO (Auth0, Okta) -- Cloud providers (AWS Cognito, Azure AD) -- Social providers (Google, GitHub) - -### Testing with MCP Inspector - -The MCP Inspector is a web-based tool for testing MCP servers. You can run it locally: -```bash -npx -y @modelcontextprotocol/inspector -``` - -#### Integrated Mode -```bash -# 1. Start Redis -docker compose up -d - -# 2. Start the server -npm run dev:integrated - -# 3. Open MCP Inspector -npx -y @modelcontextprotocol/inspector - -# 4. Connect and test: -# - Connect to http://localhost:3232/mcp -# - Navigate to the Auth tab -# - Complete the OAuth flow -# - All auth endpoints will be served from :3232 -``` - -#### Separate Mode -```bash -# 1. Start Redis -docker compose up -d - -# 2. Start both servers -npm run dev:with-separate-auth - -# 3. Open MCP Inspector -npx -y @modelcontextprotocol/inspector - -# 4. Connect and test: -# - Connect to http://localhost:3232/mcp -# - Navigate to the Auth tab -# - The auth flow will redirect to :3001 for authentication -# - After auth, tokens from :3001 will be used on :3232 -``` - -### Architecture Diagrams - -#### Integrated Mode -```mermaid -graph TD - Client["MCP Client
(Inspector)"] - MCP["MCP Server
(port 3232)
• OAuth Server
• Resource Server"] - - Client <-->|"OAuth flow & MCP resources"| MCP -``` - -#### Separate Mode -```mermaid -graph TD - Client["MCP Client
(Inspector)"] - MCP["MCP Server
(port 3232)
Resource Server"] - Auth["Auth Server
(port 3001)
OAuth Server"] - - Client <-->|"1. Discover metadata"| MCP - Client <-->|"2. OAuth flow
(register, authorize, token)"| Auth - Client <-->|"3. Use tokens for MCP resources"| MCP - MCP <-->|"Token validation
(introspect)"| Auth -``` - -## OAuth Flow Analysis - -### OAuth 2.0 + PKCE Flow Sequence - -The server implements a complete OAuth 2.0 authorization code flow with PKCE. Here's how each step maps to data storage and expiry: - -**1. Client Registration** (app setup - happens once) -``` -App → Auth Server: "I want to use OAuth, here's my info" -Auth Server → App: "OK, your client_id is XYZ, client_secret is ABC" -``` -- **Storage**: Client credentials for future OAuth flows -- **Expiry**: 30 days (long-lived app credentials) - -**2. Authorization Request** (starts each OAuth flow) -``` -User → App: "I want to connect to MCP server" -App → Auth Server: "User wants access, here's my PKCE challenge" -Auth Server: Stores pending authorization, shows auth page -``` -- **Storage**: `PENDING_AUTHORIZATION` - temporary state during flow -- **Expiry**: 10 minutes (short-lived temporary state) - -**3. Authorization Code Exchange** (completes OAuth flow) -``` -User → Auth Server: "I approve this app" -Auth Server → App: "Here's your authorization code" -App → Auth Server: "Exchange code + PKCE verifier for tokens" -Auth Server → App: "Here are your access/refresh tokens" -``` -- **Storage**: `TOKEN_EXCHANGE` - prevents replay attacks -- **Expiry**: 10 minutes (single-use, consumed immediately) - -**4. Token Storage** (long-term user session) -``` -Auth Server: Issues access_token + refresh_token -Server: Stores user installation with tokens -``` -- **Storage**: `UPSTREAM_INSTALLATION` - the actual user session -- **Expiry**: 7 days (balances security vs usability) - -**5. Token Refresh** (extends user session) -``` -App → Auth Server: "My access token expired, here's my refresh token" -Auth Server → App: "Here's a new access token" -``` -- **Storage**: `REFRESH_TOKEN` - mapping for token rotation -- **Expiry**: 7 days (matches installation lifetime) - -### Data Lifecycle Hierarchy - -**Timeline (shortest to longest expiry):** -1. **OAuth flow state** (10 minutes) - very temporary -2. **User sessions** (7 days) - medium-term -3. **Client credentials** (30 days) - long-term - -This creates a logical hierarchy where each layer outlives the layers it supports. - ## Installation ### Prerequisites @@ -239,13 +83,10 @@ cd example-remote-server # Install dependencies npm install - -# Configure environment (optional) -cp .env.example .env -# Edit .env with your settings ``` -### Configuration +## Configuration + Environment variables (`.env` file): ```bash # Server Configuration @@ -275,6 +116,37 @@ cp .env.integrated .env cp .env.separate .env ``` +## Authentication Modes + +The Everything Server supports two authentication modes to demonstrate different MCP deployment patterns: + +### Integrated Mode (Default) +The MCP server acts as its own OAuth 2.0 authorization server. This is simpler to deploy and suitable for standalone MCP servers. + +```bash +npm run dev:integrated +``` + +### Separate Mode +The MCP server delegates authentication to a standalone authorization server. This demonstrates how MCP servers can integrate with existing OAuth infrastructure. See [auth-server/README.md](auth-server/README.md) for more details about the standalone auth server. + +```bash +# Start both the auth server and MCP server +npm run dev:with-separate-auth + +# Or run them separately: +# Terminal 1: Start the authorization server +npm run dev:auth-server + +# Terminal 2: Start the MCP server in separate mode +npm run dev:separate +``` + +In production, the separate authorization server would typically be replaced with: +- Corporate SSO (Auth0, Okta) +- Cloud providers (AWS Cognito, Azure AD) +- Social providers (Google, GitHub) + ## Development ### Commands @@ -327,108 +199,39 @@ npm run lint npm test ``` -### Project Structure -``` -├── src/ -│ ├── index.ts # Express app setup and routes -│ ├── config.ts # Configuration management -│ ├── redis.ts # Redis client setup -│ ├── auth/ -│ │ └── provider.ts # OAuth auth provider implementation -│ ├── handlers/ -│ │ ├── shttp.ts # Streamable HTTP handler -│ │ ├── sse.ts # SSE transport handler -│ │ ├── fakeauth.ts # Fake upstream auth handler -│ │ └── common.ts # Shared middleware -│ ├── services/ -│ │ ├── mcp.ts # MCP server implementation -│ │ ├── auth.ts # Session ownership management -│ │ └── redisTransport.ts # Redis-backed transport -│ └── utils/ -│ └── logger.ts # Structured logging -├── docs/ -│ ├── streamable-http-design.md # SHTTP implementation details -│ └── user-id-system.md # Authentication flow documentation -├── scratch/ # Development scripts and tests -└── dist/ # Compiled JavaScript output +### Testing with MCP Inspector + +The MCP Inspector is a web-based tool for testing MCP servers: +```bash +npx -y @modelcontextprotocol/inspector ``` -## API Endpoints +#### Test Integrated Mode +```bash +# 1. Start Redis +docker compose up -d -### MCP Endpoints -- `GET/POST/DELETE /mcp` - Streamable HTTP transport endpoint - - `POST`: Initialize sessions or send messages - - `GET`: Establish SSE streams - - `DELETE`: Terminate sessions -- `GET /sse` - Legacy SSE transport endpoint -- `POST /message` - Legacy message endpoint for SSE transport +# 2. Start the server +npm run dev:integrated -### Authentication Endpoints -- `GET /fakeupstreamauth/authorize` - Fake OAuth authorization page -- `GET /fakeupstreamauth/redirect` - OAuth redirect handler -- OAuth 2.0 endpoints provided by MCP SDK auth router - -### Headers -- `Mcp-Session-Id`: Session identifier for Streamable HTTP -- `Authorization: Bearer `: OAuth access token -- Standard MCP headers as per protocol specification - -## Authentication Flow - -The server implements a complete [OAuth 2.0](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization) flow with a fake upstream provider for testing: - -1. **Client Registration**: Clients register to obtain client_id and client_secret -2. **Authorization**: Users authenticate through `/fakeupstreamauth/authorize` -3. **User Management**: localStorage-based user ID system for testing -4. **Token Exchange**: Authorization codes exchanged for access tokens -5. **Session Creation**: Authenticated tokens create owned sessions -6. **Access Control**: Sessions are isolated by user ownership - -See [docs/user-id-system.md](docs/user-id-system.md) for detailed authentication documentation. - -## Transport Methods - -### Streamable HTTP (Recommended) -Modern [transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http) supporting bidirectional communication over HTTP: -- Single endpoint for all operations -- Session management via headers -- Efficient message buffering -- Automatic reconnection support - -See [docs/streamable-http-design.md](docs/streamable-http-design.md) for implementation details. - -### Server-Sent Events (Legacy) -Backwards-compatible [transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#server-sent-events) using SSE: -- Separate endpoints for SSE streams and messages -- Session management via URL parameters -- Redis-backed message routing -- Real-time event delivery - -## Scalability Architecture - -The server is designed for horizontal scaling using Redis as the backbone: - -### Session State Management -- **Redis Storage**: All session state stored in Redis -- **5-minute TTL**: Automatic session cleanup -- **Session Ownership**: User isolation via Redis keys -- **Stateless Servers**: Any instance can handle any request - -### Message Routing -- **Pub/Sub Channels**: Redis channels for message distribution -- **Message Buffering**: Reliable delivery for disconnected clients -- **Connection State**: Tracked via pub/sub subscription counts -- **Automatic Cleanup**: No explicit cleanup required - -### Redis Key Structure -``` -session:{sessionId}:owner # Session ownership -mcp:shttp:toserver:{sessionId} # Client→Server messages -mcp:shttp:toclient:{sessionId}:{requestId} # Server→Client responses -mcp:control:{sessionId} # Control messages +# 3. Open MCP Inspector and connect to http://localhost:3232/mcp +# 4. Navigate to the Auth tab and complete the OAuth flow +# 5. All auth endpoints will be served from :3232 ``` -## Testing +#### Test Separate Mode +```bash +# 1. Start Redis +docker compose up -d + +# 2. Start both servers +npm run dev:with-separate-auth + +# 3. Open MCP Inspector and connect to http://localhost:3232/mcp +# 4. Navigate to the Auth tab +# 5. The auth flow will redirect to :3001 for authentication +# 6. After auth, tokens from :3001 will be used on :3232 +``` ### Running Tests ```bash @@ -449,12 +252,186 @@ npm test -- --coverage - **Auth Tests**: OAuth flow and session ownership - **Multi-user Tests**: User isolation and access control -### Manual Testing -The `scratch/` directory contains utility scripts for testing: -- `oauth.sh` - Test OAuth flows -- `simple-test-client.js` - Basic client implementation -- `test-shttp-client.ts` - Streamable HTTP testing -- `debug-mcp-flow.sh` - Debug MCP message flows +### Additional Testing +Use the MCP Inspector for interactive testing and debugging of OAuth flows, tool execution, and resource access. + +## Architecture & Technical Details + +### Authentication Architecture + +#### Integrated Mode +```mermaid +graph TD + Client["MCP Client
(Inspector)"] + MCP["MCP Server
(port 3232)
• OAuth Server
• Resource Server"] + + Client <-->|"OAuth flow & MCP resources"| MCP +``` + +#### Separate Mode +```mermaid +graph TD + Client["MCP Client
(Inspector)"] + MCP["MCP Server
(port 3232)
Resource Server"] + Auth["Auth Server
(port 3001)
OAuth Server"] + + Client <-->|"1. Discover metadata"| MCP + Client <-->|"2. OAuth flow
(register, authorize, token)"| Auth + Client <-->|"3. Use tokens for MCP resources"| MCP + MCP <-->|"Token validation
(introspect)"| Auth +``` + +### OAuth 2.0 + PKCE Flow Analysis + +The server implements a complete OAuth 2.0 authorization code flow with PKCE. Here's how each step maps to data storage and expiry: + +**1. Client Registration** (app setup - happens once) +``` +App → Auth Server: "I want to use OAuth, here's my info" +Auth Server → App: "OK, your client_id is XYZ, client_secret is ABC" +``` +- **Storage**: Client credentials for future OAuth flows +- **Expiry**: 30 days (long-lived app credentials) + +**2. Authorization Request** (starts each OAuth flow) +``` +User → App: "I want to connect to MCP server" +App → Auth Server: "User wants access, here's my PKCE challenge" +Auth Server: Stores pending authorization, shows auth page +``` +- **Storage**: `PENDING_AUTHORIZATION` - temporary state during flow +- **Expiry**: 10 minutes (short-lived temporary state) + +**3. Authorization Code Exchange** (completes OAuth flow) +``` +User → Auth Server: "I approve this app" +Auth Server → App: "Here's your authorization code" +App → Auth Server: "Exchange code + PKCE verifier for tokens" +Auth Server → App: "Here are your access/refresh tokens" +``` +- **Storage**: `TOKEN_EXCHANGE` - prevents replay attacks +- **Expiry**: 10 minutes (single-use, consumed immediately) + +**4. Token Storage** (long-term user session) +``` +Auth Server: Issues access_token + refresh_token +Server: Stores user installation with tokens +``` +- **Storage**: `UPSTREAM_INSTALLATION` - the actual user session +- **Expiry**: 7 days (balances security vs usability) + +**5. Token Refresh** (extends user session) +``` +App → Auth Server: "My access token expired, here's my refresh token" +Auth Server → App: "Here's a new access token" +``` +- **Storage**: `REFRESH_TOKEN` - mapping for token rotation +- **Expiry**: 7 days (matches installation lifetime) + +#### Data Lifecycle Hierarchy + +**Timeline (shortest to longest expiry):** +1. **OAuth flow state** (10 minutes) - very temporary +2. **User sessions** (7 days) - medium-term +3. **Client credentials** (30 days) - long-term + +This creates a logical hierarchy where each layer outlives the layers it supports. + +### Project Structure +``` +├── src/ # MCP server code +│ ├── index.ts # Express app setup and routes +│ ├── config.ts # Configuration management +│ ├── redis.ts # Redis client setup +│ ├── auth/ +│ │ ├── provider.ts # OAuth auth provider implementation +│ │ └── external-verifier.ts # External token verification +│ ├── handlers/ +│ │ ├── shttp.ts # Streamable HTTP handler +│ │ ├── sse.ts # SSE transport handler +│ │ ├── fakeauth.ts # Fake upstream auth handler +│ │ └── common.ts # Shared middleware +│ ├── services/ +│ │ ├── mcp.ts # MCP server implementation +│ │ ├── auth.ts # Auth service wrappers +│ │ └── redisTransport.ts # Redis-backed transport +│ └── utils/ +│ └── logger.ts # Structured logging +├── auth-server/ # Standalone authorization server +│ ├── index.ts # Auth server main entry point +│ ├── README.md # Auth server documentation +│ └── tsconfig.json # TypeScript configuration +├── shared/ # Shared between both servers +│ ├── auth-core.ts # Core auth logic +│ ├── redis-auth.ts # Redis auth operations +│ └── types.ts # Shared type definitions +├── docs/ +│ ├── streamable-http-design.md # SHTTP implementation details +│ └── user-id-system.md # Authentication flow documentation +└── dist/ # Compiled JavaScript output +``` + +### Scalability Architecture + +The server is designed for horizontal scaling using Redis as the backbone: + +#### Session State Management +- **Redis Storage**: All session state stored in Redis +- **5-minute TTL**: Automatic session cleanup +- **Session Ownership**: User isolation via Redis keys +- **Stateless Servers**: Any instance can handle any request + +#### Message Routing +- **Pub/Sub Channels**: Redis channels for message distribution +- **Message Buffering**: Reliable delivery for disconnected clients +- **Connection State**: Tracked via pub/sub subscription counts +- **Automatic Cleanup**: No explicit cleanup required + +#### Redis Key Structure +``` +session:{sessionId}:owner # Session ownership +mcp:shttp:toserver:{sessionId} # Client→Server messages +mcp:shttp:toclient:{sessionId}:{requestId} # Server→Client responses +mcp:control:{sessionId} # Control messages +``` + +### Transport Methods + +#### Streamable HTTP (Recommended) +Modern [transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http) supporting bidirectional communication over HTTP: +- Single endpoint for all operations +- Session management via headers +- Efficient message buffering +- Automatic reconnection support + +See [docs/streamable-http-design.md](docs/streamable-http-design.md) for implementation details. + +#### Server-Sent Events (Legacy) +Backwards-compatible [transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#server-sent-events) using SSE: +- Separate endpoints for SSE streams and messages +- Session management via URL parameters +- Redis-backed message routing +- Real-time event delivery + +## API Reference + +### MCP Endpoints +- `GET/POST/DELETE /mcp` - Streamable HTTP transport endpoint + - `POST`: Initialize sessions or send messages + - `GET`: Establish SSE streams + - `DELETE`: Terminate sessions +- `GET /sse` - Legacy SSE transport endpoint +- `POST /message` - Legacy message endpoint for SSE transport + +### Authentication Endpoints (Integrated Mode Only) +- `GET /fakeupstreamauth/authorize` - Fake OAuth authorization page +- `GET /fakeupstreamauth/callback` - OAuth redirect handler +- OAuth 2.0 endpoints provided by MCP SDK auth router + +### Headers +- `Mcp-Session-Id`: Session identifier for Streamable HTTP +- `Authorization: Bearer `: OAuth access token +- Standard MCP headers as per protocol specification ## Security @@ -505,10 +482,11 @@ redis-cli GET "session:{sessionId}:owner" ``` ### Debug Tools -- Development scripts in `scratch/` directory +- MCP Inspector for interactive debugging - Comprehensive test suite - Hot-reload development mode - Source maps for debugging +- Redis monitoring commands ## Contributing diff --git a/auth-server/README.md b/auth-server/README.md index abf8855..0323731 100644 --- a/auth-server/README.md +++ b/auth-server/README.md @@ -1,35 +1,32 @@ # MCP Standalone Authorization Server -This is a demonstration OAuth 2.0 authorization server for MCP. +This is a demonstration OAuth 2.0 authorization server for MCP's separate authentication mode. ## Purpose -This server demonstrates how MCP servers can delegate authentication to a separate -authorization server (Mode 2 in our implementation). In production environments, -you would typically use established OAuth providers like: +This server demonstrates how MCP servers can delegate authentication to a separate authorization server. See the main [README Authentication Modes](../README.md#authentication-modes) section for a complete overview of integrated vs separate modes. -- Auth0 -- Okta -- Google OAuth -- GitHub OAuth -- Microsoft Azure AD +In production environments, you would typically use established OAuth providers like: +- Auth0, Okta +- Google OAuth, GitHub OAuth +- Microsoft Azure AD, AWS Cognito ## Architecture -When running in separate mode, the architecture looks like: +For detailed architecture information and OAuth flow analysis, see: +- [Authentication Modes](../README.md#authentication-modes) - Overview and comparison +- [OAuth 2.0 + PKCE Flow Analysis](../README.md#oauth-20--pkce-flow-analysis) - Step-by-step flow breakdown +- [Authentication Architecture](../README.md#authentication-architecture) - Visual diagrams -1. MCP Client (e.g., Inspector) discovers auth server URL from MCP server metadata -2. Client registers and authenticates directly with this auth server -3. Auth server issues tokens -4. MCP server validates tokens by calling this auth server's introspection endpoint +This auth server specifically implements the "Auth Server" component in the separate mode architecture diagram. ## Endpoints - `/.well-known/oauth-authorization-server` - OAuth 2.0 server metadata -- `/oauth/authorize` - Authorization endpoint -- `/oauth/token` - Token endpoint -- `/oauth/register` - Dynamic client registration -- `/oauth/introspect` - Token introspection (for MCP server validation) +- `/authorize` - Authorization endpoint +- `/token` - Token endpoint +- `/register` - Dynamic client registration +- `/introspect` - Token introspection (for MCP server validation) - `/fakeupstreamauth/authorize` - Fake upstream auth page (demo only) - `/fakeupstreamauth/callback` - Fake upstream callback (demo only) - `/health` - Health check endpoint @@ -66,24 +63,32 @@ curl http://localhost:3001/.well-known/oauth-authorization-server ``` ### With MCP Inspector +See the main [Testing with MCP Inspector](../README.md#testing-with-mcp-inspector) section for complete testing instructions for both modes. + +**Quick test for this auth server:** 1. Start this auth server: `npm run dev:auth-server` -2. Start MCP server in separate mode: `AUTH_MODE=separate npm run dev` -3. Open Inspector: `npx -y @modelcontextprotocol/inspector` -4. Connect to `http://localhost:3232/mcp` -5. Auth flow will redirect to this server (port 3001) +2. Start MCP server in separate mode: `AUTH_MODE=separate npm run dev` +3. Follow the separate mode testing steps in the main README ## Configuration -The auth server uses the same environment variables as the main server: +The auth server uses the same configuration system as the main server. See [Configuration](../README.md#configuration) in the main README for complete environment variable documentation. + +**Auth server specific variables:** - `AUTH_SERVER_PORT` - Port to run on (default: 3001) - `AUTH_SERVER_URL` - Base URL (default: http://localhost:3001) - `REDIS_URL` - Redis connection (shared with MCP server) ## Production Considerations -In production: -- Use real OAuth providers instead of this demonstration server -- Separate Redis instances for auth and resource servers -- Enable HTTPS with proper certificates -- Implement proper rate limiting and monitoring -- Use secure client secrets and token rotation \ No newline at end of file +**This server is for demonstration only.** In production, use established OAuth providers. + +For comprehensive security and deployment guidance, see: +- [Security](../README.md#security) - Security measures and best practices +- [Configuration](../README.md#configuration) - Environment setup +- [Monitoring & Debugging](../README.md#monitoring--debugging) - Operational guidance + +**Production replacement options:** +- Corporate SSO (Auth0, Okta) +- Cloud providers (AWS Cognito, Azure AD) +- Social providers (Google OAuth, GitHub OAuth) \ No newline at end of file diff --git a/auth-server/index.ts b/auth-server/index.ts index 7fb446c..b801958 100644 --- a/auth-server/index.ts +++ b/auth-server/index.ts @@ -36,10 +36,10 @@ app.get('/health', (req, res) => { mode: 'authorization-server', endpoints: { metadata: `${AUTH_SERVER_URL}/.well-known/oauth-authorization-server`, - authorize: `${AUTH_SERVER_URL}/oauth/authorize`, - token: `${AUTH_SERVER_URL}/oauth/token`, - register: `${AUTH_SERVER_URL}/oauth/register`, - introspect: `${AUTH_SERVER_URL}/oauth/introspect` + authorize: `${AUTH_SERVER_URL}/authorize`, + token: `${AUTH_SERVER_URL}/token`, + register: `${AUTH_SERVER_URL}/register`, + introspect: `${AUTH_SERVER_URL}/introspect` } }); }); @@ -60,7 +60,7 @@ app.use(mcpAuthRouter({ })); // Token introspection endpoint (RFC 7662) -app.post('/oauth/introspect', express.urlencoded({ extended: false }), async (req, res) => { +app.post('/introspect', express.urlencoded({ extended: false }), async (req, res) => { try { const { token } = req.body; @@ -127,10 +127,10 @@ app.listen(AUTH_SERVER_PORT, () => { url: AUTH_SERVER_URL, endpoints: { metadata: `${AUTH_SERVER_URL}/.well-known/oauth-authorization-server`, - authorize: `${AUTH_SERVER_URL}/oauth/authorize`, - token: `${AUTH_SERVER_URL}/oauth/token`, - register: `${AUTH_SERVER_URL}/oauth/register`, - introspect: `${AUTH_SERVER_URL}/oauth/introspect` + authorize: `${AUTH_SERVER_URL}/authorize`, + token: `${AUTH_SERVER_URL}/token`, + register: `${AUTH_SERVER_URL}/register`, + introspect: `${AUTH_SERVER_URL}/introspect` } }); diff --git a/src/auth/external-verifier.ts b/src/auth/external-verifier.ts index 6842ec1..924d41f 100644 --- a/src/auth/external-verifier.ts +++ b/src/auth/external-verifier.ts @@ -56,7 +56,7 @@ export class ExternalAuthVerifier implements OAuthTokenVerifier { try { // Token introspection is OAuth 2.0 standard (RFC 7662) for validating tokens // The auth server checks if the token is valid and returns metadata about it - const response = await fetch(`${this.authServerUrl}/oauth/introspect`, { + const response = await fetch(`${this.authServerUrl}/introspect`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `token=${encodeURIComponent(token)}`,