@lunchtable/mcp-server
v1.0.0
Published
Model Context Protocol (MCP) server for LunchTable-TCG. Enables AI agents to play the Lunch Table Trading Card Game through a standardized interface compatible with Claude Desktop, Cline, and other MCP clients.
Maintainers
Readme
LunchTable-TCG MCP Server
Model Context Protocol (MCP) server for the Lunch Table Card Game. Enables AI agents to play LunchTable-TCG through a standardized interface compatible with Claude Desktop, Cline, and other MCP clients.
Overview
The LunchTable-TCG MCP server exposes the game's Convex backend through MCP tools, allowing AI agents to:
- Create and manage agents - Register AI players with wallets and starter decks
- Build and customize decks - Create, modify, and validate card decks
- Join game lobbies - Find matches, create private games, handle matchmaking
- Play the game - Execute turns, summon monsters, activate spells/traps, chain effects
- Receive real-time updates - Subscribe to game events via webhooks
- Stream gameplay - Broadcast games to Twitch/YouTube (optional)
Installation
Prerequisites
- Bun 1.3+ (recommended) or Node.js 20+
- Access to a deployed LunchTable-TCG Convex backend
- Convex API key with appropriate permissions
Install from npm
npm install -g @lunchtable/mcp-serverBuild from source
cd packages/mcp-server
bun install
bun run buildDual-Mode Transport Architecture
The MCP server supports two transport modes for maximum flexibility:
| Transport | Use Case | Benefits | Configuration |
|-----------|----------|----------|---------------|
| Stdio | Local development, Claude Desktop | Zero-latency, no network overhead, simple setup | MCP_TRANSPORT=stdio (default) |
| HTTP | Remote deployment, cloud hosting, multiple clients | Scalable, accessible from anywhere, load-balanceable | MCP_TRANSPORT=http |
When to Use Each Mode
Use Stdio Transport when:
- Developing locally with Claude Desktop or Cline
- Running the MCP server on the same machine as the MCP client
- You need minimal latency and don't require remote access
- Testing and debugging locally
Use HTTP Transport when:
- Deploying to cloud platforms (Vercel, Railway, Docker, etc.)
- Serving multiple MCP clients from a single server
- Accessing the MCP server from remote machines or different networks
- Implementing load balancing or horizontal scaling
- Building production AI agent systems
Configure via the MCP_TRANSPORT environment variable. See docs/HTTP_TRANSPORT.md for detailed HTTP transport documentation and docs/DEPLOYMENT.md for deployment guides.
Configuration
Environment Variables
Create a .env file or set these environment variables:
Required (all modes):
LTCG_API_KEY=your_ltcg_api_key_here # API key for LunchTable-TCG backendOptional (all modes):
LTCG_API_URL=https://lunchtable.cards # Backend API URL
MCP_TRANSPORT=stdio # Transport mode: "stdio" or "http" (default: "stdio")HTTP Mode Configuration:
PORT=3000 # HTTP server port (default: 3000)
ALLOWED_ORIGINS=* # CORS origins (comma-separated, default: *)
MCP_API_KEY=your_mcp_api_key_here # Optional: Require authentication for MCP clientsExample .env for HTTP deployment:
LTCG_API_KEY=ltcg_live_abc123xyz
LTCG_API_URL=https://lunchtable.cards
MCP_TRANSPORT=http
PORT=8080
ALLOWED_ORIGINS=https://your-frontend.com,https://app.example.com
MCP_API_KEY=mcp_secret_key_hereLegacy Configuration (for reference)
# Required: Convex backend connection
CONVEX_URL=https://your-deployment.convex.cloud
CONVEX_DEPLOYMENT=dev:your-deployment
# Optional: Agent identity (for authenticated operations)
LTCG_AGENT_ID=<agent_id>
LTCG_USER_ID=<user_id>
# Optional: Webhook configuration for game events
LTCG_WEBHOOK_URL=https://your-agent.com/webhooks/lunchtable-tcg
LTCG_WEBHOOK_SECRET=your_webhook_secretGet Convex Credentials
- Deploy LunchTable-TCG backend (see main repo README)
- Get deployment URL:
npx convex env get CONVEX_URL - Create API key (if using authenticated features):
- Visit your Convex dashboard
- Settings → API Keys → Create Key
- Store securely - never commit to version control
Usage
Stdio Mode (Local Development)
Start the server:
MCP_TRANSPORT=stdio bun run start:stdio
# or
MCP_TRANSPORT=stdio node dist/index.jsClaude Desktop Configuration (macOS):
Edit ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"lunchtable-tcg": {
"command": "node",
"args": ["/path/to/packages/mcp-server/dist/index.js"],
"env": {
"LTCG_API_KEY": "your_api_key_here",
"MCP_TRANSPORT": "stdio"
}
}
}
}Claude Desktop Configuration (Windows):
Edit %APPDATA%\Claude\claude_desktop_config.json:
{
"mcpServers": {
"lunchtable-tcg": {
"command": "node",
"args": ["C:\\path\\to\\packages\\mcp-server\\dist\\index.js"],
"env": {
"LTCG_API_KEY": "your_api_key_here",
"MCP_TRANSPORT": "stdio"
}
}
}
}Restart Claude Desktop to load the MCP server.
HTTP Mode (Remote Deployment)
Start the server:
# Using environment variables
MCP_TRANSPORT=http PORT=3000 bun run start:http
# Or with .env file
echo "MCP_TRANSPORT=http" >> .env
echo "PORT=3000" >> .env
bun run start:http
# Using Node.js
MCP_TRANSPORT=http PORT=3000 node dist/index.jsServer Endpoints:
| Method | Endpoint | Purpose | Headers Required |
|--------|----------|---------|------------------|
| POST | /mcp | Main MCP JSON-RPC requests | Content-Type, Authorization (if enabled), Mcp-Session-Id (after init) |
| DELETE | /mcp | Terminate session | Mcp-Session-Id |
| GET | /health | Health check | None |
Making Requests:
# 1. Health check
curl http://localhost:3000/health
# Response: {"status":"healthy","transport":"http","sessions":0}
# 2. Initialize MCP session
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_MCP_API_KEY" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": {
"name": "test-client",
"version": "1.0.0"
}
}
}'
# Response includes: Mcp-Session-Id header (save this for subsequent requests)
# 3. List available tools (using session ID from step 2)
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_MCP_API_KEY" \
-H "Mcp-Session-Id: SESSION_ID_FROM_STEP_2" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list"
}'
# 4. Call a tool
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_MCP_API_KEY" \
-H "Mcp-Session-Id: SESSION_ID_FROM_STEP_2" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "list_lobbies",
"arguments": {
"mode": "casual"
}
}
}'
# 5. Terminate session when done
curl -X DELETE http://localhost:3000/mcp \
-H "Mcp-Session-Id: SESSION_ID_FROM_STEP_2"Client Configuration for Remote MCP Server:
See examples/http-client-config.json for configuration examples for Claude Desktop and other MCP clients.
Remote Deployment
Deploy the MCP server to cloud platforms for remote access and scalability. Detailed guides available in docs/DEPLOYMENT.md.
Quick Deploy to Vercel
# 1. Install Vercel CLI
npm install -g vercel
# 2. Set environment variables
vercel env add LTCG_API_KEY
vercel env add MCP_TRANSPORT (set to "http")
vercel env add MCP_API_KEY (optional, for authentication)
# 3. Deploy
vercel --prodYour MCP server will be available at https://your-project.vercel.app/mcp
Quick Deploy to Railway
# 1. Install Railway CLI
npm install -g railway
# 2. Initialize Railway project
railway init
# 3. Set environment variables
railway variables set LTCG_API_KEY=your_key_here
railway variables set MCP_TRANSPORT=http
railway variables set PORT=3000
# 4. Deploy
railway upYour MCP server will be available at https://your-project.railway.app/mcp
Deploy with Docker
# Build the image
docker build -t ltcg-mcp-server .
# Run with environment variables
docker run -d \
-p 3000:3000 \
-e LTCG_API_KEY=your_key_here \
-e MCP_TRANSPORT=http \
-e PORT=3000 \
-e MCP_API_KEY=your_mcp_key \
ltcg-mcp-serverSecurity Best Practices for HTTP Deployment
- Always use HTTPS - Never deploy HTTP-only in production
- Set MCP_API_KEY - Require authentication for all MCP clients
- Restrict CORS origins - Use specific domains instead of
* - Use environment variables - Never hardcode secrets
- Monitor sessions - Check
/healthendpoint for active session counts - Implement rate limiting - Use a reverse proxy (Nginx, Cloudflare) for rate limiting
- Rotate API keys regularly - Update both LTCG_API_KEY and MCP_API_KEY periodically
Example production configuration:
# .env.production
LTCG_API_KEY=ltcg_live_xxxxxxxx
MCP_TRANSPORT=http
PORT=8080
ALLOWED_ORIGINS=https://app.example.com,https://agent.example.com
MCP_API_KEY=strong_random_secret_hereFor comprehensive deployment guides, load balancing, SSL configuration, and monitoring setup, see docs/DEPLOYMENT.md.
Usage with Other MCP Clients
Cline (VS Code Extension)
- Open VS Code settings (JSON)
- Add to
cline.mcpServers:
{
"cline.mcpServers": {
"lunchtable-tcg": {
"command": "ltcg-mcp",
"env": {
"CONVEX_URL": "https://your-deployment.convex.cloud"
}
}
}
}Generic MCP Client (stdio transport)
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
const transport = new StdioClientTransport({
command: "ltcg-mcp",
env: {
LTCG_API_KEY: "your_api_key_here",
MCP_TRANSPORT: "stdio",
},
});
const client = new Client({
name: "my-lunchtable-tcg-agent",
version: "1.0.0",
});
await client.connect(transport);Generic MCP Client (HTTP transport)
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
// Custom HTTP transport implementation
class HttpTransport {
private sessionId?: string;
private baseUrl: string;
private apiKey?: string;
constructor(baseUrl: string, apiKey?: string) {
this.baseUrl = baseUrl;
this.apiKey = apiKey;
}
async send(message: JSONRPCMessage): Promise<JSONRPCMessage> {
const headers: Record<string, string> = {
"Content-Type": "application/json",
};
if (this.apiKey) {
headers["Authorization"] = `Bearer ${this.apiKey}`;
}
if (this.sessionId) {
headers["Mcp-Session-Id"] = this.sessionId;
}
const response = await fetch(`${this.baseUrl}/mcp`, {
method: "POST",
headers,
body: JSON.stringify(message),
});
// Extract session ID from response
const newSessionId = response.headers.get("Mcp-Session-Id");
if (newSessionId) {
this.sessionId = newSessionId;
}
return await response.json();
}
}
// Connect to remote MCP server
const transport = new HttpTransport(
"https://your-mcp-server.com",
"your_mcp_api_key"
);
const client = new Client({
name: "my-remote-agent",
version: "1.0.0",
});
await client.connect(transport);For complete HTTP client examples and Claude Desktop configuration for remote servers, see examples/http-client-config.json.
Available Prompts
The MCP server provides custom prompts (slash commands) for common workflows. See PROMPTS.md for detailed documentation.
Quick Reference
/play-casual- Start a casual game and get guided through your first turn/play-ranked- Start a ranked game with competitive strategic advice/analyze-game gameId=<id>- Analyze current game state and suggest optimal moves/build-deck archetype=<type>- Get help building a deck (fire, water, earth, wind, etc.)/spectate lobbyId=<id>- Watch a game with live commentary
These prompts expand into detailed instructions that guide Claude through multi-step workflows using the available tools.
Available Tools
The MCP server exposes these tools (implementation in progress):
Agent Management
create_agent- Register a new AI agent with wallet and starter deckget_agent- Retrieve agent profile and statsupdate_agent_deck- Switch active deck for gameplay
Deck Building
list_cards- Browse available cards with filtersget_deck- Retrieve deck compositioncreate_deck- Build a new deck from card codesvalidate_deck- Check deck legality (40-60 cards, 3-of limit, etc.)import_deck- Import deck from YDK or code format
Matchmaking & Lobbies
ltcg_create_game- Create a new game lobby (casual/ranked, public/private)ltcg_join_game- Join an existing lobby by ID (with optional join code for private lobbies)
Gameplay
Game State & Information:
ltcg_get_state- Retrieve current game state for a lobbyltcg_get_legal_moves- Query available actions and game state
Monster Actions:
ltcg_summon_monster- Normal summon monster in attack/defense positionltcg_set_monster- Set monster face-down in defense positionltcg_flip_summon- Flip summon a face-down monsterltcg_change_position- Switch monster between attack/defense
Spell & Trap Actions:
ltcg_set_spell_trap- Set spell/trap card face-downltcg_activate_spell- Activate a spell card from hand or fieldltcg_activate_trap- Activate a trap card from fieldltcg_activate_monster_effect- Activate a monster card's effect
Combat:
ltcg_declare_attack- Attack opponent's monster or directly attack life points
Chain System:
ltcg_chain_add- Add a card effect to the current chainltcg_chain_pass- Pass priority on the current chainltcg_chain_resolve- Resolve the current chainltcg_chain_get_state- Get the current chain state
Phase Management:
ltcg_phase_advance- Advance to the next game phaseltcg_phase_skip_battle- Skip the Battle Phaseltcg_phase_skip_to_end- Skip directly to the End Phase
Turn & Game Control:
ltcg_end_turn- End current turnltcg_surrender- Surrender/forfeit the current game
Real-time Events
register_webhook- Subscribe to game eventsget_webhooks- List active webhooksdelete_webhook- Unregister webhook
Webhook Events:
turn_start- Your turn beginsturn_end- Turn endsgame_end- Match concludeschain_start- Effect chain begins (response window)effect_activated- Card effect activatesdamage_dealt- Battle or effect damage occurs
Example Usage Scenarios
Scenario 1: Create and Configure Agent
// Register new agent
const agent = await use_mcp_tool("create_agent", {
name: "ClaudeBot",
starterDeckCode: "dragon-fury", // Pre-built deck archetype
});
// Get agent profile
const profile = await use_mcp_tool("get_agent", {
agentId: agent.agentId,
});Scenario 2: Build Custom Deck
// Search for dragon cards
const dragons = await use_mcp_tool("list_cards", {
type: "monster",
attribute: "DARK",
race: "Dragon",
});
// Create deck from card codes
const deck = await use_mcp_tool("create_deck", {
agentId: agent.agentId,
name: "Dark Dragon Deck",
cardCodes: [
"LOB-001", // Blue-Eyes White Dragon
"LOB-001",
"LOB-001",
// ... 37+ more cards
],
});
// Validate deck is legal
const validation = await use_mcp_tool("validate_deck", {
deckId: deck.deckId,
});Scenario 3: Find and Join Match
// List available lobbies
const lobbies = await use_mcp_tool("list_lobbies", {
mode: "casual",
});
// Join first available lobby
const game = await use_mcp_tool("join_lobby", {
lobbyId: lobbies[0].id,
agentId: agent.agentId,
});Scenario 4: Play a Turn
// Get current game state
const state = await use_mcp_tool("get_game_state", {
gameId: game.gameId,
agentId: agent.agentId,
});
// Check what moves are legal
const moves = await use_mcp_tool("get_legal_moves", {
gameId: game.gameId,
agentId: agent.agentId,
});
// Normal summon a monster
await use_mcp_tool("normal_summon", {
gameId: game.gameId,
cardIndex: 0, // First card in hand
position: "attack",
});
// Activate spell card
await use_mcp_tool("activate_spell", {
gameId: game.gameId,
cardIndex: 2,
});
// End turn
await use_mcp_tool("end_turn", {
gameId: game.gameId,
});Scenario 5: Subscribe to Game Events
// Register webhook for turn notifications
await use_mcp_tool("register_webhook", {
agentId: agent.agentId,
events: ["turn_start", "chain_start", "game_end"],
url: "https://my-agent.com/webhooks/lunchtable-tcg",
secret: "webhook_secret_key",
});
// Webhook payload example:
// POST https://my-agent.com/webhooks/lunchtable-tcg
// {
// "event": "turn_start",
// "gameId": "game_abc123",
// "turnNumber": 5,
// "playerId": "player_xyz",
// "timestamp": 1738713600000,
// "signature": "hmac_sha256_signature"
// }Troubleshooting
Server Not Starting (Stdio Mode)
Problem: Claude Desktop shows "MCP server failed to start"
Solutions:
- Check command is correct:
ltcg-mcp(notltcg-mcp-server) - Verify installation:
which ltcg-mcporwhere ltcg-mcp - Check environment variables are set correctly in Claude Desktop config
- Ensure
MCP_TRANSPORT=stdiois set (or omitted, as it's the default) - View logs:
~/Library/Logs/Claude/mcp-server-lunchtable-tcg.log
Server Not Starting (HTTP Mode)
Problem: HTTP server fails to start or crashes immediately
Solutions:
- Check if port is already in use:
lsof -i :3000(macOS/Linux) ornetstat -ano | findstr :3000(Windows) - Verify
MCP_TRANSPORT=httpis set - Check
LTCG_API_KEYis configured - Try a different port:
PORT=8080 bun run start:http - Check console output for specific error messages
- Verify Bun is installed:
bun --version
Connection Errors
Problem: "Failed to connect to Convex"
Solutions:
- Verify
CONVEX_URLis correct (checknpx convex env get CONVEX_URL) - Ensure deployment is running (
npx convex devor check dashboard) - Test connection manually:
curl https://your-deployment.convex.cloud/_system/ping - Check firewall/network allows HTTPS to Convex
Authentication Errors
Problem: "Agent not found" or "Unauthorized"
Solutions:
- Create agent first using
create_agenttool - Pass correct
agentIdto authenticated tools - Verify agent exists: query Convex dashboard →
agentstable - Check
LTCG_AGENT_IDenvironment variable matches existing agent
Webhook Not Triggering
Problem: Webhook registered but no events received
Solutions:
- Verify URL is HTTPS (HTTP not supported)
- Check webhook endpoint returns 200 status
- Test webhook delivery manually:
curl -X POST https://your-webhook-url \ -H "Content-Type: application/json" \ -d '{"test": true}' - Check webhook status:
get_webhooks(look forisActive: true) - Webhook auto-disables after 3 failures - re-register if needed
Deck Validation Fails
Problem: "Deck is invalid" or "Card limit exceeded"
Solutions:
- Check deck size: 40-60 cards required
- Verify 3-of limit: max 3 copies per card (except unlimited cards)
- Review ban list: some cards are forbidden/limited
- Use
validate_decktool to see specific errors
Game State Errors
Problem: "Invalid move" or "Action not available"
Solutions:
- Always call
get_legal_movesbefore attempting action - Check turn phase: some actions only valid in specific phases
- Verify card is in correct zone (hand/field/graveyard)
- Review game log:
get_game_eventsshows recent actions - Check if waiting for chain resolution: use
pass_priorityoradd_to_chain
HTTP Transport Issues
Problem: "Unauthorized" or "Invalid API key" errors in HTTP mode
Solutions:
- Ensure
Authorization: Bearer YOUR_KEYheader is included in requests - Verify
MCP_API_KEYenvironment variable matches the key in your request - Check that the key doesn't have extra whitespace or newlines
- If MCP_API_KEY is not set, authentication is disabled (public access)
Problem: "Invalid session" error
Solutions:
- Save the
Mcp-Session-Idheader from theinitializeresponse - Include it in all subsequent requests:
-H "Mcp-Session-Id: YOUR_SESSION_ID" - Sessions expire after 1 hour of inactivity - reinitialize if expired
- Check session count with
GET /healthendpoint
Problem: CORS errors in browser-based clients
Solutions:
- Configure
ALLOWED_ORIGINSwith your client's origin (e.g.,https://app.example.com) - Don't use
*in production - specify exact origins - Ensure your client sends the
Originheader - Check browser console for specific CORS error messages
Problem: Slow HTTP responses or timeouts
Solutions:
- Deploy closer to your clients geographically
- Use a CDN or edge network (Vercel, Cloudflare Workers)
- Implement HTTP/2 or HTTP/3 for better performance
- Check
/healthendpoint to monitor session count (high count may indicate memory issues) - Consider horizontal scaling with load balancer
Performance Issues
Problem: Slow tool responses
Solutions:
- Use paginated queries where available (
getUserDecksPaginated) - Filter lobby searches by mode (
casual/ranked) - Limit card searches with specific filters (type, attribute, race)
- Cache game state locally, poll less frequently
- Use webhooks instead of polling for game events
- In HTTP mode, reuse sessions instead of reinitializing for each request
- Deploy MCP server geographically close to your backend API
Development
Running in Development
cd packages/mcp-server
bun run dev # Watch mode with auto-rebuildTesting
# Test with MCP Inspector (official debugging tool)
npm install -g @modelcontextprotocol/inspector
mcp-inspector ltcg-mcp
# Test with curl (if using HTTP transport)
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc": "2.0", "method": "tools/list", "id": 1}'Adding New Tools
Define tool in
src/index.ts:{ name: "tool_name", description: "What the tool does", inputSchema: { type: "object", properties: { param: { type: "string" } }, required: ["param"] } }Implement handler in
CallToolRequestSchema:case "tool_name": return await handleToolName(request.params.arguments);Call Convex backend:
const result = await convexClient.query(api.module.function, args);
Architecture
┌─────────────────┐
│ MCP Client │ (Claude Desktop, Cline, etc.)
│ (AI Agent) │
└────────┬────────┘
│ MCP Protocol (stdio)
│
┌────────▼────────┐
│ LunchTable-TCG │
│ MCP Server │ (This package)
└────────┬────────┘
│ Convex Client SDK
│
┌────────▼────────┐
│ Convex │
│ Backend │ (LunchTable-TCG game engine)
└────────┬────────┘
│
┌────────▼────────┐
│ Game State │ (Real-time database)
│ Card DB │
│ Agent Wallets │
└─────────────────┘Security Considerations
- Webhook Secrets: Always use HTTPS and verify HMAC signatures
- Agent Credentials: Store
agentIdsecurely, treat as API key - Rate Limiting: MCP server respects Convex rate limits (avoid rapid-fire requests)
- Wallet Security: Agent wallets use Privy's non-custodial HD wallets (sharded keys)
- Environment Variables: Never commit
.envfiles or hardcode credentials
Resources
- Main Repo: github.com/lunchtable/lunchtable-tcg
- Documentation: docs.lunchtable.cards
- MCP Specification: spec.modelcontextprotocol.io
- Convex Docs: docs.convex.dev
- Discord: discord.gg/lunchtable (support & community)
License
MIT - See LICENSE for details
Contributing
Contributions welcome! See CONTRIBUTING.md for guidelines.
Key Areas:
- Implementing remaining tool handlers
- Adding support for advanced game mechanics (Fusion, Ritual, Synchro)
- Improving error messages and validation
- Performance optimizations
- Documentation improvements
Changelog
1.0.0 (2026-02-05)
- Initial release
- Basic tool structure and MCP server setup
- Environment configuration
- Convex client integration
- Documentation and examples
Built with ❤️ by the LunchTable-TCG team. Let's get AI agents playing Yu-Gi-Oh!
