Someone hands you a Word template and a deadline. What data does it want? The usual answer is to open it, scroll, guess, run it, read the error, and run it again. With GroupDocs.Assembly.Mcp running locally (dnx GroupDocs.Assembly.Mcp --yes), Claude Desktop, Cursor or Copilot asks the template directly: get_template_fields returns every tag, the data names it uses and a JSON skeleton to fill, without running the engine, and when a run does fail, the error says what to change:
What data does order-lines.docx need? If it will not generate, tell me why and how to fix the template.
The step-by-step version with config and troubleshooting is in the documentation: How to find out what a template needs and why it failed.
Why inspect before you fill?
Because trial and error is the expensive way to learn a schema. An agent that guesses field names from the visible text of a document will guess CustomerName when the template reads customer.Name, and every wrong guess costs a round trip and a confusing error. A template is not prose; it is a program with a data contract, and the contract can be read.
That is all get_template_fields does. It parses the <<…>> tags, works out the names, and builds the skeleton:
-> get_template_fields {"template":{"filePath":"order-lines.docx"}}
<- { "tagCount": 3,
"dataSourceNames": [ "lines" ],
"fields": [ "lines[].Title", "lines[].Quantity" ],
"dataSkeleton": { "lines": [ { "Title": "", "Quantity": "" } ] },
"notes": [ "fields and dataSkeleton are inferred from the tags,
not from the engine; values computed by Select/GroupBy
projections are not followed." ] }
The note is honest about the method: this is static inspection. A field produced inside a Select projection is not followed. For a normal contract, letter or invoice template, the skeleton is exactly what to fill.
The skeleton also changes the conversation with you. Instead of “I tried to generate the order and it failed”, the agent can say “this template needs a list of lines, each with a title and a quantity; I found three in your email, here they are”, and only then generate. Inspection is cheap, needs no data and touches nothing, so it is the right first call for any template the agent has not seen before, and the right call again whenever someone has edited the template since.
Three failures, three answers
template problem what the server says the fix
------------------------ ---------------------------- -------------------
{{name}} placeholders "2 '{{...}}' placeholder(s). write <<[name]>>
... does not process that
syntax"
<<foreach>> never closed "Unexpected end of template. add <</foreach>>
A block tag is not closed"
data lacks a field "The template reads 'Email', add it, or
which the data does not have" allowMissingMembers
The wrong syntax. A lot of templates in the wild were written for other engines and use {{name}}. GroupDocs.Assembly leaves those as text, and inspection says so before anyone wastes a run:
-> get_template_fields {"template":{"filePath":"shipping-notice.docx"}}
<- { "tagCount": 0, "notes": [ "No <<…>> tags were found: ...",
"The template contains 2 '{{…}}' placeholder(s). GroupDocs.Assembly
does not process that syntax and leaves it as text; write
<<[name]>> instead." ] }
The unclosed block. Our order-lines.docx opens a <<foreach>> and never closes it. Inspection lists the tags happily; generation does not:
-> assemble_document {"template":{"filePath":"order-lines.docx"},
"dataJson":"{\"lines\":[{\"Title\":\"Cable\",\"Quantity\":2}]}"}
<- Document assembly failed for 'order-lines.docx': ...
Unexpected end of template. A block tag is not closed: every
<<foreach>> needs <</foreach>> and every <<if>> needs <</if>>.
The missing field. When the data lacks something the template reads, the error names the field, says names are case-sensitive and offers the switch: allowMissingMembers: true outputs nothing for missing members and empty lists instead of failing.
When the template is full of mistakes
Some templates have several errors, and fixing them one failed run at a time is slow. inlineErrors: true turns the template into its own error report: the document is generated and each faulty tag gets its message written next to it. On the sample template from the GroupDocs.Assembly examples:
-> assemble_document {"template":{"filePath":"inline-error.docx"},
"dataJson":"{\"name\":\"x\"}","inlineErrors":true}
<- Assembled 'inline-error.docx' ... The template has errors: each one
is written into the output next to its tag, starting with 'Error!'
The output contains << var [name] Error! An assignment operator is expected. >>, at the place in the document where the tag sits. Open the file, fix every marked tag, run again without the flag.
What inspection cannot see
Binary Outlook templates are the exception. A .msg file’s tags cannot be read without generating it, and the server says so rather than returning an empty list that looks like “no fields”:
-> get_template_fields {"template":{"filePath":"contracts-table.msg"}}
<- { "readable": false, "notes": [ "Tags cannot be read from a .msg
template without generating it. Save the template as DOCX, XLSX,
PPTX or EML to inspect it, or generate it with assemble_document
and inlineErrors=true to see which fields fail." ] }
One more trap we hit: a list that is empty in the data has no member types. Our contract template multiplies item.Quantity * item.UnitPrice; with "items": [] and allowMissingMembers: true, generation still failed with “Can not apply operator ‘’ to operands of type ‘System.Object’ and ‘System.Object’”*. Have the agent check that a list is not empty before it generates, and ask you what an empty contract should look like.
Honest limits
- Inspection is static:
SelectandGroupByprojections are not followed, and.msgtemplates cannot be read. - Templates are trusted input; image and document tags load the paths and URLs their expressions return.
- Evaluation mode: every output starts with “Evaluation Only. Created with GroupDocs.Assembly 26.7…”.
- Dates: pass
2026-11-12T00:00:00and format in the template with:"d MMMM yyyy"; a date-only string was shifted by a day on a UTC+2 machine, and"12.11.2026"was read as 11 December.
FAQ
How do I see what fields a Word template needs?
Ask the agent to call get_template_fields on it. You get the tags, the data names and a JSON skeleton, locally, without generating anything.
Why does my template print {{name}} instead of the value?
Because GroupDocs.Assembly tags are <<[name]>>. The server’s inspection flags {{…}} placeholders and says what to write instead.
Can Markdown be a template?
Yes. Our product-readme.md with <<[product]>> and <<[description]>> tags was inspected like a Word file and generated straight to DOCX.
Go deeper
- Documentation, canonical how-to: How to find out what a template needs and why it failed
- Documentation hub: GroupDocs.Assembly MCP Server
- Start here: Let the model fill in the data, not write the document
- Related: A hundred personalised PDFs from one prompt: mail merge with an AI agent
- Related: The chart comes from the template, the numbers come from the data
- Related: Your repo already has the data; let the agent make the PDF
- On-premise and security model: 3 architectures for AI document processing, and the one that keeps files inside your network
- Questions: GroupDocs Assembly forum
- Source: GroupDocs.Assembly.Mcp on GitHub