Skip to main content
Glama
jaysonzhao

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