Skip to main content
Glama

Get Report

get_report

Generate or retrieve a detailed markdown prediction report for a completed simulation. Use force_regenerate to rebuild cached reports.

Instructions

Generate and retrieve the prediction report for a completed simulation. If the report hasn't been generated yet, triggers generation (may take 1-3 minutes). Returns a detailed markdown analysis ready to display as an artifact in the side panel. Pass force_regenerate=true to rebuild an already-cached report.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
simulation_idYesThe simulation ID to generate/fetch a report for
force_regenerateNoIf true, invalidates any cached report and runs a fresh ReportAgent pass. Useful after backend prompt or validator changes. Off by default — reports are cached once generated, so repeat calls are free.

Implementation Reference

  • registerGetReport function – the main handler that calls the client's getOrGenerateReport, checks status, extracts summary, and returns metadata + full markdown content.
    export function registerGetReport(server: McpServer, client: MirofishClient): void {
      server.registerTool(
        "get_report",
        {
          title: "Get Report",
          description:
            "Generate and retrieve the prediction report for a completed simulation. " +
            "If the report hasn't been generated yet, triggers generation (may take 1-3 minutes). " +
            "Returns a detailed markdown analysis ready to display as an artifact in the side panel. " +
            "Pass force_regenerate=true to rebuild an already-cached report.",
          inputSchema,
          annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },
        },
        async (args) => {
          try {
            const report = await client.getOrGenerateReport(
              args.simulation_id,
              args.force_regenerate ?? false,
            );
    
            // Still generating or failed — return status only
            if (report.status !== "completed" || !report.markdown_content) {
              const statusMsg =
                report.status === "generating"
                  ? "Report is still being generated. Call get_report again in a minute."
                  : `Report status: ${report.status}`;
    
              return {
                content: [
                  {
                    type: "text" as const,
                    text: JSON.stringify(
                      {
                        report_id: report.report_id,
                        simulation_id: report.simulation_id,
                        status: report.status,
                        message: statusMsg,
                      },
                      null,
                      2,
                    ),
                  },
                ],
              };
            }
    
            // Extract summary from the report (first paragraph after title)
            const firstBlockquote = report.markdown_content.match(/^>\s*(.+?)$/m);
            const summary = firstBlockquote?.[1] ?? "Prediction report ready.";
    
            // Return metadata + full markdown as separate content items.
            // Claude Desktop and Claude Code will render the markdown block as an
            // artifact in the side panel when the LLM reproduces it in its response.
            const metadata = {
              report_id: report.report_id,
              simulation_id: report.simulation_id,
              status: "completed",
              summary,
              display_instructions:
                "The full prediction report is included below as markdown. " +
                "Output the markdown directly to the user — Claude Desktop will render " +
                "it as an artifact in the side panel. Do not summarize or truncate.",
              markdown_content: report.markdown_content,
            };
    
            return {
              content: [
                {
                  type: "text" as const,
                  text: JSON.stringify(metadata, null, 2),
                },
              ],
            };
          } catch (err) {
            throw toMcpError(err);
          }
        },
      );
    }
  • Input schema using Zod: simulation_id (required string) and force_regenerate (optional boolean).
    const inputSchema = {
      simulation_id: z.string().describe("The simulation ID to generate/fetch a report for"),
      force_regenerate: z.coerce
        .boolean()
        .optional()
        .describe(
          "If true, invalidates any cached report and runs a fresh ReportAgent pass. " +
          "Useful after backend prompt or validator changes. Off by default — reports " +
          "are cached once generated, so repeat calls are free.",
        ),
    };
  • Import and call of registerGetReport in registerAllTools to register the tool with the MCP server.
    import { registerGetReport } from "./get-report.js";
    import { registerInterviewAgent } from "./interview-agent.js";
    import { registerListSimulations } from "./list-simulations.js";
    import { registerSearchSimulations } from "./search-simulations.js";
    import { registerUploadDocument } from "./upload-document.js";
    import { registerSimulationData } from "./simulation-data.js";
    import { registerCancelSimulation } from "./cancel-simulation.js";
    
    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);
    }
  • getOrGenerateReport method: checks for cached report via GET /api/report/by-simulation/:id, or POSTs to /api/report/generate to trigger generation, then polls up to 10 minutes for completion.
    async getOrGenerateReport(
      simulationId: string,
      forceRegenerate = false,
    ): Promise<Report> {
      // First check if a cached report exists.
      if (!forceRegenerate) {
        try {
          const existing = await this.http.get<MirofishApiResponse<Report>>(
            `/api/report/by-simulation/${simulationId}`,
          );
          if (existing.data?.data?.status === "completed") {
            return existing.data.data;
          }
        } catch {
          // Not cached — fall through to generate.
        }
      }
    
      // Kick off generation (returns task_id + report_id)
      const genResp = await this.http.post<MirofishApiResponse<{ report_id: string; task_id: string }>>(
        "/api/report/generate",
        { simulation_id: simulationId, force_regenerate: forceRegenerate },
      );
      const data = genResp.data?.data;
      if (!data) {
        throw new MirofishBackendError("Report generation didn't return task_id", 500);
      }
    
      // Poll for completion (up to 10 min)
      for (let i = 0; i < 300; i++) {
        await new Promise((r) => setTimeout(r, 2000));
        try {
          const r = await this.http.get<MirofishApiResponse<Report>>(
            `/api/report/by-simulation/${simulationId}`,
          );
          const rep = r.data?.data;
          if (rep?.status === "completed") return rep;
          if (rep?.status === "failed") {
            throw new MirofishBackendError("Report generation failed", 500);
          }
        } catch (err: unknown) {
          if (axios.isAxiosError(err) && err.response?.status === 404) continue;
          throw err;
        }
      }
      throw new MirofishBackendError("Report generation timed out", 504);
    }
  • Type definitions: ReportStatus (generating|completed|failed), Report interface (report_id, simulation_id, status, markdown_content, etc.).
    export type ReportStatus = "generating" | "completed" | "failed";
    
    export interface Report {
      report_id: string;
      simulation_id: string;
      status: ReportStatus;
      outline?: { title: string; summary: string; sections: ReportSection[] };
      markdown_content?: string;
      created_at: string;
      completed_at?: string;
    }
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds behavioral context beyond annotations: it triggers generation if not cached, caches results, and returns markdown for display. It also explains the side effect of force_regenerate. No contradictions with annotations (readOnlyHint=false, destructiveHint=false, openWorldHint=true).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the core purpose. Each sentence provides necessary information without redundancy. No wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the main behavior, output format (markdown for side panel), and caching. Without an output schema, it provides enough context for an AI agent. Missing details about error conditions or validation, but overall complete for the tool's complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Both parameters have full descriptions in the schema (100% coverage). The tool description adds value: it explains the delay for generation, caching behavior, and specific use case for force_regenerate ('useful after backend prompt or validator changes').

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool generates and retrieves a prediction report for a completed simulation. It uses specific verbs ('Generate and retrieve') and resource ('prediction report'), distinguishing it from sibling tools that deal with simulation management or data.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains when to use the tool (for completed simulations), notes that report generation may take 1-3 minutes, and describes the force_regenerate parameter. While it doesn't explicitly compare with alternatives, the context is clear and there are no other report-focused tools among siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/kakarot-dev/deepmiro'

If you have feedback or need assistance with the MCP directory API, please join our Discord server