ZplCore.Mcp
1.0.0
dotnet tool install --global ZplCore.Mcp --version 1.0.0
dotnet new tool-manifest
dotnet tool install --local ZplCore.Mcp --version 1.0.0
#tool dotnet:?package=ZplCore.Mcp&version=1.0.0
nuke :add-package ZplCore.Mcp --version 1.0.0
zplcore-mcp – MCP server for zplCore.com
zplcore-mcp is a Model Context Protocol server. Coding agents (Claude Code, Claude Desktop,
VS Code / GitHub Copilot, Cursor …) can use it to render, lint, format, diff and fill ZPL II / EPL2 labels offline, so an agent can
work on a label in a loop until it is right: write ZPL, look at the PNG, read the diagnostics, fix, repeat. It also checks labels
against compliance packs and printer models, grades barcodes, imports, extracts, redacts and migrates labels, encodes GS1 Digital
Link URIs and RFID EPCs, and lifts SVG labels to native ZPL.
The server is built for untrusted input. It only uses stdio and has no network listener. The tools take label text and return results. They have no access to files, the network, printers, processes or environment variables. Every call runs in a worker process with time and memory limits (see Security).
Install
dotnet pack tools/ZplCore.Mcp -c Release -o nupkg
dotnet tool install -g ZplCore.Mcp --add-source nupkg # installs the command "zplcore-mcp"
zplcore-mcp --help
You need the .NET 10 runtime. On macOS and Linux, global tools are installed in ~/.dotnet/tools. GUI apps such as Claude Desktop
often do not have this directory in their PATH, so give them the absolute path, e.g. /Users/you/.dotnet/tools/zplcore-mcp.
Configure your client
Licence key: zplcore-mcp --license <key|file> (or ZPLCORE_LICENSE, ZPLCORE_LICENSE_FILE, a file zplcore.license next to
the server), checked offline. Without a key the outputs carry the evaluation watermark.
Claude Code (CLI, current project only, or add --scope user):
claude mcp add zplcore -- zplcore-mcp
or check it into the repository as .mcp.json:
{ "mcpServers": { "zplcore": { "type": "stdio", "command": "zplcore-mcp", "args": [] } } }
Claude Desktop: Settings → Developer → Edit Config (claude_desktop_config.json):
{ "mcpServers": { "zplcore": { "command": "/Users/you/.dotnet/tools/zplcore-mcp", "args": [] } } }
VS Code / GitHub Copilot (agent mode): .vscode/mcp.json in the workspace:
{ "servers": { "zplcore": { "type": "stdio", "command": "zplcore-mcp", "args": [] } } }
Cursor: .cursor/mcp.json in the project, or ~/.cursor/mcp.json for all projects:
{ "mcpServers": { "zplcore": { "command": "zplcore-mcp", "args": [] } } }
Options go into args, e.g. ["--timeout-seconds", "30", "--workers", "1"]:
| Option | Default | Meaning |
|---|---|---|
--workers n |
2 | parallel worker processes (1–8); more calls wait in a short queue or get "busy" |
--timeout-seconds n |
20 | wall-clock limit per call (1–120); the worker is killed when it is exceeded |
--memory-mb n |
1536 | memory limit per worker (256–8192) |
--no-os-sandbox |
– | macOS: do not run workers under sandbox-exec |
--log quiet\|info\|debug |
info | logging to stderr; tool input is never logged |
Tools
| Tool | What it does |
|---|---|
render |
ZPL/EPL → PNG (image content), SVG or PDF (blob), plus a JSON summary. labelIndex or allLabels, dpi, widthMm/heightMm, fieldValues for ^FN. |
lint |
Structured diagnostics (stable codes like ZPL1002, severity, line/column) and optionally the rendered elements with bounds. |
format |
Pretty-prints (one command per line, optional ^FX field comments) or minifies. The rendered label stays the same. |
diff |
Renders two versions and returns changed pixels and regions, overlay PNGs and a line diff. |
fill_template |
Lists the ^FN fields (number, prompt, default value) and returns the template filled with your values (^XF is expanded). |
convert_epl |
EPL2 → ZPL II. |
comply |
Compliance pre-check with rule packs (gs1-logistic, sunrise, amazon-fba, ups, udi, fedex, dhl-paket, rfid or all): findings with rule id, severity, line and bounds as JSON or SARIF 2.1.0, optional annotated PNGs. |
verify |
Scan-proof: decodes every barcode with independent decoders, checks the data, grades A–F (a digital pre-check, not an ISO verification), optional robustness checks. JSON or SARIF. |
import_label |
ZPL → editable label model JSON (typed items or exact raw ZPL), round-trip fidelity and import warnings, optional diff PNGs. |
extract |
Texts, barcodes (GS1, Digital Link, MaxiCode messages), graphics, RFID data and entities (tracking numbers, addresses, dates …) with bounds. |
redact |
The ZPL with personal data masked, replaced or removed in the same layout, plus a report of what was redacted (never the removed values) and a verification pass. |
gs1_link_build, gs1_link_parse |
GS1 element string → GS1 Digital Link URI and back (validation, canonical URI). Text only: URIs are never fetched. |
gs1_migrate |
GS1 2D migration (Sunrise 2027): adds a QR Code with Digital Link URI or a GS1 DataMatrix next to the retail barcode, with a Sunrise pre-check and optional before/after PNGs. |
rfid_encode, rfid_decode, rfid_check |
EPC encode/decode (GS1 TDS 2.3: SGTIN, SSCC, SGLN, GRAI, GIAI …) with the ^RF commands, and the RFID consistency check of a label. |
printer_profiles, printer_check, print_estimate |
Printer Twin: the built-in printer profiles, "will this label print on this model?" (printhead width, clipped fields, firmware, options, fonts, memory) and the print time estimate. |
cut_plan |
Where the cutter cuts (^MM, ~JK, ^CN, ^PQ cut interval) and why. |
lift_svg |
SVG label (text) → native ZPL (^A0 text, native barcodes, ^GB/^GC/^GE/^GD, ^GF only for the rest) with fidelity and a per-element report. PDF is not accepted by the server; use zplcore lift for local PDFs. |
list_symbologies, describe_symbology |
The barcode symbologies of the engine and their ZPL commands. |
explain_command |
Built-in metadata for a ZPL command (^BC, ~DG …): name, parameters, and how the sandbox handles it. |
get_limits |
The limits listed below, as JSON. |
Text results are JSON. Strings in them that come from the label start with a notice that marks them as untrusted data.
Limits
| Limit | Value |
|---|---|
| JSON-RPC message | 4 MiB + 64 KiB, nesting depth 16 |
| ZPL/EPL input | 2 MiB characters per field |
| Labels per call | 10 (^PQ copies, ^XF recalls and ~WC included); ^PQ capped at 10 |
| Label size | 12 M dots, longest side 12 000 dots; arguments 5–300 mm × 5–1000 mm |
| Resolution | 152, 203, 300, 600 dpi |
Graphic (^GF, ~DG, ~DY, ~DU, Z64/B64 after decompression) |
4 MiB |
| Printer storage (R:/E:/B:/A:) | 16 MiB in memory, discarded after every call |
| Field data | 64 Ki characters |
^FN values |
200 values of up to 8192 characters |
| Output | 12 MiB binary, 6 Mi characters of text per call |
| Time / memory | 20 s and 1536 MB per call (options) |
SVG (lift_svg) |
2 MiB characters, no DOCTYPE/entities, no external references, ≤ 256 nesting levels, ≤ 200 000 elements incl. <use> copies, images ≤ 20 000 px per side, ≤ 200 in per side |
| Lists, maps | packs, categories, options, disabledRules, terms (≤ 50 × 200 chars), additionalElements (≤ 20 AIs) |
Security
- stdio only. There is no HTTP/SSE transport and no listening socket. Logging goes to stderr only.
- Engine-wide limits. Every call runs in a
ZplLimitsscope: also the renderers that the compliance check, scan-proof, import, redaction, printer twin and Vector-Lift create internally get the limits above, no font provider, no system fonts and a fixed clock. - No file system, network, shell or environment access in the tools. Printer storage commands (
~DG,~DY,~DU,^DF,^IS,^IL,^XG,^IM) work on an in-memory store that exists only for one call. Drive letters and paths in object names are just names.^A@fonts can only be fonts downloaded in the same call. Host and reset commands (~HS,~JR,~PS…) have no effect. - Worker processes. Every call that processes label data runs in a separate
zplcore-mcp --workerprocess. The worker starts with an empty environment (no tokens or keys of the client), an empty scratch directory,DOTNET_EnableDiagnostics=0and a GC heap limit. It is killed when the call takes too long, uses too much memory, is cancelled by the client or returns malformed output. On macOS the worker also runs undersandbox-exec: no network, no writes outside its scratch directory, no reading of the home directory, and no other programs. - Strict validation. Unknown arguments, wrong types, values out of range and duplicate keys are rejected. The schemas in
tools/listare exactly what the server checks, including enum lists, patterns (GTIN, EPC hex, firmware, Digital Link stem) and map keys. Printer profiles are only the built-in ones (an enum); no profile files are read. - No PDF.
lift_svgtakes SVG text only, and the PDF parser (PDFium) is not shipped with the server.
The security controls and their limits are described in the documentation: https://zplcore.com/docs/mcp/#mcpsecurity
Trademarks
Zebra, ZPL, ZPL II, EPL and Link-OS are trademarks or registered trademarks of Zebra Technologies Corp. QR Code is a registered trademark of DENSO WAVE INCORPORATED. GS1, GS1 DataBar, GS1 Digital Link, EPC and EPCglobal are trademarks of GS1 AISBL. ESC/POS is a registered trademark of Seiko Epson Corporation, Intelligent Mail a registered trademark of the United States Postal Service and Mailmark a registered trademark of Royal Mail Group Ltd. Other product and company names and logos mentioned are trademarks or registered trademarks of their respective owners. We use these names only to describe compatibility with file formats, printer languages and standards. zplCore.com is an independent product and is not endorsed, sponsored or certified by these companies; compliance packs are pre-checks, not certifications.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 43 | 10/27/2026 |