html-report-server
v1.4.0
Published
MCP server for generating styled HTML reports from structured JSON — stat cards, tables, SVG charts, timelines, and more
Maintainers
Readme
html-report-server
A local MCP server for generating styled HTML reports from structured JSON. Works with Claude Code, Cursor, and any MCP-compatible client.
4 tools to render publication-quality HTML reports — stat cards, tables, SVG charts, timelines, and more — with 80-90% fewer output tokens compared to raw HTML generation.
Why
When an LLM generates HTML reports, it outputs verbose inline styles, SVG paths, and layout markup. This server lets the LLM describe the report as compact JSON blocks, and the server expands them into fully-styled HTML with charts, cards, and professional layouts — all running locally via stdio with no file uploads.
Features
| Category | Tools |
|---|---|
| Render | render_report — JSON DSL → styled HTML file (one call for an entire report) |
| Read | read_report — extract JSON structure from existing report for re-editing |
| Edit | edit_report — patch operations (replace, insert, delete blocks) |
| Reference | get_component_examples — example JSON for every block type |
Style presets
| Preset | Character |
|---|---|
| mckinsey | Executive: uppercase headers, thin borders, generous whitespace |
| clean | Modern SaaS: subtle shadows, rounded corners, no borders |
| minimal | Content-dense: tight spacing, 720px width, no decoration |
| dashboard | Data-dense: 1200px width, dark header tables, compact layout |
Block types (25)
| Category | Blocks |
|---|---|
| Text | section, heading, paragraph, list, callout |
| Data | stat_cards, hero_stats, metadata, table, before_after |
| Charts | bar_chart, line_chart, pie_chart, progress_bars |
| Layout | card_grid, comparison, timeline, steps, badges, divider |
| Tables | comparison_matrix — multi-party comparison with badge/tag columns; sectioned_table — multi-section table with subtotals |
| Diagrams | diagram — layered architecture diagrams; relationship_graph — node-and-edge graphs (hierarchical/radial/force layout, serif/mono/print modes) |
| Escape hatch | html — raw HTML (sanitized) |
Document-level options
title— report title (required)subtitle— subtitle below the titlebadge— badge label next to the title (e.g. "PERFORMANCE REPORT")style— preset namestyle_overrides— selective overrides for card/table/chart/sectionTitle tokens
Token efficiency
| Component | Raw HTML tokens | JSON DSL tokens | Savings | |---|---|---|---| | Stat card grid (3 cards) | ~350 | ~60 | 83% | | Data table (5×10) | ~600 | ~150 | 75% | | Bar chart (8 bars) | ~800 | ~60 | 92% | | SVG line chart | ~1200 | ~80 | 93% | | Before/after comparison (3 items) | ~900 | ~120 | 87% | | Steps flow (5 steps) | ~500 | ~100 | 80% | | Architecture diagram (4 layers, 16 edges) | ~8000 | ~1500 | 81% | | Full report (30 blocks) | ~13000 | ~1700 | ~87% |
Installation
Claude Code
Add to ~/.claude.json:
{
"mcpServers": {
"html-report": {
"type": "stdio",
"command": "npx",
"args": ["-y", "html-report-server@latest"]
}
}
}Cursor
Add to your MCP server configuration:
{
"html-report": {
"command": "npx",
"args": ["-y", "html-report-server@latest"]
}
}Local development
git clone https://github.com/knorq-ai/html-report-server.git
cd html-report-server
npm install
npm run build
npm run dev # or: node dist/index.jsUsage
render_report
The primary tool. Pass a complete report with title, style preset, and array of block objects:
{
"file_path": "/tmp/report.html",
"title": "Q4 Performance Report",
"subtitle": "Google Sheets → Cloud SQL Migration",
"badge": "PERFORMANCE REPORT",
"style": "mckinsey",
"blocks": [
{ "type": "section", "title": "Key Metrics" },
{
"type": "stat_cards",
"cards": [
{ "label": "Revenue", "value": "$4.2M", "delta": "+15%", "trend": "up" },
{ "label": "Users", "value": "12,847", "delta": "+28%", "trend": "up" }
]
},
{
"type": "bar_chart",
"title": "Monthly Revenue",
"data": [
{ "label": "Jan", "value": 280 },
{ "label": "Feb", "value": 310 },
{ "label": "Mar", "value": 350 }
],
"unit": "K"
}
]
}Round-trip editing
1. render_report → creates report.html
2. read_report → returns JSON structure + block summary
3. edit_report → patch operations (replace/insert/delete blocks)The JSON source is embedded as an HTML comment in the output file, enabling seamless round-trip editing without a separate database.
get_component_examples
Call this tool (no parameters) to get example JSON snippets for every block type. Useful for learning the DSL.
Security
Since this server generates HTML from user input, all output is sanitized:
- Text content: escaped via
escapeHtml()(prevents XSS in all text fields) - Inline HTML (paragraph, callout): allowlist-based sanitizer permits only safe formatting tags (
b,i,em,strong,a,code,br,span) - Raw HTML block: allowlist-based sanitizer permits layout + formatting tags, strips
<script>,<iframe>, event handlers,javascript:/data:URIs - CSS values (user-supplied colors): sanitized to reject injection characters
- HTML attributes: auto-escaped in all element builders
- JSON embedding:
-->escaped to prevent HTML comment breakout - Sanitizers run in a loop until stable to prevent nested-tag bypass attacks
Architecture
src/
├── index.ts MCP server + 4 tool definitions
├── html-engine.ts Public API barrel module
└── engine/
├── types.ts TypeScript types (Block union, presets, DSL)
├── errors.ts Structured error codes
├── file-lock.ts Per-file write serialization
├── theme.ts 4 style presets + inline style builder
├── html-utils.ts HTML escaping + sanitization
├── charts.ts SVG bar/line/pie/donut charts
├── diagrams.ts SVG layered architecture diagrams
├── graph.ts SVG relationship graph renderer
├── color-utils.ts Shared color utilities for SVG renderers
├── components.ts 25 block type renderers
├── renderer.ts Main render loop + block summarizer
└── html-io.ts File I/O + JSON comment round-tripLimitations
- No JavaScript in output: all
<script>tags and event handlers are stripped - No external CSS: output uses inline styles only (CSS variables from host)
- No image insertion: charts are inline SVG, no raster image support
- No formula recalculation: chart data is static
- CJK text width: SVG text sizing uses a codepoint-based width heuristic (CJK characters counted as ~1.8× Latin width)
License
MIT
