List Simulations
list_simulationsRetrieve past simulation runs with status and metadata to track and analyze community reaction predictions.
Instructions
List past simulation runs with their status and metadata.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max results to return (default 20) |
Implementation Reference
- MCP tool handler: registers the 'list_simulations' tool with input schema (limit), calls client.listSimulations(), and returns formatted JSON with total and simulation details.
export function registerListSimulations(server: McpServer, client: MirofishClient): void { server.registerTool( "list_simulations", { title: "List Simulations", description: "List past simulation runs with their status and metadata.", inputSchema, annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, }, async (args) => { try { const { simulations, total } = await client.listSimulations(args.limit ?? 20); const result = { total, simulations: simulations.map((s) => ({ simulation_id: s.simulation_id, project_name: s.project_name, state: s.state, entities_count: s.entities_count, created_at: s.created_at, })), }; return { content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }] }; } catch (err) { throw toMcpError(err); } }, ); } - Zod input schema for the tool: optional 'limit' (coerced int, 1-100, default 20).
const inputSchema = { limit: z.coerce.number().int().min(1).max(100).optional().describe("Max results to return (default 20)"), }; - HTTP client method listSimulations() that GETs /api/simulation/history with a limit param and returns {simulations, total}.
async listSimulations(limit = 20): Promise<{ simulations: SimulationSummary[]; total: number }> { const resp = await this.http.get<MirofishApiResponse<SimulationSummary[]>>( "/api/simulation/history", { params: { limit } }, ); const sims = resp.data?.data ?? []; return { simulations: sims, total: resp.data?.count ?? sims.length }; } - mcp-server/src/tools/index.ts:16-26 (registration)Tool registration: imports and calls registerListSimulations(server, client) inside registerAllTools().
export function registerAllTools(server: McpServer, client: MirofishClient): void { registerCreateSimulation(server, client); registerSimulationStatus(server, client); registerGetReport(server, client); registerInterviewAgent(server, client); registerListSimulations(server, client); registerSearchSimulations(server, client); registerUploadDocument(server, client); registerSimulationData(server, client); registerCancelSimulation(server, client); } - Backend Python service: SimulationManager.list_simulations() queries SurrealDB storage for simulations filtered by user_id and falls back to file store when user_id is None.
def list_simulations( self, project_id: Optional[str] = None, user_id: Optional[str] = None, ) -> list[SimSnapshot]: """List sims. If user_id is given, filter via SurrealDB first.""" results: list[SimSnapshot] = [] seen: set[str] = set() storage = _get_surreal_storage() if storage: try: rows = storage.list_simulations(limit=200, user_id=user_id) for row in rows: sid = row.get("simulation_id", "") if not sid: continue if project_id and row.get("project_id") != project_id: continue snap = store.get(sid) if snap is not None: results.append(snap) seen.add(sid) except Exception as exc: logger.warning("SurrealDB list_simulations failed: %s", exc) # File fallback: pick up anything not in SurrealDB (e.g. local # dev without a DB, or sims created before a DB migration). # # Critical: when user_id is set (hosted mode), we MUST NOT fall # back to the file store — those rows have no user_id metadata, # so returning them would leak other users' sims to whoever # asked. Self-hosted callers (user_id=None) get everything. if user_id is None: for snap in store.list(project_id=project_id): if snap.simulation_id in seen: continue results.append(snap) return results