@sheetrender/mcp
OfficialThis server lets an AI assistant generate PDFs from HTML or saved templates, manage datasets, and run batch rendering jobs via SheetRender.
render_pdf: Render a single PDF from supplied HTML, with optional Jinja
dataandpage_settings.list_templates: List saved templates with their names, ids, and last-updated dates.
render_template: Render one PDF from a saved template using a template id and row data.
create_dataset / upload_dataset: Create datasets from JSON rows or from CSV/XLSX files for batch rendering.
list_datasets: List datasets in a template's project with ids, row counts, and column keys.
create_batch_job: Queue a background job rendering one PDF per dataset row, with optional filename template and grouping.
get_job: Check batch job progress and get rendered document ids once finished.
get_document: Download an individual rendered PDF from a completed batch job.
page_settings: Shared by render tools to control page size, orientation, and margins.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@@sheetrender/mcpRender this HTML to PDF: Test"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
@sheetrender/mcp
MCP server for SheetRender. It lets your AI assistant render PDFs from HTML templates and spreadsheet data.
Setup
Get an API key from sheetrender.com under Settings → API keys, then add this to your MCP client config:
{
"mcpServers": {
"sheetrender": {
"command": "npx",
"args": ["-y", "@sheetrender/mcp"],
"env": { "SHEETRENDER_API_KEY": "sr_live_..." }
}
}
}SHEETRENDER_API_URL is also read, and defaults to https://sheetrender.com.
Set it only if you're pointing at a self-hosted or staging instance.
Related MCP server: rendoc
Hosted endpoint
The same server runs at https://mcp.sheetrender.com/mcp over Streamable
HTTP, so clients that can't spawn a local process can use it too. Nothing is
installed; each request carries your API key:
Authorization: Bearer sr_live_...Requests without that header get a 401. The key goes straight through to the SheetRender API for that one request and is never stored — the server keeps no sessions, so every request stands alone.
Where the key goes depends on the client:
Claude Code:
claude mcp add --transport http sheetrender https://mcp.sheetrender.com/mcp --header "Authorization: Bearer sr_live_..."Cursor, Windsurf, VS Code and other clients with an
mcp.json:{ "mcpServers": { "sheetrender": { "url": "https://mcp.sheetrender.com/mcp", "headers": { "Authorization": "Bearer sr_live_..." } } } }Claude API (the Messages API's MCP connector): add
{"type": "url", "url": "https://mcp.sheetrender.com/mcp", "name": "sheetrender", "authorization_token": "sr_live_..."}tomcp_servers.claude.ai, Claude Desktop and ChatGPT custom connectors take a server URL and an OAuth client, not a static header. Until the endpoint speaks OAuth, use the stdio package above there — it's the same tools, with the key in
env— or bridge withnpx mcp-remote https://mcp.sheetrender.com/mcp --header "Authorization: Bearer sr_live_..."as the command.
Two differences from the stdio server follow from the process not running on
your machine. Rendered PDFs come back inline as a base64 resource (up to 8 MB;
larger ones are reported with their size and left for the web app) instead of
as a temp-file path, and upload_dataset is not offered because there is no
local file to read — send rows with create_dataset instead.
GET /healthz answers 200 without credentials. Request bodies are capped at
25 MB; anything larger is a 413.
Running it yourself
sheetrender-mcp-http is a second bin in the package. It reads PORT
(default 8080), HOST (default 0.0.0.0), SHEETRENDER_API_URL,
MAX_BODY_BYTES and IDLE_TIMEOUT_MS (default 60000), and logs one JSON
line per request to stdout — method, path, status, duration, the JSON-RPC
method and tool name, and a fingerprint of the key, never the key. The
Dockerfile in this repo builds a non-root runtime image for it:
docker build -t sheetrender-mcp .
docker run --rm -p 8080:8080 sheetrender-mcpTools
render_pdf
Renders one PDF from HTML you supply.
Argument | Type | |
| string | Required. A full HTML document. CSS has to be inline in a |
| object | Optional. Keys become Jinja variables, so |
| object | Optional, see below. |
Returns the path of the saved PDF and its size. Under 512 KB it's also attached inline as a base64 resource, so clients that display attachments show the document itself.
Two server limits apply. HTML over 2 MB is rejected, and that's measured both on
what you send and on the document after data is substituted in, so a template
that expands a long dataset can cross the line even when the markup you wrote
doesn't. The other is the free plan, where every rendered PDF carries a "Made
with SheetRender" footer. That applies to render_pdf and render_template
alike. Paid plans don't get it.
list_templates
No arguments. Returns each saved template's name, id and last-updated date. Call it to turn a template name the user mentioned into the id the other tools want.
render_template
Renders one PDF from a template already saved in the account.
Argument | Type | |
| string | Required, from |
| object | Required. One row's values, as Jinja variables. |
| object | Optional. Omit it to keep the template's own saved page setup; passing it overrides that for this render. |
Same return as render_pdf.
create_dataset
Turns JSON rows into a dataset a batch job can render. This is the usual way to
start a batch: assemble the rows, send them, get back a dataset_id.
Argument | Type | |
| string | Required, from |
| array of objects | Required. One flat object per document. |
| string | Optional label, used as the stored filename. |
The header is the union of every row's keys in first-seen order, so rows don't have to agree on their keys — a missing one is a blank cell rather than a shifted row. Values have to be scalars: strings, numbers, booleans or null. Nested objects and arrays are rejected, and so are NaN, Infinity and whole numbers past 2^53 (send those as strings to keep them exact). The caps are 50,000 rows and 500,000 cells per call.
Returns the dataset id, row count and, for each column, the sanitized key.
That key is what template placeholders, filename_template and group_by
address, and it's often not the header verbatim — Invoice No becomes
invoice_no. Read it off this result instead of guessing.
Creating a dataset is free; only rendering counts against the plan.
upload_dataset
The same thing from a file that already exists.
Argument | Type | |
| string | Required, from |
| string | Required. A |
The first row has to be the header. Files over 20 MB, the wrong extension and
empty files are refused locally, before anything is uploaded. Same return as
create_dataset.
list_datasets
Takes template_id and lists every dataset in that template's project, newest
first, with ids, row counts and column keys. Use it to find data the user
already loaded, or to read a dataset's column keys before writing a
filename_template or picking group_by.
create_batch_job
Queues a background job that renders one PDF per row of a dataset. The whole
loop runs from here — list_templates → create_dataset or upload_dataset →
create_batch_job → get_job → get_document.
Argument | Type | |
| string | Required, from |
| string | Required, from |
| string | Optional. Output naming pattern, e.g. |
| string | Optional. Column key to group rows by, giving one multi-page PDF per distinct value. |
Returns the job id to poll with get_job. Worth knowing: filename_template
and group_by are persisted to the template and the project respectively, so
they change the defaults for later runs too.
If the server predates the public batch endpoint, the tool reports that batch jobs are unavailable rather than failing obscurely. The three dataset tools do the same for a server that predates the dataset endpoints.
get_job
Takes job_id. Returns the status, rows done and failed, and the id and
filename of every rendered document. That document list stays empty while the
job is queued, retry_queued or running, and fills in once the job reaches
succeeded, partial, failed or cancelled. Those document ids are what
get_document takes.
get_document
Takes document_id and downloads that single rendered PDF. The ids come from
get_job on a finished batch, and there's no other way to get one. Same return
as render_pdf: path, size, and an inline blob under 512 KB.
If you want a whole batch, the merged PDF and ZIP in the web app beat fetching each document in turn.
page_settings
Shared by both render tools. Every field is optional:
{
"page_size": "a4",
"orientation": "portrait",
"margins": { "top": 15, "right": 15, "bottom": 15, "left": 15 }
}page_size is lowercase: a3, a4, a5, letter, legal or tabloid.
Margins are plain numbers in millimetres, not CSS lengths.
Rendered PDFs are written to the system temp directory. API errors like a bad key, a missing template or a rate limit come back as tool errors carrying the server's own message.
The public API allows 120 requests per minute per API key. Past that it returns 429, and the tool reports that you're rate limited and should retry shortly. Batch job creation is metered separately and more tightly.
Development
You don't need node or npm on the host: scripts/dev.sh install, then
scripts/dev.sh deno task build and scripts/dev.sh deno task test.
scripts/dev.sh node dist/http.js runs the HTTP server on the host network.
MIT licensed.
Available Tools
6 toolscreate_batch_jobStart a batch PDF jobAInspect
SheetRender turns HTML templates plus spreadsheet rows into rendered PDFs. This tool queues a batch job that renders one PDF per row of an uploaded dataset, and returns the job id.
Use it when the user wants many documents at once — "an invoice for every row", "one letter per employee". The dataset must already be uploaded to the SheetRender project; this tool cannot upload spreadsheets. Rendering happens in the background: poll get_job with the returned id to see progress and collect document ids.
filename_template and group_by are saved onto the template/project, so they change the defaults for later runs, not just this one. Only pass them when the user asked to change how output is named or grouped.
| Name | Required | Description | Default |
|---|---|---|---|
| group_by | No | Column name to group rows by, producing one multi-page PDF per distinct value instead of one per row. Saved to the project. | |
| dataset_id | Yes | Id of a dataset already uploaded to the same SheetRender project. | |
| template_id | Yes | Template id from list_templates. | |
| filename_template | No | Naming pattern for output files, with column placeholders, e.g. "invoice-{{ invoice_no }}". Saved to the template. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully covers behavioral traits: it returns a job id, runs rendering in the background, and poll get_job is required. It also discloses the side-effect that filename_template and group_by are saved to the template/project, altering defaults for future runs—critical for an agent to know.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured: it opens with a one-sentence system context, then the tool's specific action, followed by usage conditions, a behavioral note, and a parameter warning. Every sentence serves a purpose and the information is front-loaded with the core purpose. While not extremely short, it is efficient and free of fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema, the description explains the return value (job id) and how to retrieve results via get_job. It covers prerequisites, background execution, and side-effects, making it fully self-contained for an agent to correctly invoke and interpret the results.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already provides complete descriptions for all four parameters, including the persistence side-effect for group_by and filename_template. The description adds usage guidance ('Only pass them when...'), but does not introduce new semantic meaning about what each parameter does beyond the schema. Given 100% schema coverage, the description meets but does not exceed the baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: it queues a batch job that renders one PDF per row of an uploaded dataset and returns a job id. It also distinguishes itself from siblings by mentioning the batch scenario ('many documents at once') versus single renders, making it specific and differentiating.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use it ('Use it when the user wants many documents at once'), provides a prerequisite (dataset must already be uploaded, cannot upload), and directs the agent to poll get_job for progress. This is clear guidance on when and how to use the tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_documentDownload a rendered documentAInspect
SheetRender turns HTML templates plus spreadsheet rows into rendered PDFs. This tool downloads one PDF produced by a batch job and returns the path to the saved file.
document_id comes from get_job on a finished batch — that is the only place these ids appear, so call get_job first and take an id from its document list. A document id is not a template id or a job id.
Use it to fetch a specific output the user asked about, or to spot-check a batch. Fetching every document of a large batch one at a time is slow; point the user at the SheetRender web app for the merged PDF or ZIP instead.
Returns the temp-file path and size; PDFs under 512 KB are also attached inline.
| Name | Required | Description | Default |
|---|---|---|---|
| document_id | Yes | Document id from a finished job's document list in get_job. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the behavioral burden. It discloses that the return includes a temp-file path and size, that PDFs under 512 KB are attached inline, and warns about performance when fetching many documents. It also notes the provenance of document_id. While it doesn't mention error handling or permissions, it covers the essential behavior for a download tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured: the first sentence states the core purpose, followed by id provenance, usage guidance, and return behavior. Every sentence adds value with no fluff, and the most critical information (spoiler: the id source) is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple tool with one parameter and no output schema, the description covers all necessary aspects: what it does, how to obtain the id, when to use it vs alternatives, and what the return includes. Nothing essential is missing for an agent to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already describes document_id with high coverage, but the description adds crucial disambiguation: it explains the id comes specifically from get_job's document list and clarifies it is not a template or job id. This goes beyond the schema's baseline, making parameter meaning clearer for the agent.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states the specific verb (download), resource (PDF from a batch job), and distinguishes it from siblings like render_pdf and get_job. It also clarifies that document_id comes from get_job, making the tool's role unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use the tool (fetch a specific document or spot-check a batch) and when to instead direct the user to the SheetRender web app for bulk downloads. It also references get_job for obtaining valid IDs, providing clear usage context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_jobCheck a batch PDF jobAInspect
SheetRender turns HTML templates plus spreadsheet rows into rendered PDFs. This tool reports the progress of a batch job started by create_batch_job.
Returns the status, rows done/failed, and — once the job reaches a finished state ("succeeded", "partial", "failed" or "cancelled") — the id and filename of every rendered document. The document list is empty while the job is still in "queued", "retry_queued" or "running", so poll again after a short wait rather than assuming zero documents.
Pass those document ids to get_document to download the individual PDFs.
| Name | Required | Description | Default |
|---|---|---|---|
| job_id | Yes | Job id returned by create_batch_job. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With zero annotations, the description carries the full behavioral burden and succeeds. It discloses the asynchronous polling nature, enumerates the complete state machine (queued, retry_queued, running, succeeded, partial, failed, cancelled), explains that the document list is empty during in-progress states, and specifies what becomes available once finished. This is exactly the behavioral context an agent needs to avoid misinterpreting empty results.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short paragraphs, zero filler. The purpose and polling caveat are front-loaded; the SheetRender context sentence and the get_document routing both earn their place. The state enumeration is necessary, not redundant, given the target states versus document-list-availability states must be distinguished.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite having no output schema and no annotations, the description fully compensates: it explains the returned fields (status, rows done/failed, document ids/filenames), the conditional availability of results, and the follow-up action. For a single-parameter polling tool, nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% — job_id is documented as 'Job id returned by create_batch_job.' The description reinforces but does not extend this: it references 'the id' of every rendered document but adds no new formatting or validation details beyond the schema. Baseline 3 is appropriate since the schema already carries the semantic weight.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb+resource: 'reports the progress of a batch job started by create_batch_job' — it monitors a job rather than producing content. It distinguishes itself from siblings by explaining the workflow position (reports on create_batch_job output, feeds get_document). The title 'Check a batch PDF job' reinforces the purpose without ambiguity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description names the prerequisite sibling (create_batch_job), the successor (get_document for downloading), and gives explicit call-timing guidance: poll again while status is in 'queued', 'retry_queued' or 'running' rather than treating an empty document list as zero results. This is concrete, actionable when-to-use guidance that maps the tool into a larger workflow.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_templatesList SheetRender templatesAInspect
SheetRender turns HTML templates plus spreadsheet rows into rendered PDFs. This tool lists the templates saved in the user's account, with the id each one needs.
Call it first whenever the user refers to a template by name ("render the invoice template") so you can map that name to an id for render_template or create_batch_job. Takes no arguments.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the behavioral burden. It clearly states it is a listing operation that returns template ids, which is the core behavior. It adds context about being a prerequisite mapping step, which helps the agent understand its role. It does not explicitly state it is read-only or non-mutating, but that is strongly implied. It also does not mention return format or pagination, but for a simple list tool this is a minor omission. The description is transparent enough for correct invocation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences, front-loaded with the domain context and the tool's purpose, then immediately gives the when-to-use guidance and the arg note. Every sentence earns its place with no filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter list tool with no output schema, the description covers the essential points: what it does, what it returns (ids), and when to call it. It does not describe the exact response structure or pagination, but those are often inferred and not critical for a simple list operation. The context about SheetRender and the mapping step adds completeness. Minor gap: it does not mention how many templates might be returned or any limits, but this is a minor omission given the tool's simplicity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has zero properties, and the description explicitly says 'Takes no arguments.' This goes beyond the schema by removing any possible ambiguity about whether arguments might be accepted (an empty schema could be misread). The explicit statement adds value and fully clarifies parameter expectations.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb-resource pair ('lists the templates saved in the user's account') and clarifies the value it provides (the id each one needs). It also distinguishes itself from siblings by positioning it as the listing step against the rendering/job tools (render_template, create_batch_job). This is unambiguous and effectively differentiates the tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly instructs when to call it ('Call it first whenever the user refers to a template by name') and points to the follow-up tools (render_template, create_batch_job). It also notes the tool takes no arguments, which is a useful usage hint. No ambiguity about when or how to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
render_pdfRender HTML to PDFAInspect
SheetRender turns HTML templates plus spreadsheet rows into rendered PDFs. This tool renders a single PDF from HTML you supply and returns the path to the saved file.
Use it for one-off documents — an invoice, a report, a certificate — where you are writing the markup yourself. Use render_template instead when the user already has a saved template.
html must be a complete HTML document (, , ) with all CSS inline in a tag: external stylesheets, fonts and scripts are not fetched. Use @page and mm/cm units for print layout.
data keys become Jinja template variables, so passing {"total": "42.00"} lets the HTML say {{ total }}. Jinja loops and conditionals work too. Omit data if the HTML has no placeholders.
Two server limits to plan for: HTML over 2 MB is rejected, measured both on what you send and on the result after data is substituted in, so keep large tables paginated rather than emitting one enormous document; and accounts on the free plan get a "Made with SheetRender" footer added to every PDF, which is expected, not a bug — mention it if the user seems surprised.
Returns the temp-file path and size; PDFs under 512 KB are also attached inline.
| Name | Required | Description | Default |
|---|---|---|---|
| data | No | Template variables as a flat JSON object. Each key becomes a Jinja variable, so {"customer": "Acme"} makes {{ customer }} available in the HTML. | |
| html | Yes | A complete HTML document with inline CSS. May contain Jinja placeholders filled from `data`. | |
| page_settings | No | Optional page setup for the PDF. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden. It transparently discloses that external resources are not fetched, that HTML over 2MB is rejected (including after substitution), that free accounts get a footer, and that return includes path/size plus inline attachment for small PDFs. This exceeds expectations for behavioral disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with clear paragraphs. Each sentence earns its place: purpose, usage (with alternative), HTML requirements, data behavior, server limits, and return format. It is detailed but not repetitive; complexity is handled without bloat.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers all necessary aspects for correct use: input requirements, template variable mechanics, output behavior, error conditions (2MB limit), and an environmental quirk (free-plan footer). It is fully self-sufficient even without annotations or output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Despite 100% schema coverage, the description adds substantial meaning beyond the schema: it explains Jinja variable substitution with a concrete example, confirms loops/conditionals work, clarifies that data can be omitted, and details page_settings usage in plain terms. This significantly aids correct invocation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: rendering a single PDF from user-supplied HTML and returning the saved file path. It also distinguishes itself from render_template by explicitly saying when to use which, making it easy for an agent to select correctly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit guidance on when to use this tool ('one-off documents... writing the markup yourself') and when to use the alternative (render_template when a saved template exists). It also warns about size limits and the free-plan footer, covering both usage context and potential pitfalls.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
render_templateRender a saved template to PDFAInspect
SheetRender turns HTML templates plus spreadsheet rows into rendered PDFs. This tool renders one PDF from a template already saved in the user's account and returns the path to the saved file.
Use it when the user wants a document in their existing design. Get template_id from list_templates. Use render_pdf instead when you are writing the HTML yourself.
data supplies one row's worth of values: each key becomes a Jinja variable in the template's HTML. To render a PDF for every row of a spreadsheet, use create_batch_job rather than calling this repeatedly.
Omit page_settings to keep the template's own saved page setup — passing it overrides that for this render only.
Free-plan accounts get a "Made with SheetRender" footer on the PDF, same as render_pdf — expected, not a bug.
Returns the temp-file path and size; PDFs under 512 KB are also attached inline.
| Name | Required | Description | Default |
|---|---|---|---|
| data | Yes | Template variables as a flat JSON object. Each key becomes a Jinja variable, so {"customer": "Acme"} makes {{ customer }} available in the HTML. | |
| template_id | Yes | Template id from list_templates. | |
| page_settings | No | Optional page setup for the PDF. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must carry behavioral disclosure. It covers the output (temp-file path, size, inline attachment under 512 KB), the page_settings override behavior, and the free-plan footer. It does not mention error cases or side effects, but the core mutating behavior (creating a PDF) is transparently described.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-organized and front-loaded with purpose. It conveys all necessary context in a compact flow: what the tool does, when to use it, how data works, page_settings caveat, free-plan note, and output details. No superfluous sentences; every line earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the nested page_settings object and no output schema, the description covers everything needed to call the tool correctly: how to obtain template_id, the data shape, optional page_settings behavior, return value specifics, and the free-plan footer. It also routes to alternatives, making it complete for an agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with detailed property descriptions, so baseline is 3. The description adds value by explaining that omitting page_settings keeps the template's saved setup and that data supplies one row of variables. It also clarifies the 'overrides for this render only' nuance not present in the schema, pushing it above baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool renders one PDF from a saved template and returns the file path. It distinguishes from siblings by naming render_pdf (for custom HTML) and create_batch_job (for multiple rows), and directs to list_templates for the ID. The verb+resource+scope is specific and unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit guidance is given for when to use this vs alternatives: use it for existing designs, render_pdf when writing HTML yourself, and create_batch_job for rendering many rows. It also instructs to get template_id from list_templates. This leaves no ambiguity about selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
6 tool updates
v0.1.2- First observed
create_batch_job - First observed
get_document - First observed
get_job - First observed
list_templates - First observed
render_pdf - First observed
render_template
TDQS
Each tool has a distinct purpose: listing templates, rendering from raw HTML, rendering from a saved template, creating a batch job, checking job progress, and downloading a specific document. The descriptions explicitly clarify when to use render_pdf vs render_template and how get_job and get_document relate, leaving no ambiguity.
All tool names follow the consistent verb_noun pattern in snake_case (list_templates, render_pdf, render_template, create_batch_job, get_job, get_document). The verbs are clear and the pattern is uniform, making it easy to predict tool behavior from the name.
Six tools is well-scoped for a PDF rendering MCP server. It covers the essential operations without bloat: listing templates, two rendering modes, batch job management, and document retrieval. Each tool earns its place in the workflow.
The core rendering lifecycle is covered: list templates, render single or batch, check job status, and download outputs. Minor gaps exist, such as no tool for uploading templates or datasets (stated as handled outside the MCP), and no cancellation or template management, but these are reasonable omissions for an integration-focused server.
Maintenance
Related MCP Connectors
Generate HTML to PDF documents in bulk or single — raw replacements or based on conditions, loops
Cloud PDF generation from HTML, CSS and XSL-FO, with PDF/A and PDF/UA support.
Turn HTML or a live URL into polished PDF and Excel files — hosted downloads, async jobs, history.
Turn HTML or templates into branded invoice & document PDFs from your agent. One call, no install.
Related MCP Servers
AlicenseBqualityBmaintenanceProvides PDF.co API functionality through the Model Context Protocol, enabling AI assistants to perform various PDF processing tasks like conversion, editing, searching, and security operations.389MIT- AlicenseAqualityCmaintenanceGenerate professional PDFs from Claude, Cursor, and other AI tools. Create invoices, contracts, reports, and certificates from templates or inline HTML markup.7591MIT

Dokmatiq DocGenofficial
AlicenseAqualityCmaintenancePDF/DOCX/Excel generation from HTML/Markdown with stationery overlay, ZUGFeRD/XRechnung e-invoicing, digital signing, form filling, and AI receipt OCR with DATEV/SKR03 export.40MIT
mcp-server-pdfnoodleofficial
AlicenseNot gradedqualityDmaintenanceEnables AI assistants to generate PDF documents from templates or raw HTML using natural language, with tools for template creation, PDF generation, and utility operations.221MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/sheetrender/sheetrender-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server