Skip to main content
Glama

MCP Auth Server

README.md8.57 kB
# MCP Auth Step by Step This repository demonstrates building an MCP (Model Context Protocol) server with HTTP transport and JWT authentication, progressing through iterative steps. This repo is a companion to the in-depth, step-by-step blog posts on "MCP Authorization". See the following: * [Understanding MCP Authorization, Step by Step, Part One](https://blog.christianposta.com/understanding-mcp-authorization-step-by-step/) * [Understanding MCP Authorization, Step by Step, Part Two](https://blog.christianposta.com/understanding-mcp-authorization-step-by-step-part-two/) * [Understanding MCP Authorization, Step by Step, Part Three](https://blog.christianposta.com/understanding-mcp-authorization-step-by-step-part-three/) Part 4 (late addition to the series): [MCP Authorization With Dynamic Client Registration](https://blog.christianposta.com/understanding-mcp-authorization-with-dynamic-client-registration/) ## MCP Authorization Specification Requirements The table below shows support for OAuth RFCs required by the MCP authorization specification across major identity providers. ### RFC Requirements Summary: - **PKCE**: Proof Key for Code Exchange (OAuth 2.1 requirement) - **RFC 8414**: OAuth 2.0 Authorization Server Metadata - **RFC 7591**: OAuth 2.0 Dynamic Client Registration Protocol - **RFC 8707**: Resource Indicators for OAuth 2.0 | Identity Provider | PKCE | RFC 8414 | RFC 7591 | RFC 8707 | |-------------------|------|----------|----------|----------| | **Okta** | Yes | Yes | Yes | N0 | | **Auth0** | Yes | Yes | Kinda | No | | **Keycloak** | Yes | Yes | Yes | No | | **Ping Federate** | Yes | Yes | Yes | Yes | | **ForgeRock** | Yes | Yes | Yes | Kinda | | **Google OAuth** | Yes | No | No | No | | **Microsoft Entra** | Yes | Yes | No | No | ## Overview The project shows how to build a secure MCP server with: - FastAPI-based HTTP transport - JWT token authentication - OAuth 2.0 metadata endpoints - Scope-based authorization - Role-based access control ## Step-by-Step Progression ### Step 1: Basic FastAPI Skeleton - **File**: `http-transport-steps/src/mcp_http/step1.py` - **What it adds**: Basic FastAPI application with health endpoint - **Key features**: - FastAPI server setup - Basic health check endpoint (`/health`) - Foundation for MCP HTTP transport ### Step 2: Basic MCP Request Handling - **File**: `http-transport-steps/src/mcp_http/step2.py` - **What it adds**: MCP protocol request/response handling - **Key features**: - MCP request parsing and validation - Basic MCP response structure - `/mcp` endpoint for MCP protocol communication - JSON-RPC style request handling ### Step 3: MCP Tools and Prompts Definitions - **File**: `http-transport-steps/src/mcp_http/step3.py` - **What it adds**: MCP tools and prompts without dispatching - **Key features**: - Tool definitions (`echo`, `get_time`) - Prompt definitions (`greeting`, `help`) - MCP protocol compliance for tools and prompts - No actual tool execution yet ### Step 4: MCP Tools Dispatching - **File**: `http-transport-steps/src/mcp_http/step4.py` - **What it adds**: Actual tool execution and prompt handling - **Key features**: - Tool dispatching and execution - Prompt retrieval and handling - Working MCP server with functional tools - Error handling for invalid requests ### Step 5: Basic JWT Infrastructure - **File**: `http-transport-steps/src/mcp_http/step5.py` - **What it adds**: JWT public key loading and JWKS endpoint - **Key features**: - Public key loading from file - JWKS (JSON Web Key Set) endpoint (`/.well-known/jwks.json`) - External token generation script (`generate_token.py`) - JWT infrastructure foundation ### Step 6: JWT Token Validation - **File**: `http-transport-steps/src/mcp_http/step6.py` - **What it adds**: JWT authentication middleware and enforcement - **Key features**: - JWT token validation middleware - Authentication enforcement on `/mcp` endpoint - User context extraction from tokens - Proper error responses for invalid/missing tokens ### Step 7: OAuth 2.0 Metadata Endpoints - **File**: `http-transport-steps/src/mcp_http/step7.py` - **What it adds**: OAuth 2.0 metadata for protected resource and authorization server - **Key features**: - `/.well-known/oauth-protected-resource` endpoint - `/.well-known/oauth-authorization-server` endpoint - Enhanced health endpoint with OAuth metadata - OAuth metadata in MCP responses ### Step 8: Scope-Based Authorization - **File**: `http-transport-steps/src/mcp_http/step8.py` - **What it adds**: Permission checking and role-based access control - **Key features**: - `check_permission` method for scope validation - Role-based access control (admin, user, guest) - 403 Forbidden responses for insufficient permissions - Scope enforcement for MCP operations ### Step 9: Enhanced MCP Integration (Planned) - **What it will add**: User context in responses and authenticated tools - **Planned features**: - User context in MCP response headers/metadata - Authenticated tools with user-aware behavior - Enhanced MCP protocol integration - Personalized responses based on user identity ## JWT Token Structure The JWT tokens include: - **User ID**: Unique identifier for the user - **Scopes**: Permissions (e.g., `mcp:read`, `mcp:tools`, `mcp:prompts`) - **Roles**: User roles (e.g., `admin`, `user`, `guest`) - **Expiration**: Token validity period ## Testing Each step includes a corresponding test script (`test_stepX.sh`) that validates: - Basic functionality - JWT authentication (steps 5+) - Authorization (steps 6+) - OAuth metadata (steps 7+) - Access control (steps 8+) ## Usage ### Prerequisites 1. Install `uv`: https://docs.astral.sh/uv/getting-started/installation/ 2. Navigate to the `http-transport-steps` directory ### Running Steps with uv ```bash # Run any step using uv run uv run step1 uv run step2 uv run step3 # ... etc ``` ### Running Step 10 with Environment Configuration Step 10 supports environment-based configuration for Keycloak and MCP server URLs. You can specify an env file (not .env) using the `--env` flag, or let it default to `keycloak_direct.env`. Two example env files are provided: - `keycloak_direct.env` (for direct Keycloak access at `localhost:8080`) - `keycloak_proxy.env` (for proxy access at `localhost:9090`) **Example usage:** ```bash # Run step 10 with a specific env file (e.g., proxy) uv run step10 --env keycloak_proxy.env ``` If the env file or environment variables are missing, the server will fall back to sensible defaults (localhost:8080, etc). ### Notes for running step11 * you will need to run step10 mcp server * you will have to allow anonymous client registration: * add trusted hosts (check keycloak logs for the right IP) * for trusted host policy, you don't need matching on URI * allowable scopes for mcp:read, etc and aud mapper * then run the step11 client ```bash uv run step11 ``` To run with mcp-inspector * you'll need to run agentgateway with config.yaml * uv run step10 --env keycloak_proxy.env * run mcp-inspector UI (note, some of the auth stuff is broken, at the moment, use this: https://github.com/christian-posta/mcp-inspector/tree/ceposta-patches) * then follow the step by step auth flow mcp scopes issue: https://github.com/modelcontextprotocol/inspector/issues/587 ### Token Generation For steps 5-8 that require JWT authentication, you can generate tokens using the `generate_token.py` script: ```bash uv run python generate_token.py --username alice --scopes mcp:read,mcp:tools uv run python generate_token.py --username bob --scopes mcp:read,mcp:prompts uv run python generate_token.py --username admin --scopes mcp:read,mcp:tools,mcp:prompts uv run python generate_token.py --username guest --scopes "" ``` ### Keycloak Token Generation To quickly get a token for testing step9/keycloak: ```bash# Get token for admin user (full access) curl -X POST "http://localhost:8080/realms/mcp-realm/protocol/openid-connect/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=password" \ -d "client_id=mcp-test-client" \ -d "username=mcp-admin" \ -d "password=admin123" \ -d "scope=openid profile email mcp:read mcp:tools mcp:prompts" | jq -r '.access_token' ``` The script will output a JWT token that can be used in the `Authorization: Bearer <token>` header for authenticated requests. ## Dependencies - FastAPI - PyJWT - cryptography - uvicorn The project uses `uv` for dependency management with `pyproject.toml` configuration.

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/christian-posta/mcp-auth-step-by-step'

If you have feedback or need assistance with the MCP directory API, please join our Discord server