mock-mcp-server
by jaysonzhao
README.md
# Mock MCP Server with Kuadrant Gateway
This project demonstrates an MCP (Model Context Protocol) server protected by Kuadrant API gateway with **token separation** — the gateway and backend use different tokens for authentication.
## Architecture
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ Client │
│ Bearer gateway-api-key-xyz │
└─────────────────────────────────────┬───────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ Kuadrant Gateway │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ AuthPolicy (API Key validation via Authorino) │ │
│ │ allNamespaces: true + selector: authorino.kuadrant.io/managed │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ HTTPRoute + RequestHeaderModifier (SET Authorization header) │ │
│ │ set: Authorization = "Bearer backend-mcp-secret-abc123" │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────┬───────────────────────────────────────┘
│
▼ (with replaced header)
┌─────────────────────────────────────────────────────────────────────────────┐
│ MCP Backend (mock-mcp-server) │
│ Validates: Bearer backend-mcp-secret-abc123 │
└─────────────────────────────────────────────────────────────────────────────┘
```
## Token Flow
| Stage | Token | Purpose |
|-------|-------|---------|
| Client → Gateway | `gateway-api-key-xyz` | Authenticates to Kuadrant/Authorino |
| Gateway → Backend | `backend-mcp-secret-abc123` | Backend validates request |
## Key Configuration Files
| File | Description |
|------|-------------|
| `kuadrant-mcp-gateway-api-key-injection.yaml` | HTTPRoute + AuthPolicy + Secrets |
| `test-mcp-gateway.sh` | Integration test script |
## Quick Start
### 1. Apply Configuration
```bash
# Apply the Kuadrant gateway configuration
oc apply -f kuadrant-mcp-gateway-api-key-injection.yaml
# Update backend to use backend token
oc set env deployment/mock-mcp-server -n ai501 --overwrite MCP_BEARER_TOKEN=backend-mcp-secret-abc123
oc rollout restart deployment/mock-mcp-server -n ai501
```
### 2. Run Tests
```bash
./test-mcp-gateway.sh [gateway_host]
```
Example output:
```
==============================================
Kuadrant MCP Gateway Test
==============================================
Gateway Host: a4bf32c33d79e4f92b3721393a6c3202-953674145.us-east-2.elb.amazonaws.com
Gateway Token: gateway-ap...
Backend Token: backend-mc...
=== Basic Connectivity Tests ===
Testing: Health check ... PASS (HTTP 200)
=== MCP Protocol Tests ===
Testing: MCP capabilities ... PASS (HTTP 200)
Testing: MCP tools list ... PASS
Testing: MCP tool call (calculate) ... PASS
=== Token Replacement Tests ===
Testing: Authorization header replaced ... PASS
Backend received: Authorization: Bearer backend-mcp-secret-abc123
=== Security Tests ===
Testing: Invalid gateway token rejection ... PASS (HTTP 401 - rejected)
==============================================
Test Summary: Passed=6 Failed=0
==============================================
```
## HTTPRoute with RequestHeaderModifier
**Important:** Use `set` (not `replace`) per Gateway API spec:
```yaml
spec:
rules:
- matches:
- path:
type: PathPrefix
value: /mcp
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
set:
- name: Authorization
value: "Bearer backend-mcp-secret-abc123"
backendRefs:
- kind: Service
name: mock-mcp-server
port: 8080
```
## AuthPolicy with API Key Validation
```yaml
apiVersion: kuadrant.io/v1
kind: AuthPolicy
metadata:
name: mock-mcp-auth-dedicated
namespace: ai501
spec:
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
name: mock-mcp-server-route
rules:
authentication:
"api-key-valid":
apiKey:
allNamespaces: true # Required to find secrets in kuadrant-system
selector:
matchLabels:
authorino.kuadrant.io/managed: "true"
credentials:
in: authorization_header
keySelector: Bearer
priority: 0
```
## Secrets
**Gateway API Key (in kuadrant-system namespace):**
```yaml
apiVersion: v1
kind: Secret
metadata:
name: api-key-secret
namespace: kuadrant-system
labels:
authorino.kuadrant.io/managed: "true"
type: Opaque
stringData:
key: gateway-api-key-xyz
```
**Backend Bearer Token (in ai501 namespace):**
```yaml
apiVersion: v1
kind: Secret
metadata:
name: mock-mcp-secret
namespace: ai501
type: Opaque
stringData:
bearer-token: backend-mcp-secret-abc123
```
## MCP Server Endpoints
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/health` | GET | Health check (no auth) |
| `/mcp` | GET | MCP protocol capabilities |
| `/mcp/tools` | GET | List available tools |
| `/mcp/tools/call` | POST | Call a tool |
| `/mcp/resources` | GET | List resources |
| `/debug-headers` | GET | Debug endpoint showing received headers |
## MCP Tools
| Tool | Description | Parameters |
|------|-------------|------------|
| `get_weather` | Get weather for a location | `location` (string) |
| `calculate` | Basic arithmetic | `operation` (add/subtract/multiply/divide), `a`, `b` |
| `get_time` | Get current time | `timezone` (optional) |
## Debugging
### Check AuthPolicy Status
```bash
oc get authpolicy mock-mcp-auth-dedicated -n ai501 -o yaml | grep -A5 "status:"
```
### Check Authorino Logs
```bash
oc logs -n kuadrant-system -l app=authorino --tail=50
```
### Test Header Replacement
```bash
curl -s http://<gateway-host>/debug-headers \
-H "Host: mock-mcp.ai501.example.com" \
-H "Authorization: Bearer gateway-api-key-xyz" | jq .Authorization
```
## Files Overview
| File | Description |
|------|-------------|
| `mock-mcp-server.py` | Python/FastAPI MCP server |
| `Dockerfile` | Container build |
| `kuadrant-mcp-gateway-api-key-injection.yaml` | Kuadrant + HTTPRoute + Secrets |
| `test-mcp-gateway.sh` | Integration test script |
| `README.md` | This file |
## Cleanup
```bash
oc delete -f kuadrant-mcp-gateway-api-key-injection.yaml
```
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessSyncing