Skip to content

Commit 2d857b7

Browse files
authored
example: oauth2 for mcp-auth (#10)
* fix: health endpoint * example: streamable http * auth: github * mcp-auth: oauth * docs
1 parent 1093eaa commit 2d857b7

23 files changed

+3315
-412
lines changed

.github/dependabot.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "github-actions"
4+
directory: "/"
5+
schedule:
6+
interval: "monthly"
7+
groups:
8+
github-actions:
9+
patterns:
10+
- "*"
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
name: Fix License Headers
2+
3+
on:
4+
pull_request_target:
5+
6+
concurrency:
7+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
8+
cancel-in-progress: true
9+
10+
jobs:
11+
header-license-fix:
12+
runs-on: ubuntu-latest
13+
14+
permissions:
15+
contents: write
16+
pull-requests: write
17+
18+
steps:
19+
- name: Checkout
20+
uses: actions/checkout@v4
21+
with:
22+
token: ${{ secrets.GITHUB_TOKEN }}
23+
24+
- name: Checkout the branch from the PR that triggered the job
25+
run: gh pr checkout ${{ github.event.pull_request.number }}
26+
env:
27+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
28+
29+
- name: Fix License Header
30+
# pin to include https://github.com/apache/skywalking-eyes/pull/168
31+
uses: apache/skywalking-eyes/header@07a607ff5b0759f5ed47306c865aac50fe9b3985
32+
with:
33+
mode: fix
34+
35+
- name: List files changed
36+
id: files-changed
37+
shell: bash -l {0}
38+
run: |
39+
set -ex
40+
export CHANGES=$(git status --porcelain | tee /tmp/modified.log | wc -l)
41+
cat /tmp/modified.log
42+
43+
echo "N_CHANGES=${CHANGES}" >> $GITHUB_OUTPUT
44+
45+
git diff
46+
47+
- name: Commit any changes
48+
if: steps.files-changed.outputs.N_CHANGES != '0'
49+
shell: bash -l {0}
50+
run: |
51+
git config user.name "github-actions[bot]"
52+
git config user.email "github-actions[bot]@users.noreply.github.com"
53+
54+
git pull --no-tags
55+
56+
git add *
57+
git commit -m "Automatic application of license header"
58+
59+
git config push.default upstream
60+
git push
61+
env:
62+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.licenserc.yaml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
header:
2+
license:
3+
spdx-id: Datalayer
4+
copyright-owner: Datalayer, Inc.
5+
copyright-year: 2023-2025
6+
content: |
7+
Copyright (c) [year] [owner]
8+
Distributed under the terms of the Modified BSD License.
9+
10+
paths-ignore:
11+
- '**/*.toml'
12+
- '**/*.apt'
13+
- '**/*.cedar'
14+
- '**/*.dash'
15+
- '**/*.fga'
16+
- '**/*.ipynb'
17+
- '**/*.j2'
18+
- '**/*.json'
19+
- '**/*.mamba'
20+
- '**/*.md'
21+
- '**/*.mdx'
22+
- '**/*.mod'
23+
- '**/*.nblink'
24+
- '**/*.rego'
25+
- '**/*.sum'
26+
- '**/*.svg'
27+
- '**/*.template'
28+
- '**/*.tsbuildinfo'
29+
- '**/*.txt'
30+
- '**/*.yaml'
31+
- '**/*.yml'
32+
- '**/*_key'
33+
- '**/*_key.pub'
34+
- '**/.*'
35+
- '**/LICENSE.txt'
36+
- '**/MANIFEST.in'
37+
- '**/build'
38+
- '**/lib'
39+
- '**/node_modules'
40+
- '**/schemas'
41+
- '**/ssh/*'
42+
- '**/static'
43+
- '**/themes'
44+
- '**/typings'
45+
- '**/*.patch'
46+
- '**/*.bundle.js'
47+
- '**/*.map.js'
48+
- 'LICENSE'
49+
- 'src/stories'
50+
- '.husky/pre-commit'
51+
52+
comment: on-failure

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
[![License](https://img.shields.io/badge/license-BSD--3--Clause-green)](LICENSE)
1818
[![Docker](https://img.shields.io/badge/docker-ready-blue)](Dockerfile)
1919

20-
> **A powerful, production-ready framework for composing and orchestrating Model Context Protocol (MCP) servers with advanced management capabilities, REST API, and modern Web UI.**
20+
> **Similar to Docker Compose - Orchestrate Model Context Protocol (MCP) servers with management capabilities, REST API, and Web UI.**
2121
2222
## 🎯 Overview
2323

examples/mcp-auth/Makefile

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,19 @@ agent:
5959
@echo ""
6060
mcp-auth-agent azure-openai:gpt-4o-mini
6161

62+
63+
# Run MCP Inspector
64+
inspector:
65+
@echo "🔍 Starting Model Context Protocol Inspector..."
66+
npx @modelcontextprotocol/inspector
67+
68+
# Test Dynamic Client Registration
69+
test-dcr:
70+
@echo "🧪 Testing Dynamic Client Registration (DCR)..."
71+
@echo "Make sure the server is running in another terminal: make server"
72+
@echo ""
73+
python test_dcr.py
74+
6275
# Run tests
6376
test:
6477
@echo "🧪 Running tests..."

examples/mcp-auth/README.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ A clear, educational example demonstrating OAuth2 authentication for MCP (Model
1515
## 📚 What You'll Learn
1616

1717
- **OAuth2** - Authorization Code flow with PKCE
18+
- **Dynamic Client Registration (DCR)** - RFC 7591 implementation for automatic client registration
1819
- **MCP Authorization** - Official specification (2025-06-18)
1920
- **Security** - Token validation, CSRF protection, resource indicators
2021
- **MCP SDK** - Building servers with FastMCP and clients with MCP SDK
@@ -39,9 +40,11 @@ make install
3940
|------|---------|------------------|
4041
| **[docs/QUICKSTART.md](docs/QUICKSTART.md)** | Get running in 5 minutes | You want to try it immediately |
4142
| **[docs/GITHUB.md](docs/GITHUB.md)** | GitHub OAuth app setup | Setting up for the first time |
43+
| **[docs/INSPECTOR.md](docs/INSPECTOR.md)** | MCP Inspector setup and testing | You want to test with MCP Inspector |
4244
| **[docs/FLOW_EXPLAINED.md](docs/FLOW_EXPLAINED.md)** | Detailed OAuth flow | You want to understand how it works |
4345
| **[docs/DIAGRAMS.md](docs/DIAGRAMS.md)** | Visual explanations | You prefer diagrams |
4446
| **[docs/IMPLEMENTATION.md](docs/IMPLEMENTATION.md)** | Technical details | You're implementing your own |
47+
| **[docs/DYNAMIC_CLIENT_REGISTRATION.md](docs/DYNAMIC_CLIENT_REGISTRATION.md)** | Dynamic Client Registration (DCR) | You want to understand automatic client registration |
4548

4649
## 📁 Project Structure
4750

@@ -75,7 +78,7 @@ mcp-auth/
7578
- OAuth2 endpoints integrated with FastAPI
7679
- Three example tools (calculator, greeter, server_info)
7780
- Token validation middleware
78-
- Compatible with both SSE and STDIO transports
81+
- Uses **HTTP Streaming (NDJSON)** transport for efficient communication
7982

8083
### 2. **MCP Client** (`mcp_auth_example/client.py`)
8184
- Built with **official MCP Python SDK**
@@ -101,22 +104,22 @@ mcp-auth/
101104
- Implements MCP Authorization specification (2025-06-18)
102105
- Exposes OAuth metadata endpoints (RFC 9728, RFC 8414)
103106
- Validates access tokens before serving tools
104-
- Provides MCP tools via HTTP/SSE transport
107+
- Provides MCP tools via **HTTP Streaming (NDJSON)** transport
105108
- Tools: calculator (add, multiply), greeter (hello, goodbye), server info
106109

107110
### 2. **MCP Client** (`mcp_auth_example/client.py`)
108111
- Handles OAuth2 flow with GitHub
109112
- Automatically opens browser for user authentication
110113
- Manages access tokens
111114
- Connects to MCP server using **MCP SDK client**
112-
- Makes authenticated requests via MCP protocol (SSE transport)
113-
- Demonstrates proper MCP tool invocation
115+
- Makes authenticated requests via MCP protocol (**HTTP Streaming transport**)
116+
- Demonstrates proper MCP tool invocation with NDJSON format
114117

115118
### 3. **Pydantic AI Agent** (`mcp_auth_example/agent.py`) ✨ NEW
116119
- Interactive CLI agent powered by **pydantic-ai**
117120
- Uses **Anthropic Claude Sonnet 4.5** model
118121
- Automatically authenticates with OAuth2
119-
- Connects to MCP server with authenticated tools
122+
- Connects to MCP server with authenticated tools via HTTP Streaming
120123
- Natural language interface to MCP tools
121124
- Example: "What is 15 + 27?" → Uses calculator_add tool
122125

File renamed without changes.

examples/mcp-auth/docs/AGENT.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ The agent provides a natural language interface to the MCP server tools, powered
6565
│ │ │
6666
│ ▼ │
6767
│ ┌─────────────────────────────────────────────────────┐ │
68-
│ │ MCPServerSSE (pydantic_ai.mcp) │ │
69-
│ │ - URL: http://localhost:8080/sse │ │
68+
│ │ MCPServerStreamableHTTP (pydantic_ai.mcp) │ │
69+
│ │ - URL: http://localhost:8080/mcp │ │
7070
│ │ - Auth: Bearer token from OAuth │ │
7171
│ │ - Tools: calculator_*, greeter_*, get_server_info │ │
7272
│ └─────────────────────────────────────────────────────┘ │
@@ -77,7 +77,7 @@ The agent provides a natural language interface to the MCP server tools, powered
7777
│ MCP Server (server.py) │
7878
│ - Validates Bearer token with GitHub │
7979
│ - Executes tool functions │
80-
│ - Returns results via SSE
80+
│ - Returns results via HTTP Streaming (NDJSON)
8181
└─────────────────────────────────────────────────────────────┘
8282
```
8383

@@ -88,16 +88,16 @@ The agent provides a natural language interface to the MCP server tools, powered
8888
- Manages PKCE flow for security
8989
- Returns access token for MCP server
9090

91-
2. **Agent Setup** (`agent.py`)
91+
3. **Agent Setup** (`agent.py`)
9292
- Creates `httpx.AsyncClient` with Bearer token
93-
- Initializes `MCPServerSSE` connection
93+
- Initializes `MCPServerStreamableHTTP` connection
9494
- Creates `Agent` with Anthropic Claude model
9595
- Registers MCP server as toolset
9696

97-
3. **Tool Invocation Flow**
97+
4. **Tool Invocation Flow**
9898
- User types natural language query
9999
- Agent (Claude) analyzes query and decides which tool to call
100-
- Agent calls tool via MCP protocol (HTTP SSE)
100+
- Agent calls tool via MCP protocol (HTTP Streaming)
101101
- MCP server validates token and executes tool
102102
- Agent receives result and formulates response
103103
- Agent displays natural language answer to user
@@ -121,17 +121,17 @@ if oauth.authenticate():
121121
```python
122122
import httpx
123123
from pydantic_ai import Agent
124-
from pydantic_ai.mcp import MCPServerSSE
124+
from pydantic_ai.mcp import MCPServerStreamableHTTP
125125

126126
# Create HTTP client with authentication
127127
http_client = httpx.AsyncClient(
128128
headers={"Authorization": f"Bearer {token}"},
129-
timeout=httpx.Timeout(30.0)
129+
timeout=30.0
130130
)
131131

132132
# Connect to MCP server
133-
mcp_server = MCPServerSSE(
134-
url=f"{server_url}/sse",
133+
mcp_server = MCPServerStreamableHTTP(
134+
url=f"{server_url}/mcp",
135135
http_client=http_client
136136
)
137137

0 commit comments

Comments
 (0)