Skip to main content
Glama
kenngcareer

Secure MCP Auth Demo

by kenngcareer
README.md
# Secure MCP Auth Demo

A small, local teaching demo that uses a real MCP Streamable HTTP server with JWT bearer-token authentication and scope-based authorization.

It is intentionally separate from the LangChain and LangGraph demos in this workspace.

## What it teaches

The demo models three roles:

| Demo user | Granted scopes |
| --- | --- |
| Alice Reader | `profile:read`, `notes:read` |
| Bob Contributor | Alice's scopes plus `notes:write` |
| Admin Auditor | All scopes, including `admin:read` |

The protected MCP tools are:

| Tool | Required scope |
| --- | --- |
| `profile_read` | `profile:read` |
| `notes_search` | `notes:read` |
| `notes_create` | `notes:write` |
| `admin_audit_log` | `admin:read` |

## The request path

```text
Streamlit teaching client
  -> Authorization: Bearer <JWT>
  -> MCP Streamable HTTP server (/mcp)
  -> validate signature, exp, iss, aud
  -> read trusted sub and scope claims
  -> allow or deny the requested tool
```

The JWT includes `sub`, `scope`, `aud`, `iss`, `iat`, `exp`, and `jti`. JWT payloads are signed, not encrypted: do not place passwords, API keys, or sensitive personal information in them.

## Run locally

This project uses an isolated virtual environment.

```powershell
.\.venv\Scripts\python.exe server.py
```

In another terminal:

```powershell
.\.venv\Scripts\streamlit.exe run app.py --server.port 8503
```

Open `http://127.0.0.1:8503`. Choose Alice, Bob, or Admin, inspect the issued token claims, and try each tool. For example, Alice receives HTTP `403` when trying `notes_create`, while Bob succeeds.

## Verify

```powershell
.\.venv\Scripts\python.exe -m unittest discover -s tests -v
```

The server also exposes MCP protected-resource metadata at:

```text
http://127.0.0.1:8765/.well-known/oauth-protected-resource/mcp
```

## Teaching boundary

The local app issues tokens itself so every part of the flow is easy to inspect. That is suitable for a lesson, not for a deployed service.

For production, replace `auth.py`'s local issuer with a trusted OAuth/OIDC authorization server such as Auth0, Okta, Microsoft Entra ID, Amazon Cognito, or a company identity provider. Keep the MCP server's validation of issuer, audience, expiry, signature, and scopes.

MCP's HTTP authorization model uses bearer tokens in the `Authorization` header on every request, validates tokens as an OAuth resource server, and uses `401` for missing or invalid credentials and `403` for insufficient scopes. See the [MCP Authorization specification](https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization).