MCP server providing AI control surface for a Three.js town simulation game. Bridges AI agents to a running game server via WebSocket, enabling queries and actions on citizens, buildings, economy, and events.
25 tools with explicit schemas and descriptions. Naming is verb-first and clear (get_*, set_*, spawn_*, etc.). Descriptions are detailed and contextual (avg ~150 chars), exceeding baseline minimums. However, several parameters lack descriptions (e.g., 'job' in set_job has no description text), and output schemas are entirely undocumented, LLMs cannot predict response structure. Error handling is minimal; no recovery guidance or categorization. Security is weak: no mention of permission gates, audit trails, or input sanitization. Composition is good, tools are single-purpose and chainable via ID returns.
Post to the town event feed. With id, the citizen says it as a speech bubble for 1 game minute.
Direct passthrough to TypeSafe Jev (System One) on OpenRouter: send a state string and typed questions (choice/score/noul with instructions and criteria) and get calibrated probabilities back. Independent of the sim.
Construct a building at the top-left tile (x,z) of its footprint. Costs treasury (see catalog in get_town). Fails if the site, or a reachable door, is unavailable.
Demolish a building by id, type or name. Residents are re-homed and staff reassigned to the default workplace of their job.
Status of the TypeSafe Jev decision layer: enabled, model, call/error counts, average confidence, tokens and cost so far, last choices.
List all buildings with type, footprint, door tile, stock, staff and residents.
No output schemas documented. LLMs cannot predict response structure, forcing them to guess what fields are returned and how to chain tools. Every tool should document its return type.
Several parameters lack descriptions: 'job' in set_job, 'id' in demolish (though 'id' is reused from const). Descriptions are required for every parameter so LLMs understand what values to pass.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 62 | 2026-07-28+ | v2 |
Detailed status of one citizen: needs, money, inventory, home, workplace, current status, speech and active AI directive.
List every citizen (id, name, job, needs hunger/energy/social/morale, money, inventory, status, AI directive), or one citizen in detail when id is given.
Economy detail: treasury, prices and price multipliers, stock per building, today's sales/production, payroll and the last 7 days of stats.
Recent town event feed (newest last): deliveries, wage shortfalls, AI decisions, festivals, character speeches.
Start here. Full overview of the sim town: time (day/hh:mm), population, happiness, treasury, prices, stock, per-citizen jobs, the Jev AI status, and a catalog of every building type, job, food, event and speed you can use in other tools. Time passes 1 game hour per 6 real seconds at 1x speed.
Put food into a citizen's inventory (they will eat it when hungry).
Add (or subtract) coins for a citizen. Result is clamped to >= 0.
Send a citizen to walk to a tile (x,z) or to a building's door (building: id, type or name). teleport=true places them instantly instead of walking.
Release a citizen from any forced activity and clear their AI directive so the baseline schedule takes over again.
Select a citizen in the 3D view (opens their panel in the browser). Pass id=null to deselect.
Force a citizen into an activity for N game minutes (default 180): eat, sleep, work, socialize, wander, shop, idle, walk. The normal schedule and the Jev layer stand down while forced; release_character ends it early.
Enable/disable the TypeSafe Jev decision layer (needs OPENROUTER_API_KEY on the sim server). When enabled, Jev re-decides every citizen's next action once per game hour.
Give a citizen a job (assigns their workplace). Fails if the position is full unless force=true. Use "unemployed" to fire them.
Set citizen needs directly (0-100 each): hunger (100 = starving), energy (0 = exhausted), social (100 = lonely), morale.
Town policy: daily tax per citizen (0-20 coins) and/or wage multiplier (0-3).
Simulation speed: 0 = paused, 1 = normal, 2 = fast, 4 = fastest.
Jump the clock. Omitted fields keep their current value. Day cannot go below day 1.
Create a new citizen. Auto-assigns a house with space; starts at the house door (or x/z when given). Job must be a valid job key (see get_town catalog) and is dropped if the workplace has no free slot.
Fire a town event: festival (morale +25 all, -30 treasury), storm (production x0.4 today), market_crash (prices -40%), windfall (treasury +120), heatwave (hunger +15 all).
No error handling or recovery guidance. Tools fail silently or with generic errors (e.g., 'tool timed out'). LLMs need actionable error messages: 'Job position full. Try force=true or choose a different job.'
No permission gates or audit trails. Destructive tools (demolish, set_need, trigger_event) execute without checking agent authority or logging who called them. Add permission checks and audit logging.
No input validation or sanitization. LLMs could pass invalid enum values, out-of-range numbers, or malicious strings. Validate early and return clear constraint violations.