firefox-relay-mcp
by nazar256
README.md
# Firefox Relay MCP Gateway
[](https://github.com/nazar256/firefox-relay-mcp/actions/workflows/ci.yml)
[](LICENSE)
Stateless Streamable HTTP MCP gateway for Firefox Relay, built for Cloudflare Workers.
## Features
- Stateless remote MCP server for Firefox Relay
- OAuth Authorization Code + PKCE (`S256`) for MCP clients
- Encrypted Firefox Relay API key envelope inside signed JWT artifacts
- Streamable HTTP MCP endpoint at `/mcp`
- Random mask list/create/update/disable operations
- Optional custom-domain mask listing when the Relay account supports it
## Requirements
- Node.js 20+
- npm
- Cloudflare account with Wrangler authentication
- A Firefox Relay account with an API key
## Connector values
```text
MCP Server URL: https://firefox-relay-mcp.xyofn8h7t.workers.dev/mcp
Authorization server base URL: https://firefox-relay-mcp.xyofn8h7t.workers.dev
Resource: https://firefox-relay-mcp.xyofn8h7t.workers.dev/mcp
```
## Use the hosted MCP in ChatGPT
The currently deployed production MCP endpoint is:
```text
https://firefox-relay-mcp.xyofn8h7t.workers.dev/mcp
```
### Connector details
Use these values when ChatGPT asks for the custom app or connector details:
```text
Name: Firefox Relay
Description: Manage Firefox Relay email masks: list, create, update, and disable random masks, and list custom-domain masks.
MCP server URL: https://firefox-relay-mcp.xyofn8h7t.workers.dev/mcp
Icon: assets/firefox-relay-icon.png
```
The repository includes a square PNG icon at [`assets/firefox-relay-icon.png`](assets/firefox-relay-icon.png). It is provided only to identify Firefox Relay compatibility. Firefox Relay is a trademark of the Mozilla Foundation; this project is independent and is not affiliated with or endorsed by Mozilla. The source icon is the [official Mozilla Relay icon](https://www.mozilla.org/media/img/nav/icons/icon-relay.aca61c9bb349.svg).
### Add and authorize it
ChatGPT’s labels vary by plan and workspace. OpenAI currently documents custom MCP apps under **Settings → Apps**; some accounts may show **Plugins** or **custom connectors** instead. Workspace administrators may need to enable developer mode or custom MCP connectors first.
1. Open ChatGPT on the web and go to **Settings → Apps** (or open the **Plugins** directory if that is what your account shows).
2. Choose **Create**, **Add custom app**, **Add connector**, or the equivalent **+** button.
3. Enter the connector details above. Upload `assets/firefox-relay-icon.png` as the icon.
4. For the connection authentication method, choose **OAuth**. The MCP URL is the server URL above; the Relay API key is entered during the browser authorization step, not in the connector description.
5. If ChatGPT shows **Scan tools**, run the scan and then choose **Create** or **Save**.
6. When the authorization page opens, open [Firefox Relay](https://relay.firefox.com) in another tab and sign in.
7. In Firefox Relay, open the **profile icon → Settings**, locate your API key, and copy it. Do not paste the key into a chat message or commit it to a repository.
8. Return to the authorization page, paste the API key into the **Firefox Relay API key** field, choose the token lifetime, and submit the consent form.
9. Return to ChatGPT. In a new chat, select **+ → More → Firefox Relay** (or mention the connected app) and ask it to manage your masks.
This gateway can list, create, update, and disable masks. Disabling is reversible; delete-mask tooling is intentionally not exposed in v1. Custom-domain listing depends on the Relay account.
For the official ChatGPT setup terminology and workspace requirements, see [Apps in ChatGPT](https://help.openai.com/en/articles/11487775-connectors-in) and [Developer mode and MCP apps in ChatGPT](https://help.openai.com/en/articles/12584461-developer-mode-and-mcp-apps-in-chatgpt).
## What it does
- Exposes MCP Streamable HTTP at `/mcp`
- Acts as its own OAuth Authorization Server for remote MCP clients
- Collects a user-provided Firefox Relay API key during OAuth consent
- Encrypts that API key into signed JWT artifacts and does not store it in a database
- Lets MCP clients list, create, update, and disable Firefox Relay masks
## Firefox Relay API key
Users can find the Firefox Relay API key in Firefox Relay under **profile icon → Settings**.
## Supported MCP tools
- `relay_list_random_masks`
- `relay_create_random_mask`
- `relay_update_random_mask`
- `relay_disable_random_mask`
- `relay_list_domain_masks`
## Install
```bash
npm install
```
## Quick start
1. Install dependencies.
2. Set Worker secrets.
3. Configure non-secret vars in `wrangler.toml` or via deploy-time environment overrides.
4. Run `npm run dev` for local testing.
5. Run `npm test` and `npm run typecheck`.
6. Deploy with `npm run deploy`.
## Configure non-secret Worker vars
Update `wrangler.toml` or your deployment environment with:
- `OAUTH_ISSUER`
- `MCP_RESOURCE`
- `MCP_AUDIENCE`
- `OAUTH_REDIRECT_HTTPS_HOSTS`
- `RELAY_DEFAULT_BASE_URL`
- `ACCESS_TOKEN_DEFAULT_TTL_DAYS`
- `ACCESS_TOKEN_MAX_TTL_DAYS`
- `AUTH_CODE_TTL_SECONDS`
`wrangler.toml` intentionally keeps placeholder URLs for independent deployments. If you deploy your own Worker, replace them with that deployment's values before production:
- `OAUTH_ISSUER=https://your-worker.example.com`
- `MCP_RESOURCE=https://your-worker.example.com/mcp`
- `MCP_AUDIENCE=https://your-worker.example.com/mcp`
## Set Worker secrets
Generate and pipe each secret directly into Wrangler:
```bash
openssl rand -base64 48 | tr -d '\n' | wrangler secret put OAUTH_JWT_SIGNING_KEY_B64
openssl rand -base64 32 | tr -d '\n' | wrangler secret put UPSTREAM_CONFIG_ENC_KEY_B64
openssl rand -base64 48 | tr -d '\n' | wrangler secret put CSRF_SIGNING_KEY_B64
```
## Deploy sequence
If you do not know the final public Worker URL yet, use this order:
1. Bootstrap deploy once to get the real `workers.dev` URL.
2. Set the three Worker secrets.
3. Redeploy with real `OAUTH_ISSUER`, `MCP_RESOURCE`, and `MCP_AUDIENCE` values.
## Run locally
```bash
npm run dev
```
## Validate
```bash
npm test
npm run typecheck
```
## Deploy
```bash
npm run deploy
```
## Public connector values
After deployment, configure remote MCP clients with:
```text
MCP Server URL: https://firefox-relay-mcp.xyofn8h7t.workers.dev/mcp
Authorization server base URL: https://firefox-relay-mcp.xyofn8h7t.workers.dev
Resource: https://firefox-relay-mcp.xyofn8h7t.workers.dev/mcp
```
## OAuth and stateless design summary
- `/register` issues deterministic public `client_id` values for allowlisted redirect URIs
- `/authorize` validates PKCE S256, renders consent, validates the Firefox Relay API key, and issues a short-lived signed auth-code JWT
- `/token` exchanges the auth code for bearer access and refresh JWTs
- JWTs carry an AES-GCM encrypted Relay config envelope; plaintext credentials are never persisted server-side
- `/mcp` verifies the access token, decrypts the Relay config, creates a fresh Worker-safe MCP server and transport, and serves the request
## Stateless caveats
- Auth codes are not one-time-use across all isolates because no server-side state is stored
- Refresh tokens cannot be globally revoked without a stateful primitive
- Strict global rate limiting requires Durable Objects, KV, or Cloudflare-managed rate limiting
## Manual smoke test notes
1. Register a client with an allowlisted redirect URI.
2. Complete `/authorize` with a Firefox Relay API key.
3. Exchange the returned code at `/token`.
4. Call `/mcp` with the returned bearer token.
5. Confirm tools list and successful mask operations.
## Privacy and security notes
- The Worker encrypts the Firefox Relay API key into MCP JWT artifacts and does not store it in a database.
- The Worker is designed to avoid logging API keys, bearer tokens, decrypted envelopes, cookies, or CSRF tokens.
- Upstream Relay errors are sanitized before they are returned to MCP clients.
## Known limitations
- Auth codes are not globally one-time-use without stateful storage.
- Refresh tokens cannot be globally revoked without stateful storage.
- Strict global rate limiting requires Durable Objects, KV, or a Cloudflare-managed alternative.
- Domain-mask behavior depends on account capabilities and may require Relay premium/custom-domain support.
## Project docs
- `docs/PRODUCT_REQUIREMENTS.md`
- `docs/IMPLEMENTATION_PLAN.md`
- `docs/PROJECT_STATE.md`
- `docs/DECISIONS.md`
- `docs/RUNBOOK.md`
## Contributing
See `CONTRIBUTING.md`.
## Security
See `SECURITY.md`.
## License
MIT
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues