8000 GitHub - ap-dev-github/mcp-harness: A custom agent loop in React that connects any model to any remote MCP server, with encrypted keys and per-action approval. Runs on Cloudflare. · GitHub
[go: up one dir, main page]

Skip to content

About

A custom agent loop in React that connects any model to any remote MCP server, with encrypted keys and per-action approval. Runs on Cloudflare.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

mcp-harness

A custom agent loop in React that plugs any model into any remote MCP server. One Cloudflare Worker serves the app and does everything that needs a secret.

Browser (React)                    Worker                          Outside
agent loop, approvals   ──────►   login, Vault (encrypted)  ─────► model APIs
sees text + results only          model adapters, MCP client ────► MCP servers

The only shipped dependencies are react and react-dom. The Worker has none.

Security model

  • Accounts: Google sign-in through Firebase. The Worker verifies the ID token, then uses its own signed HttpOnly session cookie. No Firebase token stays in the browser.

  • Isolation: each user has their own Vault Durable Object and their own AES-256 key, derived from ENCRYPTION_KEY and their user id.

  • Secrets: model keys and MCP tokens are write-only and never reach the browser.

  • Rate limits (src/worker/limits.ts): per IP and per user, in the RateLimiter Durable Object.

    Scope Limit
    Any API call, per IP 240 / minute
    Login, per IP 10 / minute, 60 / hour
    Model calls, per user 30 / minute, 500 / day
    Tool calls, per user 60 / minute, 2000 / day
    Settings changes, per user 30 / minute, 300 / day
    MCP sign-ins, per user 10 / minute, 50 / day
  • Other limits: 10 models and 10 servers per user, 2 MB per chat request, 256 KB per tool call.

  • Outbound URLs: public https only, no redirects with secrets, and changing a model's URL drops its key. Production also sets global_fetch_strictly_public.

  • Browser: strict CSP and security headers in public/_headers. Other sites can't send state-changing requests.

  • Tools: anything not marked read-only needs approval in the chat.

  • Deletion: Settings → Delete my data wipes the user's vault.

Models

Add a URL, key and model id. The format is detected from the URL, or pick one:

Format Example URL Also covers
OpenAI-compatible https://api.openai.com/v1 OpenRouter, Groq, Mistral, DeepSeek, vLLM…
Claude https://api.anthropic.com
Gemini https://generativelanguage.googleapis.com/v1beta

Set up

You need Node 22+, a Cloudflare account and a Firebase project.

  1. In the Firebase console, create a project, then turn on Google under Authentication → Sign-in method.

  2. Copy the project id and the Web API key from Project settings. The Web API key identifies the project in browsers; it isn't a password.

  3. Configure the app:

    cp wrangler.example.toml wrangler.toml    # set your Firebase project id and auth domain
    cp .dev.vars.example .dev.vars            # set ENCRYPTION_KEY and FIREBASE_API_KEY
    npm install
    

    wrangler.toml and .dev.vars are gitignored. Generate ENCRYPTION_KEY with openssl rand -base64 48.

Run locally

npm run dev                       # http://localhost:8787

Use localhost, not 127.0.0.1. The dev env may connect to MCP servers running on localhost.

Deploy

npx wrangler login
npm run "deploy prod"
npx wrangler secret put ENCRYPTION_KEY --env production    # use a new key, not your dev one
npx wrangler secret put FIREBASE_API_KEY --env production

This creates the mcp-harness-production Worker, which serves both the app and the API, with its Durable Objects. No KV or D1 setup is needed.

Then add the Worker's hostname under Firebase Authentication → Settings → Authorized domains, or Google sign-in will fail. A deployed harness can only reach public MCP servers.

Back up ENCRYPTION_KEY somewhere safe. If it's lost or changed, saved keys become unreadable and users must enter them again.

Current limits

  • Chats live in the page's memory and are gone on refresh.
  • The agent loop runs in the page, so closing the tab stops it.
  • Remote HTTP MCP servers only, using tools. No stdio, resources, prompts or elicitation.

License

MIT

About

A custom agent loop in React that connects any model to any remote MCP server, with encrypted keys and per-action approval. Runs on Cloudflare.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

0