[{"data":1,"prerenderedAt":20},["ShallowReactive",2],{"doc-mcp":3},{"blocks":4,"markdown":19},[5,8,12,14,17],{"kind":6,"html":7},"html","\u003Cp>Forma speaks \u003Ca href=\"https:\u002F\u002Fmodelcontextprotocol.io\" target=\"_blank\" rel=\"noopener noreferrer\">Model Context Protocol\u003C\u002Fa>, so an\nagent can reach an oracle without you writing an integration for it. Six\ntools, the same guarantees as the HTTP API, and the same prices.\u003C\u002Fp>\n\u003Ch2 id=\"the-endpoint\">The endpoint\u003C\u002Fh2>\n",{"kind":9,"lang":10,"code":11},"code","","https:\u002F\u002Fmcp.formalogic.io\u002Fmcp",{"kind":6,"html":13},"\u003Cp>\u003Cstrong>No API key needed.\u003C\u002Fstrong> Your client signs in with your Forma account (OAuth) the\nfirst time it calls a tool. For a client that cannot do OAuth, an API key sent as\na bearer token works too. Hosted, so the tools an agent sees are always the\ncurrent ones. Setup for each client is in \u003Ca href=\"\u002Fconnect\">Connect your agent\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ch2 id=\"the-tools\">The tools\u003C\u002Fh2>\n\u003Ch3 id=\"forma-status\">forma_status()\u003C\u002Fh3>\n\u003Cp>Which Forma account this session is signed in as. Free.\u003C\u002Fp>\n\u003Cp>Ask for this first when a connection has just been set up. \u003Ccode>list_oracles\u003C\u002Fcode>\nanswers identically for every caller, so a working connection and one signed in\nto someone else's account look the same through it; this answers with something\nonly a live, authenticated session can know.\u003C\u002Fp>\n",{"kind":9,"lang":15,"code":16},"json","{ \"org_id\": \"org_01M2G6ZW…\", \"plan\": \"free\", \"requests_per_minute\": 10, \"features\": [] }",{"kind":6,"html":18},"\u003Ch3 id=\"list-oracles\">list_oracles()\u003C\u002Fh3>\n\u003Cp>Every oracle available to your account, with each one's \u003Ccode>formats\u003C\u002Fcode>,\n\u003Ccode>default_format\u003C\u002Fcode> and \u003Ccode>drawable_formats\u003C\u002Fcode> (the ones \u003Ccode>show_figure\u003C\u002Fcode> can draw). Free. Call it before guessing a name — the catalogue is the\ncontract and it grows.\u003C\u002Fp>\n\u003Ch3 id=\"ask-oracle-oracle-intent-format-allow-generated-data\">ask_oracle(oracle, intent, format?, allow_generated_data?)\u003C\u002Fh3>\n\u003Cdiv class=\"doc-table\">\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Argument\u003C\u002Fth>\n\u003Cth>\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>oracle\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>a name from \u003Ccode>list_oracles\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>intent\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>what you want, described normally — not a template, not a specification — with the values to plot\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>format\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>optional; defaults to that oracle's own. Pick one of \u003Ccode>drawable_formats\u003C\u002Fcode> when the person should see it\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>allow_generated_data\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>optional, charts only; \u003Ccode>true\u003C\u002Fcode> accepts illustrative values when the intent gives none\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003C\u002Fdiv>\n\u003Cp>Forma does not fetch data. The agent puts the values in \u003Ccode>intent\u003C\u002Fcode>, fetching them\nfirst if the person wants real numbers; a chart request without them is refused\nwith \u003Ccode>DATA_REQUIRED\u003C\u002Fcode>, unbilled.\u003C\u002Fp>\n\u003Cp>The answer is checked against the oracle's rules before it is returned, so\n\u003Ccode>status\u003C\u002Fcode> is a verdict rather than a guess: \u003Ccode class=\"chip chip--valid\">valid\u003C\u002Fcode> with a \u003Ccode>result\u003C\u002Fcode> and a\n\u003Ccode>verified_by\u003C\u002Fcode> citation, \u003Ccode class=\"chip chip--invalid\">invalid\u003C\u002Fcode> where the check refused it and said why, or\n\u003Ccode class=\"chip chip--error\">error\u003C\u002Fcode> which is ours, unbilled, and worth retrying. See\n\u003Ca href=\"\u002Fverdicts\">Verdicts\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ch3 id=\"show-figure-figure-token-format\">show_figure(figure_token, format?)\u003C\u002Fh3>\n\u003Cdiv class=\"doc-table\">\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Argument\u003C\u002Fth>\n\u003Cth>\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>figure_token\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>the \u003Ccode>figure.token\u003C\u002Fcode> from an \u003Ccode>ask_oracle\u003C\u002Fcode> answer, passed exactly as given\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>format\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>png\u003C\u002Fcode> (the default), which can be looked at, or \u003Ccode>svg\u003C\u002Fcode>, returned as text for saving to a file\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003C\u002Fdiv>\n\u003Cp>Draws a \u003Ccode class=\"chip chip--valid\">valid\u003C\u002Fcode> answer whose \u003Ccode>figure.drawable\u003C\u002Fcode> is true, so the person sees the\nchart or drawing and not only its source. An answer that cannot be drawn says why\nin \u003Ccode>figure.reason\u003C\u002Fcode>. Free: the answer was already paid for.\u003C\u002Fp>\n\u003Ch3 id=\"whats-new-since\">whats_new(since?)\u003C\u002Fh3>\n\u003Cp>What changed for callers — endpoints, oracles, tools — newest first. \u003Ccode>since\u003C\u002Fcode> is\nan optional \u003Ccode>YYYY-MM-DD\u003C\u002Fcode>; pass the \u003Ccode>latest\u003C\u002Fcode> from an earlier call to see only what\narrived after it. Free. The same entries are in the \u003Ca href=\"\u002Fchangelog\">Changelog\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ch3 id=\"send-feedback-sentiment-message-oracle-request-id\">send_feedback(sentiment, message, oracle?, request_id?)\u003C\u002Fh3>\n\u003Cdiv class=\"doc-table\">\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Argument\u003C\u002Fth>\n\u003Cth>\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>sentiment\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>positive\u003C\u002Fcode>, \u003Ccode>negative\u003C\u002Fcode> or \u003Ccode>neutral\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>message\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>why, in a sentence or two; up to 2000 characters\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>oracle\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>optional; the oracle it is about\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>request_id\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>optional; the answer it is about. Left empty, the latest \u003Ccode>ask_oracle\u003C\u002Fcode> answer made with the same credential is used, when it was for the same oracle\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003C\u002Fdiv>\n\u003Cp>Tells the people who build Forma what worked and what did not. Free. See\n\u003Ca href=\"\u002Fnews-feedback\">News and feedback\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ch2 id=\"errors-an-agent-can-act-on\">Errors an agent can act on\u003C\u002Fh2>\n\u003Cp>Every failure comes back as an \u003Ccode class=\"chip chip--error\">error\u003C\u002Fcode> object with a \u003Ccode>kind\u003C\u002Fcode>, so a model can\nbranch instead of the tool call dying.\u003C\u002Fp>\n\u003Cdiv class=\"doc-table\">\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>\u003Ccode>kind\u003C\u002Fcode>\u003C\u002Fth>\n\u003Cth>Meaning\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>unauthorized\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Not signed in, or the sign-in or key is unrecognised, revoked or expired — a human has to act\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>quota_exceeded\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>The allowance is spent; signing in again or switching keys will not help\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>not_found\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>No such oracle — call \u003Ccode>list_oracles\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>invalid_request\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>The request or the requested format was refused; \u003Ccode>context\u003C\u002Fcode> names the valid ones\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>upstream_unavailable\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>A service the oracle depends on is briefly unavailable. Waiting is the right next move\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>backend_unreachable\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Network or DNS, after retries\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003C\u002Fdiv>\n\u003Cp>Every error also carries \u003Ccode>retryable\u003C\u002Fcode> — whether waiting could change the answer —\nand \u003Ccode>request_id\u003C\u002Fcode>, the id stamped on the failure. Quote the \u003Ccode>request_id\u003C\u002Fcode> when\nreporting a problem; it identifies the call in our logs.\u003C\u002Fp>\n\u003Cp>Transient failures are retried before anything is returned, so a \u003Ccode>kind\u003C\u002Fcode> that\nreaches your agent is one worth acting on.\u003C\u002Fp>\n\u003Ch2 id=\"cost\">Cost\u003C\u002Fh2>\n\u003Cp>Identical to the HTTP API. \u003Ccode>forma_status\u003C\u002Fcode> and \u003Ccode>list_oracles\u003C\u002Fcode> are free;\n\u003Ccode>ask_oracle\u003C\u002Fcode> costs the oracle's credits and the answer says what it cost. See\n\u003Ca href=\"\u002Flimits\">Limits and credits\u003C\u002Fa>.\u003C\u002Fp>\n","# MCP tools\n\n> Every tool the MCP server gives an agent — what it takes, returns and costs. Setting it up is in Connect your agent.\n\nForma speaks [Model Context Protocol](https:\u002F\u002Fmodelcontextprotocol.io), so an\nagent can reach an oracle without you writing an integration for it. Six\ntools, the same guarantees as the HTTP API, and the same prices.\n\n## The endpoint\n\n```\nhttps:\u002F\u002Fmcp.formalogic.io\u002Fmcp\n```\n\n**No API key needed.** Your client signs in with your Forma account (OAuth) the\nfirst time it calls a tool. For a client that cannot do OAuth, an API key sent as\na bearer token works too. Hosted, so the tools an agent sees are always the\ncurrent ones. Setup for each client is in [Connect your agent](https:\u002F\u002Fdocs.formalogic.io\u002Fconnect).\n\n## The tools\n\n### forma_status()\n\nWhich Forma account this session is signed in as. Free.\n\nAsk for this first when a connection has just been set up. `list_oracles`\nanswers identically for every caller, so a working connection and one signed in\nto someone else's account look the same through it; this answers with something\nonly a live, authenticated session can know.\n\n```json\n{ \"org_id\": \"org_01M2G6ZW…\", \"plan\": \"free\", \"requests_per_minute\": 10, \"features\": [] }\n```\n\n### list_oracles()\n\nEvery oracle available to your account, with each one's `formats`,\n`default_format` and `drawable_formats` (the ones `show_figure` can draw). Free. Call it before guessing a name — the catalogue is the\ncontract and it grows.\n\n### ask_oracle(oracle, intent, format?, allow_generated_data?)\n\n| Argument | |\n|---|---|\n| `oracle` | a name from `list_oracles` |\n| `intent` | what you want, described normally — not a template, not a specification — with the values to plot |\n| `format` | optional; defaults to that oracle's own. Pick one of `drawable_formats` when the person should see it |\n| `allow_generated_data` | optional, charts only; `true` accepts illustrative values when the intent gives none |\n\nForma does not fetch data. The agent puts the values in `intent`, fetching them\nfirst if the person wants real numbers; a chart request without them is refused\nwith `DATA_REQUIRED`, unbilled.\n\nThe answer is checked against the oracle's rules before it is returned, so\n`status` is a verdict rather than a guess: `valid` with a `result` and a\n`verified_by` citation, `invalid` where the check refused it and said why, or\n`error` which is ours, unbilled, and worth retrying. See\n[Verdicts](https:\u002F\u002Fdocs.formalogic.io\u002Fverdicts).\n\n### show_figure(figure_token, format?)\n\n| Argument | |\n|---|---|\n| `figure_token` | the `figure.token` from an `ask_oracle` answer, passed exactly as given |\n| `format` | `png` (the default), which can be looked at, or `svg`, returned as text for saving to a file |\n\nDraws a `valid` answer whose `figure.drawable` is true, so the person sees the\nchart or drawing and not only its source. An answer that cannot be drawn says why\nin `figure.reason`. Free: the answer was already paid for.\n\n### whats_new(since?)\n\nWhat changed for callers — endpoints, oracles, tools — newest first. `since` is\nan optional `YYYY-MM-DD`; pass the `latest` from an earlier call to see only what\narrived after it. Free. The same entries are in the [Changelog](https:\u002F\u002Fdocs.formalogic.io\u002Fchangelog).\n\n### send_feedback(sentiment, message, oracle?, request_id?)\n\n| Argument | |\n|---|---|\n| `sentiment` | `positive`, `negative` or `neutral` |\n| `message` | why, in a sentence or two; up to 2000 characters |\n| `oracle` | optional; the oracle it is about |\n| `request_id` | optional; the answer it is about. Left empty, the latest `ask_oracle` answer made with the same credential is used, when it was for the same oracle |\n\nTells the people who build Forma what worked and what did not. Free. See\n[News and feedback](https:\u002F\u002Fdocs.formalogic.io\u002Fnews-feedback).\n\n## Errors an agent can act on\n\nEvery failure comes back as an `error` object with a `kind`, so a model can\nbranch instead of the tool call dying.\n\n| `kind` | Meaning |\n|---|---|\n| `unauthorized` | Not signed in, or the sign-in or key is unrecognised, revoked or expired — a human has to act |\n| `quota_exceeded` | The allowance is spent; signing in again or switching keys will not help |\n| `not_found` | No such oracle — call `list_oracles` |\n| `invalid_request` | The request or the requested format was refused; `context` names the valid ones |\n| `upstream_unavailable` | A service the oracle depends on is briefly unavailable. Waiting is the right next move |\n| `backend_unreachable` | Network or DNS, after retries |\n\nEvery error also carries `retryable` — whether waiting could change the answer —\nand `request_id`, the id stamped on the failure. Quote the `request_id` when\nreporting a problem; it identifies the call in our logs.\n\nTransient failures are retried before anything is returned, so a `kind` that\nreaches your agent is one worth acting on.\n\n## Cost\n\nIdentical to the HTTP API. `forma_status` and `list_oracles` are free;\n`ask_oracle` costs the oracle's credits and the answer says what it cost. See\n[Limits and credits](https:\u002F\u002Fdocs.formalogic.io\u002Flimits).\n",1793819974148]