### Local Development: MCP Server Setup Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Instructions for setting up and running the MCP server locally, including copying the environment example file, filling in necessary variables, installing dependencies, and starting the development server. ```bash cd mcp-server npm install npm run dev # tsx --env-file=.env src/app (live reload) npm run typecheck # tsc ``` -------------------------------- ### Example Response for get-student-info Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Example JSON output for the 'get-student-info' tool, showing a student's profile with aptitude score and specialization. ```json { "studentId": "BS-2507", "name": "Bean", "age": 9, "aptitudeScore": 98, "battleExperience": "Advanced", "specialization": "Tactical Analysis" } ``` -------------------------------- ### Example Response for get-my-army Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Example JSON output for the 'get-my-army' tool, showing the structure of an authenticated user's army record. ```json { "armyName": "Dragon Army", "commanderId": "BS-2401", "commanderName": "Ender Wiggin", "soldiers": [ { "studentId": "BS-2507", "name": "Bean", "rank": "Toon Leader", "battlesWon": 8 }, { "studentId": "BS-2612", "name": "Crazy Tom", "rank": "Toon Leader", "battlesWon": 7 }, { "studentId": "BS-2345", "name": "Hot Soup", "rank": "Soldier", "battlesWon": 6 } ], "armyRecord": { "wins": 12, "losses": 0 } } ``` -------------------------------- ### Example Response for get-opponent-army Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Example JSON output for the 'get-opponent-army' tool, displaying an opponent army's details including known tactics. ```json { "armyName": "Salamander Army", "commanderId": "BS-2198", "commanderName": "Bonzo Madrid", "soldiers": [ { "studentId": "BS-2234", "name": "Bernard", "rank": "Toon Leader", "battlesWon": 10 } ], "armyRecord": { "wins": 15, "losses": 3 }, "knownTactics": ["Wall formations", "Aggressive rushes"] } ``` -------------------------------- ### Authorization Endpoint (GET) Source: https://github.com/loginov-rocks/remote-mcp-auth/blob/main/README.md Initiates the authorization code grant flow. ```APIDOC ## GET /oauth/authorize ### Description Initiates the authorization code grant flow. ### Method GET ### Endpoint /oauth/authorize ``` -------------------------------- ### GET /oauth/authorize - Render Authorization Form Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Renders an HTML form for user authorization. It forwards all PKCE and OAuth parameters as hidden fields for submission. ```sh curl -s "https://abc123.execute-api.us-east-1.amazonaws.com/oauth/authorize?\ client_id=98f974d2-5ab1-467d-b043-64edbb2a840b&\ code_challenge=qpxvR2wuni9VNrukgHOgVqGc1WljDfVbDFIYtwmKeos&\ code_challenge_method=S256&\ redirect_uri=https%3A%2F%2Fclaude.ai%2Fapi%2Fmcp%2Fauth_callback&\ response_type=code&\ scope=claudeai&\ state=MAtaiBZWWmmNvjGaDFEiLuAbSv_FUJ3k91XYnWcZpts" # Returns HTML page with an form # and hidden fields for all OAuth/PKCE parameters ``` -------------------------------- ### GET /oauth/authorize — Authorization Page Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Renders an HTML form for user authorization, forwarding OAuth and PKCE parameters. ```APIDOC ## GET /oauth/authorize — Authorization Page ### Description Renders an HTML form that asks the user to enter their Student ID. All PKCE and OAuth parameters from Claude are forwarded as hidden fields so they can be submitted back via `POST /oauth/authorize`. ### Method GET ### Endpoint `/oauth/authorize` ### Query Parameters - **client_id** (string) - Required - The client ID for the application. - **code_challenge** (string) - Required - The code challenge for PKCE. - **code_challenge_method** (string) - Required - The method used for the code challenge (e.g., S256). - **redirect_uri** (string) - Required - The URI to redirect to after authorization. - **response_type** (string) - Required - The response type, typically 'code'. - **scope** (string) - Required - The requested scope of access. - **state** (string) - Required - An opaque value used to maintain state between the request and callback. ### Response #### Success Response (200) - Returns an HTML page with an input form for 'student_id' and hidden fields for all OAuth/PKCE parameters. ``` -------------------------------- ### GET /oauth/authorize - JavaScript Handler Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Handles the GET request for the authorization page by injecting OAuth/PKCE parameters into hidden form fields. ```js // getAuthorizeHandler.mjs export const getAuthorizeHandler = (event) => { const params = event.queryStringParameters; return { statusCode: 200, headers: { 'Content-Type': 'text/html' }, body: `

Battle School Computer

`, }; }; ``` -------------------------------- ### GET /.well-known/oauth-authorization-server - Server Metadata Discovery Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Returns the OAuth 2.1 authorization server metadata document. Claude calls this endpoint first to discover all other OAuth endpoints. The issuer is dynamically derived from the API Gateway domain. ```APIDOC ## GET /.well-known/oauth-authorization-server ### Description Returns the OAuth 2.1 authorization server metadata document. Claude calls this endpoint first to discover all other OAuth endpoints. The issuer is dynamically derived from the API Gateway domain. ### Method GET ### Endpoint /.well-known/oauth-authorization-server ### Response #### Success Response (200) - **issuer** (string) - The base URL of the authorization server. - **authorization_endpoint** (string) - The URL for the authorization endpoint. - **token_endpoint** (string) - The URL for the token endpoint. - **registration_endpoint** (string) - The URL for the dynamic client registration endpoint. - **grant_types_supported** (array) - An array of supported grant types. - **code_challenge_methods_supported** (array) - An array of supported code challenge methods. ### Request Example ```sh curl -s https://abc123.execute-api.us-east-1.amazonaws.com/.well-known/oauth-authorization-server | jq . # { # "issuer": "https://abc123.execute-api.us-east-1.amazonaws.com", # "authorization_endpoint": "https://abc123.execute-api.us-east-1.amazonaws.com/oauth/authorize", # "token_endpoint": "https://abc123.execute-api.us-east-1.amazonaws.com/oauth/token", # "registration_endpoint": "https://abc123.execute-api.us-east-1.amazonaws.com/oauth/register", # "grant_types_supported": ["authorization_code", "client_credentials"], # "code_challenge_methods_supported": ["S256"] # } ``` ``` -------------------------------- ### Manage SSE Sessions Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Handles Server-Sent Events (SSE) sessions. GET /sse opens a persistent SSE connection, and POST /messages routes client messages to the correct session. ```typescript public async getSse(req: McpAuthenticatedRequest, res: Response): Promise { const transport = new SSEServerTransport('/messages', res); this.transportsMap.set(transport.sessionId, transport); res.on('close', () => this.transportsMap.delete(transport.sessionId)); await this.mcpServer.connect(transport); } public async postMessages(req: McpAuthenticatedRequest, res: Response): Promise { const { sessionId } = req.query; if (!sessionId || typeof sessionId !== 'string') { res.status(400).send('Session ID missing'); return; } const transport = this.transportsMap.get(sessionId); if (!transport) { res.status(400).send(`Transport not found for session ID ${sessionId}`); return; } await transport.handlePostMessage(req, res); } ``` ```shell # Open SSE stream curl -N -H "Authorization: Bearer " \ -H "Accept: text/event-stream" \ http://localhost:3000/sse # event: endpoint # data: /messages?sessionId= # Send a message to the SSE session curl -X POST "http://localhost:3000/messages?sessionId=" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"tools/list","id":1}' ``` -------------------------------- ### Implement Streamable HTTP Transport Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Implements the current MCP Streamable HTTP transport. POST /mcp initializes a new session, subsequent requests use the 'mcp-session-id' header. GET /mcp handles server-to-client streams, DELETE /mcp closes a session. ```typescript public async postMcp(req: McpAuthenticatedRequest, res: Response): Promise { const sessionId = req.headers['mcp-session-id']; let transport: StreamableHTTPServerTransport; if (sessionId && this.transportsMap.has(sessionId as string)) { // Resume existing session transport = this.transportsMap.get(sessionId as string)!; } else if (!sessionId && isInitializeRequest(req.body)) { // Create new session on initialize transport = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID(), onsessioninitialized: (id) => { this.transportsMap.set(id, transport); }, }); transport.onclose = () => { if (transport.sessionId) this.transportsMap.delete(transport.sessionId); }; await this.mcpServer.connect(transport); } else { res.status(400).json({ jsonrpc: '2.0', error: { code: -32000, message: 'Bad Request' }, id: null }); return; } await transport.handleRequest(req, res, req.body); } ``` ```shell # Initialize a new MCP session curl -s -X POST http://localhost:3000/mcp \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{}},"id":1}' # Response includes mcp-session-id header # List tools using the session curl -s -X POST http://localhost:3000/mcp \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -H "mcp-session-id: " \ -d '{"jsonrpc":"2.0","method":"tools/list","id":2}' ``` -------------------------------- ### GET / - Health Check Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Returns HTTP 200 to confirm the Lambda function is reachable. This endpoint is used by Claude during initial MCP server connection discovery. ```APIDOC ## GET / ### Description Returns HTTP 200 to confirm the Lambda function is reachable. Used by Claude during initial MCP server connection discovery. ### Method GET ### Endpoint / ### Request Example ```sh curl -s -o /dev/null -w "%{{http_code}}" \ https://abc123.execute-api.us-east-1.amazonaws.com/ # 200 ``` ``` -------------------------------- ### Docker Deployment: Build, Tag, and Push for Google Cloud Run Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Steps to build a Docker image for the MCP server, tag it for Google Container Registry, and push it to the registry. Lists required environment variables for Cloud Run deployment. ```bash cd mcp-server docker build -t mcp-server . docker tag mcp-server us-west1-docker.pkg.dev///mcp-server docker push us-west1-docker.pkg.dev///mcp-server # Required Cloud Run environment variables ACCESS_TOKEN_SECRET= OAUTH_API_BASE_URL=https://abc123.execute-api.us-east-1.amazonaws.com PORT=3000 ``` -------------------------------- ### Run MCP Inspector Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Use the MCP Inspector to test your integration. Ensure you point it to the correct local address and provide a valid Bearer token. ```sh npx @modelcontextprotocol/inspector@0.13 # Point the inspector at http://localhost:3000 # Use the SSE or Streamable HTTP transport option # Provide a valid Bearer token in the Authorization header ``` -------------------------------- ### AWS Lambda Deployment: Package and Environment Variables Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Commands to package the OAuth function source code for AWS Lambda upload and lists required environment variables for the Lambda function, including secret keys and TTLs. ```bash # Package source files for upload cd oauth-function npm run package # creates oauth-function.zip from src/*.mjs # Required Lambda environment variables ACCESS_TOKEN_SECRET= REFRESH_TOKEN_SECRET= ACCESS_TOKEN_TTL=900 # 15 minutes in seconds REFRESH_TOKEN_TTL=2592000 # 30 days in seconds AUTH_CODES_TABLE_NAME=RemoteMcpAuthCodes AUTH_CODES_TTL=300 # 5 minutes in seconds ``` -------------------------------- ### MCP Tool: `get-opponent-army` Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Accepts an `armyName` parameter and returns the opponent army's record, including known tactics. Requires a valid authenticated session. ```APIDOC ## MCP Tool: `get-opponent-army` — Public Army Lookup by Name ### Description Accepts an `armyName` parameter and returns the opponent army's record, including known tactics. Demonstrates public data access that still requires a valid authenticated session. ### Tool Signature `get-opponent-army({ armyName: string })` ### Parameters #### Query Parameters - **armyName** (string) - Required - Name of the opponent army to research ### Request Example ```sh # Claude tool call: get-opponent-army with armyName="Salamander Army" ``` ### Response Example ```json { "armyName": "Salamander Army", "commanderId": "BS-2198", "commanderName": "Bonzo Madrid", "soldiers": [ { "studentId": "BS-2234", "name": "Bernard", "rank": "Toon Leader", "battlesWon": 10 } ], "armyRecord": { "wins": 15, "losses": 3 }, "knownTactics": ["Wall formations", "Aggressive rushes"] } ``` ``` -------------------------------- ### Build and Push Docker Image for Cloud Run Source: https://github.com/loginov-rocks/remote-mcp-auth/blob/main/README.md Commands to build a Docker image and push it to Google Artifact Registry for deployment to Cloud Run. Ensure your Docker image is tagged correctly with your project and repository details. ```sh docker build -t mcp-server . docker tag mcp-server us-west1-docker.pkg.dev/project/repo/mcp-server docker push us-west1-docker.pkg.dev/project/repo/mcp-server ``` -------------------------------- ### MCP Tool: `get-student-info` Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Looks up a student by name (case-insensitive) and returns their full profile including aptitude score, battle experience, and specialization. ```APIDOC ## MCP Tool: `get-student-info` — Student Profile Lookup ### Description Looks up a student by name (case-insensitive) and returns their full profile including aptitude score, battle experience, and specialization. ### Tool Signature `get-student-info({ studentName: string })` ### Parameters #### Query Parameters - **studentName** (string) - Required - Name of the student to look up ### Request Example ```sh # Claude tool call: get-student-info with studentName="Bean" ``` ### Response Example ```json { "studentId": "BS-2507", "name": "Bean", "age": 9, "aptitudeScore": 98, "battleExperience": "Advanced", "specialization": "Tactical Analysis" } ``` ``` -------------------------------- ### Register MCP Tool: get-student-info Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Registers the 'get-student-info' tool to look up student profiles by name. It requires a `studentName` parameter and an authenticated session to query the `studentService`. Returns detailed student information. ```typescript this.server.tool( 'get-student-info', 'Get detailed information about a student', { studentName: z.string().describe('Name of the student to look up') }, ({ studentName }, { authInfo }) => { if (!authInfo) return this.respondWithText('Unauthorized'); const studentInfo = this.studentService.getStudentInfo(studentName); return this.respondWithJson(studentInfo); } ); // StudentService.ts public getStudentInfo(name: string): Student | null { return this.students.find( (s) => s.name.toLowerCase() === name.toLowerCase() ) ?? null; } ``` -------------------------------- ### McpStreamableController Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Implements the current MCP Streamable HTTP transport, recommended for new implementations. ```APIDOC ## POST /mcp ### Description Handles initialization of new MCP sessions or routing subsequent requests to existing sessions. ### Method POST ### Endpoint `/mcp` ### Parameters #### Headers - **Authorization** (string) - Required - Bearer token for authentication. - **mcp-session-id** (string) - Optional - The ID of an existing MCP session to route the request to. If omitted and `initialize` is in the body, a new session is created. #### Request Body - **initialize** (object) - When present without `mcp-session-id` header, this initializes a new session. Contains protocol version and capabilities. - **jsonrpc** (string) - Required - Specifies the JSON-RPC version. - **method** (string) - Required - The method to call. - **params** (object) - Optional - Parameters for the method call. - **id** (number | string) - Required - The ID of the request. ### Request Example (Initialize Session) ```sh curl -s -X POST http://localhost:3000/mcp \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{}},"id":1}' ``` ### Response #### Success Response (200) - **mcp-session-id** (string) - Header containing the session ID for new sessions. - **jsonrpc** (string) - Specifies the JSON-RPC version. - **result** (any) - The result of the method call. - **id** (number | string) - The ID of the request. ### Response Example (Subsequent Request) ```sh curl -s -X POST http://localhost:3000/mcp \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -H "mcp-session-id: " \ -d '{"jsonrpc":"2.0","method":"tools/list","id":2}' ``` ## GET /mcp ### Description Handles server-to-client streams for an existing MCP session. ### Method GET ### Endpoint `/mcp` ### Parameters #### Headers - **Authorization** (string) - Required - Bearer token for authentication. - **mcp-session-id** (string) - Required - The ID of the MCP session. ### Response #### Success Response (200) - **Stream** - A stream of data from the server to the client. ## DELETE /mcp ### Description Closes an existing MCP session. ### Method DELETE ### Endpoint `/mcp` ### Parameters #### Headers - **Authorization** (string) - Required - Bearer token for authentication. - **mcp-session-id** (string) - Required - The ID of the MCP session to close. ### Response #### Success Response (204) - No Content. ``` -------------------------------- ### Dynamic Client Registration Source: https://github.com/loginov-rocks/remote-mcp-auth/blob/main/README.md Allows clients to dynamically register with the authorization server. ```APIDOC ## POST /oauth/register ### Description Allows clients to dynamically register with the authorization server. ### Method POST ### Endpoint /oauth/register ``` -------------------------------- ### Register OAuth 2.1 Client Dynamically Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt This cURL command demonstrates dynamic client registration by sending a JSON body with client metadata to the `/oauth/register` endpoint. The server generates and returns a new `client_id` (UUID) upon successful registration. ```sh curl -s -X POST https://abc123.execute-api.us-east-1.amazonaws.com/oauth/register \ -H "Content-Type: application/json" \ -d '{ "client_name": "claudeai", "grant_types": ["authorization_code", "refresh_token"], "response_types": ["code"], "token_endpoint_auth_method": "none", "scope": "claudeai", "redirect_uris": ["https://claude.ai/api/mcp/auth_callback"] }' | jq . # { # "client_id": "98f974d2-5ab1-467d-b043-64edbb2a840b", # "client_name": "claudeai", # "grant_types": ["authorization_code", "refresh_token"], # "response_types": ["code"], # "token_endpoint_auth_method": "none", # "scope": "claudeai", # "redirect_uris": ["https://claude.ai/api/mcp/auth_callback"] # } ``` ```javascript // postRegisterHandler.mjs import { randomUUID } from 'crypto'; export const postRegisterHandler = (event) => { const params = JSON.parse(event.body); const clientId = randomUUID(); return { statusCode: 201, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ client_id: clientId, client_name: params.client_name, grant_types: params.grant_types, response_types: params.response_types, token_endpoint_auth_method: params.token_endpoint_auth_method, scope: params.scope, redirect_uris: params.redirect_uris, }), }; }; ``` -------------------------------- ### POST /oauth/token - Initial Token Exchange Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Performs an initial token exchange using the authorization code grant type. Requires the authorization code and code verifier. ```sh # Initial token exchange (authorization_code grant) curl -s -X POST https://abc123.execute-api.us-east-1.amazonaws.com/oauth/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=authorization_code&\ code=&\ code_verifier=&\ redirect_uri=https%3A%2F%2Fclaude.ai%2Fapi%2Fmcp%2Fauth_callback&\ client_id=98f974d2-5ab1-467d-b043-64edbb2a840b" | jq . # { # "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", # "token_type": "Bearer", # "expires_in": 900, # "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", # "scope": "claudeai" # } ``` -------------------------------- ### Register MCP Tool: get-opponent-army Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Registers the 'get-opponent-army' tool for public army lookup by name. It requires an `armyName` parameter and an authenticated session to access `armyService`. Returns the opponent's army record. ```typescript this.server.tool( 'get-opponent-army', 'Get information about an opponent army', { armyName: z.string().describe('Name of the opponent army to research') }, ({ armyName }, { authInfo }) => { if (!authInfo) return this.respondWithText('Unauthorized'); const opponentArmy = this.armyService.getOpponentArmy(armyName); return this.respondWithJson(opponentArmy); } ); // ArmyService.ts public getOpponentArmy(name: string): Army | null { return this.armies.find( (army) => army.armyName.toLowerCase() === name.toLowerCase() ) ?? null; } ``` -------------------------------- ### POST /oauth/authorize - JavaScript Handler Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Handles the POST request for authorization, validates the student ID, creates an authorization code, and constructs the redirect URL. ```js // postAuthorizeHandler.mjs import { createCode } from './authCodes.mjs'; export const postAuthorizeHandler = async (event) => { const body = event.isBase64Encoded ? Buffer.from(event.body, 'base64').toString('utf8') : event.body; const params = Object.fromEntries(new URLSearchParams(body)); if (!params.student_id) return { statusCode: 400 }; const code = await createCode(params.student_id, params.code_challenge); const redirectUrl = new URL(params.redirect_uri); redirectUrl.searchParams.set('code', code); if (params.state) redirectUrl.searchParams.set('state', params.state); return { statusCode: 302, headers: { Location: redirectUrl.toString() } }; }; ``` -------------------------------- ### OAuthController.getWellKnown Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Proxies and caches the Well-Known metadata document from the Authorization Server. Claude always queries the MCP Server base URL first. ```APIDOC ## GET /.well-known/oauth-authorization-server ### Description Retrieves the OAuth authorization server metadata, proxied and cached by the MCP Server. ### Method GET ### Endpoint `/.well-known/oauth-authorization-server` ### Response #### Success Response (200) - **metadata** (object) - The authorization server metadata document. ### Response Example ```json { "issuer": "https://abc123.execute-api.us-east-1.amazonaws.com" } ``` ``` -------------------------------- ### POST /oauth/authorize - Process Authorization Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Accepts the submitted form, generates an authorization code, and redirects the user to the callback URI with the code and state. ```sh curl -s -o /dev/null -w "%{http_code} %{redirect_url}" \ -X POST https://abc123.execute-api.us-east-1.amazonaws.com/oauth/authorize \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "student_id=BS-2401&\ client_id=98f974d2-5ab1-467d-b043-64edbb2a840b&\ code_challenge=qpxvR2wuni9VNrukgHOgVqGc1WljDfVbDFIYtwmKeos&\ code_challenge_method=S256&\ redirect_uri=https%3A%2F%2Fclaude.ai%2Fapi%2Fmcp%2Fauth_callback&\ response_type=code&\ scope=claudeai&\ state=MAtaiBZWWmmNvjGaDFEiLuAbSv_FUJ3k91XYnWcZpts" # 302 https://claude.ai/api/mcp/auth_callback?code=&state=MAtaiBZWW... ``` -------------------------------- ### MCP Tool: `get-my-army` Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Retrieves the full army record for the authenticated user, identified by their `clientId`. ```APIDOC ## MCP Tool: `get-my-army` — Authenticated User's Army ### Description Returns the full army record for the authenticated user, identified by their `clientId` (resolved from the JWT `sub`). Demonstrates how `authInfo.clientId` flows from the middleware into a tool handler. ### Tool Signature `get-my-army()` ### Parameters None ### Request Example ```sh # Via MCP Inspector (session already initialized) # Tool call — invoked by Claude when the user asks "What army am I in?" # Authenticated as student BS-2401 (Ender Wiggin) ``` ### Response Example ```json { "armyName": "Dragon Army", "commanderId": "BS-2401", "commanderName": "Ender Wiggin", "soldiers": [ { "studentId": "BS-2507", "name": "Bean", "rank": "Toon Leader", "battlesWon": 8 }, { "studentId": "BS-2612", "name": "Crazy Tom", "rank": "Toon Leader", "battlesWon": 7 }, { "studentId": "BS-2345", "name": "Hot Soup", "rank": "Soldier", "battlesWon": 6 } ], "armyRecord": { "wins": 12, "losses": 0 } } ``` ``` -------------------------------- ### Generate JWT Tokens (HS256) Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Implements a custom zero-dependency JWT generator using HS256. Requires 'crypto' module. Use `createAccessToken` and `createRefreshToken` for token creation, and `validateRefreshToken` for validation. ```javascript // tokens.mjs — custom zero-dependency JWT implementation (HS256) import { createHmac } from 'crypto'; const generateJwt = (secret, sub, expiresIn) => { const header = base64UrlEncode(JSON.stringify({ alg: 'HS256', typ: 'JWT' })); const now = Math.floor(Date.now() / 1000); const payload = base64UrlEncode(JSON.stringify({ sub, exp: now + expiresIn })); const sig = createHmac('sha256', secret) .update(`${header}.${payload}`).digest('base64') .replace(/\+/g,'-').replace(/\//g,'_').replace(/=/g,''); return `${header}.${payload}.${sig}`; }; export const createAccessToken = (studentId) => ({ accessToken: generateJwt(ACCESS_TOKEN_SECRET, studentId, ACCESS_TOKEN_TTL), expiresIn: ACCESS_TOKEN_TTL, }); export const createRefreshToken = (studentId) => ({ refreshToken: generateJwt(REFRESH_TOKEN_SECRET, studentId, REFRESH_TOKEN_TTL), expiresIn: REFRESH_TOKEN_TTL, }); export const validateRefreshToken = (token) => validateJwt(REFRESH_TOKEN_SECRET, token); ``` -------------------------------- ### Register MCP Tool: get-my-army Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Registers the 'get-my-army' tool, which retrieves the authenticated user's army details. It uses `authInfo.clientId` to fetch data from the `armyService`. Requires a valid authenticated session. ```typescript this.server.tool( 'get-my-army', 'Get information about your army including soldiers and battle record', ({ authInfo }) => { if (!authInfo) return this.respondWithText('Unauthorized'); const myArmy = this.armyService.getMyArmy(authInfo.clientId); return this.respondWithJson(myArmy); } ); // ArmyService.ts public getMyArmy(studentId: string): Army | null { return this.armies.find((army) => army.commanderId === studentId || army.soldiers.some((s) => s.studentId === studentId) ) ?? null; } ``` -------------------------------- ### POST /oauth/register - Dynamic Client Registration Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Accepts a JSON body with OAuth client metadata from Claude and returns a newly generated `client_id` (UUID). This is the Dynamic Client Registration endpoint as defined in OAuth 2.1. ```APIDOC ## POST /oauth/register ### Description Accepts a JSON body with OAuth client metadata from Claude and returns a newly generated `client_id` (UUID). This is the Dynamic Client Registration endpoint as defined in OAuth 2.1. ### Method POST ### Endpoint /oauth/register ### Parameters #### Request Body - **client_name** (string) - Required - The name of the client. - **grant_types** (array) - Required - An array of grant types supported by the client. - **response_types** (array) - Required - An array of response types supported by the client. - **token_endpoint_auth_method** (string) - Required - The method used for token endpoint authentication. - **scope** (string) - Required - The scope of the client's access. - **redirect_uris** (array) - Required - An array of redirect URIs for the client. ### Request Example ```sh curl -s -X POST https://abc123.execute-api.us-east-1.amazonaws.com/oauth/register \ -H "Content-Type: application/json" \ -d '{ "client_name": "claudeai", "grant_types": ["authorization_code", "refresh_token"], "response_types": ["code"], "token_endpoint_auth_method": "none", "scope": "claudeai", "redirect_uris": ["https://claude.ai/api/mcp/auth_callback"] }' | jq . # { # "client_id": "98f974d2-5ab1-467d-b043-64edbb2a840b", # "client_name": "claudeai", # "grant_types": ["authorization_code", "refresh_token"], # "response_types": ["code"], # "token_endpoint_auth_method": "none", # "scope": "claudeai", # "redirect_uris": ["https://claude.ai/api/mcp/auth_callback"] # } ``` ### Response #### Success Response (201) - **client_id** (string) - The newly generated client ID (UUID). - **client_name** (string) - The name of the client. - **grant_types** (array) - An array of grant types supported by the client. - **response_types** (array) - An array of response types supported by the client. - **token_endpoint_auth_method** (string) - The method used for token endpoint authentication. - **scope** (string) - The scope of the client's access. - **redirect_uris** (array) - An array of redirect URIs for the client. #### Response Example ```json { "client_id": "98f974d2-5ab1-467d-b043-64edbb2a840b", "client_name": "claudeai", "grant_types": ["authorization_code", "refresh_token"], "response_types": ["code"], "token_endpoint_auth_method": "none", "scope": "claudeai", "redirect_uris": ["https://claude.ai/api/mcp/auth_callback"] } ``` ``` -------------------------------- ### Server Metadata Discovery Source: https://github.com/loginov-rocks/remote-mcp-auth/blob/main/README.md Retrieves the authorization server's metadata, including its capabilities and endpoints. ```APIDOC ## GET /.well-known/oauth-authorization-server ### Description Retrieves the authorization server's metadata, including its capabilities and endpoints. ### Method GET ### Endpoint /.well-known/oauth-authorization-server ``` -------------------------------- ### McpSseController Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Manages Server-Sent Events (SSE) sessions. This is a deprecated but supported transport method. ```APIDOC ## GET /sse ### Description Opens a persistent Server-Sent Events (SSE) connection and registers a transport keyed by `sessionId`. ### Method GET ### Endpoint `/sse` ### Parameters #### Query Parameters - **Authorization** (string) - Required - Bearer token for authentication. ### Response #### Success Response (200) - **SSE Stream** - A persistent SSE connection. ### Request Example ```sh curl -N -H "Authorization: Bearer " \ -H "Accept: text/event-stream" \ http://localhost:3000/sse ``` ## POST /messages ### Description Routes client messages to the correct SSE session. ### Method POST ### Endpoint `/messages` ### Parameters #### Query Parameters - **sessionId** (string) - Required - The ID of the SSE session to route the message to. - **Authorization** (string) - Required - Bearer token for authentication. #### Request Body - **message** (object) - The message payload to send to the session. Expected to be JSON-RPC 2.0 compliant. ### Request Example ```sh curl -X POST "http://localhost:3000/messages?sessionId=" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"tools/list","id":1}' ``` ``` -------------------------------- ### Authorization Endpoint (POST) Source: https://github.com/loginov-rocks/remote-mcp-auth/blob/main/README.md Handles the authorization grant, typically after user consent. ```APIDOC ## POST /oauth/authorize ### Description Handles the authorization grant, typically after user consent. ### Method POST ### Endpoint /oauth/authorize ``` -------------------------------- ### POST /oauth/authorize — Authorization Processing Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Accepts the submitted form, generates an authorization code, and redirects the user. ```APIDOC ## POST /oauth/authorize — Authorization Processing ### Description Accepts the submitted form (URL-encoded body), generates a one-time authorization code stored in DynamoDB (with PKCE `code_challenge`), and redirects the user back to the Claude callback URI with `code` and `state` parameters. ### Method POST ### Endpoint `/oauth/authorize` ### Parameters #### Request Body - **student_id** (string) - Required - The student's identifier. - **client_id** (string) - Required - The client ID for the application. - **code_challenge** (string) - Required - The code challenge for PKCE. - **code_challenge_method** (string) - Required - The method used for the code challenge (e.g., S256). - **redirect_uri** (string) - Required - The URI to redirect to after authorization. - **response_type** (string) - Required - The response type, typically 'code'. - **scope** (string) - Required - The requested scope of access. - **state** (string) - Required - An opaque value used to maintain state between the request and callback. ### Response #### Success Response (302) - Redirects to the `redirect_uri` with `code` and `state` parameters. #### Response Example `https://claude.ai/api/mcp/auth_callback?code=&state=MAtaiBZWW...` ``` -------------------------------- ### Discover OAuth 2.1 Authorization Server Metadata Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt This cURL command retrieves the OAuth 2.1 authorization server metadata document. Claude uses this endpoint first to discover other OAuth endpoints. The issuer URL is dynamically determined by the API Gateway domain. ```sh curl -s https://abc123.execute-api.us-east-1.amazonaws.com/.well-known/oauth-authorization-server | jq . # { # "issuer": "https://abc123.execute-api.us-east-1.amazonaws.com", # "authorization_endpoint": "https://abc123.execute-api.us-east-1.amazonaws.com/oauth/authorize", # "token_endpoint": "https://abc123.execute-api.us-east-1.amazonaws.com/oauth/token", # "registration_endpoint": "https://abc123.execute-api.us-east-1.amazonaws.com/oauth/register", # "grant_types_supported": ["authorization_code", "client_credentials"], # "code_challenge_methods_supported": ["S256"] # } ``` ```javascript // getWellKnownHandler.mjs — handler implementation export const getWellKnownHandler = (event) => { const issuer = `https://${event.requestContext.domainName}`; return { statusCode: 200, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ issuer, authorization_endpoint: `${issuer}/oauth/authorize`, token_endpoint: `${issuer}/oauth/token`, registration_endpoint: `${issuer}/oauth/register`, grant_types_supported: ['authorization_code', 'client_credentials'], code_challenge_methods_supported: ['S256'], }), }; }; ``` -------------------------------- ### JWT Generation and Validation Utilities Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Provides utility functions for generating and validating JSON Web Tokens (JWTs) using the HS256 algorithm. These functions are essential for creating access and refresh tokens and verifying their authenticity. ```APIDOC ## JWT Utilities (tokens.mjs) ### Description Provides functions to create and validate JWTs for access and refresh tokens. ### Functions - **createAccessToken(studentId)**: Creates a new access token for the given student ID. - **createRefreshToken(studentId)**: Creates a new refresh token for the given student ID. - **validateRefreshToken(token)**: Validates a refresh token and returns its payload if valid, otherwise null. ### Usage Example ```js import { createAccessToken, createRefreshToken, validateRefreshToken } from './tokens.mjs'; const studentId = 'student123'; const accessToken = createAccessToken(studentId); const refreshToken = createRefreshToken(studentId); console.log(accessToken); console.log(refreshToken); const isValid = validateRefreshToken(refreshToken.refreshToken); console.log(isValid); ``` ``` -------------------------------- ### POST /oauth/token — Token Exchange Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Handles token exchange for authorization codes and refresh tokens, returning JWT tokens. ```APIDOC ## POST /oauth/token — Token Exchange ### Description Handles both `authorization_code` (with PKCE `code_verifier` validation) and `refresh_token` grant types. Returns short-lived JWT access tokens and long-lived JWT refresh tokens. Both tokens carry the `studentId` as the JWT `sub` claim. ### Method POST ### Endpoint `/oauth/token` ### Parameters #### Request Body - **grant_type** (string) - Required - The grant type, either 'authorization_code' or 'refresh_token'. - **code** (string) - Required (if grant_type is 'authorization_code') - The authorization code received from the authorization endpoint. - **code_verifier** (string) - Required (if grant_type is 'authorization_code') - The original code verifier for PKCE. - **redirect_uri** (string) - Required - The redirect URI used during authorization. - **client_id** (string) - Required - The client ID for the application. - **refresh_token** (string) - Required (if grant_type is 'refresh_token') - The refresh token to obtain a new access token. ### Response #### Success Response (200) - **access_token** (string) - The JWT access token. - **token_type** (string) - The type of token, typically 'Bearer'. - **expires_in** (integer) - The time in seconds until the access token expires. - **refresh_token** (string) - The JWT refresh token. - **scope** (string) - The granted scope. #### Response Example ```json { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "Bearer", "expires_in": 900, "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "scope": "claudeai" } ``` ``` -------------------------------- ### Root Endpoint Source: https://github.com/loginov-rocks/remote-mcp-auth/blob/main/README.md The root endpoint of the API. ```APIDOC ## GET / ### Description This is the root endpoint of the API. ### Method GET ### Endpoint / ``` -------------------------------- ### Test Express Auth Middleware with cURL Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Tests the Express authentication middleware by sending requests to a local endpoint. Verifies responses for requests with and without a valid Authorization header. ```bash # Test auth middleware directly curl -s -o /dev/null -w "%{http_code}" \ http://localhost:3000/mcp \ -X POST -H "Content-Type: application/json" # 401 (no token) curl -s -o /dev/null -w "%{http_code}" \ http://localhost:3000/mcp \ -X POST \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" # 200 ``` -------------------------------- ### DynamoDB Auth Code Store Source: https://context7.com/loginov-rocks/remote-mcp-auth/llms.txt Manages short-lived authorization codes in DynamoDB. Use `createCode` to store a new code with a challenge and expiration, `findCode` to retrieve it, and `deleteCode` to consume it during token exchange. ```javascript // authCodes.mjs import { DynamoDBClient } from '@aws-sdk/client-dynamodb'; import { DeleteCommand, DynamoDBDocumentClient, GetCommand, PutCommand } from '@aws-sdk/lib-dynamodb'; import { randomBytes } from 'crypto'; const client = DynamoDBDocumentClient.from(new DynamoDBClient()); // Store a new auth code linked to studentId + PKCE challenge export const createCode = async (studentId, codeChallenge) => { const code = randomBytes(32).toString('hex'); const expiration = Math.floor(Date.now() / 1000) + AUTH_CODES_TTL; await client.send(new PutCommand({ TableName: AUTH_CODES_TABLE_NAME, Item: { code, codeChallenge, expiration, studentId }, })); return code; // returned to the user via redirect }; // Retrieve a code record (returns null if not found) export const findCode = async (code) => { const result = await client.send(new GetCommand({ TableName: AUTH_CODES_TABLE_NAME, Key: { code }, })); return result?.Item ?? null; }; // Consume a code (called once, during token exchange) export const deleteCode = (code) => client.send(new DeleteCommand({ TableName: AUTH_CODES_TABLE_NAME, Key: { code } })); ``` -------------------------------- ### Token Exchange Source: https://github.com/loginov-rocks/remote-mcp-auth/blob/main/README.md Exchanges an authorization code or refresh token for an access token. ```APIDOC ## POST /oauth/token ### Description Exchanges an authorization code or refresh token for an access token. ### Method POST ### Endpoint /oauth/token ```