mcp-dashboards 2.0.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -31
- package/dist/index.js +38 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp-app.html +407 -359
- package/dist/preview-server.d.ts +9 -0
- package/dist/preview-server.d.ts.map +1 -0
- package/dist/preview-server.js +174 -0
- package/dist/preview-server.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +402 -130
- package/dist/server.js.map +1 -1
- package/dist/url-safety.d.ts +30 -0
- package/dist/url-safety.d.ts.map +1 -0
- package/dist/url-safety.js +164 -0
- package/dist/url-safety.js.map +1 -0
- package/package.json +22 -15
package/README.md
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
### Your AI can talk about data. Now it can show it.
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/mcp-dashboards)
|
|
8
|
+
[](https://glama.ai/mcp/servers/@KyuRish/mcp-dashboards)
|
|
9
|
+
[](https://glama.ai/mcp/servers/@KyuRish/mcp-dashboards)
|
|
8
10
|
[](LICENSE)
|
|
9
11
|
[](https://buymeacoffee.com/kyuish)
|
|
10
12
|
[](https://github.com/sponsors/KyuRish)
|
|
@@ -13,8 +15,8 @@
|
|
|
13
15
|
<img src="assets/demo.gif" width="400" alt="MCP Dashboards demo" />
|
|
14
16
|
<br>
|
|
15
17
|
<a href="assets/dashboard-example.png"><img src="assets/dashboard-example.png" width="115" height="220" alt="Infrastructure Command Center dashboard" /></a>
|
|
16
|
-
<a href="assets/chart-catalog.png"><img src="assets/chart-catalog.png" width="115" height="220" alt="Chart Catalog -
|
|
17
|
-
<a href="assets/theme-catalog.png"><img src="assets/theme-catalog.png" width="115" height="220" alt="Theme Catalog -
|
|
18
|
+
<a href="assets/chart-catalog.png"><img src="assets/chart-catalog.png" width="115" height="220" alt="Chart Catalog - 31 chart tools" /></a>
|
|
19
|
+
<a href="assets/theme-catalog.png"><img src="assets/theme-catalog.png" width="115" height="220" alt="Theme Catalog - 21 themes" /></a>
|
|
18
20
|
<br><sub>Click any thumbnail to see full size</sub>
|
|
19
21
|
</p>
|
|
20
22
|
|
|
@@ -24,7 +26,7 @@ We use AI for everything - analysis, reports, strategy. But when it comes to act
|
|
|
24
26
|
|
|
25
27
|
## The solution
|
|
26
28
|
|
|
27
|
-
MCP Dashboards renders interactive charts, dashboards, and KPI widgets directly inside your AI conversation.
|
|
29
|
+
MCP Dashboards renders interactive charts, dashboards, and KPI widgets directly inside your AI conversation. 31 chart tools covering 44+ chart subtypes (bar has stacked/drilldown, hero has 11 variants, etc.), 21 themes, 4 visual discovery catalogs, live polling, PNG/PPT/A4 export - all from a single MCP server. No browser tabs, no copy-paste, no context switching.
|
|
28
30
|
|
|
29
31
|
## Quick Start
|
|
30
32
|
|
|
@@ -56,9 +58,11 @@ claude mcp add dashboard -- npx -y mcp-dashboards --stdio
|
|
|
56
58
|
|
|
57
59
|
```bash
|
|
58
60
|
npx mcp-dashboards
|
|
59
|
-
# Server starts on http://
|
|
61
|
+
# Server starts on http://127.0.0.1:3001/mcp
|
|
60
62
|
```
|
|
61
63
|
|
|
64
|
+
Bound to localhost by default. See [Configuration](#configuration) if you need to expose it on your network or allow browser access from a non-localhost origin.
|
|
65
|
+
|
|
62
66
|
### Supported clients
|
|
63
67
|
|
|
64
68
|
Works in any MCP Apps-compatible client: **Claude Desktop**, **Claude Web**, **VS Code** (GitHub Copilot), **Goose**, **Postman**, **MCPJam**. ChatGPT support is rolling out.
|
|
@@ -77,36 +81,18 @@ No API to learn. Describe what you want in plain English:
|
|
|
77
81
|
|
|
78
82
|
The AI picks the right tool, formats your data, and renders the chart inline. Click any data point to ask follow-up questions.
|
|
79
83
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
Other MCP chart tools generate static images. MCP Dashboards renders **interactive HTML** inside your conversation.
|
|
83
|
-
|
|
84
|
-
### Explore your data in-chat
|
|
85
|
-
|
|
86
|
-
- **Hover tooltips** on every data point - no guessing values
|
|
87
|
-
- **Click to select** any bar, slice, or point - selections feed back to the AI for follow-up questions
|
|
88
|
-
- **Drill-down** into bar charts with breadcrumb navigation
|
|
89
|
-
- **Zoom & pan** on geo maps, treemaps, and heatmaps - scroll-wheel zoom up to 12x with hi-res re-rendering
|
|
90
|
-
- **Live polling** - real-time charts that auto-update from any API (stock prices, server metrics, crypto)
|
|
91
|
-
- **KPI sparklines** - inline trend mini-charts in dashboard metric cards
|
|
92
|
-
|
|
93
|
-
### Meeting in 5 minutes? Export and go
|
|
94
|
-
|
|
95
|
-
- **PPT slides** - one-click download as a 16:9 title slide or background-ready image
|
|
96
|
-
- **A4 documents** - paginated multi-page export with intelligent page breaks that never cut through a chart
|
|
97
|
-
- **PNG** - per-chart screenshots with title and theme baked in
|
|
98
|
-
- **CSV** - raw data export from any table
|
|
84
|
+
**Don't know where to start?** Ask *"show me the catalog"* — opens a master dashboard with one live visual tile per customization dimension (a real bar chart for charts, a pie for themes, a progress ring for hero variants, a neon-glowing card for effects). Click any tile, hit Ask, and you'll drill into that sub-catalog.
|
|
99
85
|
|
|
100
|
-
|
|
86
|
+
## Interactive charts, not images
|
|
101
87
|
|
|
102
|
-
|
|
88
|
+
Every chart is **interactive HTML** rendered directly in your conversation:
|
|
103
89
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
**
|
|
90
|
+
- **Explore in-chat** - hover tooltips, click-to-select (feeds back to the AI), drill-down with breadcrumbs, scroll-zoom up to 12x on maps and heatmaps
|
|
91
|
+
- **Live polling** - real-time charts that auto-update from any API on a timer
|
|
92
|
+
- **Export anywhere** - PPT (16:9 slides), A4 (paginated with smart page breaks), PNG, CSV
|
|
107
93
|
|
|
108
94
|
<details>
|
|
109
|
-
<summary><strong>All
|
|
95
|
+
<summary><strong>All Tools</strong></summary>
|
|
110
96
|
|
|
111
97
|
| Tool | Type | Best For |
|
|
112
98
|
|------|------|----------|
|
|
@@ -142,6 +128,18 @@ Boardroom gold, neon cyberpunk, forest earth, clinical white. Mix palettes, typo
|
|
|
142
128
|
| `render_from_json` | Auto-detect | Any JSON data - picks the best chart automatically |
|
|
143
129
|
| `render_from_url` | URL fetch | Fetches JSON from a URL and auto-visualizes |
|
|
144
130
|
|
|
131
|
+
**Discovery / Catalogs** — visual entry points for browsing what's available:
|
|
132
|
+
|
|
133
|
+
| Tool | Shows | When to use |
|
|
134
|
+
|------|-------|-------------|
|
|
135
|
+
| `render_catalog` | Master catalog with 4 live preview tiles | Don't know where to start. Click any tile, hit Ask, drill in. |
|
|
136
|
+
| `render_chart_catalog` | All 31 chart types with mini previews | Looking for the right chart for your data |
|
|
137
|
+
| `render_theme_catalog` | All 21 themes with color/typography/effects | Picking a theme |
|
|
138
|
+
| `render_hero_catalog` | All 11 hero metric variants | Picking a KPI widget style |
|
|
139
|
+
| `render_effects_catalog` | All 5 effect presets, each applied to a real card | Picking an animation/glow style |
|
|
140
|
+
|
|
141
|
+
Typography is still configurable on every chart via `typography=<name>` (8 options listed under [Themes](#themes)) — it just doesn't have its own catalog because all 8 options were visually identical without per-card font loading, which wasn't worth the build for one preview tool.
|
|
142
|
+
|
|
145
143
|
</details>
|
|
146
144
|
|
|
147
145
|
<details>
|
|
@@ -170,7 +168,7 @@ Boardroom gold, neon cyberpunk, forest earth, clinical white. Mix palettes, typo
|
|
|
170
168
|
|
|
171
169
|
## Themes
|
|
172
170
|
|
|
173
|
-
|
|
171
|
+
21 built-in themes. Pass `theme` to any tool.
|
|
174
172
|
|
|
175
173
|
| Family | Themes |
|
|
176
174
|
|--------|--------|
|
|
@@ -178,6 +176,7 @@ Boardroom gold, neon cyberpunk, forest earth, clinical white. Mix palettes, typo
|
|
|
178
176
|
| **Black/AI** | `black-tron` (cyan neon), `black-elegance` (warm gold), `black-matrix` (green hacker) |
|
|
179
177
|
| **Forest** | `forest-amber` (autumn), `forest-earth` (terracotta) |
|
|
180
178
|
| **Sky** | `sky-light` (airy blue), `sky-ocean` (deep navy), `sky-twilight` (sunset) |
|
|
179
|
+
| **Office** | `office-red` (corporate red, white bg - report-ready) |
|
|
181
180
|
| **Gray/ML** | `gray-hf` (warm yellow accent), `gray-copilot` (teal on dark) |
|
|
182
181
|
|
|
183
182
|
Mix-and-match with `palette`, `typography` (8 options: system, mono, professional, editorial, bold, techno, cyberpunk, luxury), and `effects` (5 presets: none, subtle, shimmer, neon, energetic).
|
|
@@ -219,7 +218,37 @@ For public APIs, use the URL directly:
|
|
|
219
218
|
|
|
220
219
|
Built on [MCP Apps](https://modelcontextprotocol.io/docs/extensions/apps). You ask the AI to visualize data, it calls the right tool, and the chart renders inline in your conversation. Self-contained - zero CDN, zero external requests.
|
|
221
220
|
|
|
222
|
-
**
|
|
221
|
+
**MCP Apps supported** (inline rendering): Claude Desktop, VS Code Insiders + MCP Apps extension, Goose, Postman.
|
|
222
|
+
|
|
223
|
+
**No MCP Apps support?** No problem. Every chart response also includes a clickable link to the same interactive chart in your browser:
|
|
224
|
+
- `http://localhost:PORT/chart/{id}` - the clickable link in chat. Backed by a tiny same-machine HTTP server bound to 127.0.0.1, lazy-started on the first preview request.
|
|
225
|
+
- `file:///.../chart-{id}.html` - the persistent shareable artifact. Same HTML bytes, written to disk so you can email, archive, or open it after the server has shut down.
|
|
226
|
+
|
|
227
|
+
Why both: Claude Code (VS Code) strips `file://`, `vscode://`, and `command://` URL schemes from chat markdown, so only `http://` produces a working clickable link. The file:// path is provided for sharing and offline viewing. Tool annotations (`readOnlyHint`, `idempotentHint`, `openWorldHint`) help clients reason about tool behavior.
|
|
228
|
+
|
|
229
|
+
## Configuration
|
|
230
|
+
|
|
231
|
+
All optional. Defaults are safe — set these only if you need to override.
|
|
232
|
+
|
|
233
|
+
| Env var | Default | What it does |
|
|
234
|
+
|---------|---------|--------------|
|
|
235
|
+
| `MCP_DASHBOARDS_RETAIN_DAYS` | `7` | How long to keep chart preview HTML files on disk. `0` disables auto-cleanup. |
|
|
236
|
+
| `MCP_DASHBOARDS_DISABLE_PREVIEW` | unset | Kill switch — no HTML files written, no preview server started, no preview links. Inline rendering still works in MCP Apps clients. |
|
|
237
|
+
| `MCP_HTTP_BIND_HOST` | `127.0.0.1` | HTTP-transport bind host. Stays on localhost by default. Set to `0.0.0.0` only if you trust your network. |
|
|
238
|
+
| `MCP_CORS_ALLOWED_ORIGINS` | localhost only | Comma-separated origins allowed to call the HTTP endpoint from a browser. Set this to add a non-localhost origin (e.g. `https://your-app.com`). |
|
|
239
|
+
| `MCP_URL_ALLOWLIST` | empty | Comma-separated hostnames that bypass the SSRF guard for `render_from_url` / `poll_http`. Use only for internal endpoints you fully trust. |
|
|
240
|
+
| `MCP_OUTBOUND_RATE_PER_SEC` | `10` | Per-host throttle for outbound HTTP calls. |
|
|
241
|
+
| `MCP_OUTBOUND_BURST` | `20` | How many initial requests can fire immediately before the rate kicks in. |
|
|
242
|
+
| `POLL_PRESET_<NAME>_URL` | — | Server-side preset URL for live polling. See [Live Polling](#live-polling). |
|
|
243
|
+
| `POLL_PRESET_<NAME>_HEADERS` | — | Auth headers (JSON object) for the matching preset URL. |
|
|
244
|
+
|
|
245
|
+
### What's on disk
|
|
246
|
+
|
|
247
|
+
Chart HTML files are written to `<system temp>/mcp-dashboards/` and auto-deleted after 7 days. The chart's built-in download button (PNG / PPT / A4) is the recommended way to save anything permanently.
|
|
248
|
+
|
|
249
|
+
Ask your AI to *"list chart files"* or *"delete chart files older than 1 day"* anytime — invokes `list_chart_files` / `delete_chart_files`.
|
|
250
|
+
|
|
251
|
+
**Requirements:** Node.js 18+.
|
|
223
252
|
|
|
224
253
|
<details>
|
|
225
254
|
<summary><strong>Contributing</strong></summary>
|
|
@@ -242,6 +271,14 @@ If MCP Dashboards is useful to you:
|
|
|
242
271
|
[](https://buymeacoffee.com/kyuish)
|
|
243
272
|
[](https://github.com/sponsors/KyuRish)
|
|
244
273
|
|
|
274
|
+
## Privacy
|
|
275
|
+
|
|
276
|
+
All processing happens locally. No data is collected, transmitted, or stored externally.
|
|
277
|
+
|
|
278
|
+
External calls only happen when *you* explicitly ask — `render_from_url` and `poll_http` need a URL or preset you provide. Both refuse to fetch private, loopback, or link-local addresses (your `192.168.*` network, AWS metadata at `169.254.169.254`, etc.) so a prompt-injected AI can't quietly reach internal services. They also throttle per hostname so a runaway loop won't get your IP banned from a real API.
|
|
279
|
+
|
|
280
|
+
Credentials in env var presets never leave your machine. The browser preview server and the optional HTTP transport both bind to `127.0.0.1` by default and are not reachable from other devices. Chart HTML files live in your system temp folder and auto-delete after 7 days. See [Configuration](#configuration) to change any of this.
|
|
281
|
+
|
|
245
282
|
## License
|
|
246
283
|
|
|
247
284
|
[FSL-1.1-MIT](LICENSE) - Free to use for any purpose except building a competing commercial product. Each version converts to MIT two years after release. For commercial licensing, contact [contact@kyuish.com](mailto:contact@kyuish.com).
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,36 @@ async function startStreamableHTTPServer(factory) {
|
|
|
12
12
|
const express = await import("express");
|
|
13
13
|
const cors = await import("cors");
|
|
14
14
|
const app = express.default();
|
|
15
|
-
|
|
15
|
+
// CORS: default to localhost-only to prevent drive-by attacks from any
|
|
16
|
+
// webpage the user happens to visit (a malicious site could otherwise POST
|
|
17
|
+
// to http://localhost:3001/mcp and invoke our tools - save_file etc.).
|
|
18
|
+
// Override with MCP_CORS_ALLOWED_ORIGINS=https://your-host.com,... for
|
|
19
|
+
// legitimate browser-based access from non-localhost origins.
|
|
20
|
+
const defaultOrigins = [
|
|
21
|
+
`http://localhost:${port}`,
|
|
22
|
+
`http://127.0.0.1:${port}`,
|
|
23
|
+
];
|
|
24
|
+
const envOrigins = (process.env.MCP_CORS_ALLOWED_ORIGINS ?? "")
|
|
25
|
+
.split(",")
|
|
26
|
+
.map((s) => s.trim())
|
|
27
|
+
.filter(Boolean);
|
|
28
|
+
const allowedOrigins = envOrigins.length > 0 ? envOrigins : defaultOrigins;
|
|
29
|
+
if (envOrigins.includes("*")) {
|
|
30
|
+
console.warn("[mcp-dashboards] WARNING: MCP_CORS_ALLOWED_ORIGINS contains '*' - allowing any origin. This is a serious security risk; only use for trusted environments.");
|
|
31
|
+
}
|
|
32
|
+
app.use(cors.default({
|
|
33
|
+
origin: (origin, cb) => {
|
|
34
|
+
// Same-origin requests / curl / non-browser callers have no Origin header
|
|
35
|
+
if (!origin)
|
|
36
|
+
return cb(null, true);
|
|
37
|
+
if (allowedOrigins.includes("*") || allowedOrigins.includes(origin)) {
|
|
38
|
+
return cb(null, true);
|
|
39
|
+
}
|
|
40
|
+
cb(null, false);
|
|
41
|
+
},
|
|
42
|
+
credentials: false,
|
|
43
|
+
methods: ["GET", "POST", "OPTIONS"],
|
|
44
|
+
}));
|
|
16
45
|
app.use(express.default.json());
|
|
17
46
|
app.all("/mcp", async (req, res) => {
|
|
18
47
|
const server = factory();
|
|
@@ -38,8 +67,14 @@ async function startStreamableHTTPServer(factory) {
|
|
|
38
67
|
}
|
|
39
68
|
}
|
|
40
69
|
});
|
|
41
|
-
|
|
42
|
-
|
|
70
|
+
// Default-bind to 127.0.0.1 so LAN attackers can't reach port 3001 directly
|
|
71
|
+
// and bypass the CORS allowlist (cors only triggers when an Origin header is
|
|
72
|
+
// sent; a raw curl from another machine has no Origin and would otherwise
|
|
73
|
+
// be waved through). Override with MCP_HTTP_BIND_HOST=0.0.0.0 (or any
|
|
74
|
+
// interface) for trusted deployment scenarios.
|
|
75
|
+
const bindHost = process.env.MCP_HTTP_BIND_HOST || "127.0.0.1";
|
|
76
|
+
const httpServer = app.listen(port, bindHost, () => {
|
|
77
|
+
console.log(`MCP Dashboards server listening on http://${bindHost}:${port}/mcp`);
|
|
43
78
|
});
|
|
44
79
|
const shutdown = () => {
|
|
45
80
|
console.log("\nShutting down...");
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";AAEA;;;;GAIG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AAGnG,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,KAAK,UAAU,yBAAyB,CACtC,OAAwB;IAExB,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC;IAEtD,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;IAElC,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
|