fmg-mcp
README.md
# fmg-mcp
An MCP (Model Context Protocol) server that drives [Azgaar's Fantasy Map
Generator](https://azgaar.github.io/Fantasy-Map-Generator/) in a real browser
via Playwright, so Claude (or any MCP client) can generate maps, inspect
them, and export screenshots / SVG / JSON.
FMG is a client-side web app with no public API, so this server works by
puppeting an actual instance of the page — clicking buttons, filling
inputs, and reading its in-memory JS state — rather than reimplementing its
generation algorithms.
There are two ways to run this: **locally over stdio** (for Claude
Desktop/Code) or **remotely over HTTP** (to use as a "custom connector" URL
in claude.ai). Pick one.
## Option A: Local, stdio (Claude Desktop / Claude Code)
```bash
cd fmg-mcp
npm install
npx playwright install chromium # downloads a headless Chromium build
npm run build
```
Register it:
```json
{
"mcpServers": {
"fmg": {
"command": "node",
"args": ["/absolute/path/to/fmg-mcp/dist/stdio.js"],
"env": {
"FMG_HEADLESS": "true",
"FMG_OUTPUT_DIR": "/absolute/path/to/fmg-output"
}
}
}
}
```
Environment variables (all optional):
- `FMG_URL` — override the FMG URL (defaults to the GitHub Pages instance).
- `FMG_HEADLESS` — `"false"` to watch the browser while it works. Defaults to headless.
- `FMG_OUTPUT_DIR` — where screenshots/exports are written. Defaults to `./fmg-output`.
## Option B: Remote, HTTP (claude.ai "Add custom connector")
This runs the same tools over Streamable HTTP at `/mcp`, so you can host it
somewhere and give claude.ai the URL. It needs a real browser, so it must
run on a container/VM host, not a serverless/edge platform.
### Deploy on Render.com (free/starter tier, easiest)
1. Push this folder to a GitHub repo.
2. In Render: **New > Blueprint**, point it at the repo — it will pick up
`render.yaml` and `Dockerfile` automatically and build the image.
3. Render auto-generates an `AUTH_TOKEN` env var for you (see the service's
Environment tab) — copy it.
4. Once deployed, your MCP URL is `https://<your-service>.onrender.com/mcp`.
### Deploy anywhere else that runs Docker (Fly.io, Railway, a VPS, etc.)
```bash
docker build -t fmg-mcp .
docker run -p 8787:8787 -e AUTH_TOKEN=$(openssl rand -hex 24) fmg-mcp
```
Put whatever host/domain that ends up behind at `https://your-host/mcp`.
### Add it to claude.ai
Settings → Connectors → **Add custom connector**, then:
- **URL**: `https://your-host/mcp`
- If you set `AUTH_TOKEN`, choose the auth option that lets you supply a
bearer token, and paste the token value in.
⚠️ **Security note:** anyone with the URL *and* token can drive a real
browser through your server. Always set `AUTH_TOKEN` on anything reachable
from the public internet — don't leave it unset outside of local testing.
### Notes on the HTTP deployment
- Playwright's official Docker base image (`mcr.microsoft.com/playwright`)
is used so Chromium and its OS dependencies are already present — no
extra `apt-get`/`playwright install` step needed in the container.
- The server keeps one browser page per MCP session (keyed by the
`Mcp-Session-Id` header the SDK manages automatically), so map state
persists across tool calls within a conversation, same as the stdio
version.
- Free hosting tiers that spin containers down when idle will lose
in-memory map state between calls — fine for occasional use, but if you
want state to reliably survive idle periods, use a plan that keeps the
container warm.
## Tools
| Tool | What it does |
|---|---|
| `open_map` | Launches/reuses the browser session and waits for FMG to load. Call first. |
| `new_map` | Generates a new map, optionally with a specific seed and/or heightmap template. |
| `get_map_info` | Reads seed, dimensions, and counts of cultures/states/burgs/religions from the page state. |
| `screenshot` | Saves a PNG of the map (or full page) to the output directory. |
| `export_svg` | Saves the live map SVG to a `.svg` file. |
| `export_json` | Best-effort dump of FMG's internal `pack`/`grid`/`notes` data to JSON. |
| `click` | Clicks any element by CSS selector — for UI FMG doesn't have a dedicated tool for. |
| `inspect_globals` | Lists map-related `window` globals FMG currently exposes, to help you write `run_js` calls. |
| `run_js` | Evaluates arbitrary JS in the page (e.g. calling FMG's own save/generate functions directly). |
| `close_browser` | Closes the browser session. |
## A note on fragility
FMG doesn't publish a stable API, and its internal function/variable names
and UI selectors have changed across versions over the project's history.
The tools above use the most common/longstanding selectors and globals
(`#regenerateMap`, `window.pack`, `window.seed`, etc.), but if the deployed
version has drifted:
1. Use `inspect_globals` and `run_js` to poke around and find the current
equivalents (e.g. `run_js` with `"Object.keys(window).filter(k => /gener/i.test(k))"`).
2. Use `click` with browser devtools-inspected selectors as a fallback for
any UI action not covered by a dedicated tool.
## Example session
```
open_map
new_map { "seed": "123456789", "template": "Continents" }
get_map_info
screenshot { "fileName": "continents.png" }
export_svg { "fileName": "continents.svg" }
```
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues