cofinance.land MCP server: developer reference
Looking for the short version? Start at /docs/mcp. Writing an agent? Read the guide for AI agents.
A hosted, read-only Model Context Protocol server over our curated 318-page wiki on European cohousing finance. Seven free tools that need no API key and cost nothing, plus one paid tool (ask_wiki) that reads the wiki for you and charges credits.
Read this before you connect
Most of what follows is a list of things this server is not. That is deliberate. A knowledge tool that oversells its coverage is worse than no tool, because a model will trust it.
- The corpus is narrow: 318 pages today, about 596.2k characters. You can read the whole thing end to end. It is hand-written and actively being extended, so every figure on this page is a snapshot of the corpus as it stands rather than a ceiling — re-read it, or call
wiki_list, instead of caching what it says today. - Coverage varies by jurisdiction and is still growing. There are 196 funding programmes on file, alongside legal-form and financing notes. Germany, Italy and Spain, including Catalonia, have country-specific coverage; 147 of the 318 pages are German. The jurisdictions on file right now are
CH,DE,DE-BB,DE-BE,DE-BW,DE-BW-FR,DE-BW-HD,DE-BW-TU,DE-BY,DE-BY-M,DE-HB,DE-HE,DE-HE-F,DE-HH,DE-MV,DE-NI,DE-NW,DE-NW-K,DE-RP,DE-SH,DE-SL,DE-SN,DE-SN-DD,DE-SN-L,DE-ST,DE-TH,ES,ES-AN,ES-AR,ES-AR-ZAR,ES-AS,ES-CB,ES-CE,ES-CL,ES-CM,ES-CN,ES-CT,ES-CT-B,ES-CT-B-BCN,ES-CT-B-MAN,ES-CT-GI-PAL,ES-CT-L-LLE,ES-EX,ES-GA,ES-IB,ES-MC,ES-MD,ES-MD-MAD,ES-ML,ES-NC,ES-PV,ES-PV-ALA-VIT,ES-RI,ES-VC,EU,IT,IT-21,IT-23,IT-25,IT-32,IT-32-BZ,IT-32-TN,IT-34,IT-36,IT-42,IT-45,IT-52,IT-55,IT-57,IT-62,IT-65,IT-67,IT-72,IT-75,IT-77,IT-78,IT-82,IT-88,NO. Jurisdictions absent from that list are not covered yet. Read that as a gap in a growing wiki, not as a verdict; and do not read it the other way either, as a commitment that any particular country is on its way. - An empty result means “not covered here”. It does not mean “no such funding exists”. A query about French cooperative housing finance correctly returns nothing from this server today. That is the honest meaning of
openWorldHint: false, and it is the single most important thing for a model to get right here: someone making a real financing decision must not read our gap as the absence of a programme. Say the wiki does not cover it yet — do not substitute a figure recalled from training data. - Freshness is wildly uneven. 316 of 318 pages carry a
lastVerifieddate, but the dates span2015-11-09to2026-10-05— two of them are eleven years old — and 257 pages are flaggedvolatile, meaning their figures are known to move. Near total date coverage is not the same as currency. ReadlastVerifiedas a date, not as a badge. Every tool result states it, or states that the page has never been verified — the field is never quietly dropped. - One tool spends money. Exactly one. The free wiki tools are anonymous and cost nothing — no model call happens behind them.
ask_wikiis the single exception: it requires a credential (an OAuth sign-in or an API key) and charges credits to that account, roughly one chat turn's worth, and every successful call states what it cost. It is labelled_meta.tier: "paid"intools/list, so a client can see the difference before calling rather than at the paywall. Nothing else on this server can spend your credits. - Anonymous rate limiting is best-effort, not a security boundary. See rate limits.
- Both protocol eras are served, but they are not the same server to a client. A modern
2026-07-28caller getsserver/discover,tools/listandtools/calland noping; a legacy caller gets theinitializehandshake exactly as before. See protocol version.
What it is good at
This is a bounded, curated, source-cited corpus, not an open-web scraper. That is why every free tool declares openWorldHint: false: the answer set is closed, so an empty result genuinely means “this wiki does not cover it” rather than “the search failed”. Every page carries its sources and its own freshness verdict, so a model can cite the primary source instead of citing us — and can tell you when a number is too old to trust.
Endpoint and transport
| Method | Behaviour |
|---|---|
POST /mcp | The MCP endpoint. One JSON-RPC 2.0 message per request. Requests answer 200 with a JSON-RPC body; notifications answer 202 with no body. |
GET /mcp | 405 Method Not Allowed. There is no SSE stream — see below. |
OPTIONS /mcp | 204 CORS preflight, against a strict origin allowlist. Never echoes a wildcard. |
DELETE /mcp | 204 no-op. The server is stateless, so there is no session to tear down. |
The transport is Streamable HTTP, in its request/response form only.
- No SSE streaming. A
GET /mcp— which is a client asking to open a server-to-client stream — returns405. The spec explicitly permits this, and well-behaved clients fall back to plain POST. There are no server-initiated messages to stream. - Stateless: no
Mcp-Session-Id. The server never issues one, so clients never send one back. Every request is authorised independently.initializemay be re-sent at any time; it is a pure capability handshake. - No JSON-RPC batching. An array body is rejected with
-32600, in both eras and on every supported revision. - No self-hosting. The server is not published as a runnable package; the hosted endpoint is the only way to use it today.
- Request bodies are capped at 256 KB, checked before parsing. Larger bodies get
413. Content-Typemust beapplication/json, compared by media type rather than by substring. Anything else — including an absent header, which is the other un-preflighted cross-site body shape — is415.Acceptis ignored.- A request carrying an
Originheader that is not on the server’s allowlist is rejected with403. An absentOriginis fine — that is the normal non-browser MCP client.
Protocol version and negotiation
This server is dual-era
It implements MCP revision 2026-07-28 (modern, per-request metadata) and revisions 2025-06-18 / 2025-03-26 (legacy, initialize handshake), on the one /mcp endpoint. The era is chosen per request, from the message itself: an initialize request selects legacy; a request carrying _meta["io.modelcontextprotocol/protocolVersion"], or a modern MCP-Protocol-Version header, or the method server/discover, selects modern.
Legacy handshake clients
You get exactly what you got before, byte for byte.
initializenegotiates2025-06-18or2025-03-26— never 2026-07-28, because a legacy client cannot speak it. An unsupported or absentparams.protocolVersionis answered with our latest legacy revision rather than an error; the lifecycle spec requires a version in the reply, not a failure.- If the
MCP-Protocol-Versionheader is absent, the server assumes2025-03-26, per the transport spec. ping,tools/listandtools/callall work. Results carry noresultType, and a JSON-RPC error comes back at HTTP 200.- Successful responses echo the negotiated revision in the
MCP-Protocol-Versionresponse header.
Modern stateless clients
Send MCP-Protocol-Version: 2026-07-28, Mcp-Method, Mcp-Name (on tools/call) and a _meta carrying the required io.modelcontextprotocol/protocolVersion and io.modelcontextprotocol/clientCapabilities (clientInfo optional).
server/discover— the mandatory modern RPC. ReturnssupportedVersions: ["2026-07-28"],capabilities: { tools: { listChanged: false }, extensions: {} },instructions, and_meta["io.modelcontextprotocol/serverInfo"].tools/listcarriesresultType,ttlMs: 300000andcacheScope: "public";tools/callcarriesresultType: "complete"with ourserverInfomerged into_meta.initializeandpingare not available to you.pingis404/-32601; the revision removed it.initializeis still answered, under legacy semantics, because the spec makes it the era selector.- We advertise no extensions. There is no SSE, no session and no
Mcp-Session-Id;GETis405andDELETEis a204no-op (legacy teardown).
Unknown-version clients
A revision we serve in neither era is HTTP 400:
{
"jsonrpc": "2.0",
"id": <id or null>,
"error": {
"code": -32022,
"message": "Unsupported protocol version",
"data": {
"supported": ["2026-07-28", "2025-06-18", "2025-03-26"],
"requested": "<echoed, sanitised>"
}
}
}It is checked twice: a cheap pre-parse header screen, which cannot know the request id and so answers id: null, and again after the parse, where the id is carried.
Other modern-only errors: -32020 (header mismatch) at 400 when MCP-Protocol-Version, Mcp-Method or Mcp-Name is missing or does not match the body; -32602 at 400 for a missing required _meta field. -32001 (auth required) and -32002 (rate limited) are unchanged — still 200 and 429 respectively, in both eras.
Advertised capabilities are { "tools": { "listChanged": false } } and nothing else: no prompts, no resources, no logging, no completions. The tool registry is static per deploy, so notifications/tools/list_changed is never emitted.
Methods this server implements at all: initialize, ping, server/discover, tools/list, tools/call — but the reachable set is per era, as above, and a method that exists in the other era is -32601 just like one that exists nowhere. Well-formed notifications (including notifications/initialized) are accepted and answered 202 with no body.
Authentication
You do not need an API key for the wiki tools. All of these are free and work anonymously. A credential raises your rate limit, makes your usage attributable and revocable, and is the only way to reach ask_wiki, which charges credits. Anonymous callers get a -32001 for that tool and are never billed.
Two credentials are accepted on the same Authorization: Bearer header, told apart by shape:
- OAuth 2.1 — for hosts such as Claude.ai that sign a user in. The server is a resource server only; Clerk is the authorization server. Discovery follows RFC 9728 at
/.well-known/oauth-protected-resource, which every 401 names inWWW-Authenticate. Scopes aremcp:readandmcp:ask; dynamic client registration and PKCE are supported. Tokens are verified locally against the issuer JWKS, including theaudclaim, which must name this endpoint. - API key — for CLIs and scripts. Shape
cfl_live_+ 64 hex.
Create one in Settings → API keys. The plaintext secret is shown exactly once and is never stored in a readable form; only its SHA-256 digest is kept, so a database leak does not hand anyone a working credential. Keys look like cfl_live_…, are limited to 10 active per account, and revocation takes effect on the very next request.
Authorization: Bearer cfl_live_7f3a…| What you send | What happens |
|---|---|
| No Authorization header | Anonymous. Free tools work. This is the documented way to use the server, and it is not an error. |
| A malformed, unknown or revoked key | 401 with JSON-RPC code -32001 and one generic message, “Invalid or revoked API key”. All three failure modes share that message on purpose, so the endpoint cannot be used to enumerate valid keys. The response carries WWW-Authenticate: Bearer realm="cofinance-land-mcp", error="invalid_token". |
| A valid key | Authenticated. Your rate-limit bucket is keyed on the key id, and usage is attributable to it. |
A supplied credential that does not work is an error
The server never silently downgrades a bad key to anonymous. If it did, a user whose key had been revoked would keep getting 200s from the free tools and reasonably conclude they were still authenticated.
Tool reference
Eight tools. The seven free tools are read-only, idempotent, non-destructive and closed-world (openWorldHint: false), and all read the same compiled-in corpus: no database round-trip, no model call, no per-request cost. The eighth, ask_wiki, is the paid exception and is described last.
Shared behaviour worth knowing before you read the schemas: German spelling is folded three ways, so Mietshauser, Mietshaeuser and Mietshäuser all reach the same pages; compounds partially match, so Genossenschaft reaches Wohnungsgenossenschaft. limit is clamped to 25 rather than rejected. The whole response text is capped at 16,000 characters, and results are dropped from the end with a notice rather than the cap being breached — check _meta.hasMore and page with offset.
The public corpus has three page types — funding-program, entity-form and legal-topic. A fourth internal type documents the product itself and is withheld from this server and from the public wiki alike, so you will never see it in a result.
wiki_search — ranked keyword search
Returns a relevance-centred snippet per hit (max 320 characters) plus the id needed to read the page in full.
{
"type": "object",
"properties": {
"query": { "type": "string" },
"jurisdiction":{ "type": "string" },
"type": { "type": "string",
"enum": ["funding-program","entity-form","legal-topic"] },
"legalForms": { "type": "array", "items": { "type": "string" } },
"tags": { "type": "array", "items": { "type": "string" } },
"limit": { "type": "integer", "minimum": 1, "maximum": 25 },
"offset": { "type": "integer", "minimum": 0 }
},
"required": ["query"],
"additionalProperties": false
}Default limit is 10. An unknown tag or legalForm simply matches nothing.
How the jurisdiction filter behaves
A country page matches only that country or a subdivision of it. Pass a country to include its regions — DE shows the Saxony page — and pass a region to narrow to it. EU-level pages match EU member states only, not CH or NO; Switzerland and Norway are EEA/EFTA, and this corpus records nothing about which EU instruments reach them, so silence is the honest answer. An unrecognised code returns nothing rather than a broadened result.
Concretely: funding_programs({ jurisdiction: "FR" }) returns nothing. It used to return four German programmes under a header claiming they matched France — a fabricated answer for someone making a real financing decision. The filter now prefers a false negative, which you recover in one call by dropping the filter, over a wrongly-asserted match, which you cannot recover from at all.
wiki_get — one page in full
{
"type": "object",
"properties": {
"id": { "type": "string" }
},
"required": ["id"],
"additionalProperties": false
}Ids are stable lowercase slugs (kfw-134, syndikat-direktkredit, eg-cooperative). An unknown id returns isError: true with the full list of valid ids, so a model can correct itself in one step. Bodies over 2,000 characters are cut with the cut marked inline and a link to the public page.
wiki_list — browse the index
{
"type": "object",
"properties": {
"jurisdiction": { "type": "string" },
"type": { "type": "string",
"enum": ["funding-program","entity-form","legal-topic"] },
"legalForms": { "type": "array", "items": { "type": "string" } },
"tags": { "type": "array", "items": { "type": "string" } },
"limit": { "type": "integer", "minimum": 1, "maximum": 25 },
"offset": { "type": "integer", "minimum": 0 }
},
"required": [],
"additionalProperties": false
}One compact line per page — id, title, type, jurisdiction, freshness, link — and no body prose. With no arguments it returns the first 25 pages and sets _meta.hasMore with a nextOffset, so page through it to see the whole index. Once you have, treat that as the corpus boundary.
funding_programs — programmes, freshness first
{
"type": "object",
"properties": {
"jurisdiction": { "type": "string" },
"legalForms": { "type": "array", "items": { "type": "string" } },
"limit": { "type": "integer", "minimum": 1, "maximum": 25 },
"offset": { "type": "integer", "minimum": 0 }
},
"required": [],
"additionalProperties": false
}The same pages wiki_list would give you with type: "funding-program", but with freshness leading every entry and a header stating how many of the shown entries are volatile or unverified. This is the highest-churn part of the corpus.
wiki_get_many — up to eight pages in one round trip
{
"type": "object",
"properties": {
"ids": { "type": "array", "items": { "type": "string" } }
},
"required": ["ids"],
"additionalProperties": false
}Bodies share one response budget, so eight ids return eight shorter bodies rather than eight full ones, and anything shortened is named. An id that does not exist is reported alongside the ones that do — the call does not fail because one id was wrong — and the result is flagged _meta.degraded so a missing page cannot quietly become a hole in your answer.
affordability — equity into a price ceiling
{
"type": "object",
"properties": {
"jurisdiction": { "type": "string" },
"equityTotal": { "type": "number" },
"households": { "type": "integer", "minimum": 1 },
"propertyKind": { "type": "string",
"enum": ["einfamilienhaus","eigentumswohnung",
"mehrfamilienhaus","land"] },
"buyerKind": { "type": "string",
"enum": ["natural-persons","entity"] },
"agentUsed": { "type": "boolean" },
"maxLoanToPrice": { "type": "number" },
"interestRate": { "type": "number" },
"repaymentRate": { "type": "number" }
},
"required": ["jurisdiction", "equityTotal"],
"additionalProperties": false
}Germany only. Returns the purchase-price ceiling the equity can carry, the Kaufnebenkosten broken out by line at the rate for that Land, and an indicative monthly payment. Every figure carries its own source URL and verified-on date, the same as a wiki page.
Two refusals are deliberate. A bare DE is rejected: Grunderwerbsteuer runs 3.5 % in Bayern to 6.5 % in four Länder, a €9,000 spread on a €300,000 purchase, so there is no honest national average to fall back on. And interestRate and repaymentRate have no defaults — omit them and you get the ceiling with no monthly figure, because a rate nobody has been offered is not a fact and this tool will not supply one. Whatever you do pass is echoed back labelled as an assumption.
conflicts — can these routes be combined?
{
"type": "object",
"properties": {
"ids": { "type": "array", "items": { "type": "string" } },
"entityForm": { "type": "string" },
"hasChildUnder18": { "type": "boolean" },
"willOwnerOccupy": { "type": "boolean" }
},
"required": ["ids"],
"additionalProperties": false
}Takes programme ids and structural route ids together — the forks that matter here are mostly between the two. Reports mutually exclusive pairs, hard eligibility exclusions for the applicant you describe, and separately the gates you have not answered, so a model asks rather than assumes.
An empty conflict list is not clearance, and the tool says so in its own output: it returns what it checked and what it did not. Budget exhaustion, application deadlines and the Kumulierungsverbote written into individual Richtlinien are outside this corpus entirely.
ask_wiki — a grounded answer, paid
{
"type": "object",
"properties": {
"question": { "type": "string" }
},
"required": ["question"],
"additionalProperties": false
}The one tool that runs a model. It reads the wiki and writes a prose answer that names the jurisdiction of every programme it cites and carries each page’s freshness through. Requires a credential (OAuth scope mcp:ask, or an API key) and spends credits from that account, roughly one chat turn per call; the cost is appended to every answer. Tagged _meta.tier: "paid" in tools/list. Not idempotent. It answers only from the corpus and says so when the wiki is silent.
A worked call
POST https://mcp.cofinance.land/mcp
Content-Type: application/json
MCP-Protocol-Version: 2025-06-18
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "wiki_get",
"arguments": { "id": "kfw-134" }
}
}HTTP/1.1 200 OK
Content-Type: application/json
MCP-Protocol-Version: 2025-06-18
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{
"type": "text",
"text": "# KfW Programm 134 …\n- Freshness: VOLATILE — figures, rates and deadlines on this page change; re-verify against the listed source before relying on it. Last verified 2026-06-06.\n…"
}
],
"_meta": {
"results": [
{
"pageId": "kfw-134",
"lastVerified": "2026-06-06",
"volatile": true,
"sources": ["https://www.kfw.de/…"],
"truncated": false
}
],
"corpusPageCount": 318,
"totalMatches": 1,
"truncated": false,
"hasMore": false,
"nextOffset": null
}
}
}Provenance rides in _meta and is restated in words inside content[0].text. That duplication is deliberate: most MCP clients never surface _meta to the model, so the freshness caveat has to survive in the text the model actually reads.
A tool that runs and fails returns isError: true inside a successful JSON-RPC result, per the tools spec, so the model can see what went wrong and adapt. Protocol-level failures — unknown tool, bad params — come back as JSON-RPC errors instead.
Client setup
Claude Code
claude mcp add --transport http cofinance-land https://mcp.cofinance.land/mcpclaude mcp add --transport http cofinance-land https://mcp.cofinance.land/mcp \
--header "Authorization: Bearer cfl_live_YOUR_KEY_HERE"Claude Desktop
Add this to your claude_desktop_config.json and restart the app.
{
"mcpServers": {
"cofinance-land": {
"type": "http",
"url": "https://mcp.cofinance.land/mcp"
}
}
}{
"mcpServers": {
"cofinance-land": {
"type": "http",
"url": "https://mcp.cofinance.land/mcp",
"headers": {
"Authorization": "Bearer cfl_live_YOUR_KEY_HERE"
}
}
}
}Raw HTTP — the initialize handshake
curl -sS -X POST https://mcp.cofinance.land/mcp \
-H 'Content-Type: application/json' \
-H 'MCP-Protocol-Version: 2025-06-18' \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {},
"clientInfo": { "name": "curl", "version": "1.0.0" }
}
}'{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-06-18",
"capabilities": { "tools": { "listChanged": false } },
"serverInfo": {
"name": "cofinance-land",
"version": "1.0.0",
"title": "Cofinance Land"
},
"instructions": "Read-only tools over cofinance.land's small, hand-curated wiki …"
}
}Then tools/list to enumerate, and tools/call to invoke. There is no session to establish; notifications/initialized is accepted (202) but not required.
Raw HTTP — the modern server/discover
The 2026-07-28 equivalent. No handshake: the metadata rides on every request, and the mirrored headers must agree with the body or you get a -32020.
curl -sS -X POST https://mcp.cofinance.land/mcp \
-H 'Content-Type: application/json' \
-H 'MCP-Protocol-Version: 2026-07-28' \
-H 'Mcp-Method: server/discover' \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "server/discover",
"params": {
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}'Rate limits
| Caller | Sustained | Burst | Keyed on |
|---|---|---|---|
| Anonymous | 120 / hour | 20 | Client IP |
| With an API key | 1,200 / hour | 60 | API key id |
Exceeding a bucket returns 429 with a Retry-After header, JSON-RPC code -32002, and error.data.retryAfterSeconds carrying the same number for clients that only read the JSON body.
Anonymous per-IP limiting is best-effort, not a security gate
The client IP is taken from the first value of X-Forwarded-For, which in principle a caller could forge to mint unlimited distinct buckets. We tested it rather than guessing: thirty requests carrying the same forged header exhausted a bucket, and twelve carrying twelve different forged headers were all rejected rather than each getting a fresh allowance. Forging the header does not work. What we still have not confirmed is whether that shared bucket is keyed on your real IP or on a single global fallback — so we describe the limit as best-effort rather than promising you an allowance nobody else can spend.
What actually contains the anonymous surface is that it is cheap, read-only, and spends no credits: every tool reads a corpus compiled into the bundle, with no database write, no model call and no third-party API behind it. Bulk-reading it costs us bandwidth and nothing else — and you can read the whole corpus on the public wiki anyway.
NAT’d offices share an IP and therefore share the anonymous bucket. If you hit it, create an API key and move to the authenticated bucket.
Status and error codes
| HTTP | JSON-RPC code | When |
|---|---|---|
| 200 | — | A request was answered (including tool results with isError: true). |
| 202 | — | A notification was accepted. No body. |
| 400 | -32700 | Body was not valid JSON. |
| 400 | -32600 | Not a valid single JSON-RPC 2.0 message; batches; unreadable body. |
| 400 | -32022 | Unsupported protocol version, in either era. Carries error.data.supported and the echoed error.data.requested. Screened once on the header before parsing (id: null) and once after (id carried). |
| 400 | -32020 | Modern era only: MCP-Protocol-Version, Mcp-Method or Mcp-Name missing, or not matching the body. |
| 400 | -32602 | Modern era only: a required _meta field is missing. |
| 401 | -32001 | Authorization header present but malformed, unknown or revoked. |
| 403 | -32600 | Origin header present and not on the allowlist. |
| 404 | -32601 | Modern era only: a method that exists in the legacy era but not this one — ping, and any unknown method. |
| 405 | -32600 | GET — no SSE stream is offered here. |
| 413 | -32600 | Body over 256 KB. |
| 415 | -32600 | Content-Type is not application/json. |
| 429 | -32002 | Rate limited. Retry-After header and error.data.retryAfterSeconds. |
| 500 | -32603 | Internal error. Carries a correlation reference; details are logged server-side only. |
| 503 | -32603 | The MCP service is disabled by its kill-switch. |
In the legacy era every JSON-RPC error is returned with 200: -32601 for an unknown method, -32602 for an unknown tool or invalid params, and -32001 if a tool requiring authentication is called without a verified key. In the modern era the protocol-level failures above are lifted to their HTTP status — 400 for -32020 and -32022, 404 for -32601 — while everything else, including -32001, stays at 200.
Error messages never echo internal detail. A handler that throws is logged in full server-side against a correlation id, and you receive a generic failure carrying only that reference.
Pricing and credits
The four wiki tools are free
wiki_search, wiki_get, wiki_list and funding_programs declare no authentication requirement, read only from a corpus compiled into the deploy, and write no usage event. There is no model call behind them. Calling them costs you nothing and costs us nothing per call.
cofinance.land itself runs on a credits model for its paid agent runs (1 credit = €0.01), and ask_wiki bills against that same wallet — the one belonging to the API key's owner. It is metered like any other agent run: actual model tokens, times the configured markup, floored at the per-action minimum. A single question is roughly the cost of one chat turn, and the exact figure is appended to every successful answer rather than left for you to reconstruct from an invoice. There is no subscription and no plan to buy. If the wallet is empty the call is refused before any model runs, with a top-up link and a reminder that the free tools still work. Paid tools are tagged _meta.tier: "paid" in tools/list, so a client can tell the tiers apart before calling rather than after.
Freshness semantics
Two fields travel with every page, in _meta and in the result text. Neither is a quality score, and the absence of one is never a positive signal:
| Field | Meaning |
|---|---|
lastVerified | ISO date a human last checked the page against its source, or null. Never omitted — an absent key would be indistinguishable from a serialisation bug, whereas an explicit null says “we looked, there is no date”. In text it renders as never verified. Read the date itself: a 2015 check and a 2026 check are not the same claim. |
volatile | True when the page carries figures, rates or deadlines that move. Re-verify against the cited source before quoting any number from a volatile page. volatile: false does not mean “stable” — it means nobody flagged it as fast-changing. That is the absence of an editorial judgement, not a positive one, and it says nothing about whether the page has ever been checked. |
As of now: 316 of 318 pages have a date at all, 257 are flagged volatile, and recorded verifications run from 2015-11-09 to 2026-10-05. Those numbers are computed from the corpus at build time, not typed in, so this paragraph cannot drift away from the truth.
Explicitly not supported
- SSE / server-initiated streaming (
GET /mcp→ 405). - Sessions (
Mcp-Session-Idis never issued). - JSON-RPC batching (arrays are rejected).
- MCP resources, prompts, logging, sampling and completions.
- Self-hosting or an on-prem build.
- Write operations of any kind. Every tool is read-only.
- Open-web lookup. The corpus is closed and curated by hand.
pingandinitializefor a modern2026-07-28caller — the revision removed the first and replaced the second withserver/discover. Legacy callers keep both.- MCP extensions. We advertise none.
Found something wrong, or a figure that has moved? Tell us — corrections to a 318-page corpus land fast.