convergence-gambit-mcp

convergence-gambit-mcp

Connects Claude to the campaign's LegendKeeper wiki, allowing interaction with campaign resources, charter, and planned tools for NPCs and locations.

Category
Visit Server

README

The Convergence Gambit MCP Server

Bespoke, single-tenant MCP server connecting Claude to the campaign's LegendKeeper wiki. Two clients, one project, design philosophy baked into source. No multi-tenancy, no database, no apologies.

Current state: walking skeleton, now behind GitHub OAuth. No LK API key yet, LegendKeeper calls backed by an in-memory fake seeded with campaign data. Every tool now sits behind OAuth (see "Authentication" below) — only GitHub account Kishotta is ever issued a token. Its job is to prove the full path: Claude mobile app → custom connector → GitHub login → Cloudflare Worker → LegendKeeperClient seam.

Skeleton toolset

Tool Purpose
ping Proves the transport.
get_charter Serves the Architecture & Presentation Charter verbatim.
list_resources Proves the client seam (fake-backed).
get_resource Proves parameterized reads.

Setup (day one)

Prereqs: Node 18+, a free Cloudflare account.

npm install
npx wrangler login        # opens browser, authorizes wrangler
npm run typecheck         # sanity check
npm run dev               # local server at http://localhost:8787/mcp
npx wrangler deploy       # → https://convergence-gambit-mcp.<account>.workers.dev

Optional local verification before deploying:

npx @modelcontextprotocol/inspector
# connect to http://localhost:8787/mcp (Streamable HTTP)
# Inspector will walk you through the GitHub login popup — see Authentication below

Then on the phone: Customize → Connectors → Add custom connector, paste https://convergence-gambit-mcp.<account>.workers.dev/mcp. Claude will prompt a GitHub login before the connector activates. Once connected, ask Claude to ping and list_resources. If Morte comes back, the skeleton walks.

Authentication

Every tool sits behind GitHub OAuth (@cloudflare/workers-oauth-provider + a GitHub-OAuth defaultHandler, in src/auth/). No token is ever issued to any GitHub account other than Kishotta — the callback in src/auth/github-handler.ts rejects everyone else with a 403 before completeAuthorization is ever called. This is stricter than Cloudflare's own reference pattern (which authenticates any GitHub user and just hides extra tools) because the campaign data behind these tools is spoiler-sensitive, not just at mutation risk.

One-time setup, before wrangler dev or deploy will work:

  1. Create two GitHub OAuth Apps at github.com/settings/developers → OAuth Apps → New OAuth App:
    • Dev: Authorization callback URL http://localhost:8787/callback
    • Prod: Authorization callback URL https://convergence-gambit-mcp.<account>.workers.dev/callback (or the custom domain, once phase 3 lands — a new callback URL is needed on that cutover too)
  2. Create the KV namespace OAuthProvider needs for state + client-approval storage (already done for this repo; re-run only if it's ever deleted):
    npx wrangler kv namespace create OAUTH_KV
    # paste the resulting id into wrangler.jsonc's kv_namespaces binding
    
  3. Local dev: copy .dev.vars.example to .dev.vars (gitignored) and fill in the dev app's client id/secret, plus a random COOKIE_ENCRYPTION_KEY (any random string — used to HMAC-sign the client-approval cookie):
    node -e "console.log(crypto.randomUUID())"
    
  4. Production secrets, from the prod app:
    npx wrangler secret put GITHUB_CLIENT_ID
    npx wrangler secret put GITHUB_CLIENT_SECRET
    npx wrangler secret put COOKIE_ENCRYPTION_KEY   # can reuse the dev value or generate a new one
    

Once all three secrets exist in both places, npm run dev / wrangler deploy work as before, just with GitHub login gating /mcp and /sse.

Two different "Client ID"s — don't cross them. This tripped us up on first deploy. There are two unrelated OAuth relationships stacked here:

Who authenticates to whom Where the credential lives
GitHub OAuth App our Worker → github.com wrangler secret put GITHUB_CLIENT_ID / _SECRET — never touched by Claude
This server's own OAuth clients Claude → our Worker auto-registered by Claude itself via /register (RFC 7591) — nobody ever types this in

When adding the custom connector in Claude, enter only the server URL and leave any Client ID / Client Secret fields blank. If you paste the GitHub OAuth App's credentials into Claude's connector setup, /authorize will fail with Invalid client. The clientId provided does not match to this client. (thrown by @cloudflare/workers-oauth-provider when it can't find that client_id in OAUTH_KV — because it was never registered there in the first place). Also: Worker secrets and KV are different storage systems — don't add GITHUB_CLIENT_ID etc. as KV key-value pairs in the OAUTH_KV namespace's dashboard browser; wrangler secret put (or the dashboard's Variables & Secrets tab) is the only thing that actually reaches env.GITHUB_CLIENT_ID in the Worker.

Version drift note. The agents package (Cloudflare's McpAgent) moves fast. If npm install or typecheck complains, scaffold Cloudflare's current authless remote-MCP template into a scratch directory (npm create cloudflare@latest -- scratch --template=cloudflare/ai/demos/remote-mcp-authless), copy its package.json dependency versions and any changed McpAgent/serve idioms into this repo, and keep our src/ content. The template is the authority on plumbing; this repo is the authority on everything above the seam.

The seam

Everything meaningful lives behind one interface:

src/lk/types.ts   LegendKeeperClient + domain types (from the API screenshot)
src/lk/fake.ts    In-memory implementation, seeded with campaign articles
src/index.ts      MCP tools — talk only to the interface

When the real API ships, we add src/lk/http.ts implementing LegendKeeperClient against the v2 endpoints and swap one constructor call in index.ts. Tools never change at cutover.

Speculative type fields are tagged SPEC-DRIFT — grep for them when the real docs land.

Nightly backups (stub)

A cron trigger (0 9 * * * in wrangler.jsonc) calls src/backup.ts nightly, which exports the project via LegendKeeperClient.exportProject() and writes a snapshot to the BACKUPS R2 bucket (convergence-gambit-backups), pruning anything older than 30 days.

Whether the real LegendKeeper API can export a whole project at all is unconfirmed (SPEC-DRIFT CRITICAL UNKNOWN #3 in src/lk/types.ts) — today this runs against the fake client, which proves the R2 storage and retention path end-to-end with fake data. When the real answer is known, only src/lk/client.ts needs to change.

One-time setup before this can deploy: R2 must be enabled on the Cloudflare account (dashboard only, not scriptable), then create the bucket:

npx wrangler r2 bucket create convergence-gambit-backups

To exercise the cron locally, with npm run dev already running: curl "http://localhost:8787/cdn-cgi/handler/scheduled".

Phases

  1. Walking skeleton (done) — authless, fake-backed, deployed, connected from the phone.
  2. Auth (done) — GitHub OAuth in front of every tool (see "Authentication" above), allowlisted to Kishotta only. Only now, with auth in place, is it safe to move on to real LegendKeeper credentials: npx wrangler secret put LK_API_KEY / LK_PROJECT_ID.
  3. Custom domain — point connoreaves.dev (or kishotta.com) DNS at Cloudflare, uncomment the route in wrangler.jsonc, redeploy to mcp.connoreaves.dev.
  4. Real client — src/lk/http.ts against the shipped API.
  5. Charter-aware tools — create_npc_article, create_location_article, stage_reveal, the markdown→LK converter. Designed only after phase 4 confirms the two critical unknowns.

Phases 4 and 5 both trigger on the same event (LegendKeeper publishing the v2 API docs) and are the reason this repo currently has nothing left to do — see docs/real-api-cutover.md for the full runbook for that day, written up in advance so it isn't reconstructed from scratch later.

The two critical unknowns (verify the day the docs drop)

  1. Does the API expose the visibility model? Element/tab/block secrecy is load-bearing for the whole architecture charter. If absent, every write tool must warn that a manual secrecy pass is required before the article is player-safe.
  2. What format do page documents accept? Expected: ProseMirror-style JSON, not markdown. The converter targets whatever this turns out to be; until then LKDocument.content is deliberately unknown.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured