mcp-dashboards 2.1.0 → 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 CHANGED
@@ -26,7 +26,7 @@ We use AI for everything - analysis, reports, strategy. But when it comes to act
26
26
 
27
27
  ## The solution
28
28
 
29
- MCP Dashboards renders interactive charts, dashboards, and KPI widgets directly inside your AI conversation. 31 tools covering 44+ chart subtypes (bar has stacked/drilldown, hero has 11 variants, etc.), 21 themes, live polling, PNG/PPT/A4 export - all from a single MCP server. No browser tabs, no copy-paste, no context switching.
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.
30
30
 
31
31
  ## Quick Start
32
32
 
@@ -58,9 +58,11 @@ claude mcp add dashboard -- npx -y mcp-dashboards --stdio
58
58
 
59
59
  ```bash
60
60
  npx mcp-dashboards
61
- # Server starts on http://localhost:3001/mcp
61
+ # Server starts on http://127.0.0.1:3001/mcp
62
62
  ```
63
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
+
64
66
  ### Supported clients
65
67
 
66
68
  Works in any MCP Apps-compatible client: **Claude Desktop**, **Claude Web**, **VS Code** (GitHub Copilot), **Goose**, **Postman**, **MCPJam**. ChatGPT support is rolling out.
@@ -79,6 +81,8 @@ No API to learn. Describe what you want in plain English:
79
81
 
80
82
  The AI picks the right tool, formats your data, and renders the chart inline. Click any data point to ask follow-up questions.
81
83
 
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.
85
+
82
86
  ## Interactive charts, not images
83
87
 
84
88
  Every chart is **interactive HTML** rendered directly in your conversation:
@@ -88,7 +92,7 @@ Every chart is **interactive HTML** rendered directly in your conversation:
88
92
  - **Export anywhere** - PPT (16:9 slides), A4 (paginated with smart page breaks), PNG, CSV
89
93
 
90
94
  <details>
91
- <summary><strong>All 31 Tools</strong></summary>
95
+ <summary><strong>All Tools</strong></summary>
92
96
 
93
97
  | Tool | Type | Best For |
94
98
  |------|------|----------|
@@ -124,6 +128,18 @@ Every chart is **interactive HTML** rendered directly in your conversation:
124
128
  | `render_from_json` | Auto-detect | Any JSON data - picks the best chart automatically |
125
129
  | `render_from_url` | URL fetch | Fetches JSON from a URL and auto-visualizes |
126
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
+
127
143
  </details>
128
144
 
129
145
  <details>
@@ -204,13 +220,33 @@ Built on [MCP Apps](https://modelcontextprotocol.io/docs/extensions/apps). You a
204
220
 
205
221
  **MCP Apps supported** (inline rendering): Claude Desktop, VS Code Insiders + MCP Apps extension, Goose, Postman.
206
222
 
207
- **No MCP Apps support?** No problem. When the server detects your client can't render inline, every chart response includes:
208
- - A clickable `http://localhost:XXXX/chart/{id}` link - opens the full interactive dashboard in your default browser
209
- - A standalone HTML file (`file:///...chart-{id}.html`) - self-contained, works offline, can be emailed or archived
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.
210
228
 
211
- Works in Claude Code, Cursor, older VS Code, and any other MCP client. Tool annotations (`readOnlyHint`, `idempotentHint`, `openWorldHint`) help clients reason about tool behavior.
229
+ ## Configuration
212
230
 
213
- **Opt-out**: set env var `MCP_DASHBOARDS_DISABLE_PREVIEW=1` to skip the preview links entirely.
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`.
214
250
 
215
251
  **Requirements:** Node.js 18+.
216
252
 
@@ -237,7 +273,11 @@ If MCP Dashboards is useful to you:
237
273
 
238
274
  ## Privacy
239
275
 
240
- All processing happens locally. No data is collected, transmitted, or stored. External network calls are `render_from_url` and `poll_http` - both require you to explicitly provide the URL. Credentials in env var presets never leave your machine. The browser preview server binds only to `127.0.0.1` (localhost) and is not reachable from other devices.
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.
241
281
 
242
282
  ## License
243
283
 
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
- app.use(cors.default());
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
- const httpServer = app.listen(port, () => {
42
- console.log(`MCP Dashboards server listening on http://localhost:${port}/mcp`);
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":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}