Every change Wellknown observed on this MCP server, newest first, with what it was before and what it became. Tool-surface changes carry the definition diff. Nothing here is edited after the fact.
Changed the definition of "import_document"
⟨248 unchanged words⟩ plan includes a number of imports a month (twelve times that over the year on an annual plan), counted when one starts — failed and ⟨58 unchanged words⟩
Changed the definition of "answer_import" and "import_document"
⟨142 unchanged words⟩ poll get_import; the template is usually written inunderaminute.few minutes. Free.
⟨160 unchanged words⟩ in code. Then poll `get_import` every few seconds;a one-pageandocumentimport is usually ready inunderaminute.few minutes. Galley may ask up to three questions about ⟨136 unchanged words⟩
Added "answer_import", "get_import", "import_document" and 1 more; changed the definition of "list_templates" (16 tools before, 20 now)
⟨35 unchanged words⟩ , og-card, certificate and more) already loaded. Each template says where it came from in `origin`: `library` (a starter), `import` (made from the person's own document by import_document) or `own` (made with create_template). Free.
Answer an import's questions — Answer the questions get_import shows on an import in `awaiting_answers`. Each answer is one of its question's option values — nothing else is accepted — plus `path`, a lowercase dotted field name such as `payment_terms`, when the answer makes a paragraph a field. Who answers: answer a question yourself when the evidence decides it (a paragraph of payment terms is `field_with_default`; a table with a quantity column is `repeating`); ask the person when it is about their business (which party they are, whether to keep a signature image). Mark each answer `answered_by: "agent"` (the default) …
Changed the definition of "render" and "validate_data"
⟨97 unchanged words⟩ per PDF page; cache hits are never billed. For a reader who is not in the US, send `data.lang` (a BCP 47 tag such as `fi` or `pt-BR`) if the template's schema has a `lang` property (check get_template first; the starter library's templates do for new accounts and after a library refresh): the document's fixed text, dates, money and paper size follow it, and `data.labels` overrides single strings. On a template that does not declare them they are ordinary unknown fields (a warning, or a 422 on a closed schema). Read `warnings` in the answer: fields the template did not use, and a language it has no text for. No API key needed to start — the ⟨16 unchanged words⟩
⟨48 unchanged words⟩ or validate_data to dry-run a payload for free. If get_template shows a `lang` property in the schema, add `lang` (a BCP 47 tag such as `fi` or `pt-BR`) for the reader's language, and `labels` (key to text) to reword single strings. Do not send them to a template whose schema lacks them: they are unknown fields there (a warning on an open schema, a 422 on a closed one).
Changed the definition of "create_template", "render" and "update_template"
⟨309 unchanged words⟩ anyOf":[{"type":"string"},{"type":"number"},{"properties":{"bottom":{"type":["string","number"]},"left":{"type":["string","number"]},"right":{"type":["string","number"]},"top":{"type":["string","number"]}},"type":"object"}],"description":"PDF margins, CSS lengths in `in`, `px`, `cm` or `mm`: `18mm`, or per side. A bare number is px."},"on_blocked_asset":{"description":"What to ⟨269 unchanged words⟩
Changed the definition of "create_account", "link_account" and "unlink_account"
⟨11 unchanged words⟩ permanent API key. Call it once with anemail: aemail.verificationA link issentmailed to that address and the tool returns `status: "pending_verification"`.`Afterwiththeahumanfour-characterclicks`request_code`. **Tell
Changed the definition of "create_account", "create_template", "get_render" and 4 more
⟨37 unchanged words⟩ link, call it again with the same email, from this same client, and it returns the API key, once. The key is not released before theclick.click, and it goes only to the client that asked for the link that was clicked. The click also binds this client to the ⟨21 unchanged words⟩ has an account, no second one ismade.**made, and no key comes back.** You get `status: "existing_account"`, `verified: ⟨50 unchanged words⟩ is waiting for are on the first one. A key on the connection changes this only if it is a live key for that same account. The trial in this session is upgraded in ⟨8 unchanged words⟩ trial are kept. The free tier is 5renders
Added "rotate_key"; changed the definition of "create_account" and "usage" (15 tools before, 16 now)
⟨176 unchanged words⟩ the trial are kept. The free tier is205 renders a month;pricingSolobeyondisthat$5isaatmonth for 500. Pricing: https://galleyrender.com/pricing. Store the key as a secret ⟨9 unchanged words⟩
Certificate recorded, valid to 2026-12-15
Authorization not required
Unknown → Live
First tool surface recorded: 15 tools (server version 0.1.0)
https://mcp.galleyrender.com/mcp (mcp_streamable_http) — from mcp_registry, with the record
Showing the latest 13 events. The API returns up to 500 and filters by kind: ?kind=tool_surface_changed
Check an import, see its questions or its preview — The state of a document import and what to do next (`next_step`). Poll it after import_document and after answer_import. - `awaiting_answers`: up to three questions, each with its options, the recommended one, and its evidence — the words on the page (`evidence.text`) and an image of the region. The rule for who answers: answer a question yourself when the evidence decides it (a paragraph of payment terms is `field_with_default`; a table with a quantity column is `repeating`); ask the person when it is about their business (which party they are, whether to keep a signature image). Then answe…
Make a template from a document the person already has — Turn a document the person already sends — their invoice, letterhead, minutes, a form — into a Galley template that reproduces its look, with a JSON Schema you can fill. PDF only (exported from the program that made it, not a scan), up to 10 pages and 20 MB. **Getting the file to Galley — send exactly one:** - `upload: true`, the usual answer in a chat. A file the person dropped into the conversation reaches you as pages to read, not as bytes you can pass on, so this returns a one-time upload link (15 minutes, one use) for the person and a curl line for an agent with a shell. Ask the person …
Save an import as a template — Save a `ready` import as a template on this account, once the person has seen the preview and says it is right. Returns the template's ref (`name@1`), its fields, and how to render it. `name` defaults to the one import_document was given, then the draft's own. It counts against the plan's template limit like any template of the account's own (`plan_required` at the limit). Saving again returns the same template. The import's copy of the document is deleted 7 days after it finished; the template stays, and `update_template` publishes changes to it. Free; its renders bill as renders.
⟨49 unchanged words⟩ a payload from somewhere you do not control. `warnings` lists fields the template would not use, each with a `did_you_mean` where there is a near match, and, where the template's schema declares `lang`, what `data.lang` would do.
⟨9 unchanged words⟩ intend to render. Checked against the template's JSONSchemaSchema; fields it does not use come back in `warnings`, not as errors. `lang` andnothing`labels`else.at the root are honoured only if the template's schema declares them (check get_template); otherwise they are ordinary unknown fields."},"template":{"description":"Template to ⟨50 unchanged words⟩
⟨175 unchanged words⟩ anyOf":[{"type":"string"},{"type":"number"},{"properties":{"bottom":{"type":["string","number"]},"left":{"type":["string","number"]},"right":{"type":["string","number"]},"top":{"type":["string","number"]}},"type":"object"}],"description":"PDF margins, CSS lengths in `in`, `px`, `cm` or `mm`: `18mm`, or per side. A bare number is px."},"on_blocked_asset":{"description":"What to ⟨208 unchanged words⟩
⟨215 unchanged words⟩ anyOf":[{"type":"string"},{"type":"number"},{"properties":{"bottom":{"type":["string","number"]},"left":{"type":["string","number"]},"right":{"type":["string","number"]},"top":{"type":["string","number"]}},"type":"object"}],"description":"PDF margins, CSS lengths in `in`, `px`, `cm` or `mm`: `18mm`, or per side. A bare number is px."},"on_blocked_asset":{"description":"What to ⟨286 unchanged words⟩
⟨56 unchanged words⟩ and it needs no tool call at all. **Only a client with an identity of its own can be linked.** A connector added with the shared URL and no client id is recognised by its IP address and User-Agent, and every user of a hosted connector shares those: they call from their vendor's servers. Linking that would link all of them, so it is refused. Add this server with a personal URL instead — `https://mcp.galleyrender.com/mcp/c/<id>`, with a random `<id>` of your own (https://galleyrender.com/docs/connect makes one) — or send `X-Galley-Client-Id` with at least 128 random bits, then link. Two ways to prove the account is yours. ⟨60 unchanged words⟩ minted for this client, which `unlink_account` revokes.**The client id is coarse.** Without an `X-Galley-Client-Id` header it is derived**Whoeverfromhas theIPclientaddressidandactstheasUser-Agent,thesoaccount.**onAapersonalsharedconnectormachine,URL orbehind one office NAT with the samea client,another person can landidonheadertheissameaidentitycredentialandoncereachlinked:thiskeepaccount.itUselike aheader instead wherever the client allows onekey, and `unlink_account` when you are done on ⟨7 unchanged words⟩
⟨46 unchanged words⟩ any machine that is not yours, andonwheneveranyaclientpersonalwhoseconnectoridentityURLisor asharedclientoneid(nomay`X-Galley-Client-Id`haveheaderbeenmeansseenIPbyplussomebodyUser-Agent).else. Calls afterwards fall back to the keyless trial. ⟨8 unchanged words⟩
⟨41 unchanged words⟩ an existing template is `update_template`, not this.Free.Free, but each plan keeps a limited number of templates of your own (the starter library never counts): at the limit this returns `plan_required` with how many the account has, and `update_template` still works.
⟨26 unchanged words⟩ a URL that has expired — signed URLsarelastshort-livedan hour, the storedobjectfile lasts until the render's `expires_at` (the plan's retention). Past `expires_at` the file isnot.deleted and this returns `retention_expired` (410) with the render and the template version to render again. Free, and never re-renders.
⟨85 unchanged words⟩ `cached: true`, free and instant. Billing isone unitper PNG or JPG andoneper PDF page; cache hits are never billed. No API key needed to start — the first call mints a10-rendertrial of 10 PDF pages or 10 images and returns its token.
⟨27 unchanged words⟩ paid plan to subscribe to. Solo $5/mo (200 PDF pages or 500rendersimages, webhooks, cloud delivery), Starter $19/mo (2,000 PDF pages or 5,000 images), Growth $79/mo (12,000 PDF pages or 30,000 images, priority queue, 90-day retention), Scale $249/mo (60,000 PDF pages or 150,000 images, dedicated pool, SLA). Call `usage` first ⟨42 unchanged words⟩
⟨24 unchanged words⟩ and — on a keyless trial — howmanymuch of the trial's 10trialPDFrenderspagesremain.or 10 images remains. Check it before a large batch. Free.
⟨7 unchanged words⟩ : its id, its plan, how manyrendersPDFarepages or images its trial or free tier has left (`renders_remaining`, one per page or image), and — the part no other tool answers ⟨16 unchanged words⟩ linked with `link_account`), or `trial` (the keylessten-rendertrial). Call it before a batch, ⟨48 unchanged words⟩
Only numbers and dates differ: this server embeds live figures in the definition, so the text moves without the contract changing.
⟨27 unchanged words⟩ a keyless trial — how many of the5010 trial renders remain. Check it before a large batch. Free.
Mint a new API key and retire the old one — Get a fresh API key for the account this connection is already acting on — the answer to a key that has been lost, leaked, pasted into a chat window, or left on a machine that is not yours. **Two calls, on purpose.** `rotate_key({})` mints the new key and shows it **once**; it revokes nothing, so whatever is running on the old key keeps running. Give the new key to the person, wait until they tell you it is saved, then call `rotate_key({ confirm_saved: true, revoke_key_id: "…" })` with the id from `other_live_keys` to kill the old one. Revoking first would take their integration down between…