MCP server
Your documents, generated by your AI assistant.
The official DocMake server for the Model Context Protocol. Ask Claude for an invoice in plain language;
it picks the template, fills in the blanks (the data payload), and hands you
the finished PDF.
It ships on npm as @docmake/mcp and runs locally through npx, so the only requirements are Node.js 18 or
newer and a DocMake API key. It works on the free plan, and it gives an assistant six tools: list
templates, inspect a template's fields, make a document (render_document),
create a template, import a DOCX, and check usage. The source is on GitHub under the MIT license, and the
same six tools are also
hosted at app.docmake.io/mcp/v1
if you would rather install nothing.
A conversation, not an integration
MCP is the open standard that lets AI assistants use external tools. With the DocMake server installed, your assistant gains six document tools and uses them on its own: it finds the right template, asks you for any missing values, and saves the rendered file to your Downloads folder.
Renders are strict by default. If a blank (a variable in the API) has no
value, the assistant gets the exact list of missing fields instead of a half-empty document, so it asks you
rather than inventing numbers.
Templates stay in DocMake: design them once in the visual editor or start from the gallery, then render them from anywhere.
Setup
- 01 Create a free DocMake account and add a template: start from the gallery, import a DOCX, or design your own.
- 02 Create an API key in Settings → API Keys.
- 03 Add the server to your AI tool with the config on the right. Node.js 18+ is the only requirement.
Rendered files are saved to ~/Downloads/DocMake
by default; set DOCMAKE_OUTPUT_DIR to change it.
{
"mcpServers": {
"docmake": {
"command": "npx",
"args": ["-y", "@docmake/mcp@latest"],
"env": {
"DOCMAKE_API_KEY": "dm_your_api_key"
}
}
}
} Settings > Developer > Edit Config, then restart Claude Desktop.
claude mcp add docmake \
--env DOCMAKE_API_KEY=dm_your_api_key \
-- npx -y @docmake/mcp@latest One command in your terminal. Works in the CLI and the IDE extensions.
{
"mcpServers": {
"docmake": {
"command": "npx",
"args": ["-y", "@docmake/mcp@latest"],
"env": {
"DOCMAKE_API_KEY": "dm_your_api_key"
}
}
}
} Add to .cursor/mcp.json in your project or the global Cursor settings.
Remote, nothing to install
The same six tools, hosted
DocMake also runs the server for you at
https://app.docmake.io/mcp/v1,
spoken over streamable HTTP. A client that supports remote MCP needs no package and no Node.js: just the
URL and one header,
Authorization: Bearer dm_...,
carrying the same API key the REST API uses.
Two things differ from the local package, because the server runs on our side rather than on your machine.
render_document returns a
short-lived download link instead of writing the file to disk, and
import_docx takes the document as
base64 rather than a path. Strict rendering, workspace scoping and the plan rate limits behave as they do
over REST, where one MCP message counts as one request.
Claude.ai and ChatGPT add remote servers as custom connectors, and those are documented around an OAuth flow rather than a static key, so this setup does not reach them yet. For Claude Desktop, use the npx configuration above.
claude mcp add --transport http docmake \
https://app.docmake.io/mcp/v1 \
--header "Authorization: Bearer dm_your_api_key" Adds the server to the current project. Pass --scope user to make it available everywhere.
{
"mcpServers": {
"docmake": {
"url": "https://app.docmake.io/mcp/v1",
"headers": {
"Authorization": "Bearer dm_your_api_key"
}
}
}
} Add to .cursor/mcp.json in your project or the global Cursor settings. A url instead of a command marks it remote.
{
"servers": {
"docmake": {
"type": "http",
"url": "https://app.docmake.io/mcp/v1",
"headers": {
"Authorization": "Bearer ${input:docmake-api-key}"
}
}
}
} Add to .vscode/mcp.json. The input placeholder makes VS Code prompt for the key instead of storing it in the file.
Side by side
Same six tools, same workspace, same dm_
key. Pick on where you want the work to happen, not on what you get.
| Local, @docmake/mcp | Hosted, /mcp/v1 | |
|---|---|---|
| Transport | stdio, run by your client through npx | Streamable HTTP, one POST per message |
| Requirements | Node.js 18 or newer | Nothing installed |
| Auth | DOCMAKE_API_KEY in the environment | Authorization: Bearer dm_... header |
| Tools | The same six | The same six |
| A rendered file | Written to DOCMAKE_OUTPUT_DIR, ~/Downloads/DocMake by default, never overwriting | A signed download link that needs no key and expires |
| import_docx | A path on your machine | The file base64 encoded, up to 10 MB |
| Resources and prompts | Advertised alongside the tools | Tools only, both lists are empty |
| Version | 0.1.1 on npm | 0.1.0, reported in the handshake |
| Rate limit | The workspace budget, one call is one request | The same budget, one message is one request |
Six tools, the full document loop
The same six on both servers, with the same names, the same arguments and the same answers. Everything an assistant needs to go from a request to a rendered file, including creating and importing templates without leaving the conversation.
list_templates
List templates
The templates in the connected workspace, newest edit first, with search and pagination. Start here when you need a template id.
- search
- string
- Filter by name, substring match
- page
- integer
- From 1
- per_page
- integer
- Max 100, default 20
Returns data: id, name, created_at, updated_at, variables_count, render_count. meta: current_page, last_page, per_page, total.
Read only.
get_template
Get template fields
One template plus its field tree: every blank it expects, as dotted keys shaped like the data payload, with list fields carrying their per-item subfields. Call it before rendering.
- template_id
- string, required
- From list_templates
- include_schema
- boolean
- Also return the raw document schema. Default false, can be large
Returns id, name, created_at, updated_at, fields (recursive: key, name, label, type, required, default, example), unused.
Read only. A calculation is an output, so it is in neither list.
render_document
Render a document
Render a template to PDF or DOCX. Answers with a short-lived download link, not the file bytes, and refuses rather than filling a document with gaps.
- template_id
- string, required
- data
- object, required
- Keys match the template fields
- format
- pdf or docx
- Default pdf
- filename
- string
- Without extension
- locale
- string
- BCP 47, for example ro-RO. Defaults to the workspace setting
- page_size
- a4 or letter
- Defaults to the workspace setting
- strict
- boolean
- Default true
Returns document_id, filename, format, size_bytes, render_time_ms, warnings, download_url, download_expires_at.
Writes. Not idempotent: each call produces a document.
create_template
Create a template
Create a template from a document schema: a rich-text tree with typed blank nodes, rules and repeated sections. The quickest way to learn the format is get_template with include_schema true.
- name
- string, required
- Max 255
- schema
- object, required
- Root must be type "doc" with a content array
Returns id, name, variables, edit_url.
Writes. Counts against the template allowance.
import_docx
Import a DOCX as template
Turn a Word document into an editable template: headings, paragraphs, tables and styling are converted, then you add blanks in the editor or inspect the result with get_template.
- file_base64
- string, required
- The .docx bytes, base64. Max 10 MB decoded
- name
- string
- Defaults to "Imported document"
Returns id, name, import_warnings, edit_url.
Writes. The local package takes a file path instead.
get_usage
Get usage and limits
Plan, documents used against the monthly allowance, template count, AI credits and the per-minute rate limit. Check it when renders start failing on quota.
Returns plan, billing_period, renders, templates, credits, api_calls, rate_limit.
Read only. Takes no arguments.
Prefer raw HTTP? The same capabilities are available over the REST API, where the errors, the
X-DocMake-Warnings header and strict mode are documented in full.
One run, end to end
This is what an assistant actually does, shown as raw JSON-RPC against the hosted server so you can follow it with nothing but curl. Every call and every answer below was run against https://app.docmake.io/mcp/v1 with a real key and pasted back unedited; the key and the signature are redacted.
0. Open a session
Streamable HTTP: one POST per message, with the key in the Authorization header. The server answers the handshake with a session id to send back on every later call.
curl -sS -X POST https://app.docmake.io/mcp/v1 \
-H "Authorization: Bearer dm_xxx" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize",
"params":{"protocolVersion":"2025-06-18","capabilities":{},
"clientInfo":{"name":"curl","version":"1.0"}}}'mcp-session-id: b988daa4-cb37-470d-92f5-fe6badbe3dc1
{"jsonrpc":"2.0","id":1,"result":{
"protocolVersion":"2025-06-18",
"capabilities":{"tools":{"listChanged":false},
"resources":{"listChanged":false},
"prompts":{"listChanged":false}},
"serverInfo":{"name":"docmake","version":"0.1.0"}, ... }}1. Find the template
{"jsonrpc":"2.0","id":3,"method":"tools/call",
"params":{"name":"list_templates","arguments":{"search":"formula"}}}{
"data": [
{
"id": "tmpl_xYucq408uKkJ",
"name": "Docs formula example",
"created_at": "2026-09-03T05:48:46+00:00",
"updated_at": "2026-09-03T05:49:21+00:00",
"variables_count": 5,
"render_count": 2
}
],
"meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}2. Ask what it needs
Keys are dotted and shaped like the payload, so an assistant can build the data object without guessing. A list field carries its per-item fields. Calculations are outputs and appear nowhere in this tree.
{"jsonrpc":"2.0","id":4,"method":"tools/call",
"params":{"name":"get_template","arguments":{"template_id":"tmpl_xYucq408uKkJ"}}}{
"id": "tmpl_xYucq408uKkJ",
"name": "Docs formula example",
"fields": [
{
"key": "client", "name": "client", "label": "Client",
"type": "object", "required": false, "default": null, "example": null,
"fields": [
{ "key": "client.name", "name": "name", "label": "Client name",
"type": "string", "required": false, "default": null, "example": null }
]
},
{
"key": "items", "name": "items", "label": "Items",
"type": "array", "required": false, "default": null, "example": null,
"fields": [
{ "key": "items.product", ... },
{ "key": "items.qty", ... },
{ "key": "items.unit_price", ... }
]
}
],
"unused": []
}3. Render, and read the warnings
The answer carries a warnings array in the same shape as the REST
API's X-DocMake-Warnings header: empty here, because nothing was
missing. The link needs no API key and expires, so it can be handed straight to the person who asked.
{"jsonrpc":"2.0","id":5,"method":"tools/call",
"params":{"name":"render_document","arguments":{
"template_id":"tmpl_xYucq408uKkJ","format":"pdf","filename":"quote-northwind",
"data":{"client":{"name":"Northwind Trading SRL"},"discount_percent":10,
"items":[{"product":"Consulting","qty":1,"unit_price":2500},
{"product":"Internal audit","qty":2,"unit_price":800},
{"product":"Training","qty":3,"unit_price":350}]}}}}{
"document_id": "doc_M6fQVkMHLp04",
"filename": "quote-northwind.pdf",
"format": "pdf",
"size_bytes": 21384,
"render_time_ms": 1386,
"warnings": [],
"download_url": "https://app.docmake.io/mcp/documents/doc_M6fQVkMHLp04?expires=...&signature=...",
"download_expires_at": "2026-09-03T06:50:22+00:00"
}4. What happens when something is missing
The same call without a client name. Renders are strict by default here, so nothing is produced and the tool answers with the problem and the way out. The assistant asks you for the value rather than inventing one.
{
"content": [
{
"type": "text",
"text": "Nothing was rendered: client.name has no value. Ask the user for the right values and call render_document again, or pass strict:false to render anyway with missing values left blank."
}
],
"isError": true
}Source and listings
The local server is open source, published on npm, and listed in the official Model Context Protocol registry, so you can read the code before you run it.
Questions
- What is the DocMake MCP server?
- An open-source npm package (@docmake/mcp) that connects AI assistants to your DocMake account through the Model Context Protocol. Once installed, assistants like Claude can list your templates, check which fields they need, and render finished PDF or DOCX documents from a plain conversation.
- Which AI tools work with it?
- Any MCP client: Claude Desktop, Claude Code, Cursor, Zed, Windsurf, and others. Configuration is the same everywhere: run @docmake/mcp via npx with your API key in the environment. Claude Code, Cursor and VS Code can also point at the hosted server instead, with the API key sent as an Authorization header.
- Is it open source?
- Yes. The server is published at github.com/docmake-io/mcp under the MIT license, the package is @docmake/mcp on npm, and it is listed in the official Model Context Protocol registry as io.docmake/mcp.
- Can I use it without installing anything?
- Yes. DocMake hosts the same six tools at https://app.docmake.io/mcp/v1 over streamable HTTP. Point a client that supports remote MCP at that URL and send your API key as an Authorization: Bearer dm_... header. Three things differ from the local package: rendered documents come back as short-lived download links rather than local files, import_docx takes base64 instead of a file path, and the hosted server exposes tools only, where the package also advertises resources and a prompt.
- Does it need a paid plan?
- No. The free plan includes API access, so the MCP server works from the moment you sign up. Paid plans raise the monthly document volume and remove the footer branding.
- Is my data safe?
- The local server runs on your machine and talks only to the DocMake API over HTTPS with your API key. Rendered documents are saved to a folder you control. The hosted server runs inside DocMake and handles your data the same way the REST API does, under the same privacy policy. Nothing is sent to any third party either way.