Fellow Aiden brew.link MCP server
Fellow Aiden brew.link MCP server
A remote MCP server on Cloudflare Workers that turns a Fellow Aiden brew profile into a shareable brew.link URL. It exposes two tools: a local-only profile validator and an explicitly mutating tool that creates a profile through Fellow's private API and returns its share link. It works with native Streamable HTTP clients such as Codex and Claude Code, while retaining the existing Claude.ai browser-connector path.
Built with Cloudflare's agents SDK (McpAgent, a Durable Object per session) over the Streamable HTTP transport at /mcp, plus @modelcontextprotocol/sdk and zod.
Tools
Tool | What it does |
| External write; require approval. Validates the profile, then |
| Read-only. Validates the profile against every Aiden constraint without calling Fellow's API. Returns |
Profile input schema
All fields are required (except profileType, which defaults to 0). Validated before any API call:
Field | Type | Constraint |
| integer | use |
| string | 1–50 chars, charset |
| number | one of |
| boolean | |
| number | one of |
| integer |
|
| number | one of |
| boolean | |
| integer |
|
| integer |
|
| number[] | each one of |
| boolean | |
| integer |
|
| integer |
|
| number[] | each one of |
Project layout
src/
index.ts MCP server (McpAgent), the two tools, CORS + auth gate + routing
fellow.ts Fellow API client: login → devices → create profile → share (401 re-login retry)
profile.ts zod schema + cross-field length validation
env.d.ts secret typings merged into the generated Env
wrangler.jsonc Worker config (Durable Object binding MCP_OBJECT + migration)
test-tool.ps1 end-to-end handshake test (calls a tool and prints the result)1. Install
npm install2. Set the three secrets
The Worker reads three secrets from env — never hardcode them. Set each in your deployed Worker:
npx wrangler secret put FELLOW_EMAIL
npx wrangler secret put FELLOW_PASSWORD
npx wrangler secret put MCP_AUTH_TOKENFELLOW_EMAIL/FELLOW_PASSWORD— your Fellow account login (the same one the Fellow app uses).MCP_AUTH_TOKEN— a long random string you choose. It gates the/mcpendpoint so only your connector can call it. Generate one with:[Convert]::ToBase64String((1..32 | ForEach-Object { Get-Random -Max 256 }))
Windows / PowerShell gotcha: do not pipe a value into
wrangler secret put(e.g.echo $x | wrangler secret put …) — PowerShell prepends a UTF‑8 BOM and the stored secret gets a hidden leading character, so logins/auth then fail mysteriously. Instead run the command with no pipe and paste the value at the interactive prompt, or pipe throughcmd:cmd /c "type secret.txt" | npx wrangler secret put FELLOW_PASSWORD.
Local development
For npm run dev, copy .dev.vars.example to the gitignored .dev.vars. Use a distinct, non-production local token. Validation-only tests do not call Fellow, so their Fellow credentials should also remain isolated placeholders:
FELLOW_EMAIL=local-validation@example.invalid
FELLOW_PASSWORD=local-validation-placeholder
MCP_AUTH_TOKEN=local-validation-token-not-a-secretnpm run dev # http://127.0.0.1:8787 (MCP at /mcp, health at /health)Wrangler reads these values from .dev.vars; do not supply a real token with wrangler --var or expand one into the command line.
3. Deploy
npm run deployWrangler prints the public URL. Your MCP endpoint is that URL + /mcp:
https://fellow-aiden-mcp.<your-workers-subdomain>.workers.dev/mcp(If this is your first Worker, Cloudflare will prompt you to register a free *.workers.dev subdomain.)
4. Authentication model
The /mcp endpoint requires the MCP_AUTH_TOKEN shared secret, accepted two ways so every client works:
Authorization: Bearer <MCP_AUTH_TOKEN>header — used by curl, Codex, Claude Code, and API MCP clients.?token=<MCP_AUTH_TOKEN>query param on the URL — used by Claude.ai web, whose "Add custom connector" UI currently has no field for a bearer token or custom header (only OAuth client ID/secret). Putting the secret in the URL is the practical way to authenticate the web connector.
/health is open (no auth) for liveness checks. Requests with a missing/wrong token get HTTP 401.
5. Test end-to-end (before wiring a client)
A full test run uses four Streamable HTTP messages (initialize → notifications/initialized → tools/list → tools/call) that share an Mcp-Session-Id. The included test-tool.ps1 does this for you and verifies each tool's read/write annotation. It reads MCP_AUTH_TOKEN inside the PowerShell process, first from the process environment and then from the gitignored .dev.vars; it does not accept a token argument and does not launch a child process containing the token.
# Local validation with isolated placeholder values in .dev.vars
# (no Fellow API call and no profile created):
./test-tool.ps1 -Url "http://127.0.0.1:8787/mcp" -ValidateOnly
# To validate a deployed endpoint without mutating Fellow, set MCP_AUTH_TOKEN in
# the process environment that launches PowerShell, then use -ValidateOnly:
./test-tool.ps1 -Url "https://fellow-aiden-mcp.<subdomain>.workers.dev/mcp" -ValidateOnlyDo not put real tokens in command arguments, wrangler --var, curl headers, or test URLs: process listings, shell history, and terminal transcripts may retain them. A full run without -ValidateOnly creates a real Fellow profile and must be performed only when that mutation is explicitly intended.
Raw curl
Health (no auth):
curl https://fellow-aiden-mcp.<subdomain>.workers.dev/healthWrong/no token is rejected:
curl -i -X POST "https://fellow-aiden-mcp.<subdomain>.workers.dev/mcp" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
--data '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}'
# -> HTTP/1.1 401 UnauthorizedFor authenticated MCP requests, use test-tool.ps1 or a client that sources bearer credentials from an environment variable. The raw curl examples intentionally cover only unauthenticated health and rejection checks so a real credential is never expanded into curl's process arguments.
6. Add it to Codex
Codex supports remote Streamable HTTP servers and can source a bearer token from the environment. Keep the endpoint free of query secrets and use a dedicated local variable for the connector token:
# ~/.codex/config.toml
[mcp_servers.fellow-aiden]
url = "https://fellow-aiden-mcp.<your-workers-subdomain>.workers.dev/mcp"
bearer_token_env_var = "FELLOW_AIDEN_MCP_AUTH_TOKEN"
enabled = true
enabled_tools = ["create_aiden_brew_link", "validate_aiden_profile"]
default_tools_approval_mode = "prompt"
[mcp_servers.fellow-aiden.tools.validate_aiden_profile]
approval_mode = "approve"
[mcp_servers.fellow-aiden.tools.create_aiden_brew_link]
approval_mode = "prompt"Set FELLOW_AIDEN_MCP_AUTH_TOKEN in the environment that launches Codex to the same value as the Worker's MCP_AUTH_TOKEN, then start a fresh Codex session. validate_aiden_profile may run automatically because it is local and read-only; create_aiden_brew_link remains approval-gated because it writes a real profile and share link.
Do not place the token in the URL or directly in config.toml. The query-token compatibility path described below exists only for the browser connector that cannot send a custom bearer header.
7. Add it to Claude.ai (web) as a custom connector
Go to Settings → Connectors → Add custom connector.
Remote MCP server URL: paste your endpoint with the token in the URL:
https://fellow-aiden-mcp.<subdomain>.workers.dev/mcp?token=<MCP_AUTH_TOKEN>Leave Advanced settings (OAuth Client ID/Secret) blank — this server uses the URL token, not OAuth.
Save. Claude will connect and discover
create_aiden_brew_linkandvalidate_aiden_profile. In a chat, enable the connector and ask Claude to create a brew profile; it returns abrew.link.
Why the token is in the URL: Claude.ai's web connector UI has no bearer-token/header field (only OAuth). The query-param token is the supported way to authenticate. Treat the full URL (with token) as a secret. If you'd rather not put a secret in a URL, the alternative is to implement OAuth via Cloudflare's
workers-oauth-provider— a larger change.
Claude Code / API connector
Use the header form with the client's secure environment-variable or secret-store support. Do not embed the bearer value in a CLI argument, checked-in configuration, or URL.
Scripts
npm run dev wrangler dev (local, reads .dev.vars)
npm run deploy wrangler deploy
npm run type-check tsc --noEmit
npm run cf-typegen regenerate worker-configuration.d.ts after wrangler.jsonc changesNotes & limitations
Single brewer assumed. The brewer id is read from
GET /devices?dataType=realelement[0]. Multi-brewer accounts would need a selector.401 handling. Any Fellow call returning
401triggers one re-login + retry, per Fellow's API behavior.No persistence. The server is stateless per call (the Durable Object only backs MCP session transport); nothing about your brews is stored.
Unofficial API. Endpoints/headers are reverse-engineered from the open-source
9b/fellow-aidenpackage and may change without notice.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/ga815647/fellow-aiden-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server