MCP server separation into Authorization Server (AS) and Resource Server (RS) roles per spec PR #338 (#982)
Co-authored-by: Paul Carleton <paulc@anthropic.com>
This commit is contained in:
parent
d0443a1832
commit
17f9c00c53
1 changed files with 1851 additions and 1603 deletions
|
|
@ -1,91 +1,139 @@
|
|||
# Simple MCP Server with GitHub OAuth Authentication
|
||||
# MCP OAuth Authentication Demo
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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)
|
||||
---
|
||||
|
||||
## Overview
|
||||
## Setup Requirements
|
||||
|
||||
This simple demo to show to set up a server with:
|
||||
- GitHub OAuth2 authorization flow
|
||||
- Single tool: `get_user_profile` to retrieve GitHub user information
|
||||
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. Create a GitHub OAuth App:
|
||||
- Go to GitHub Settings > Developer settings > OAuth Apps > New OAuth App
|
||||
- Application name: Any name (e.g., "Simple MCP Auth Demo")
|
||||
- Homepage URL: `http://localhost:8000`
|
||||
- Authorization callback URL: `http://localhost:8000/github/callback`
|
||||
- Click "Register application"
|
||||
- Note down your Client ID and Client Secret
|
||||
|
||||
## Required Environment Variables
|
||||
|
||||
You MUST set these environment variables before running the server:
|
||||
**Create a GitHub OAuth App:**
|
||||
- Go to GitHub Settings > Developer settings > OAuth Apps > New OAuth App
|
||||
- **Authorization callback URL:** `http://localhost:9000/github/callback`
|
||||
- Note down your **Client ID** and **Client Secret**
|
||||
|
||||
**Set environment variables:**
|
||||
```bash
|
||||
export MCP_GITHUB_GITHUB_CLIENT_ID="your_client_id_here"
|
||||
export MCP_GITHUB_GITHUB_CLIENT_SECRET="your_client_secret_here"
|
||||
export MCP_GITHUB_CLIENT_ID="your_client_id_here"
|
||||
export MCP_GITHUB_CLIENT_SECRET="your_client_secret_here"
|
||||
```
|
||||
|
||||
The server will not start without these environment variables properly set.
|
||||
---
|
||||
|
||||
## Running the Servers
|
||||
|
||||
## Running the Server
|
||||
### Step 1: Start Authorization Server
|
||||
|
||||
```bash
|
||||
# Set environment variables first (see above)
|
||||
# Navigate to the simple-auth directory
|
||||
cd examples/servers/simple-auth
|
||||
|
||||
# Run the server
|
||||
uv run mcp-simple-auth
|
||||
# Start Authorization Server on port 9000
|
||||
uv run mcp-simple-auth-as --port=9000
|
||||
```
|
||||
|
||||
The server will start on `http://localhost:8000`.
|
||||
**What it provides:**
|
||||
- OAuth 2.0 flows (registration, authorization, token exchange)
|
||||
- GitHub OAuth integration for user authentication
|
||||
- Token introspection endpoint for Resource Servers (`/introspect`)
|
||||
- User data proxy endpoint (`/github/user`)
|
||||
|
||||
### Transport Options
|
||||
---
|
||||
|
||||
This server supports multiple transport protocols that can run on the same port:
|
||||
### Step 2: Start Resource Server (MCP Server)
|
||||
|
||||
#### SSE (Server-Sent Events) - Default
|
||||
```bash
|
||||
uv run mcp-simple-auth
|
||||
# or explicitly:
|
||||
uv run mcp-simple-auth --transport sse
|
||||
# In another terminal, navigate to the simple-auth directory
|
||||
cd examples/servers/simple-auth
|
||||
|
||||
# Start Resource Server on port 8001, connected to Authorization Server
|
||||
uv run mcp-simple-auth-rs --port=8001 --auth-server=http://localhost:9000 --transport=streamable-http
|
||||
```
|
||||
|
||||
SSE transport provides endpoint:
|
||||
- `/sse`
|
||||
|
||||
#### Streamable HTTP
|
||||
### Step 3: Test with Client
|
||||
|
||||
```bash
|
||||
uv run mcp-simple-auth --transport streamable-http
|
||||
cd examples/clients/simple-auth-client
|
||||
# Start client with streamable HTTP
|
||||
MCP_SERVER_PORT=8001 MCP_TRANSPORT_TYPE=streamable_http uv run mcp-simple-auth-client
|
||||
```
|
||||
|
||||
Streamable HTTP transport provides endpoint:
|
||||
- `/mcp`
|
||||
|
||||
## How It Works
|
||||
|
||||
This ensures backward compatibility without needing multiple server instances. When using SSE transport (`--transport sse`), only the `/sse` endpoint is available.
|
||||
### RFC 9728 Discovery
|
||||
|
||||
## Available Tool
|
||||
**Client → Resource Server:**
|
||||
```bash
|
||||
curl http://localhost:8001/.well-known/oauth-protected-resource
|
||||
```
|
||||
```json
|
||||
{
|
||||
"resource": "http://localhost:8001",
|
||||
"authorization_servers": ["http://localhost:9000"]
|
||||
}
|
||||
```
|
||||
|
||||
### get_user_profile
|
||||
**Client → Authorization Server:**
|
||||
```bash
|
||||
curl http://localhost:9000/.well-known/oauth-authorization-server
|
||||
```
|
||||
```json
|
||||
{
|
||||
"issuer": "http://localhost:9000",
|
||||
"authorization_endpoint": "http://localhost:9000/authorize",
|
||||
"token_endpoint": "http://localhost:9000/token"
|
||||
}
|
||||
```
|
||||
|
||||
The only tool in this simple example. Returns the authenticated user's GitHub profile information.
|
||||
## Legacy MCP Server as Authorization Server (Backwards Compatibility)
|
||||
|
||||
**Required scope**: `user`
|
||||
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):
|
||||
|
||||
**Returns**: GitHub user profile data including username, email, bio, etc.
|
||||
### Running the Legacy Server
|
||||
|
||||
```bash
|
||||
# Start legacy authorization server on port 8002
|
||||
uv run mcp-simple-auth-legacy --port=8002
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
**Differences from the new architecture:**
|
||||
- **MCP server acts as AS:** The MCP server itself provides OAuth endpoints (old spec behavior)
|
||||
- **No separate RS:** The server handles both authentication and MCP tools
|
||||
- **Local token validation:** Tokens are validated internally without introspection
|
||||
- **No RFC 9728 support:** Does not provide `/.well-known/oauth-protected-resource`
|
||||
- **Direct OAuth discovery:** OAuth metadata is at the MCP server's URL
|
||||
|
||||
If the server fails to start, check:
|
||||
1. Environment variables `MCP_GITHUB_GITHUB_CLIENT_ID` and `MCP_GITHUB_GITHUB_CLIENT_SECRET` are set
|
||||
2. The GitHub OAuth app callback URL matches `http://localhost:8000/github/callback`
|
||||
3. No other service is using port 8000
|
||||
4. The transport specified is valid (`sse` or `streamable-http`)
|
||||
### Testing with Legacy Server
|
||||
|
||||
You can use [Inspector](https://github.com/modelcontextprotocol/inspector) to test Auth
|
||||
```bash
|
||||
# Test with client (will automatically fall back to legacy discovery)
|
||||
cd examples/clients/simple-auth-client
|
||||
MCP_SERVER_PORT=8002 MCP_TRANSPORT_TYPE=streamable_http uv run mcp-simple-auth-client
|
||||
```
|
||||
|
||||
The client will:
|
||||
1. Try RFC 9728 discovery at `/.well-known/oauth-protected-resource` (404 on legacy server)
|
||||
2. Fall back to direct OAuth discovery at `/.well-known/oauth-authorization-server`
|
||||
3. Complete authentication with the MCP server acting as its own AS
|
||||
|
||||
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.
|
||||
|
||||
## Manual Testing
|
||||
|
||||
### Test Discovery
|
||||
```bash
|
||||
# Test Resource Server discovery endpoint (new architecture)
|
||||
curl -v http://localhost:8001/.well-known/oauth-protected-resource
|
||||
|
||||
# Test Authorization Server metadata
|
||||
curl -v http://localhost:9000/.well-known/oauth-authorization-server
|
||||
```
|
||||
|
||||
### Test Token Introspection
|
||||
```bash
|
||||
# After getting a token through OAuth flow:
|
||||
curl -X POST http://localhost:9000/introspect \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-d "token=your_access_token"
|
||||
```
|
||||
|
|
|
|||
Loading…
Reference in a new issue