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:
Inna Harper 2025-06-23 14:19:03 +01:00 • committed by GitHub
commit 17f9c00c53
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -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"
```