convergence-gambit-mcp
Connects Claude to the campaign's LegendKeeper wiki, allowing interaction with campaign resources, charter, and planned tools for NPCs and locations.
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:
- 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)
- Dev: Authorization callback URL
- 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 - Local dev: copy
.dev.vars.exampleto.dev.vars(gitignored) and fill in the dev app's client id/secret, plus a randomCOOKIE_ENCRYPTION_KEY(any random string — used to HMAC-sign the client-approval cookie):node -e "console.log(crypto.randomUUID())" - 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 ClaudeThis server's own OAuth clients Claude → our Worker auto-registered by Claude itself via /register(RFC 7591) — nobody ever types this inWhen 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,
/authorizewill fail withInvalid client. The clientId provided does not match to this client.(thrown by@cloudflare/workers-oauth-providerwhen it can't find that client_id inOAUTH_KV— because it was never registered there in the first place). Also: Worker secrets and KV are different storage systems — don't addGITHUB_CLIENT_IDetc. as KV key-value pairs in theOAUTH_KVnamespace's dashboard browser;wrangler secret put(or the dashboard's Variables & Secrets tab) is the only thing that actually reachesenv.GITHUB_CLIENT_IDin the Worker.
Version drift note. The
agentspackage (Cloudflare'sMcpAgent) moves fast. Ifnpm installortypecheckcomplains, 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 itspackage.jsondependency versions and any changedMcpAgent/serveidioms into this repo, and keep oursrc/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
- Walking skeleton (done) — authless, fake-backed, deployed, connected from the phone.
- Auth (done) — GitHub OAuth in front of every tool (see
"Authentication" above), allowlisted to
Kishottaonly. 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. - Custom domain — point
connoreaves.dev(orkishotta.com) DNS at Cloudflare, uncomment the route inwrangler.jsonc, redeploy tomcp.connoreaves.dev. - Real client —
src/lk/http.tsagainst the shipped API. - 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)
- 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.
- What format do
pagedocuments accept? Expected: ProseMirror-style JSON, not markdown. The converter targets whatever this turns out to be; until thenLKDocument.contentis deliberatelyunknown.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。