Home · Guides

Generate Word proposals and contracts from a chat message

A proposal is the least interesting document you write and the one that most often decides whether you get paid. The MCP Docx server turns one sentence into a real .docx: letterhead, cover title, summary, scope, deliverables, a timeline table, a priced investment table and a signature block. It writes Word files rather than PDFs on purpose, because the client is going to want a change to clause four and you want them to be able to make it.

Install

claude mcp add docx -- npx -y @theluckystrike/mcp-docx

Cursor and Claude Desktop take the same server as a config block:

{
  "mcpServers": {
    "docx": {
      "command": "npx",
      "args": ["-y", "@theluckystrike/mcp-docx"]
    }
  }
}

The npm publish is pending, so until it lands use the .mcpb bundle from the latest release or a clone and build. Per client paths are on the setup pages.

Set the letterhead once

business_set stores the sender block printed on every document: name, address, email, VAT id, IBAN, bank, logo, letterhead colour, default currency, tax rate and payment terms. It is the same field set as MCP Invoice, so one profile serves both and the proposal you accepted becomes the invoice you send. A missing profile never blocks a document; the response tells you the sender block is a placeholder.

A proposal in one call

You: Write a proposal for Beta Corp. Checkout rebuild, 4,500 EUR, 50% on
signature 50% on delivery, three phases: discovery 1 week, build 3 weeks,
launch 1 week. Valid until the end of the year.

  proposal_create {
    client: "Beta Corp", project_title: "Checkout rebuild",
    scope: ["Audit the current funnel", "Rebuild the checkout", "Ship and measure"],
    timeline: [{phase: "Discovery", duration: "1 week"}, ... ],
    price: {amount: 4500, currency: "EUR", terms: "50% on signature, 50% on delivery"},
    valid_until: "2026-12-31"
  }
  -> PROP-2026-0001, EUR 4,500.00
  -> ~/.local/share/mcp-servers/docx/documents/checkout-rebuild.docx

The file opens in Word, Pages, LibreOffice and Google Docs. Every amount carries its currency code, so there are no bare numbers for a client to misread. References are PROP-YYYY-NNNN for proposals and AGR-YYYY-NNNN for agreements, and the counter is written before the record is stored, so a crash burns a number rather than reusing one on a second sent document.

Contracts, with the caveat printed on the document

contract_create writes a freelance service agreement skeleton: parties, services, term, fee, IP, confidentiality, contractor status, termination, liability and governing law, with [BRACKETED PLACEHOLDERS] where a decision is yours. The document itself says it is a drafting template and not legal advice, because nothing here has been reviewed by a lawyer in any jurisdiction. Treat it as the thing you send to a lawyer, not the thing you send to a client.

Filling a template you already use

doc_fill_template replaces {{placeholders}} in an existing .docx and writes a new file, keeping every style, table, header, footer and image, because everything except the paragraphs it rewrites is copied byte for byte. Call it with no values and it lists the placeholders the template actually contains, which is the fastest way to end an argument about a name that did not get replaced.

The part worth knowing is why so many template fillers fail on real files. A .docx paragraph is a sequence of runs, and Word routinely breaks a placeholder you typed as {{client}} into three runs after an edit or a spell-check pass: {{cli, ent, }}. Per-run replacement finds nothing and the document comes back with the placeholder still in it, silently. This server substitutes on the joined text of each paragraph instead, writes the result into the first run so its formatting survives, and blanks the remaining runs of that paragraph. The trade is stated plainly: a paragraph that mixes bold and regular text around a placeholder comes back in the first run's formatting. A placeholder with no value is left in place and reported, never blanked.

The numbering.xml insight

Reading a document back uses no dependency at all. A .docx is a ZIP, so node:zlib opens it and a small WordprocessingML walk pulls out paragraphs, heading levels from w:pStyle, list items and tables in document order. One detail decides whether doc_read is useful: in OOXML a numbered list and a bullet list are the same element. The distinction lives nowhere in the paragraph itself. It is recorded only by resolving that paragraph's w:numId against word/numbering.xml. Skip that resolution and every numbered list in the file reads back as bullets, which quietly destroys the structure of exactly the documents people want to read back: contracts, scopes of work and anything with numbered clauses.

There is no doc_to_pdf, deliberately

Every pure JavaScript path from Word to PDF needs a native dependency, a headless Chromium or a cloud API. This collection ships none of those, so npx works on any machine with Node and nothing else. doc_to_html writes semantic HTML with a print stylesheet: open it and print to PDF. The tool description says the same thing, so the model does not promise a file it cannot produce.

Free tier and Pro

Free covers doc_create, doc_from_markdown, doc_read and doc_to_html without limit, 3 proposals or contracts per calendar month combined, and templates with up to 10 placeholders. Pro ($19 once) removes those limits and adds your logo and brand colour on the letterhead. Product page: MCP Docx. Side by side with the alternatives: docx comparison.

Questions

Can it export a PDF?

No, and that is a deliberate choice. Every pure JavaScript route from .docx to PDF needs LibreOffice, a Chromium binary or a cloud API, none of which this collection ships. doc_to_html writes semantic HTML with a print stylesheet, so you open it and print to PDF.

Why did my template placeholder not get replaced?

Call doc_fill_template with no values and it lists the placeholders the file actually contains. Names are matched exactly, whitespace inside the braces is ignored, and the response names every key you passed that the template does not have. Placeholders split across runs by Word are handled, because substitution runs on the joined paragraph text.

Is the generated contract safe to sign?

Not as it stands. contract_create writes a drafting skeleton with bracketed placeholders and prints on the document that it is a template and not legal advice. Nothing in it has been reviewed by a lawyer in any jurisdiction. Send it to yours.

Can it read an existing Word file?

Yes. doc_read extracts headings with levels, paragraphs, list items and tables in document order, and format json returns the block structure. It reads .docx only; .doc, .rtf and Pages files are refused with a message that says so. It does not report fonts, colours, comments, tracked changes or footnotes.

Where do the files and the reference numbers live?

Under ~/.local/share/mcp-servers/docx/, with generated files in a documents subfolder when you do not pass out_path. Every mutating call runs inside an advisory lock, so two clients on one data directory cannot allocate the same reference number. The server makes no network request of any kind.

Related

All MCP servers and prices · All guides