|
| 1 | +# MCP Server + Access Self-Hosted App |
| 2 | + |
| 3 | +A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) server protected by Cloudflare Access as a self-hosted application. Unlike the [Access for SaaS demo](../remote-mcp-cf-access/), this approach requires **no OAuth implementation** — Cloudflare Access handles authentication automatically. |
| 4 | + |
| 5 | +The MCP server demonstrates: |
| 6 | + |
| 7 | +- Validating the Access JWT signature against your team's public keys using [`jose`](https://www.npmjs.com/package/jose) |
| 8 | +- Verifying the JWT issuer and audience claims |
| 9 | +- Reading user identity from the validated JWT |
| 10 | +- Conditionally exposing tools based on user identity |
| 11 | + |
| 12 | +## Getting Started |
| 13 | + |
| 14 | +Clone the repo and install dependencies: |
| 15 | + |
| 16 | +```bash |
| 17 | +npm install |
| 18 | +``` |
| 19 | + |
| 20 | +### Create a self-hosted Access application |
| 21 | + |
| 22 | +1. In [Cloudflare One](https://one.dash.cloudflare.com), go to **Access controls** > **Applications** > **Add an application** > **Self-hosted**. |
| 23 | +2. Set the **Application domain** to your Worker URL (e.g., `mcp-access-self-hosted.<your-subdomain>.workers.dev`). |
| 24 | +3. Add an Access policy to control who can connect (e.g., allow emails ending in `@yourcompany.com`). |
| 25 | + |
| 26 | +### Configure environment variables |
| 27 | + |
| 28 | +Update `wrangler.jsonc` with your Access application details: |
| 29 | + |
| 30 | +- `TEAM_DOMAIN`: Your Cloudflare One team domain (e.g., `https://<your-team-name>.cloudflareaccess.com`) |
| 31 | +- `POLICY_AUD`: Your application's [AUD tag](https://developers.cloudflare.com/cloudflare-one/access-controls/applications/http-apps/authorization-cookie/validating-json/#get-your-aud-tag) (found under **Access controls** > **Applications** > your app > **Basic information**) |
| 32 | + |
| 33 | +### Deploy |
| 34 | + |
| 35 | +```bash |
| 36 | +wrangler deploy |
| 37 | +``` |
| 38 | + |
| 39 | +### Test |
| 40 | + |
| 41 | +Test the remote server using [Inspector](https://modelcontextprotocol.io/docs/tools/inspector): |
| 42 | + |
| 43 | +```bash |
| 44 | +npx @modelcontextprotocol/inspector@latest |
| 45 | +``` |
| 46 | + |
| 47 | +Enter `https://mcp-access-self-hosted.<your-subdomain>.workers.dev/mcp` and connect. You will be prompted to log in through your Access identity provider. |
| 48 | + |
| 49 | +### Connect from Claude Desktop |
| 50 | + |
| 51 | +Open Claude Desktop, go to Settings > Developer > Edit Config, and add: |
| 52 | + |
| 53 | +```json |
| 54 | +{ |
| 55 | + "mcpServers": { |
| 56 | + "access-self-hosted": { |
| 57 | + "type": "http", |
| 58 | + "url": "https://mcp-access-self-hosted.<your-subdomain>.workers.dev/mcp" |
| 59 | + } |
| 60 | + } |
| 61 | +} |
| 62 | +``` |
| 63 | + |
| 64 | +### Local Development |
| 65 | + |
| 66 | +```bash |
| 67 | +wrangler dev |
| 68 | +``` |
| 69 | + |
| 70 | +Note: In local development, `Cf-Access-Jwt-Assertion` is not set by Access. You can test by manually setting the header or by using `cloudflared access` to tunnel through Access. |
0 commit comments