User Guide

Welcome to ZReport. This guide will help you master report design, from simple lists to complex analytical dashboards.

New to reporting? Start with the Tutorial to build your first report in 5 minutes.

Interface Overview

The designer is divided into four main areas:

1. Toolbox (Left)

Your palette of building blocks. Contains Text, Image, Table, Chart, and more.Drag and drop these items onto the canvas to add them to your report.

2. Design Canvas (Center)

This represents your page. It is divided into horizontal Bands. What you see here is a template; the final report will repeat these bands for each record in your data.

3. Data Dictionary (Panel)

Shows your data structure. Drag fields like ProductName directly onto the canvas to create data-bound text boxes instantly.

4. Properties (Right)

Fine-tune the selected element. Change fonts, colors, borders, or edit the Expression to add logic.


Tutorial: Your First Report

Let's build a simple Employee List report.

Step 1: Setup

Click New Report β†’ Blank Report. In the Page Setup dialog, choose A4 and Portrait.

Step 2: Add a Title

Drag a Text element into the Report Header band.

  • Double-click and type "Employee Directory".
  • In Properties, set Font Size to 24 and Bold.
  • Align it to Center.

Step 3: Define Data

Ensure you have a data source connected (e.g., "Employees"). The Detail band represents one row of data.

Step 4: Add Fields

Drag 3 Text elements into the Detail band:

  1. Type {Employees.FirstName} in the first box.
  2. Type {Employees.LastName} in the second.
  3. Type {Employees.Department} in the third.

Tip: You can also drag fields directly from the Data Dictionary.

Step 5: Add Headers

In the Page Header band (above Detail), add 3 Text elements to label your columns: "First Name", "Last Name", "Department". Make them Bold with a bottom border.

Step 6: Preview

Click the Preview button (Eye icon). You should see a list of all employees formatted as you designed!


Bands Explained

Bands are the containers for your elements. Understanding bands is key to mastering reporting.

Band TypeFrequencyExample Content
Report HeaderOnce (Start)Report Title, Company Logo, Cover Letter
Page HeaderEvery Page (Top)Column Headers, Date, "Confidential" label
Group HeaderPer Group"Region: North", Group-specific charts
DetailPer RecordTransaction rows, Product details
Group FooterPer GroupSubtotals: {Sum(Sales)}, "Total for North"
Report FooterOnce (End)Grand Totals, Signatures, Terms & Conditions
Page FooterEvery Page (Bottom)Page Numbers ({PageNumber}), Copyright
SummaryOnce (End, separate page)Executive summary, final charts
No DataIf query is empty"No records found for this period."

Grouping Data

Grouping allows you to organize data into logical sections, such as Sales by Region or Employees by Department.

How to Create a Group

  1. Right-click on the Detail band or use the "Add Group" button.
  2. Define the Group Expression (e.g., $F{Region}). whenever this value changes, a new group starts.
  3. This creates a Group Header (before the details) and a Group Footer (after the details).

Group-Level Aggregations

In the Group Footer, you can calculate totals specifically for that group.

$V{TotalSales_Region}

Reset Type: "Group"


Elements Guide

T Text Element

The most versatile element. Supports both static text and expressions.

  • Mixed Content: Total: $F{Amount:currency}
  • Font Styling: Customize font, size, weight, and color in the Properties panel.
  • Alignment: Precise control over horizontal and vertical text alignment.

β–¦ Table & Grid

Tables provide structured row/column layout, while Grids offer flexible responsive layouts.

  • Dynamic Columns: Tables can automatically generate columns based on data.
  • Alternate Row Colors: Built-in support for zebra-striping.
  • Grid Layout: Use the Grid element for complex dashboard layouts (CSS Grid-like).

πŸ“Š Chart & Visualization

Visualize your data with Bar, Line, Pie, Area, Scatter, and Donut charts.

  • Series Mapping: Map data fields to X and Y axes.
  • Styling: Control colors, legends, and axis titles.
  • Barcode/QR: Generate standard barcodes (Code128, EAN) or QR codes from field data.

πŸ“„ Advanced Layouts

  • Subreports: Embed another report for master-detail views.
  • CrossTab: Create pivot tables for complex data intersections (Row/Column summaries).
  • Rich Text: Use the Tiptap-powered editor for formatted paragraphs.

Data Sources

The Data Dictionary panel is where you define and manage data sources for a project. These sources are shared across all reports in the same project.

Add a Data Source

  1. Open the Data Dictionary panel.
  2. Click the + button.
  3. Enter a name and choose a type.
  4. For SQL or REST, provide the query or URL.

Use Fields

  • Expand a source to see its fields once a schema is available.
  • Drag a field onto the canvas to create a bound Text element.
  • Reference fields in expressions with $F{fieldName}.

SQL (Relational)

Use a SQL query to fetch rows from a configured database connection.

JSON / REST API

Connect to a REST endpoint and provide a URL that returns JSON data.

Parameter

Use report parameters as a lightweight data source for parameter-driven elements.


Data Binding ($F, $P, $V, $R)

ZReport uses a JasperReports-style syntax to reference data. Every data-bound expression must be wrapped in curly braces {...} with a prefix.

$F (Fields)

Raw data from your data source. Use for row-level details.

$F{Name}

$P (Parameters)

Global inputs passed at runtime (e.g. Date ranges, User filters).

$P{StartDate}

$V (Variables)

Calculated values like sums or counts. Managed by the engine.

$V{TotalSales}

$R (Rich Content)

Structured rich content (formatted text, tables, images) from a parameter. See docs.

$R{content}

Parameters & Variables Detail

Parameters ($P)

Parameters are external inputs. You define them in the Report Inspector.

  • Types: String, Number, Boolean, Date.
  • Prompting: If Is For Prompting is checked, the user will see a dialog form before running the report.
  • Default Value: Fallback value if no input is provided.

System Variables

ZReport provides built-in variables to handle page numbering and report metadata.

VariableDescription
{PageNumber}Current page index
{TotalPages}Total page count (valid in Page headers/footers)
{RecordNumber}Current row index (1-based)
{PrintDate}Report generation timestamp
{GroupRecordNumber}Row index within current group

Formatting & Patterns

Apply display patterns to your data using the colon : syntax within the expression.

Number & Currency

  • $F{Price:currency} β†’ $1,234.56
  • $F{Quantity:number:0} β†’ 1235 (Rounded)
  • $F{Score:number:2} β†’ 98.50
  • FORMAT(1234.5, 2, ",") β†’ 1,234.50

Dates & Time

Default format is yyyy-MM-dd if no pattern is specified.

  • $F{CreatedAt:date:yyyy-MM-dd} β†’ 2024-03-15
  • $F{CreatedAt:date:MMM dd, yyyy} β†’ Mar 15, 2024
  • $F{CreatedAt:date:HH:mm} β†’ 14:30

Date Management Detail

Dates are stored as real Date values. If you render a date without a format, ZReport will display it using the short default format yyyy-MM-dd.

Parameter Date Input: The parameter dialog uses a date picker and stores a Date value.
System Date: {PrintDate} is the current timestamp.
Date Functions: Use NOW() for date+time and TODAY() for date-only values.
// Default short date behavior $P{startDate} -> 2026-01-21 // Custom formatting $P{startDate:date:MMM dd, yyyy} -> Jan 21, 2026 // Date math (Add 7 days) {DATEADD($P{startDate}, 7, "days")} -> 2026-01-28 // System date {PrintDate:date:yyyy-MM-dd HH:mm} -> 2026-01-21 16:41

Date values are rendered in the browser's local timezone. If you need a specific timezone, pass a preformatted string or include the timezone in the data source.

Text Transformation

  • $F{Code:uppercase} β†’ ABC-123
  • $F{Status:capitalize} β†’ Active

Functions Reference

ZReport includes a powerful functional library with 50+ functions for calculations and data manipulation.

Logical

  • IF(cond, true, false) - Ternary logic
  • ISNULL(val) - Checks if value is null
  • IFNULL(val, default) - Coalesce null
  • COALESCE(a, b, ...) - First non-null value
  • ISEMPTY(val) - Null or empty string
  • ISBLANK(val) - Null or whitespace
  • AND(a, b) / OR(a, b) / NOT(a) - Logical gates
  • SWITCH(val, case1, res1, ...) - Multi-case match
  • BETWEEN(val, min, max) - Range check
  • INLIST(val, a, b, ...) - List membership

Math

  • SUM(f) / AVG(f) / MIN(f) / MAX(f) - Aggregations
  • ROUND(val, decimals) - Rounding
  • FLOOR(val) / CEIL(val) - Round down/up
  • ABS(val) - Absolute value
  • MOD(n, d) - Modulo remainder
  • POW(base, exp) - Power
  • SQRT(val) - Square root

String

  • CONCAT(a, b, ...) - Join text
  • LEFT/RIGHT/MID(str, n) - Substring
  • REPLACE(str, find, rep) - Search & replace
  • CONTAINS(str, sub) - Search text
  • UPPER(str) / LOWER(str) - Case conversion
  • PROPER(str) - Capitalize each word
  • TRIM(str) - Remove whitespace
  • PADLEFT/PADRIGHT(str, len, char) - Padding
  • REPEAT(str, n) - Repeat text
  • REVERSE(str) - Reverse text
  • WORDCOUNT(str) - Count words
  • LEN(str) - String length

Date

  • NOW() / TODAY() - Current time/date
  • YEAR/MONTH/DAY(date) - Extract parts
  • DATEADD(date, n, unit) - Add days/months/years
  • DATEDIFF(d1, d2) - Diff in days
  • FORMATDATE(date, pattern) - Custom format
  • AGE(birthdate) - Calculate age in years

Conversion

  • TOSTRING(val) - Convert to string
  • TONUMBER(val) - Convert to number
  • TODATE(val) - Convert to date
  • FORMAT(num, decimals, sep) - Number format
  • CURRENCY(num, symbol, dec) - Currency format
  • PERCENTAGE(num, decimals) - Percentage format

Conditional Logic

You can hide elements or entire bands based on data conditions using the printWhen property.

How it works:

The engine evaluates your expression. If it results in false, 0, or an empty string "", the element is not rendered.

// Hide band if total is zero $V{SumSales} > 0 // Only show logo for specific companies $F{CompanyID} == "ACME"

Inline Logic (IF)

Use the IF function for dynamic content within a single text box.

Status: {IF($F{IsPaid}, "Paid", "PENDING")}

Preview & Exporting

Formats

Click the Preview button to generate the report.

  • PDF: High-fidelity print-ready documents (vector based).
  • Excel: Data-heavy reports. Preserves numeric types and formulas where possible.
  • JSON: Download raw data or report definition.
  • HTML: Web-native view.

Saving & Loading

Persistence

When working within a project, ZReport autosaves your changes every 60 seconds. You can manually save at any time using Ctrl+S.

Reports are stored in the database. You can also download the .zreport JSON definition file to version control locally.


Keyboard Shortcuts

General

Save Ctrl + S
Undo Ctrl + Z
Redo Ctrl + Shift + Z
Copy / Cut Ctrl + C / X
Paste / Duplicate Ctrl + V / D
Delete Del / Backspace

Tools & Canvas

Select / Deselect V / Esc
Text / Rectangle T / R
Line / Image L / I
Move Element Arrows
Nudge (10px) Shift + Arrows
Select element underneath Alt + Click

Limits & Troubleshooting

Expressions not rendering?

Ensure every expression starts with $F, $P, or $V and is wrapped in {...}. Plain braces without a prefix are treated as legacy fields.

TotalPages is always 0?

TotalPages is calculated at the very end of the rendering process. It is only valid in Page Header, Page Footer, or Summary bands.

Current Limitations:

  • Charts require at least one category and one value field to render.
  • Subreports must exist in the same project to be referenced.
  • CrossTab elements are currently limited to one row and one column grouping.
  • Rich Text formatting is limited to basic bold/italic/underline and lists in PDF exports.

Expression Engine

The expression parser evaluates JasperReports-style expressions at runtime.

Syntax

PatternTypeExample
$F{field}Data field$F{customerName}
$F{source.field}Qualified field$F{orders.total}
$P{param}Parameter$P{reportTitle}
$V{var}Variable$V{subtotal}
$V{SystemVar}System variable$V{PageNumber}
$R{param}Rich content$R{content}

Format Specifiers

Append :format to apply formatting:

  • $F{price:currency} – Format as currency
  • $F{date:date:yyyy-MM-dd} – Format as date
  • $F{name:uppercase} – Convert to uppercase
  • $F{code:pad:6:0} – Left-pad with zeros

System Variables

  • PageNumber – Current page number
  • TotalPages – Total page count (available after render)
  • PrintDate – Current date/time
  • ReportName – Name of the report
  • RecordNumber – Current record index
  • GroupRecordNumber – Record index within current group

Rich Content & Rich Text Elements

Rich content is a JSON array of blocks called RichContent (headings, styled paragraphs, lists, tables, images). There are two ways to fill a block at export time β€” Method 1: a $R{paramName} expression on a Text element, and Method 2: a bindParam on a dedicated Rich Text element. Both read the array from parameters, so the request body is identical. An advanced id-map override is also available when you POST an inline template.

Pick the method by element type. $R{paramName} is evaluated only on a Text element (Method 1). A Rich Text element ignores $R{paramName} and prints it literally β€” bind that element with bindParam (Method 2) instead. Either way, the element must have canGrow: true (or no canGrow), or the content is clipped to the box.

Method 1 β€” $R{paramName} on a Text element

The simplest method, and the only one fully supported in the visual designer. Add a Text element, set its content to $R{paramName}, enable Can Grow, then pass the RichContent JSON array as that parameter. Works with a saved report (reportId / reportName) or an inline template.

  1. Drag a Text element onto the band.
  2. Set its content to $R{bodyContent} (any parameter name works).
  3. Enable Can Grow in the element's properties.
  4. POST the matching parameter as a RichContent array:
{
  "reportId": "rpt_abc123",
  "parameters": {
    "bodyContent": [
      {
        "type": "paragraph",
        "align": "center",
        "content": [
          { "text": "Normal text " },
          { "text": "bold text", "bold": true },
          { "text": " colored", "color": "#ff0000", "fontSize": 14 }
        ]
      },
      { "type": "heading", "level": 2, "content": [{ "text": "Section Title" }] },
      { "type": "hr" }
    ]
  }
}

The parameter name inside $R{…} must exactly match the key in parameters, and the value must be a real JSON array β€” not a JSON-encoded string.

Method 2 β€” bindParam on a Rich Text element

Use a dedicated richtext element and set its bindParam to a parameter name. At export time the engine resolves parameters[bindParam] to that element's content, so you send the same RichContent array under parameters as in Method 1.

Note: a richtext element does not evaluate $R{paramName} β€” that is Method 1's Text-element behavior. There is also no field for bindParam in the visual designer yet, so set it directly in the template JSON: either POST an inline template (below) or edit the saved report definition.

{
  "template": {
    "pages": [
      {
        "bands": [
          {
            "type": "detail",
            "elements": [
              {
                "id": "student-comment",
                "type": "richtext",
                "x": 10,
                "y": 10,
                "width": 180,
                "height": 40,
                "bindParam": "commentBody",
                "canGrow": true
              }
            ]
          }
        ]
      }
    ]
  },
  "format": "pdf",
  "parameters": {
    "commentBody": [
      {
        "type": "paragraph",
        "content": [
          { "text": "Overall performance: ", "bold": true },
          { "text": "Very good" }
        ]
      }
    ]
  }
}

Advanced β€” id-map override by element id

When you POST an inline template (not a saved reportId), you can override any richtext element by its id without setting bindParam. The key in richContent must match the element id, so one template can render different rich text per request. The reportId / reportName Export API routes do not read this richContent map β€” use Method 1 or Method 2 for saved reports.

{
  "template": {
    "version": "1.0",
    "metadata": {
      "id": "student-report",
      "name": "Student Report",
      "createdAt": "2026-06-01",
      "updatedAt": "2026-06-01"
    },
    "settings": {
      "paperSize": { "type": "A4" },
      "orientation": "portrait",
      "margins": { "top": 20, "right": 20, "bottom": 20, "left": 20 },
      "units": "mm"
    },
    "dataSources": [],
    "parameters": [],
    "variables": [],
    "styles": [],
    "pages": [
      {
        "id": "page-1",
        "name": "Page 1",
        "bands": [
          {
            "id": "detail",
            "type": "detail",
            "height": 80,
            "elements": [
              {
                "id": "student-comment",
                "type": "richtext",
                "x": 10,
                "y": 10,
                "width": 180,
                "height": 40,
                "canGrow": true,
                "defaultFont": { "family": "Helvetica", "size": 12 },
                "defaultColor": "#000000"
              }
            ]
          }
        ]
      }
    ]
  },
  "format": "pdf",
  "richContent": {
    "student-comment": [
      {
        "type": "heading",
        "level": 2,
        "content": [{ "text": "Conduct" }]
      },
      {
        "type": "paragraph",
        "content": [
          { "text": "Punctuality: ", "bold": true },
          { "text": "Excellent", "color": "#047857" }
        ]
      },
      {
        "type": "list",
        "ordered": false,
        "items": [
          { "content": [{ "text": "Participates actively in class" }] },
          { "content": [{ "text": "Completes assignments on time" }] }
        ]
      }
    ]
  }
}

Rich Text Resolution Order

When a richtext element is rendered, ZReport uses the first structured content source it finds:

  1. richContent[element.id] in the request body.
  2. parameters[element.bindParam], when bindParam is set.
  3. element.richContent, the content saved by the designer.
  4. element.content, legacy HTML fallback.

For PDFs, canGrow: true or an omitted canGrow allows rich text to flow across pages when it exceeds the element box. Set canGrow: false to clip content to the element box.

Block Types

TypeDescriptionKey Properties
paragraphText paragraph with inline formattingalign, content
headingHeading (h1-h6)level (1-6), content
listList with configurable style (bullets, numbers, letters, roman, checkboxes)style, items
tableTable with headers and rowsheaders, rows
imageInline image (base64 data URI)src, width, height
hrHorizontal rule / dividerβ€”

Inline Text Properties

Each block that accepts content takes an array of inline text objects with these properties:

PropertyTypeDescription
textstring (required)The text content
boldbooleanBold text
italicbooleanItalic text
underlinebooleanUnderlined text
strikethroughbooleanStrikethrough text
colorstringText color (hex, e.g. "#ff0000")
fontSizenumberFont size in points
fontFamilystringFont family name
linkstringURL to make the text a hyperlink

List Styles

Set the style property on a list block to control the marker type. If omitted, defaults to "bullet" (or "number" when ordered: true for backward compatibility).

StyleMarkerExample
bulletFilled circleβ€’ Item
number1, 2, 3...1. Item
letter-upperA, B, C...A. Item
letter-lowera, b, c...a. Item
roman-upperI, II, III...I. Item
roman-loweri, ii, iii...i. Item
checkCheckboxβ˜‘ Done / ☐ Pending
radioRadio button● Selected / β—‹ Option

For check and radio lists, each item accepts a checked boolean. It ticks the checkbox (β˜‘/☐) for check, and fills the radio dot (●/β—‹) for radio \u2014 set checked: true on the option you want pre-selected. radio is cosmetic (it renders the glyph; it does not enforce single-selection), so mark exactly one item if you want true radio semantics. In PDF the checkbox/radio markers are drawn as crisp vector shapes, so they never depend on font glyph coverage; DOCX uses the β˜‘/● glyphs. The canvas/HTML preview shows a plain list.

In the designer, the rich-text editor toolbar has a list-style dropdown (Bullet, Numbered, Letters, Roman, Checklist, Radio). For Checklist and Radio, select an item and use the β˜‘/● toggle button to mark it as checked / pre-selected.

Add "layout": "horizontal" to flow the items in a wrapping row instead of stacking them β€” ideal for a rating scale. Works with any style; markers and selection behave the same.

{
  "type": "list",
  "style": "radio",
  "layout": "horizontal",
  "items": [
    { "content": [{ "text": "Excellent" }], "checked": false },
    { "content": [{ "text": "Very Good" }], "checked": true },
    { "content": [{ "text": "Good" }], "checked": false },
    { "content": [{ "text": "Fair" }], "checked": false },
    { "content": [{ "text": "Poor" }], "checked": false }
  ]
}
{
  "type": "list",
  "style": "check",
  "items": [
    { "content": [{ "text": "Design mockups" }], "checked": true },
    { "content": [{ "text": "API integration" }], "checked": true },
    { "content": [{ "text": "Write tests" }], "checked": false }
  ]
}

A radio list with one pre-selected option (the item with checked: true renders as ●, the rest as β—‹):

{
  "type": "list",
  "style": "radio",
  "items": [
    { "content": [{ "text": "Pass" }], "checked": true },
    { "content": [{ "text": "Pass with corrections" }], "checked": false },
    { "content": [{ "text": "Fail" }], "checked": false }
  ]
}

Full Example

[
  {
    "type": "heading",
    "level": 1,
    "content": [{ "text": "Invoice Summary" }]
  },
  {
    "type": "paragraph",
    "content": [
      { "text": "Thank you for your order. " },
      { "text": "Order #12345", "bold": true },
      { "text": " has been confirmed." }
    ]
  },
  {
    "type": "table",
    "headers": [
      { "content": [{ "text": "Item" }] },
      { "content": [{ "text": "Qty" }] },
      { "content": [{ "text": "Price" }] }
    ],
    "rows": [
      [
        { "content": [{ "text": "Widget A" }] },
        { "content": [{ "text": "2" }] },
        { "content": [{ "text": "$49.99" }] }
      ]
    ]
  },
  {
    "type": "list",
    "style": "bullet",
    "items": [
      { "content": [{ "text": "Free shipping included" }] },
      { "content": [{ "text": "30-day return policy", "italic": true }] }
    ]
  },
  {
    "type": "list",
    "style": "check",
    "items": [
      { "content": [{ "text": "Payment received" }], "checked": true },
      { "content": [{ "text": "Order shipped" }], "checked": false }
    ]
  },
  { "type": "hr" },
  {
    "type": "paragraph",
    "align": "center",
    "content": [
      { "text": "Visit our website", "link": "https://example.com", "color": "#0563C1" }
    ]
  }
]

Supported in PDF and DOCX exports. The element's position and dimensions (x, y, width, height) from the report designer are used to place the rich content block.


Export Services

ZReport supports exporting rendered reports to multiple formats.

PDF

High-fidelity vector PDF using @react-pdf/renderer. Supports text, images, tables, charts (rasterized), and barcodes.

Excel

Spreadsheet export using exceljs. Preserves numeric types, applies basic styling, and maps tables to worksheets.

HTML

Web-native HTML output. Useful for embedding reports in portals or sending via email.

DOCX

Word document export using docx. Best for text-heavy reports that need editing downstream.


Export API

Generate reports in various formats programmatically using our REST API.

Base URL

https://api.zreport.cloud

Authentication

All API requests require an API key. Include it in the Authorization header:

Authorization: Bearer YOUR_API_KEY

Generate API keys from your organization settings at Settings β†’ API Keys.

Export Endpoints

POST/api/export/pdf

Export a report as PDF.

POST https://api.zreport.cloud/api/export/pdf
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY

{
  "reportId": "rpt_abc123",
  "data": {
    "orders": [
      { "id": 1, "product": "Widget", "amount": 99.99 }
    ]
  },
  "parameters": {
    "title": "Q4 Sales Report",
    "startDate": "2024-10-01"
  }
}
POST/api/export/excel

Export a report as Excel (.xlsx). Same request body as PDF.

POST/api/export/html

Export a report as HTML. Same request body as PDF.

POST/api/export/docx

Export a report as Word document (.docx). Same request body as PDF.

Code Examples

Playground

Test the Export API directly from this page.

Response

On success, the API returns the file as a binary stream with appropriate content-type headers. On error:

{
  "success": false,
  "error": {
    "code": "INVALID_REQUEST",
    "message": "Report ID is required"
  }
}

Rate Limits

PlanExports/day
Free100
Pro5,000
EnterpriseUnlimited

MCP Server

ZReport exposes a Model Context Protocol server that lets AI agents (Claude Desktop, Claude Code, ChatGPT, custom integrations) read, generate, and design reports in your organization β€” programmatically, in natural language.

1POST https://api.zreport.cloud/mcp
2Authorization: Bearer zr_…
3Accept: application/json, text/event-stream

Prerequisites

  • A ZReport organization with at least one project.
  • An API key generated from Settings β†’ API Keys (or via POST /api/v1/organizations/:orgId/api-keys). Tokens carry the zr_ prefix and are shown only once at creation. Legacy mr_ tokens issued before the rebrand keep working.

Connecting Clients

Most AI clients speak stdio MCP, so we bridge to the HTTP transport via the mcp-remote helper.

Claude Desktop

Edit your Claude Desktop config:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • Linux: ~/.config/Claude/claude_desktop_config.json
1{
2 "mcpServers": {
3 "zreport": {
4 "command": "npx",
5 "args": [
6 "-y",
7 "mcp-remote",
8 "https://api.zreport.cloud/mcp",
9 "--header",
10 "Authorization: Bearer zr_abc123..."
11 ]
12 }
13 }
14}

Restart Claude Desktop. The 24 ZReport tools appear in the tools panel.

Claude Code

Drop the same block into .mcp.json at your workspace root, or into ~/.claude/mcp.json for a global config.

ChatGPT (Custom GPTs)

  1. Create a new Custom GPT.
  2. Open Connectors β†’ Add MCP Server.
  3. URL: https://api.zreport.cloud/mcp
  4. Authorization header: Bearer zr_abc123...

MCP Inspector (Testing)

For one-off debugging, run the official inspector:

1npx @modelcontextprotocol/inspector

Opens a UI at http://localhost:6274. Choose Streamable HTTP, paste the ZReport URL, add the Authorization header, and click Connect.

Try a prompt: β€œList my projects, then create a sales report in project 1 with a detail band containing a table bound to my orders data source.”

Tools & Resources

The server exposes 24 tools across three groups, plus rich resource feeds for schemas and existing reports.

Read

ToolPurpose
list_projectsList projects in the organization.
list_reportsList reports in a project.
get_reportFetch the full ReportDefinition JSON.
list_data_sourcesList configured data sources.
get_data_source_schemaField names and types for a data source.
preview_data_sourceUp to 50 sample rows.

Generate

ToolPurpose
generate_reportRender to PDF, Excel, or DOCX. Returns inline base64 plus a single-use 1-hour download URL.

Design

ToolPurpose
create_reportCreate a blank report. Returns page geometry in mm.
apply_operations ⭐Batched design β€” preferred. Apply many ops atomically in one transaction. See below.
replace_reportWholesale replace of the entire ReportDefinition. Use for import-template flows; prefer apply_operations for incremental edits.
set_data_sourceBind a data source to a report.
add_parameterDefine a report parameter (referenced as $P{name}).
add_fieldDeclare an ad-hoc field ($F{name}).
add_variableComputed variable, e.g. sum($F{amount}), referenced as $V{name}.
add_band / update_bandPage Header, Detail, Group, Summary, Footer, etc. Heights in mm.
add_groupAdd a grouping level with header/footer bands.
add_element / update_element / remove_elementPlace and edit text, image, table, chart, barcode, shape, etc. All coordinates are in mm.
add_page / remove_page / update_page / duplicate_pageManage multi-page reports. Each page renders as its own section β€” PDF starts a fresh paper-page sequence, DOCX a new section, Excel a new worksheet.

Multi-page reports

Reports can carry multiple pages (ReportDefinition.pages: Page[]). Each page has its own bands and renders as a distinct section:

  • PDF: each page begins a fresh paper-page sequence; $V{PageNumber} counts continuously across the whole document.
  • DOCX: each page becomes its own section β€” new sections start on a new physical page.
  • Excel: each page becomes its own worksheet, named from Page.name.

The band and element tools target a specific page where applicable:add_band and add_group accept an optional pageId(defaults to the first page); single-instance bands like pageHeader /detail / pageFooter are scoped per page β€” each page can have its own. update_band, add_element,update_element, and remove_element look their target up by id across every page, so they work regardless of which page it lives on.

Batched design with apply_operations

For anything more than a one-line tweak, batch your mutations into a singleapply_operations call. Each entry has the same shape as the matching single-op tool, minus the top-level reportId, plus an op discriminator (named op rather than type because several schemas already usetype for the value's own type and would otherwise collide):

1{
2 "reportId": 42,
3 "operations": [
4 { "op": "set_data_source", "dataSourceId": "..." },
5 { "op": "add_parameter", "name": "asOf", "type": "date" },
6 { "op": "add_band", "type": "pageHeader", "height": 30 },
7 { "op": "add_element", "bandId": "band-...", "element": { /* full element */ } },
8 { "op": "update_band", "bandId": "band-...", "height": 25 }
9 ]
10}
  • Atomic. All ops run in one db transaction. If any fails, nothing is persisted.
  • Pre-validation. Element shapes parse before the transaction opens; Zod errors come back with paths like operations[3].element.font.size.
  • Error locator. Failures include data.opIndex and data.opType so the model can target the fix.
  • Cap: 200 ops per call. Split into turns above that.

Resources

Beyond tools, the server publishes resource URIs that agents can fetch for richer context:

URIContents
zreport://reports/{reportId}Full ReportDefinition JSON for an existing report.
zreport://schemas/element/{type}JSON Schema for each of the 14 element variants (text, image, table, chart, barcode, …).
zreport://schemas/report-elementDiscriminated union over all 14 element types.
zreport://schemas/expression-functionsCatalog of 70+ expression functions with signatures and examples.

Expressions

Most element fields and variables accept the same expression syntax used in the designer:

  • $F{fieldName} β€” current row's field value
  • $P{paramName} β€” scalar parameter passed at generation time
  • $V{variableName} β€” computed variable (often an aggregate)
  • $R{paramName} β€” rich content (HTML / structured text) sourced from a parameter. Use inside a text element with isRichText: true to inject formatted text, tables, or images. Distinct from $P, which yields a plain scalar.
  • Function calls β€” sum($F{amount}), format($F{date}, 'yyyy-MM-dd'), upper($F{name})

Typical Workflow

  1. Discover β€” list_projects, list_data_sources, get_data_source_schema.
  2. Create β€” create_report, set_data_source, add_parameter.
  3. Design β€” add_band, add_group, add_element.
  4. Populate β€” add_field, add_variable, update_element with expressions.
  5. Generate β€” generate_report for a sample preview.
  6. Iterate β€” refine via update_element and update_band.
  7. Export β€” final generate_report in PDF / Excel / DOCX.

Limits, Errors & Security

Rate Limits (per API key)

EndpointDefaultNotes
General /mcp600 / minAll read & design tools.
generate_report200 / minResource-intensive renders.
preview_data_source300 / minHits live data sources.

Generated files larger than 25Β MB return a download URL only (no inline base64). Download URLs are single-use and expire after 1 hour.

Error Kinds

MCP errors carry a structured data.kind field for programmatic handling:

KindMeaning
validationInput failed Zod schema. Inspect the issues array.
not_foundResource missing. Also returned for cross-org access (prevents leakage).
invariant_failureDocument constraint violation (duplicate IDs, circular refs, …).
data_source_errorUnderlying connection or query failed.
generation_failedRenderer threw β€” unsupported combinations, missing fonts, etc.
quota_exceededPer-tool rate limit tripped. Wait and retry.
unsupportedFeature not yet implemented.

Troubleshooting

SymptomLikely Cause & Fix
401 UnauthorizedBad / missing Authorization: Bearer zr_… header. Verify or regenerate the token.
406 Not AcceptableMissing Accept: application/json, text/event-stream. The MCP SDK requires both values.
404 on a download URLURL expired (>1h) or already claimed. Regenerate the report.
unsupported for format: 'html'Server-side HTML export isn't implemented. Use pdf, excel, or docx.
Data source returns no rowsUse preview_data_source to diagnose; check the data source configuration and server logs.

Privacy & Security

  • API tokens are bearer credentials. Treat them like passwords β€” they grant full access to the issuing organization.
  • Tokens are SHA-256 hashed at rest. The full value is shown only once at creation; lost tokens must be regenerated.
  • Tokens are redacted from access logs (URL-path tokens are rewritten before logging) and from audit arguments (sensitive keys like password, token, secret are replaced with ***).
  • Cross-org access returns not_found, never forbidden β€” this prevents disclosing the existence of resources owned by other organizations.
Tip: Use the MCP Inspector to probe tool behaviour in isolation before wiring an agent. Start with a tiny detail band, then add headers, footers, and groups iteratively β€” small steps catch invariant errors early.