MCP代理身份验证演示
E2E演示 经过身份验证的MCP(模型上下文协议) 具有多用户、多会话支持。Firebase Auth令牌从浏览器通过代理流到MCP服务器——端到端的用户身份相同。
带OAuth 2.1+DCR身份验证的Claude桌面连接器
目录
特性
| 功能 | 描述 | |
|---|---|---|
| :close_lock_with_key: | Firebase身份验证 | 电子邮件/密码+谷歌登录 |
| :屏蔽: | 按请求令牌隔离 | 多用户、多会话安全 |
| :zap: | 自动发现MCP工具 | 放入文件 mcp-server/tools/,重新启动,完成 |
| :箭头_逆时针: | 401重试客户端 | AuthenticatedMCPClient 具有自动令牌刷新功能 |
| :齿轮: | 配置驱动 | YAML中的所有设置,无需更改代码即可交换LLM模型 |
| :bar_chart: | 结构化输出 | 代理返回JSON,前端渲染天气卡 |
| :bust_in_剪影: | 基于作用域的RBAC | 工具检查Firebase自定义声明的范围 |
| :globe_with_meridians: | OAuth 2.1+DCR | Claude Desktop通过OAuth与动态客户端注册连接 |
| :云: | 云运行就绪 | 单端口部署,支持HTTPS+隧道,用于本地测试 |
快速开始
先决条件
- 启用电子邮件/密码登录的Firebase项目
- Firebase服务帐户JSON(项目设置>服务帐户>生成)
- Firebase web API密钥(项目设置>常规>web API密钥)
- 什么之中的一个:
- 奥拉玛 使用模型在本地运行(例如。, ollama pull qwen3.5:9b) - Gemini API密钥 从https://aistudio.google.com/apikey
1.配置
# Copy env templates
cp .env.example .env
cp frontend/.env.example frontend/.env编辑 .env:
AUTH_PROVIDER=firebase
FIREBASE_PROJECT_ID=your-firebase-project-id
FIREBASE_SA_PATH=.secrets/firebase-service-account.json
# For Ollama (local)
LLM_MODEL=openai/qwen3.5:9b
LLM_BASE_URL=http://localhost:11434/v1
LLM_API_KEY=ollama编辑 frontend/.env:
VITE_FIREBASE_API_KEY=your-firebase-web-api-key
VITE_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
VITE_FIREBASE_PROJECT_ID=your-firebase-project-id将您的Firebase服务帐户设置为JSON格式:
mkdir -p .secrets
cp /path/to/your-service-account.json .secrets/firebase-service-account.json2.使用Docker运行(推荐)
docker compose up --build -d就这样,打开 http://localhost:8000登录,询问“东京天气”。
| 服务 | URL | 描述 |
|---|---|---|
| 代理API+前端 | http://localhost:8000 | 单端口——兼容云运行 |
| MCP服务器 | http://localhost:8001 | 内部,由代理api调用 |
# View logs
docker compose logs -f
# Stop
docker compose down2b。不使用Docker运行
要求:Python 3.12+,Node.js 18+
# Create conda env (one-time)
conda create -n mcp-auth python=3.12 -y
conda activate mcp-auth
# Install Python dependencies
pip install -r mcp-server/requirements.txt
pip install -r agent-api/requirements.txt
# Install frontend dependencies
cd frontend && npm install && cd ..窗户:
scripts\start.bat # Starts all 3 services
scripts\stop.bat # Stops all servicesLinux/Mac:
chmod +x scripts/start.sh
scripts/start.sh # Starts all 3 services (Ctrl+C to stop)手册(3个端子):
# Terminal 1: MCP Server
PYTHONPATH=. python -m uvicorn run_mcp_server:app --host 0.0.0.0 --port 8001
# Terminal 2: Agent API
PYTHONPATH=. python -m uvicorn run_agent_api:app --host 0.0.0.0 --port 8000
# Terminal 3: Frontend
cd frontend && npm run dev打开http://localhost:5173(dev)或http://localhost:8000(Docker)。
3.直接测试MCP服务器
python scripts/test_mcp_server.py 项目结构
mcp-authchain/
├── configs/
│ ├── settings.yaml # Ports, scopes, roles, LLM config
│ └── agent.yaml # Agent name, model, instructions
├── commons/
│ ├── config.py # YAML loader with env var interpolation
│ ├── firebase_auth.py # Firebase Admin SDK init + token verification
│ ├── mcp_client.py # AuthenticatedMCPClient + 401-retry
│ ├── token_refresh.py # Refresh strategies (Firebase REST, WebSocket)
│ └── types.py # FirebaseUser dataclass
├── mcp-server/
│ ├── main.py # FastMCP app + pluggable bearer auth middleware
│ ├── auth/ # Pluggable auth providers (Firebase, Azure AD, JWT)
│ ├── oauth/ # OAuth 2.1 + DCR for Claude Desktop integration
│ │ ├── endpoints.py # Well-known, /register, /authorize, /token
│ │ ├── store.py # In-memory client/code/token storage
│ │ ├── token_service.py # RS256 JWT minting + verification
│ │ ├── pkce.py # PKCE S256 validation
│ │ └── templates.py # Firebase login page HTML
│ └── tools/
│ ├── __init__.py # Auto-discovery of BaseMCPTool subclasses
│ ├── base.py # BaseMCPTool base class
│ └── weather.py # Sample tool: Open-Meteo weather API
├── agent-api/
│ ├── main.py # FastAPI app entry point
│ ├── auth_middleware.py # Firebase auth dependency for FastAPI
│ ├── agent_setup.py # ADK Agent + McpToolset + header_provider
│ ├── service/
│ │ └── agent.py # AgentService -- agent lifecycle + chat execution
│ ├── routes/
│ │ ├── chat.py # POST /chat -- thin route, delegates to service
│ │ └── health.py # GET /health
│ └── utils/ # Typed MCP client utilities with 401-retry
│ ├── base.py # BaseToolClient (inherits AuthenticatedMCPClient)
│ └── weather_client.py # WeatherMCPClient
├── frontend/
│ └── src/
│ ├── App.tsx # Main app with auth state
│ ├── firebase.ts # Firebase config
│ ├── api.ts # API client + structured response parser
│ └── components/
│ ├── Login.tsx # Email/password + Google sign-in
│ ├── Chat.tsx # Search input + response rendering
│ └── WeatherCard.tsx # Gradient weather widget
├── scripts/
│ ├── test_mcp_server.py # MCP server E2E test script
│ ├── start.sh # Start all services (Linux/Mac)
│ ├── start.bat # Start all services (Windows)
│ └── stop.bat # Stop all services (Windows)
├── docs/
│ ├── adding-tools.md # How to add new MCP tools
│ ├── auth-middleware.md # How to change auth middleware
│ ├── creating-agents.md # How to create new agents
│ ├── auth-chain.md # How the auth chain works (multi-user, multi-session)
│ └── oauth-dcr-setup.md # OAuth 2.1 + DCR setup for Claude Desktop
└── docker-compose.yml # All 3 services文档
| 指南 | 说明 |
|---|---|
| 添加工具 | 如何添加带有身份验证和范围检查的新MCP工具 |
| 认证中间件 | 如何更改或替换身份验证中间件(Firebase、Auth0、Keycloak、自定义) |
| 创建代理 | 如何创建新代理、子代理、基于角色的代理和传递上下文 |
| 认证链 | 多用户、多会话身份验证如何在令牌隔离的情况下端到端工作 |
| OAuth+DCR设置 | 如何通过OAuth 2.1将Claude Desktop与动态客户端注册连接起来 |
Claude桌面集成
使用OAuth 2.1+DCR将Claude Desktop连接到您的MCP服务器:
# 1. Add Firebase Web SDK config to .env
FIREBASE_WEB_API_KEY=your-firebase-web-api-key
FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
# 2. Start MCP server
conda activate mcp-auth
python -m uvicorn run_mcp_server:app --host 0.0.0.0 --port 8001
# 3. Expose via tunnel (for local testing)
pip install pycloudflared
cloudflared tunnel --url http://localhost:8001
# → https://random-words.trycloudflare.com
# 4. Set OAUTH_ISSUER to tunnel URL in .env and restart server
# 5. In Claude Desktop: Settings → Connectors → Add
# URL: https://random-words.trycloudflare.com/mcpClaude Desktop将自动发现OAuth端点,注册自己(DCR),并打开浏览器进行Firebase登录。看 OAuth+DCR设置 完整的指南。
配置参考
所有敏感配置都位于 .env (忽略了)。 configs/settings.yaml 通过以下方式从env变量读取 ${VAR:default}.
.env
# Auth provider: firebase | azure_ad | jwt
AUTH_PROVIDER=firebase
FIREBASE_PROJECT_ID=your-project-id
FIREBASE_SA_PATH=.secrets/firebase-service-account.json
# OAuth 2.1 (for Claude Desktop)
OAUTH_ISSUER=https://your-server.run.app # Must match public URL
FIREBASE_WEB_API_KEY=your-firebase-web-api-key
FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
# LLM
LLM_MODEL=openai/qwen3.5:9b
LLM_BASE_URL=http://localhost:11434/v1
LLM_API_KEY=ollama切换身份验证提供程序
# Firebase (default)
AUTH_PROVIDER=firebase
# Azure AD
AUTH_PROVIDER=azure_ad
AZURE_TENANT_ID=your-tenant-id
AZURE_CLIENT_ID=your-client-id
# Generic JWT (Auth0, Keycloak, any OIDC)
AUTH_PROVIDER=jwt
JWT_JWKS_URL=https://your-provider.com/.well-known/jwks.json
JWT_ISSUER=https://your-provider.com/
JWT_AUDIENCE=your-api-audience切换LLM模型
# Ollama (local)
LLM_MODEL=openai/qwen3.5:9b
LLM_BASE_URL=http://localhost:11434/v1
LLM_API_KEY=ollama
# Gemini (cloud)
LLM_MODEL=gemini/gemini-2.5-flash
GEMINI_API_KEY=your-gemini-api-key建筑
系统概述
graph LR
subgraph Browser
FE["Frontend
React + Vite"]
FB["Firebase Auth
Login UI"]
end
subgraph Agent API :8000
MW["Auth Middleware
Validates Firebase JWT"]
ADK["Google ADK Agent
LiteLLM / Ollama"]
SS["Session Service
Per-user isolation"]
end
subgraph MCP Server :8001
BM["Bearer Auth
Pluggable provider"]
FM["FastMCP
Streamable HTTP"]
TL["Tools
Auto-discovered"]
end
subgraph External
WA["Weather API
Open-Meteo"]
end
FB -->|"id_token"| FE
FE -->|"Bearer token"| MW
MW --> SS
SS -->|"token in session"| ADK
ADK -->|"same Bearer token
via header_provider"| BM
BM --> FM
FM --> TL
TL --> WA
style Browser fill:#e8f4fd,stroke:#4285f4
style FM fill:#e8f5e9,stroke:#34a853
style ADK fill:#fce4ec,stroke:#ea4335
style BM fill:#fff3e0,stroke:#fbbc04
style MW fill:#fff3e0,stroke:#fbbc04身份验证令牌流
sequenceDiagram
participant U as User
participant FE as Frontend
participant FB as Firebase
participant API as Agent API
participant MCP as MCP Server
participant Tool as Weather Tool
U->>FE: Sign in (email/password)
FE->>FB: signInWithEmailAndPassword()
FB-->>FE: id_token (JWT, 1h TTL)
U->>FE: "weather in Tokyo"
FE->>FE: getIdToken(true)
FE->>API: POST /chat + Bearer token
API->>API: verify_token(jwt) ✓
API->>API: Create ADK session
state: {user_token: jwt}
API->>MCP: POST /mcp + same Bearer token
MCP->>MCP: verify_token(jwt) ✓
MCP->>Tool: get_weather("Tokyo")
Tool-->>MCP: {city: "Tokyo", temp: 15.3}
MCP-->>API: Tool result
API-->>FE: {response: ..., weather: ...}
FE-->>U: Weather card + summary多用户会话隔离
graph TB
subgraph "Concurrent Requests"
A["User A
token_A"] -->|POST /chat| S1["Session A
{user_token: token_A}"]
B["User B
token_B"] -->|POST /chat| S2["Session B
{user_token: token_B}"]
C["User C
token_C"] -->|POST /chat| S3["Session C
{user_token: token_C}"]
end
subgraph "Shared (Stateless)"
AG["ADK Agent"]
RN["Runner"]
end
subgraph "MCP Server"
V["Validates each
request independently"]
end
S1 -->|header_provider reads token_A| AG
S2 -->|header_provider reads token_B| AG
S3 -->|header_provider reads token_C| AG
AG --> RN
RN -->|"Bearer token_A"| V
RN -->|"Bearer token_B"| V
RN -->|"Bearer token_C"| V
style S1 fill:#e3f2fd,stroke:#1976d2
style S2 fill:#fce4ec,stroke:#c62828
style S3 fill:#e8f5e9,stroke:#2e7d32
style V fill:#fff3e0,stroke:#ef6c00端到端的用户身份相同。 登录时发出的Firebase JWT令牌在浏览器中保持不变→ 代理api→ MCP服务器。MCP服务器看到的是实际用户,而不是服务帐户。
多用户安全。 每个请求都会创建一个隔离的ADK会话。用户A的令牌永远不会泄露给用户B。MCP服务器是无状态的——独立验证每个请求。
Claude桌面OAuth流程
sequenceDiagram
participant CD as Claude Desktop
participant AC as Anthropic Cloud
participant MCP as MCP Server
participant BR as User's Browser
participant FB as Firebase Auth
CD->>AC: Use MCP tool
AC->>MCP: POST /mcp
MCP-->>AC: 401 + WWW-Authenticate
AC->>MCP: GET /.well-known/oauth-protected-resource
MCP-->>AC: {authorization_servers, scopes}
AC->>MCP: GET /.well-known/openid-configuration
MCP-->>AC: {endpoints}
AC->>MCP: POST /register (DCR)
MCP-->>AC: {client_id}
AC->>BR: Open /authorize (PKCE)
BR->>MCP: GET /authorize
MCP-->>BR: Firebase login page
BR->>FB: Sign in (Google / email)
FB-->>BR: Firebase ID token
BR->>MCP: POST /authorize/callback
MCP-->>BR: {redirect_url with auth code}
BR->>AC: Redirect to claude.ai/callback?code=X
AC->>MCP: POST /token (code + PKCE verifier)
MCP-->>AC: {access_token (RS256 JWT), refresh_token}
AC->>MCP: POST /mcp + Bearer JWT
MCP-->>AC: Tool result
AC-->>CD: ResponseMCP服务器支持 双重认证:Firebase令牌(来自前端/代理api)和OAuth发布的RS256 JWT(来自Claude Desktop)。两者均由同一机构验证 BearerAuthMiddleware.
许可证
麻省理工学院
