Skip to main content
Glama
hasankhadra

DocuGenerate MCP Server

by hasankhadra
README.md
# DocuGenerate MCP Server

A local [Model Context Protocol](https://modelcontextprotocol.io) server that wraps the
[DocuGenerate](https://docugenerate.com) document-generation API, so **Claude Desktop can
generate documents (invoices, contracts, letters) from your templates** — just by asking.

This is a **local demo build**: TypeScript, the official MCP SDK, and **STDIO** transport.
You register it in Claude Desktop and it runs on your machine.

> The productionised “official” version would instead be a **remote HTTP MCP server with
> OAuth** — this local stdio build is deliberately the demo shape.

## Tools

| Tool | Args | Returns |
| --- | --- | --- |
| `list_templates` | *(optional)* `name_contains` | Each template's `id`, `name`, and `merge_fields` (the tags to supply). |
| `get_template_fields` | `template_id` | Merge fields for one template (fallback / double-check). |
| `generate_document` | `template_id`, `data` (object of field→value), `format?` = `pdf` \| `docx` (default `pdf`) | A **hosted URL** to the generated document (a link, not binary). |

## How it maps to the DocuGenerate API

Confirmed against the [API Quick Start](https://docugenerate.com/developers/quickstart) and
live probes of `api.docugenerate.com`:

- **Base URL:** `https://api.docugenerate.com/v1`
- **Auth header:** `Authorization: <API Key>` — the **raw key**, no `Bearer ` prefix.
- `GET /template` → list templates (each has `id`, `name`, `tags.valid` = merge fields)
- `GET /template/{id}` → one template
- `POST /document` with `{ template_id, data: [ {...} ], output_format: ".pdf" }` → responds
  with `document_uri` (the hosted document link).

## Setup

Requires **Node 20+**.

```bash
npm install
npm run build      # compiles to dist/ via tsc
```

Get your API key from the DocuGenerate **Settings** page (<https://app.docugenerate.com>).

> **Before the demo:** create at least one template in the DocuGenerate dashboard —
> for the prompts below, make an **“Invoice”** template with merge tags such as
> `Company Name`, `Invoice Number`, `Date`, `Due Date`, `Line Items`, and `Total`.
> `list_templates` will report each template's exact merge fields.

### Register in Claude Desktop

Edit `claude_desktop_config.json`:

- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`

Add this server (use the **absolute** path to the built `dist/index.js`):

```json
{
  "mcpServers": {
    "docugenerate": {
      "command": "node",
      "args": ["/absolute/path/to/DocuGenerate-mcp/dist/index.js"],
      "env": {
        "DOCUGENERATE_API_KEY": "your_api_key_here"
      }
    }
  }
}
```

Then **fully quit and reopen Claude Desktop**. The `docugenerate` tools appear under the
🔌 / tools menu.

## Demo prompts

Once registered, try these in Claude Desktop:

1. **“List my DocuGenerate templates.”**
2. **“Generate an invoice from the Invoice template for Acme Corp — 3 line items:
   Design $1200, Development $3400, Hosting $200 — due in 30 days.”**
3. **“Now generate the same as a DOCX.”**

Claude will call `list_templates` to discover the Invoice template and its fields, then
`generate_document` (PDF, then DOCX) and hand you back the document URLs.

## Local testing (without Claude Desktop)

You can drive the server over stdio directly. Set the key and run the smoke test:

```bash
export DOCUGENERATE_API_KEY=your_api_key_here
npm run build
node dist/index.js   # server waits for MCP JSON-RPC on stdin; Ctrl-C to exit
```

A quick end-to-end `generate_document` smoke test (replace `TEMPLATE_ID` with a real id from
`list_templates`):

```bash
export DOCUGENERATE_API_KEY=your_api_key_here
TEMPLATE_ID=your_template_id node --input-type=module -e '
import { spawn } from "node:child_process";
const srv = spawn("node", ["dist/index.js"], { env: process.env });
let buf = "";
srv.stdout.on("data", d => { buf += d.toString();
  for (const line of buf.split("\n")) { if (!line.trim()) continue;
    try { const m = JSON.parse(line);
      if (m.id === 2) { console.log(m.result.content[0].text); srv.kill(); process.exit(0); }
    } catch {} }
});
srv.stderr.on("data", d => process.stderr.write("[srv] " + d));
const send = o => srv.stdin.write(JSON.stringify(o) + "\n");
send({ jsonrpc:"2.0", id:1, method:"initialize", params:{ protocolVersion:"2024-11-05", capabilities:{}, clientInfo:{ name:"cli", version:"0" } } });
send({ jsonrpc:"2.0", method:"notifications/initialized" });
send({ jsonrpc:"2.0", id:2, method:"tools/call", params:{ name:"generate_document",
  arguments:{ template_id: process.env.TEMPLATE_ID,
    data: { "Company Name": "Acme Corp", "Total": "$4,800" }, format: "pdf" } } });
setTimeout(() => { srv.kill(); process.exit(1); }, 15000);
'
```

## Error handling

Every tool returns a readable error instead of crashing. Failures surface the HTTP status
and the DocuGenerate error body, with a hint for the common cases:

- **401 / 403** → “check that `DOCUGENERATE_API_KEY` is set to a valid key…”
- **404** → “the `template_id` may be wrong or deleted. Use `list_templates`…”
- **429** → “rate limit hit; wait a moment and try again.”
- Network/DNS/TLS failures and non-JSON responses are also caught and reported.

## Troubleshooting

- **`generate_document` returns a 500 “Cannot read properties of undefined (reading 'length')”.**
  This is a DocuGenerate-side error that means the *template* file is malformed — a
  hand-assembled `.docx` missing the standard Office parts (`styles.xml`, `settings.xml`,
  etc.) will upload fine but fail at render time. Fix: author the template in **Microsoft
  Word / Google Docs** (or upload it through the DocuGenerate dashboard) so it's a complete
  `.docx`, then re-upload. A normal Word-authored invoice template works.

## Configuration

| Env var | Required | Default |
| --- | --- | --- |
| `DOCUGENERATE_API_KEY` | ✅ | — |
| `DOCUGENERATE_BASE_URL` | — | `https://api.docugenerate.com/v1` |

## License

MIT