28MCP server for coding agents
zplcore-mcp is a Model Context Protocol server: coding agents such as Claude Code, Claude Desktop, VS Code/GitHub Copilot or Cursor use it to render, check and fix ZPL labels offline in a loop – write ZPL, look at the PNG, read the diagnostics, improve. 26 tools: render, lint, format, diff, fill_template, convert_epl, comply, verify, import_label, extract, redact, gs1_link_build/_parse, gs1_migrate, rfid_encode/_decode/_check, printer_profiles, printer_check, print_estimate, cut_plan, lift_svg, list_symbologies, describe_symbology, explain_command, get_limits.
dotnet pack tools/ZplCore.Mcp -c Release -o nupkg dotnet tool install -g ZplCore.Mcp --add-source nupkg # command "zplcore-mcp", needs the .NET 10 runtime claude mcp add zplcore -- zplcore-mcp # Claude Code (current project; --scope user for all)
Claude Code (.mcp.json in the repository)
{ "mcpServers": { "zplcore": { "type": "stdio", "command": "zplcore-mcp", "args": [] } } }Claude Desktop (claude_desktop_config.json)
{ "mcpServers": { "zplcore": { "command": "/Users/you/.dotnet/tools/zplcore-mcp", "args": [] } } }GUI apps often do not have ~/.dotnet/tools in their PATH – use the absolute path.
VS Code / GitHub Copilot (.vscode/mcp.json)
{ "servers": { "zplcore": { "type": "stdio", "command": "zplcore-mcp", "args": [] } } }Cursor (.cursor/mcp.json)
{ "mcpServers": { "zplcore": { "command": "zplcore-mcp", "args": [] } } }Example run (shortened)
Prompt: “Create a 100 × 150 mm GS1 shipping label for this shipment and check it against the GS1 logistics rules.”
lint– 0 diagnosticscomply gs1-logistic– 2 errors: ZPL3104 SSCC X-dimension 0.375 mm < 0.495 mm, ZPL3105 bar height 13 mm < 31.75 mm- Agent: SSCC barcode set to
^BY4and 270 dots high, text 3 mm and up, layout adjusted comply gs1-logistic– 0 errors ·verify– 3 of 3 barcodes read, grade A ·render– PNG, 100 × 150 mm, 203 dpi
Label, findings and grades are real engine results; a pre-check, not a certification.
Security model
Isolated
- stdio only: no HTTP/SSE, no listening socket; logs go to stderr only and never contain tool input
- Tools take label text and return results – no access to files, the network, printers, processes or environment variables; printer storage commands work on a store that lives for one call
- Every call runs in its own worker process with an empty environment (no client tokens), time and memory limits; on macOS also under
sandbox-exec(no network, no writes outside its scratch folder, home directory unreadable) - No PDF:
lift_svgtakes SVG text only, PDFium is not shipped with the server
Bounded
- Strict schemas: unknown arguments, wrong types, out-of-range values and duplicate keys are rejected
- Every call inside a
ZplLimitsscope (see below): 10 labels, 12 M dots, 4 MiB graphics, 16 MiB printer storage, 64 Ki characters of field data - 20 s and 1536 MB per call (configurable:
--timeout-seconds,--memory-mb,--workers) - SVG: 2 Mi characters, no DOCTYPE/entities, no external references, ≤ 256 levels, ≤ 200,000 elements
- Strings from the label are marked as untrusted data in the result

