Skip to main content
Glama
jkpe

mcp-fetch-worker

by jkpe

mcp-fetch-worker

A generic MCP connector for bots and agents that need to call your self-hosted APIs without handing over long-lived credentials.

Put Cloudflare Access in front of this Worker with Managed OAuth, and bots like Grok Bot or OpenClaw can connect via Dynamic Client Registration (DCR). You approve access when the bot first connects; revoke it any time from Access. The bot gets a scoped token tied to the connector, not a generic API key it can reuse elsewhere.

Production MCP URL: https://<your-domain>/mcp

Why this exists

Managed bots are good at tool calling, but most homelab and self-hosted apps don't ship an MCP server. You could:

  • Use a service token: persistent access via custom headers. Fine for scripts; risky for bots you don't fully trust.

  • Let the bot use Chrome: it opens your web UI, you sign in through SSO, repeat. Works, but burns tokens and doesn't scale.

  • Build a bespoke MCP per app: correct, but a lot of work for a Home Assistant API or a random internal dashboard.

This Worker is the middle ground: one thin MCP connector that exposes a single http_fetch tool. Point it at APIs on the same origin (already behind Access), and the bot can GET/POST them using the OAuth token you approved. No dedicated MCP server required on the other end.

See First World Problem: How do I grant my bots access to my stuff without it wrecking everything? for the full write-up.

Related MCP server: Cloudflare Control

How it works

Bot (Grok Bot, OpenClaw, Cursor, …)
  → OAuth via Cloudflare Access Managed OAuth (you approve)
  → MCP at /mcp (this Worker)
  → http_fetch to allowed origins on your domain
  → Access JWT forwarded on outbound requests
  1. Access handles authentication: Managed OAuth + DCR. The Worker is not an OAuth server; it validates the Cf-Access-Jwt-Assertion Access forwards.

  2. This Worker serves Streamable HTTP MCP with one tool: http_fetch.

  3. Your APIs sit on the same origin behind Access. Create Linked App Token policies so the forwarded JWT is accepted downstream.

Outbound fetches are restricted to the Worker's own origin by default (ALLOWED_ORIGINS overrides this).

What it does

  • Serves MCP at /mcp (and /sse as a legacy alias) using the Agents SDK createMcpHandler

  • Exposes one tool, http_fetch, for GET/POST requests against allowed origins

  • Validates Cf-Access-Jwt-Assertion against your team's JWKS when CF_ACCESS_TEAM_DOMAIN and CF_ACCESS_AUD are set

  • Forwards the caller's Access JWT on outbound fetches (Cf-Access-Jwt-Assertion, Cf-Access-Token, Authorization: Bearer)

Deploy

npm install
npm run cf-typegen   # regenerate Env types from wrangler.jsonc
npx wrangler deploy

Configuration lives in wrangler.jsonc. Workers Logs and Traces are enabled by default via the observability block.

Custom domain route

Add a Worker route in wrangler.jsonc (or via the dashboard):

"routes": [
  {
    "pattern": "example.com/mcp*",
    "zone_name": "example.com"
  }
]

Then redeploy. The MCP endpoint is https://<your-domain>/mcp.

Environment variables

Set in wrangler.jsonc vars, as secrets (wrangler secret put), or in .dev.vars for local dev (see .dev.vars.example):

Variable

Required

Description

CF_ACCESS_TEAM_DOMAIN

Production

https://<team>.cloudflareaccess.com

CF_ACCESS_AUD

Production

AUD tag from your Access application

ALLOWED_ORIGINS

No

Comma-separated fetch allowlist (default: Worker origin)

MAX_RESPONSE_BYTES

No

Truncate bodies above this size (default: 65536)

DEFAULT_HEADERS

No

JSON object of default outbound headers (secret; see below)

When CF_ACCESS_* vars are unset, the Worker still serves MCP (useful for wrangler dev) but does not validate Access JWTs. Set both vars in production.

Default headers for API keys

Store extra outbound headers as a Worker secret so http_fetch can call APIs that need a key without putting secrets in chat or baking one API into the Worker:

wrangler secret put DEFAULT_HEADERS
# paste: {"X-Api-Key":"your-key-here"}

For local dev, set a non-empty value in wrangler.jsonc vars, pass --var DEFAULT_HEADERS='{"X-Api-Key":"..."}' to wrangler dev, or use wrangler secret put on the deployed Worker. When secrets.required is configured, .dev.vars only loads those secret names, so put DEFAULT_HEADERS in vars or use --var locally.

DEFAULT_HEADERS must be a JSON object with string values, e.g. {"X-Api-Key":"..."}. On every http_fetch call, those headers are merged into the outbound request. Headers you pass in the tool call override defaults on name conflicts. Access JWT forwarding (Cf-Access-Jwt-Assertion, Cf-Access-Token, Authorization) always wins and cannot be overridden by defaults.

Unset or empty DEFAULT_HEADERS adds no extra headers.

Cloudflare Access setup

  1. Add a self-hosted Access application for your MCP URL (e.g. https://<your-domain>/mcp or a path covering /mcp*)

  2. Enable Managed OAuth on the application (Advanced settings); this enables DCR for MCP clients

  3. Copy the application's AUD tag into CF_ACCESS_AUD

  4. Set CF_ACCESS_TEAM_DOMAIN to your team domain (e.g. https://<team>.cloudflareaccess.com)

  5. Configure Access policies for who may connect: time-bound, email-based, or whatever fits your approval model

For downstream Access-protected APIs on the same origin, create Linked App Token policies on those applications so the forwarded JWT is accepted.

MCP client configuration

Paste this URL into Cursor, Grok Bot, OpenClaw, or any Streamable HTTP MCP client:

https://<your-domain>/mcp

Use Streamable HTTP transport (not legacy SSE). The client will OAuth through Access Managed OAuth on first connect; that's your human-in-the-loop approval step.

Local development

npm run dev

MCP is available at http://localhost:8787/mcp without Access validation.

http_fetch tool

{
  "url": "/api/example",
  "method": "GET"
}
  • url: absolute URL or same-origin path

  • method: GET (default) or POST

  • headers: optional extra headers (override DEFAULT_HEADERS on conflict)

  • body: optional POST body

DEFAULT_HEADERS (secret) are applied first; tool headers override them. Access JWT headers are always applied last.

Returns JSON with status, headers, body, and truncated flag.

F
license - not found
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to dynamically discover and invoke containerized tools that can be registered at runtime without redeployment. Built on Cloudflare Workers with scale-to-zero containers for secure, isolated tool execution.
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to manage Cloudflare infrastructure including DNS records, cache purging, SSL settings, Workers, and analytics through the Cloudflare API. Eliminates dashboard context-switching by allowing natural language control of domain management and infrastructure operations.
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI assistants to create and manage short URLs via the MCP protocol, with OAuth authentication through Cloudflare Access.
    12
    Apache 2.0

View all related MCP servers

Related MCP Connectors

  • Odoo ERP for AI agents: hosted OAuth endpoint, gated writes, one endpoint for every instance.

  • The bridge from K2 agents through Wrangler to your master AI - safe, approval-gated Cloudflare ops.

  • SaaS intelligence for AI agents. 5 unified tools cover 1,000+ services with 91-96% token savings.

View all MCP Connectors

Latest Blog Posts

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/jkpe/mcp-fetch-worker'

If you have feedback or need assistance with the MCP directory API, please join our Discord server