Implementation Notes
Table of contents
Architecture
This MCP server uses a hybrid architecture combining GitHub Pages (for data hosting) and Cloudflare Workers (for MCP protocol implementation):
System Components
- GitHub Pages (Data Layer)
- Hosts static TTRPG data in
/data/*.json - Serves documentation and website
- Free, globally distributed via GitHub’s CDN
- Hosts static TTRPG data in
- Cloudflare Worker (Server Layer)
- Implements MCP using the official TypeScript SDK (
@modelcontextprotocol/sdk) - Uses Streamable HTTP transport in JSON response mode (no SSE)
- Fetches data from GitHub Pages on-demand
- Executes tool logic (random selection, generation)
- Deployed at:
https://ttrpg-mcp.tedt.org/mcp
- Implements MCP using the official TypeScript SDK (
File Structure
GitHub Pages:
data/*.json- Public TTRPG data (encounters, names, locations, etc.)mcp.json.md- Server manifest template (published as/mcp.json)- Documentation pages (README, guides, etc.)
demo.md- Interactive demo page
Cloudflare Worker:
cloudflare-mcp-server/src/index.ts- Worker entrypoint and/mcproutingcloudflare-mcp-server/src/mcp/server.ts- Registers tools/resources/prompts onMcpServercloudflare-mcp-server/src/tools/registry.ts- Central tool registry (Zod schemas)cloudflare-mcp-server/src/data/fetch.ts- JSON fetch with in-memory + Cache API cachingcloudflare-mcp-server/wrangler.toml- Worker configuration- Implements: tools/resources/prompts via MCP SDK handlers
How It Works
┌─────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ MCP Client │ ─HTTP──→│ Cloudflare Worker│ ─GET───→│ GitHub Pages │
│ (VS Code, │ ←JSON──┤ (MCP Protocol) │ ←JSON──┤ (Data Files) │
│ Claude) │ │ /mcp endpoint │ │ /data/*.json │
└─────────────┘ └──────────────────┘ └─────────────────┘
MCP uses JSON-RPC messages under the hood. This Worker responds with JSON (no SSE) and is designed to be stateless.
Request Flow Example
- Client connects: Sends
initializemethod to/mcp - Worker responds: Returns capabilities (tools, resources, prompts)
- Client requests tools: Sends
tools/listmethod - Worker returns: 7 tool definitions
- Client calls tool:
tools/callwithgenerate_npc_name - Worker fetches data: Gets
names.jsonfrom GitHub Pages - Worker generates: Randomly selects a name
- Worker returns: JSON-RPC response with result
Why This Architecture?
Advantages:
- ✅ Free hosting: Both GitHub Pages and Cloudflare Workers have generous free tiers
- ✅ Global distribution: CDN on both layers for fast access worldwide
- ✅ Full MCP protocol: Proper JSON-RPC 2.0 implementation
- ✅ Scalable: Can handle thousands of requests
- ✅ Version controlled: All data and code in Git
- ✅ No database needed: Static JSON files are sufficient
- ✅ Easy updates: Push to GitHub to update data, deploy worker for code changes
Limitations:
- ⚠️ Read-only: Cannot modify data from the MCP client
- ⚠️ No state persistence: Each request is independent
- ⚠️ Static data: Requires rebuild/deploy to update
Future Enhancements
- Add more data:
- More encounter types
- Additional name cultures
- Expanded treasure tables
- More plot hooks
- Create generation examples:
- Add sample JavaScript generation code
- Provide Python reference implementation
- Document generation algorithms
- Improve schemas:
- Add more detailed validation
- Include examples in tool schemas
- Better error descriptions
- Add resources:
- Full data dumps as resources
- Reference tables
- Rule summaries
Data Format Notes
Encounters
Organized by: environment → difficulty → array of encounters Each encounter has: name, creatures, description
Names
Organized by: race → gender → array of names
Locations
Organized by: type → prefixes/suffixes Names generated by combining prefix + suffix
Personality Traits
Flat arrays of: traits, ideals, bonds, flaws, quirks
Treasure
Organized by: type (individual/hoard) → CR range → currency dice
Weather
Organized by: climate → season (if applicable) → array of descriptions
Plot Hooks
Organized by: theme → array of hooks
Contributing
To add more content:
- Edit the appropriate JSON file in
data/ - Follow the existing structure
- Commit and push to GitHub
- Changes go live automatically on GitHub Pages
Operational Notes
/mcpacceptsPOST;GET /mcpreturns405- CORS is restricted via
ALLOWED_ORIGINS(comma-separated). Requests without anOriginheader are allowed. - Data reads are cached (in-memory + Cloudflare Cache API). TTL is controlled by
DATA_CACHE_TTL_SECONDS.
License
MIT License - Use freely for your campaigns!