You have code
Give your agent a render tool.
It signs itself up.
JSON in, PDF out. Every render deterministic, cached, and signed.
Start here
One address, and your assistant can make documents.
Galley is a hosted MCP server. Paste the address into Claude, ChatGPT, Claude Code or Cursor and the
assistant gets 16 tools. It can render any of the 43 starter templates,
create and version templates of its own, and check usage. It can also call create_account
to get its own key without sending you off to a web page.
MCP endpoint
https://mcp.galleyrender.com/mcp
Streamable HTTP, stateless, and no auth needed to start. The first render call
mints a trial of 10 PDF pages or 10 images and returns its token.
Not writing code? Pick a document and see it filled in with your own data →
Two clicks, and no terminal
Copy the address above, paste it into your assistant's connector settings, and ask for a document.
That's all the setup there is. The trial is per connection and doesn't need a card, a key or a
sign-up. When you want to keep the work for good, the assistant calls create_account
with your address and you click one link.
Four assistants, and the steps for each
Every step below is quoted from the product's own documentation. Pick the one you use.
https://mcp.galleyrender.com/mcp
Streamable HTTP, with no sign-in, key or OAuth. Your first documents are free. When you want
more, ask your assistant to make you an account. You'll get an email that shows who asked and a
short code, and you confirm it there. Already have a key? The last step in every tab below is
where it goes: a header for Claude Code and Cursor, and, for Claude.ai and ChatGPT, a personal
address plus the link_account tool.
Claude.ai
The web app at claude.ai, and Claude Desktop. Free, Pro, Max, Team and Enterprise. On Team and Enterprise an owner adds it once for the organization, then everyone connects to it.
- Open claude.ai →
Customize→Connectors. - Click
+, thenAdd custom connector. - Paste your personal address into the URL field. It's made here, in your browser, and nobody else has it:
https://mcp.galleyrender.com/mcp/c/… - Leave
Advanced settingsalone. That's where an OAuth client id and secret would go, and Galley doesn't need either. - Click
Add. Galley's tools are now in the tools menu of any new chat. - Try it: ask for one of the documents below and watch it approve the tool call.
- Use your key. Claude.ai's connector dialog can't send an HTTP header, so the key goes in through a tool instead. Ask Claude: run link_account with my Galley key. If you'd rather not paste a key into a chat, ask it to run create_account with my email address. An address that already has an account gets a one-time code by email instead of a second account, and
link_accounttakes that code. Check it worked with run whoami. This works because of your personal address: Claude calls Galley from Anthropic's servers, so on the shared address every Claude user looks the same, and that one can't be linked to anybody's account.what to say textRun link_account with this key: glr_sk_… or, with no key to hand: Run create_account with my email, then link_account with the code that arrives.
On Team or Enterprise the first step is an owner's job: Organization settings → Connectors → Add → Custom → Web. Everyone else then finds it under Customize → Connectors and clicks Connect.
Keep your personal address to yourself. Once it's linked, whoever has it is using your account, the same as with a key. Don't paste it into a shared document. If somebody else might have seen it, ask for unlink_account and add Galley again with a new one. On a Team or Enterprise plan, an address an owner adds for the organization is shared by everyone in it.
ChatGPT
The ChatGPT web app. Plus, Pro, Business, Enterprise and Education, on the web. ChatGPT's free plan can't add a custom connector. On a free account, use Claude, which can.
- In ChatGPT, open
Settings→Security and loginand turn onDeveloper mode. - Go to chatgpt.com/plugins.
- Click the
+button and create a developer-mode app for a remote MCP server. - Paste your personal address as the server URL. It's made here, in your browser, and nobody else has it:
https://mcp.galleyrender.com/mcp/c/… - Leave authentication empty, because Galley doesn't need any.
- Save. Your new app appears under
Drafts. It's yours to use, and nothing is submitted to OpenAI or reviewed by anyone. - In a chat, enable it and ask for a document. ChatGPT asks you to confirm the first time it makes a file. That prompt is normal for any action that writes something.
- Use your key. Leave the authentication fields empty (Galley doesn't use OAuth) and hand the key over with a tool instead: run link_account with my Galley key. No key to hand? Run create_account with my email address. If that address already has an account, we email it a one-time code, and
link_accounttakes the code. Run whoami confirms which account you're on. It works because of your personal address: ChatGPT calls Galley from OpenAI's servers, so on the shared address every ChatGPT user looks the same, and that one can't be linked to anybody's account.what to say textRun link_account with this key: glr_sk_… or, with no key to hand: Run create_account with my email, then link_account with the code that arrives.
Older ChatGPT builds and older help articles call this a connector instead of an app. It's the same thing.
Keep your personal address to yourself. Once it's linked, whoever has it is using your account, the same as with a key. Don't paste it into a shared document. If somebody else might have seen it, ask for unlink_account and add Galley again with a new one. On a Team or Enterprise plan, an address an owner adds for the organization is shared by everyone in it.
Claude Code
The terminal tool. For people who do write code. Any plan that runs Claude Code.
- Add the server.
--scope usermakes it available in every project. Leave it off and it's only added to the current one.terminal bashclaude mcp add --transport http --scope user \ galley https://mcp.galleyrender.com/mcp - Check it:
claude mcp listshould showgalleyconnected. - Ask for a render. The first call with no key mints a trial and hands the token back in the response.
- Use your key. Add it as a header and every call is on your account rather than on the keyless trial. Re-run the add command with
--header; it replaces the entry. Then ask Claude to run whoami — it should sayauthenticated_via: "header".terminal bashclaude mcp add --transport http galley https://mcp.galleyrender.com/mcp \ --header "Authorization: Bearer $GALLEY_API_KEY"
Cursor
The editor. Any plan.
- Put this in
~/.cursor/mcp.jsonfor every project, or.cursor/mcp.jsonin a repo for just that one.~/.cursor/mcp.json json{ "mcpServers": { "galley": { "url": "https://mcp.galleyrender.com/mcp" } } } - Open the
Customizepanel in the sidebar and make suregalleyis toggled on. A server that's toggled off doesn't load or appear in chat. - Ask for a render. The first call with no key mints a trial and hands the token back in the response.
- Use your key. Add a
headersentry beside theurland every call is on your account rather than on the keyless trial. Reload the server from theCustomizepanel, then ask for whoami — it should sayauthenticated_via: "header".~/.cursor/mcp.json json{ "mcpServers": { "galley": { "url": "https://mcp.galleyrender.com/mcp", "headers": { "Authorization": "Bearer glr_sk_…" } } } }
One call, both halves
Or call the endpoint yourself.
It's an ordinary REST API with a bearer token. MCP and REST use the same renderer, cache and template store, so a template your agent made in an MCP session is the one your production code renders.
POST /v1/render
{
"template": "invoice@1",
"format": "pdf",
"data": { … }
} 200 OK
{
"id": "rnd_7hq2m4x8k1bv",
"status": "succeeded",
"url": "https://…?signature=…",
"page_count": 1,
"billable_units": 1,
"cached": false
} cached is true. You get the same file back,
with no render and no charge.
curl -sS https://api.galleyrender.com/v1/render \
-H "Authorization: Bearer $GALLEY_API_KEY" \
-H 'content-type: application/json' \
-d '{
"template": "invoice@1",
"format": "pdf",
"data": {
"invoice_number": "INV-1042",
"issued_on": "2026-09-16",
"seller": { "name": "Galley Render" },
"buyer": { "name": "Acme Robotics" },
"line_items": [
{ "description": "Starter plan, September", "quantity": 1, "unit_price": 19 }
]
}
}' Small jobs finish inside the request and come back 200 with a URL. See POST /v1/render.
// Node 22+. No dependencies.
const res = await fetch("https://api.galleyrender.com/v1/render", {
method: "POST",
headers: {
authorization: `Bearer ${process.env.GALLEY_API_KEY}`,
"content-type": "application/json",
},
body: JSON.stringify({
template: "invoice@1",
format: "pdf",
data: {
invoice_number: "INV-1042",
issued_on: "2026-09-16",
seller: { name: "Galley Render" },
buyer: { name: "Acme Robotics" },
line_items: [{ description: "Starter plan", quantity: 1, unit_price: 19 }],
},
}),
});
const render = await res.json();
if (!res.ok) throw new Error(render.error.message);
console.log(render.url); // signed, expires in an hour
console.log(render.page_count); // 1
console.log(render.cached); // false the first time, true after You don't need an SDK, but there is one: galley-render on npm and PyPI.
# Python 3.9+. Standard library only.
import json, os, urllib.request
body = json.dumps({
"template": "invoice@1",
"format": "pdf",
"data": {
"invoice_number": "INV-1042",
"issued_on": "2026-09-16",
"seller": {"name": "Galley Render"},
"buyer": {"name": "Acme Robotics"},
"line_items": [{"description": "Starter plan", "quantity": 1, "unit_price": 19}],
},
}).encode()
req = urllib.request.Request(
"https://api.galleyrender.com/v1/render",
data=body,
headers={
"Authorization": f"Bearer {os.environ['GALLEY_API_KEY']}",
"Content-Type": "application/json",
},
)
render = json.load(urllib.request.urlopen(req))
print(render["url"], render["page_count"], render["cached"]) Swap urllib for requests or httpx if you already have one.
Get a key
There is no signup form.
Not for you, anyway. An account is a tool call, and your agent can make it without leaving the session it's in.
-
Start without one
The first 10 PDF pages or 10 images don't need a key. Point a client at the MCP address above and call
render. A trial account is minted on the spot, and its token comes back in the response. -
Ask for the key when you need it
Call
create_accountwith an email address. We email a link, and the call returns a four-character request code. The link opens a page that shows who asked and the same code. If it matches, confirm it, callcreate_accountagain with the same address, and the API key comes back once. It can't be recovered. We only store a hash of it, so neither the dashboard nor support can read it back to you. Send a randomX-Galley-Client-Idon both calls; without one, your client has no identity of its own and the key is shown on the page instead.Over MCP, no key requiredshellcurl -sS https://mcp.galleyrender.com/mcp \ -H 'content-type: application/json' \ -H 'accept: application/json, text/event-stream' \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "create_account", "arguments": { "email": "you@example.com" } } }' -
Keep everything you already made
When you confirm the request, the trial account of the client that asked is upgraded in place. Templates you created and renders you made during the trial stay on the account, and the free tier of 5 PDF pages or 5 images a month starts from there. Each email address gets one account, so
you+galley@example.comreaches the accountyou@example.comalready has. If the address already has an account, we email a one-time code forlink_accountinstead, and nobody has to paste a key into a chat.