|
1 |
| -# Simple MCP Server with GitHub OAuth Authentication |
| 1 | +# MCP OAuth Authentication Demo |
2 | 2 |
|
3 |
| -This is a simple example of an MCP server with GitHub OAuth authentication. It demonstrates the essential components needed for OAuth integration with just a single tool. |
| 3 | +This example demonstrates OAuth 2.0 authentication with the Model Context Protocol using **separate Authorization Server (AS) and Resource Server (RS)** to comply with the new RFC 9728 specification. |
4 | 4 |
|
5 |
| -This is just an example of a server that uses auth, an official GitHub mcp server is [here](https://github.com/github/github-mcp-server) |
| 5 | +--- |
6 | 6 |
|
7 |
| -## Overview |
8 | 7 |
|
9 |
| -This simple demo to show to set up a server with: |
10 |
| -- GitHub OAuth2 authorization flow |
11 |
| -- Single tool: `get_user_profile` to retrieve GitHub user information |
| 8 | +## Running the Servers |
12 | 9 |
|
| 10 | +### Step 1: Start Authorization Server |
13 | 11 |
|
14 |
| -## Prerequisites |
| 12 | +```bash |
| 13 | +# Navigate to the simple-auth directory |
| 14 | +cd examples/servers/simple-auth |
| 15 | + |
| 16 | +# Start Authorization Server on port 9000 |
| 17 | +uv run mcp-simple-auth-as --port=9000 |
| 18 | +``` |
15 | 19 |
|
16 |
| -1. Create a GitHub OAuth App: |
17 |
| - - Go to GitHub Settings > Developer settings > OAuth Apps > New OAuth App |
18 |
| - - Application name: Any name (e.g., "Simple MCP Auth Demo") |
19 |
| - - Homepage URL: `http://localhost:8000` |
20 |
| - - Authorization callback URL: `http://localhost:8000/github/callback` |
21 |
| - - Click "Register application" |
22 |
| - - Note down your Client ID and Client Secret |
| 20 | +**What it provides:** |
| 21 | +- OAuth 2.0 flows (registration, authorization, token exchange) |
| 22 | +- Simple credential-based authentication (no external provider needed) |
| 23 | +- Token introspection endpoint for Resource Servers (`/introspect`) |
23 | 24 |
|
24 |
| -## Required Environment Variables |
| 25 | +--- |
25 | 26 |
|
26 |
| -You MUST set these environment variables before running the server: |
| 27 | +### Step 2: Start Resource Server (MCP Server) |
27 | 28 |
|
28 | 29 | ```bash
|
29 |
| -export MCP_GITHUB_GITHUB_CLIENT_ID="your_client_id_here" |
30 |
| -export MCP_GITHUB_GITHUB_CLIENT_SECRET="your_client_secret_here" |
31 |
| -``` |
| 30 | +# In another terminal, navigate to the simple-auth directory |
| 31 | +cd examples/servers/simple-auth |
32 | 32 |
|
33 |
| -The server will not start without these environment variables properly set. |
| 33 | +# Start Resource Server on port 8001, connected to Authorization Server |
| 34 | +uv run mcp-simple-auth-rs --port=8001 --auth-server=http://localhost:9000 --transport=streamable-http |
34 | 35 |
|
| 36 | +# With RFC 8707 strict resource validation (recommended for production) |
| 37 | +uv run mcp-simple-auth-rs --port=8001 --auth-server=http://localhost:9000 --transport=streamable-http --oauth-strict |
35 | 38 |
|
36 |
| -## Running the Server |
| 39 | +``` |
37 | 40 |
|
38 |
| -```bash |
39 |
| -# Set environment variables first (see above) |
40 | 41 |
|
41 |
| -# Run the server |
42 |
| -uv run mcp-simple-auth |
| 42 | +### Step 3: Test with Client |
| 43 | + |
| 44 | +```bash |
| 45 | +cd examples/clients/simple-auth-client |
| 46 | +# Start client with streamable HTTP |
| 47 | +MCP_SERVER_PORT=8001 MCP_TRANSPORT_TYPE=streamable_http uv run mcp-simple-auth-client |
43 | 48 | ```
|
44 | 49 |
|
45 |
| -The server will start on `http://localhost:8000`. |
46 | 50 |
|
47 |
| -### Transport Options |
| 51 | +## How It Works |
48 | 52 |
|
49 |
| -This server supports multiple transport protocols that can run on the same port: |
| 53 | +### RFC 9728 Discovery |
50 | 54 |
|
51 |
| -#### SSE (Server-Sent Events) - Default |
| 55 | +**Client → Resource Server:** |
52 | 56 | ```bash
|
53 |
| -uv run mcp-simple-auth |
54 |
| -# or explicitly: |
55 |
| -uv run mcp-simple-auth --transport sse |
| 57 | +curl http://localhost:8001/.well-known/oauth-protected-resource |
| 58 | +``` |
| 59 | +```json |
| 60 | +{ |
| 61 | + "resource": "http://localhost:8001", |
| 62 | + "authorization_servers": ["http://localhost:9000"] |
| 63 | +} |
56 | 64 | ```
|
57 | 65 |
|
58 |
| -SSE transport provides endpoint: |
59 |
| -- `/sse` |
60 |
| - |
61 |
| -#### Streamable HTTP |
| 66 | +**Client → Authorization Server:** |
62 | 67 | ```bash
|
63 |
| -uv run mcp-simple-auth --transport streamable-http |
| 68 | +curl http://localhost:9000/.well-known/oauth-authorization-server |
| 69 | +``` |
| 70 | +```json |
| 71 | +{ |
| 72 | + "issuer": "http://localhost:9000", |
| 73 | + "authorization_endpoint": "http://localhost:9000/authorize", |
| 74 | + "token_endpoint": "http://localhost:9000/token" |
| 75 | +} |
64 | 76 | ```
|
65 | 77 |
|
66 |
| -Streamable HTTP transport provides endpoint: |
67 |
| -- `/mcp` |
68 | 78 |
|
| 79 | +## Legacy MCP Server as Authorization Server (Backwards Compatibility) |
69 | 80 |
|
70 |
| -This ensures backward compatibility without needing multiple server instances. When using SSE transport (`--transport sse`), only the `/sse` endpoint is available. |
| 81 | +For backwards compatibility with older MCP implementations, a legacy server is provided that acts as an Authorization Server (following the old spec where MCP servers could optionally provide OAuth): |
71 | 82 |
|
72 |
| -## Available Tool |
| 83 | +### Running the Legacy Server |
73 | 84 |
|
74 |
| -### get_user_profile |
| 85 | +```bash |
| 86 | +# Start legacy authorization server on port 8002 |
| 87 | +uv run mcp-simple-auth-legacy --port=8002 |
| 88 | +``` |
| 89 | + |
| 90 | +**Differences from the new architecture:** |
| 91 | +- **MCP server acts as AS:** The MCP server itself provides OAuth endpoints (old spec behavior) |
| 92 | +- **No separate RS:** The server handles both authentication and MCP tools |
| 93 | +- **Local token validation:** Tokens are validated internally without introspection |
| 94 | +- **No RFC 9728 support:** Does not provide `/.well-known/oauth-protected-resource` |
| 95 | +- **Direct OAuth discovery:** OAuth metadata is at the MCP server's URL |
75 | 96 |
|
76 |
| -The only tool in this simple example. Returns the authenticated user's GitHub profile information. |
| 97 | +### Testing with Legacy Server |
| 98 | + |
| 99 | +```bash |
| 100 | +# Test with client (will automatically fall back to legacy discovery) |
| 101 | +cd examples/clients/simple-auth-client |
| 102 | +MCP_SERVER_PORT=8002 MCP_TRANSPORT_TYPE=streamable_http uv run mcp-simple-auth-client |
| 103 | +``` |
77 | 104 |
|
78 |
| -**Required scope**: `user` |
| 105 | +The client will: |
| 106 | +1. Try RFC 9728 discovery at `/.well-known/oauth-protected-resource` (404 on legacy server) |
| 107 | +2. Fall back to direct OAuth discovery at `/.well-known/oauth-authorization-server` |
| 108 | +3. Complete authentication with the MCP server acting as its own AS |
79 | 109 |
|
80 |
| -**Returns**: GitHub user profile data including username, email, bio, etc. |
| 110 | +This ensures existing MCP servers (which could optionally act as Authorization Servers under the old spec) continue to work while the ecosystem transitions to the new architecture where MCP servers are Resource Servers only. |
81 | 111 |
|
| 112 | +## Manual Testing |
82 | 113 |
|
83 |
| -## Troubleshooting |
| 114 | +### Test Discovery |
| 115 | +```bash |
| 116 | +# Test Resource Server discovery endpoint (new architecture) |
| 117 | +curl -v http://localhost:8001/.well-known/oauth-protected-resource |
84 | 118 |
|
85 |
| -If the server fails to start, check: |
86 |
| -1. Environment variables `MCP_GITHUB_GITHUB_CLIENT_ID` and `MCP_GITHUB_GITHUB_CLIENT_SECRET` are set |
87 |
| -2. The GitHub OAuth app callback URL matches `http://localhost:8000/github/callback` |
88 |
| -3. No other service is using port 8000 |
89 |
| -4. The transport specified is valid (`sse` or `streamable-http`) |
| 119 | +# Test Authorization Server metadata |
| 120 | +curl -v http://localhost:9000/.well-known/oauth-authorization-server |
| 121 | +``` |
90 | 122 |
|
91 |
| -You can use [Inspector](https://github.com/modelcontextprotocol/inspector) to test Auth |
| 123 | +### Test Token Introspection |
| 124 | +```bash |
| 125 | +# After getting a token through OAuth flow: |
| 126 | +curl -X POST http://localhost:9000/introspect \ |
| 127 | + -H "Content-Type: application/x-www-form-urlencoded" \ |
| 128 | + -d "token=your_access_token" |
| 129 | +``` |
0 commit comments