@databrainhq/mcp-server 0.2.17 → 0.3.0-rc.10
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/.claude-plugin/marketplace.json +21 -0
- package/.claude-plugin/plugin.json +13 -0
- package/.mcp.json +11 -0
- package/README.md +171 -7
- package/dist/apps/server.d.ts +323 -0
- package/dist/apps/server.js +11 -0
- package/dist/apps/server.js.map +1 -0
- package/dist/apps/stdio.d.ts +2 -0
- package/dist/apps/stdio.js +16 -0
- package/dist/apps/stdio.js.map +1 -0
- package/dist/chunk-5IGP6A6T.js +496 -0
- package/dist/chunk-5IGP6A6T.js.map +1 -0
- package/dist/chunk-CUPL7CAN.js +75 -0
- package/dist/chunk-CUPL7CAN.js.map +1 -0
- package/dist/chunk-ERTAKB2H.js +11093 -0
- package/dist/chunk-ERTAKB2H.js.map +1 -0
- package/dist/chunk-N7X762VU.js +34 -0
- package/dist/chunk-N7X762VU.js.map +1 -0
- package/dist/chunk-OCBTNAAO.js +1946 -0
- package/dist/chunk-OCBTNAAO.js.map +1 -0
- package/dist/chunk-Z3ZHN4UW.js +130 -0
- package/dist/chunk-Z3ZHN4UW.js.map +1 -0
- package/dist/cli.d.ts +15 -0
- package/dist/cli.js +495 -0
- package/dist/cli.js.map +1 -0
- package/dist/custom-chart/runtime-shim.js +146 -0
- package/dist/custom-chart/template/AGENTS.md +374 -0
- package/dist/custom-chart/template/README.md +374 -0
- package/dist/custom-chart/template/chart.css +28 -0
- package/dist/custom-chart/template/chart.ts +192 -0
- package/dist/custom-chart/template/custom-chart.d.ts +78 -0
- package/dist/custom-chart/template/icon.svg +1 -0
- package/dist/custom-chart/template/manifest.json +23 -0
- package/dist/custom-chart/template/package.json +14 -0
- package/dist/custom-chart/template/sample-data.json +18 -0
- package/dist/custom-chart/template/tsconfig.json +12 -0
- package/dist/index.js +65 -9787
- package/dist/index.js.map +1 -1
- package/dist/main-KZRHWE3K.js +857 -0
- package/dist/main-KZRHWE3K.js.map +1 -0
- package/dist/test-only-K7QTSVO4.js +38 -0
- package/dist/test-only-K7QTSVO4.js.map +1 -0
- package/package.json +17 -5
- package/skills/author-dashboard/SKILL.md +30 -0
- package/skills/embed-dashboard/SKILL.md +23 -0
- package/skills/style-dashboard/SKILL.md +58 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "databrain",
|
|
3
|
+
"owner": {
|
|
4
|
+
"name": "Databrain"
|
|
5
|
+
},
|
|
6
|
+
"metadata": {
|
|
7
|
+
"description": "Agent workflows for Databrain analytics."
|
|
8
|
+
},
|
|
9
|
+
"plugins": [
|
|
10
|
+
{
|
|
11
|
+
"name": "databrain",
|
|
12
|
+
"description": "Author, style, and embed Databrain dashboards from an agent conversation, and render them as interactive tiles in chat.",
|
|
13
|
+
"version": "0.2.17",
|
|
14
|
+
"source": {
|
|
15
|
+
"source": "npm",
|
|
16
|
+
"package": "@databrainhq/mcp-server",
|
|
17
|
+
"version": "0.2.17"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "databrain",
|
|
3
|
+
"version": "0.2.17",
|
|
4
|
+
"description": "Author, style, and embed Databrain dashboards from an agent conversation, and render them as interactive tiles in chat.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Databrain",
|
|
7
|
+
"url": "https://usedatabrain.com"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://usedatabrain.com",
|
|
10
|
+
"repository": "https://github.com/databrainhq/mcp-server",
|
|
11
|
+
"license": "UNLICENSED",
|
|
12
|
+
"keywords": ["analytics", "dashboard", "databrain", "embed", "mcp-apps"]
|
|
13
|
+
}
|
package/.mcp.json
ADDED
package/README.md
CHANGED
|
@@ -13,13 +13,81 @@ Works with Codex, Claude, Cursor, Windsurf, and any MCP-compatible client.
|
|
|
13
13
|
|
|
14
14
|
## Setup (2 minutes)
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
There are two ways in. Pick one.
|
|
17
|
+
|
|
18
|
+
| | Best for | You need |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| **A. Hosted connector** | Claude, ChatGPT, Cursor, VS Code, Claude Code | Your Databrain sign-in. Nothing to install. |
|
|
21
|
+
| **B. Local server + service token** | Codex, Windsurf, any stdio client, self-hosted Databrain, CI | A service token in the MCP config |
|
|
22
|
+
|
|
23
|
+
With A you act as yourself: calls run in the workspaces you approve, with your role in each, and the audit log shows your name. With B calls run as the organization (`actor=system`).
|
|
24
|
+
|
|
25
|
+
### A. Hosted connector
|
|
26
|
+
|
|
27
|
+
Server URL: **`https://mcp.usedatabrain.com/mcp`** (beta: `https://mcp.beta.usedatabrain.com/mcp`).
|
|
28
|
+
Your AI app opens a Databrain sign-in page, you pick one or more workspaces (or "All workspaces I can access") and click Allow. No token to copy.
|
|
29
|
+
|
|
30
|
+
When you approve more than one workspace, the AI names the workspace on each call (`workspace` or `workspaceName`); `whoami` lists the ones you approved. With "All workspaces I can access", workspaces you get later are included, and `create_workspace` can make a new one if your role allows it.
|
|
31
|
+
|
|
32
|
+
The hosted connector includes chart and KPI MCP Apps. `ask_question` returns an inline tile, and `list_widgets` opens a chart chooser in compatible hosts. Both current `_meta.ui.resourceUri` and legacy `_meta['ui/resourceUri']` pointers are included; other hosts retain the text summary and structured data. Tile controls retain the answer's granted workspace. Saving requires `mcp:dashboards:write`, `mcp:query`, the live workspace role, and `APPLY_TO_PRODUCTION` confirmation. No new environment variable is needed, including on self-hosted installs.
|
|
33
|
+
|
|
34
|
+
<details>
|
|
35
|
+
<summary><b>Claude (claude.ai and Claude Desktop)</b></summary>
|
|
36
|
+
|
|
37
|
+
Settings > Connectors > **Add custom connector**. Name `Databrain`, URL `https://mcp.usedatabrain.com/mcp`. Click **Connect** and sign in. Custom connectors need a paid Claude plan.
|
|
38
|
+
</details>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><b>Claude Code</b></summary>
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
claude mcp add --transport http databrain https://mcp.usedatabrain.com/mcp
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Then run `/mcp` in Claude Code, pick `databrain` and sign in.
|
|
48
|
+
</details>
|
|
49
|
+
|
|
50
|
+
<details>
|
|
51
|
+
<summary><b>Cursor</b></summary>
|
|
52
|
+
|
|
53
|
+
[](https://cursor.com/install-mcp?name=databrain&config=eyJ1cmwiOiJodHRwczovL21jcC51c2VkYXRhYnJhaW4uY29tL21jcCJ9)
|
|
54
|
+
|
|
55
|
+
Or add to `~/.cursor/mcp.json`:
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{ "mcpServers": { "databrain": { "url": "https://mcp.usedatabrain.com/mcp" } } }
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Cursor signs you in with OAuth the first time a tool runs.
|
|
62
|
+
</details>
|
|
63
|
+
|
|
64
|
+
<details>
|
|
65
|
+
<summary><b>VS Code (GitHub Copilot agent mode)</b></summary>
|
|
66
|
+
|
|
67
|
+
[Install in VS Code](https://insiders.vscode.dev/redirect/mcp/install?name=databrain&config=%7B%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fmcp.usedatabrain.com%2Fmcp%22%7D), or:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
code --add-mcp '{"name":"databrain","type":"http","url":"https://mcp.usedatabrain.com/mcp"}'
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
VS Code asks you to sign in to Databrain when the server starts.
|
|
74
|
+
</details>
|
|
75
|
+
|
|
76
|
+
<details>
|
|
77
|
+
<summary><b>ChatGPT</b></summary>
|
|
78
|
+
|
|
79
|
+
Once Databrain is in the ChatGPT directory, search for **Databrain** and connect. Until then, a workspace admin can add it as a custom MCP connection with the URL `https://mcp.usedatabrain.com/mcp` and OAuth ([OpenAI guide](https://developers.openai.com/api/docs/guides/custom-mcp-server)).
|
|
80
|
+
</details>
|
|
81
|
+
|
|
82
|
+
### B. Local server with a service token
|
|
83
|
+
|
|
84
|
+
#### 1. Get your Service Token
|
|
17
85
|
|
|
18
86
|
1. Log in to your Databrain instance (cloud or self-hosted)
|
|
19
87
|
2. Go to **Settings → Service Tokens**
|
|
20
88
|
3. Create a new token and copy it
|
|
21
89
|
|
|
22
|
-
|
|
90
|
+
#### 2. Add to your AI client
|
|
23
91
|
|
|
24
92
|
> **Self-hosted?** Also set `DATABRAIN_API_URL` in the `env` block — see [Self-hosted Databrain](#self-hosted-databrain) below.
|
|
25
93
|
|
|
@@ -125,6 +193,25 @@ npx @databrainhq/mcp-server
|
|
|
125
193
|
```
|
|
126
194
|
</details>
|
|
127
195
|
|
|
196
|
+
### Interactive chart tiles (opt-in)
|
|
197
|
+
|
|
198
|
+
The installed package also exposes an MCP Apps entry for hosts that render inline app resources. Select it explicitly with:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
npx --yes --package @databrainhq/mcp-server databrain-mcp-chart-apps
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
In an MCP client configuration, use `npx` as the command and these arguments:
|
|
205
|
+
|
|
206
|
+
```json
|
|
207
|
+
{
|
|
208
|
+
"command": "npx",
|
|
209
|
+
"args": ["--yes", "--package", "@databrainhq/mcp-server", "databrain-mcp-chart-apps"]
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
This opt-in entry adds the chart and KPI app resources plus their read-only interaction tools. The default `databrain-mcp-server` entry remains unchanged for existing clients that do not render MCP Apps.
|
|
214
|
+
|
|
128
215
|
### Self-hosted Databrain
|
|
129
216
|
|
|
130
217
|
Running Databrain on your own infrastructure? Point the MCP server at your instance by setting `DATABRAIN_API_URL` alongside your token:
|
|
@@ -261,6 +348,27 @@ At least one of `DATABRAIN_SERVICE_TOKEN` or `DATABRAIN_API_TOKEN` must be set.
|
|
|
261
348
|
|
|
262
349
|
---
|
|
263
350
|
|
|
351
|
+
## Hosted (HTTPS) deployment
|
|
352
|
+
|
|
353
|
+
`node dist/index.js --http` starts the same server as a hosted Streamable HTTP endpoint at `/mcp`. Callers authenticate with an OAuth bearer token on every request; the server never reads `DATABRAIN_SERVICE_TOKEN` or `DATABRAIN_API_TOKEN` in this mode. Full design notes are in [`specs/hosted-http.md`](specs/hosted-http.md).
|
|
354
|
+
|
|
355
|
+
| Variable | Required | Default | Description |
|
|
356
|
+
|----------|----------|---------|-------------|
|
|
357
|
+
| `DATABRAIN_HOSTED_PUBLIC_URL` | Yes | — | Exact public HTTPS URL of the endpoint, ending in `/mcp` (e.g. `https://mcp.usedatabrain.com/mcp`). Used for discovery metadata and audience checks. |
|
|
358
|
+
| `DATABRAIN_HOSTED_ISSUER` | Yes | — | HTTPS origin of the trusted authorization server. Bearer tokens are verified against `<issuer>/oauth/principal`. |
|
|
359
|
+
| `DATABRAIN_HOSTED_BIND` | No | `127.0.0.1` | Listener address. Set `0.0.0.0` in a container so the load balancer can reach it. |
|
|
360
|
+
| `DATABRAIN_HOSTED_PORT` | No | `3144` | Listener port. |
|
|
361
|
+
|
|
362
|
+
`GET /health` (or `HEAD`) returns `200 {"status":"ok"}` with no authentication. It is the only route that skips the Host check, so an ALB health check with the target IP:port as Host succeeds. Point the target group health check at `/health`.
|
|
363
|
+
|
|
364
|
+
The `Dockerfile` at the repo root builds the hosted server from source: `docker build -t databrain-mcp-hosted .` then run it with the two required variables and `-p 3144:3144`.
|
|
365
|
+
|
|
366
|
+
The load balancer **must forward the original `Host` header unchanged**. Requests to `/mcp` and the `/.well-known/oauth-protected-resource` metadata are answered only when Host matches the host of `DATABRAIN_HOSTED_PUBLIC_URL`; anything else gets `403 invalid_host`.
|
|
367
|
+
|
|
368
|
+
**Current limits.** Without `DATABRAIN_HOSTED_ADAPTER_MODULE` (an absolute path to a trusted delegated adapter, see the spec), the default adapter verifies identity only. `whoami`, tool/resource/prompt discovery and OAuth verification work today; every data tool answers `503 delegated_backend_adapter_required` until that adapter is configured.
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
264
372
|
## Available Prompts
|
|
265
373
|
|
|
266
374
|
Prompts are guided workflows your AI assistant can follow. Ask for them by name or describe what you want.
|
|
@@ -279,9 +387,9 @@ Prompts are guided workflows your AI assistant can follow. Ask for them by name
|
|
|
279
387
|
|
|
280
388
|
## Tools Reference
|
|
281
389
|
|
|
282
|
-
|
|
390
|
+
50 tools organized by category (plus 6 chart App tools on the hosted connector and the opt-in `databrain-mcp-chart-apps` entry, and `create_workspace` on the hosted connector: 57 hosted tools total). Your AI assistant picks the right tools automatically. You do not need to call them directly.
|
|
283
391
|
|
|
284
|
-
> **Note:** Datasource
|
|
392
|
+
> **Note:** Datasource creation happens outside MCP. Workspace creation does too, except on the hosted connector: `create_workspace` works there when you granted "All workspaces I can access" and your role may create workspaces. Datamarts can be planned with `create_datamart` in `dry_run` mode and created only with `confirm: "APPLY_TO_PRODUCTION"`. The semantic layer is managed via MCP tools (`get_semantic_layer`, `update_semantic_layer`, `start_semantic_layer_generation`, `get_semantic_layer_generation_status`).
|
|
285
393
|
|
|
286
394
|
<details>
|
|
287
395
|
<summary><b>Infrastructure — Exploration and setup</b> (6)</summary>
|
|
@@ -291,7 +399,8 @@ Prompts are guided workflows your AI assistant can follow. Ask for them by name
|
|
|
291
399
|
| `list_datasources` | List connected datasources |
|
|
292
400
|
| `discover_datasource_schema` | Inspect a datasource to see available tables and columns |
|
|
293
401
|
| `list_datamarts` | List datamarts |
|
|
294
|
-
| `list_workspaces` | List all workspaces (shows datamart/datasource connections) |
|
|
402
|
+
| `list_workspaces` | List all workspaces (shows datamart/datasource connections). Hosted: only the workspaces you granted |
|
|
403
|
+
| `create_workspace` | Hosted connector only: create a workspace (needs an "All workspaces" grant and a role that may create one) |
|
|
295
404
|
| `sync_datasource` | Trigger datasource schema sync |
|
|
296
405
|
| `create_datamart` | Dry-run or create a datamart from selected tables and relationships |
|
|
297
406
|
</details>
|
|
@@ -332,7 +441,7 @@ Prompts are guided workflows your AI assistant can follow. Ask for them by name
|
|
|
332
441
|
</details>
|
|
333
442
|
|
|
334
443
|
<details>
|
|
335
|
-
<summary><b>Query & Semantic Layer</b> (
|
|
444
|
+
<summary><b>Query & Semantic Layer</b> (11): Ask questions and manage data documentation</summary>
|
|
336
445
|
|
|
337
446
|
| Tool | Description |
|
|
338
447
|
|------|-------------|
|
|
@@ -341,14 +450,37 @@ Prompts are guided workflows your AI assistant can follow. Ask for them by name
|
|
|
341
450
|
| `update_semantic_layer` | Improve semantic layer quality (add descriptions, synonyms, example questions) |
|
|
342
451
|
| `start_semantic_layer_generation` | Start semantic-layer generation for a datamart |
|
|
343
452
|
| `get_semantic_layer_generation_status` | Check semantic-layer generation progress |
|
|
453
|
+
| `search_semantic_model` | Find relevant v2 entities and their related entities |
|
|
454
|
+
| `get_semantic_entity` | Read one v2 entity by kind and name with the current content hash |
|
|
455
|
+
| `propose_semantic_change` | Validate candidate YAML or a patch and return its plan without writing |
|
|
456
|
+
| `apply_semantic_change` | Preview by default, or apply live with a reviewed hash and production confirmation |
|
|
457
|
+
| `eval_semantic_model` | Run saved queries and optional questions and return pass rate and verdicts |
|
|
458
|
+
|
|
459
|
+
Semantic-layer generation uses the datamart ID returned by `list_datamarts` and calls the service-token API. Pass `datamartId` directly when the ID is already known.
|
|
460
|
+
|
|
461
|
+
For a v2 model, the five model tools use `datamartId` and the configured service credential. They never request a token from the user or mint a guest token. Hosted eval also requires `mcp:query`; hosted apply requires `mcp:datamarts:write` even for its dry run.
|
|
462
|
+
|
|
463
|
+
1. Use `search_semantic_model` with `question` and optional `k` (default 10, maximum 100). If the server has no retrieval route, the tool pulls the model and ranks name, alias, synonyms and description, then includes adjacent entities. Hidden tables and columns are excluded from local search.
|
|
464
|
+
2. Use `get_semantic_entity` with `kind` and an exact `name`. Column names use `table.column`. Kinds are `table`, `column`, `measure`, `metric`, `join`, `entity`, `glossary`, `saved_query`, `instruction` and `access_rule`.
|
|
465
|
+
3. Use `propose_semantic_change` with exactly one of `source` (complete YAML), `yaml_patch`, or `change`. It returns the candidate source, validation errors, the server plan and `expected_content_hash`. Invalid source returns errors and no plan.
|
|
466
|
+
4. Use `eval_semantic_model` with the proposed `source` and optional `questions`. Omitting source evaluates the stored model. The server returns pass rate and individual verdicts.
|
|
467
|
+
5. Review the plan. Call `apply_semantic_change` with the exact returned `source` and `expected_content_hash`. Its `dry_run` defaults to true. A live apply requires `dry_run: false` and user supplied `confirm: "APPLY_TO_PRODUCTION"`. The assistant must never supply confirmation on its own. Explicit `expected_content_hash: null` selects the first apply only when no layer is stored. Apply changes the live model for all consumers.
|
|
468
|
+
|
|
469
|
+
A YAML patch merges mappings and named lists by name, including tables and columns. Other lists replace the original list. An empty list clears a list. Null removes a field. For example, `yaml_patch: "tables:\n - name: orders\n description: Customer purchases\n"` changes that description and preserves other tables and fields. Patch output normalizes YAML formatting and does not preserve comments. Review the returned source.
|
|
470
|
+
|
|
471
|
+
A structured change uses `{ "operation": "upsert", "kind": "column", "table": "orders", "name": "amount", "value": { "description": "Order total" } }`. Upsert merges fields. Use `operation: "remove"` without `value` to remove one named entity. The backend validates all resulting references.
|
|
472
|
+
|
|
473
|
+
HTTP 409 conflicts and 422 validation or projection refusals return tool errors with the backend reason and details. A conflict requires a fresh proposal and review. Plan, eval and readiness need the corresponding backend routes; these tools return backend errors if those routes are absent.
|
|
474
|
+
|
|
344
475
|
</details>
|
|
345
476
|
|
|
346
477
|
<details>
|
|
347
|
-
<summary><b>Dashboards & Widgets</b> (
|
|
478
|
+
<summary><b>Dashboards & Widgets</b> (9) — Discover dashboards, picture them, and CRUD widgets on customer embeds</summary>
|
|
348
479
|
|
|
349
480
|
| Tool | Description |
|
|
350
481
|
|------|-------------|
|
|
351
482
|
| `list_dashboards` | List dashboards (by data app, workspace, or globally) |
|
|
483
|
+
| `dashboard_snapshot` | A PNG of a dashboard or one chart, light or dark, as the signed-in user sees it. Needs a Databrain sign-in (OAuth), not a service token |
|
|
352
484
|
| `list_widgets` | List widgets on an embed for a specific client |
|
|
353
485
|
| `validate_metric_spec` | Validate a SQL-backed metric target without saving |
|
|
354
486
|
| `create_or_update_metric_from_query` | Dry-run or apply a SQL-backed metric create/update |
|
|
@@ -369,6 +501,38 @@ Production writes through `create_or_update_metric_from_query` default to `dry_r
|
|
|
369
501
|
| `list_scheduled_reports` | List configured scheduled reports for a dashboard/client scope |
|
|
370
502
|
</details>
|
|
371
503
|
|
|
504
|
+
<details>
|
|
505
|
+
<summary><b>Custom chart types</b> (5)</summary>
|
|
506
|
+
|
|
507
|
+
| Tool | Description |
|
|
508
|
+
|------|-------------|
|
|
509
|
+
| `custom_chart_scaffold` | Return the files of a new chart project (manifest, chart.ts, css, icon, sample data, author guide). Nothing is written or persisted |
|
|
510
|
+
| `custom_chart_validate` | Validate a manifest and bundle with the local rules and, when a service token is configured, the server rules. Never persists |
|
|
511
|
+
| `custom_chart_upload` | Dry-run or upload a built bundle as a private chart (version 1) or a preview version; `publish: true` publishes in the same apply |
|
|
512
|
+
| `list_custom_charts` | List the company's custom chart types with status and version ids |
|
|
513
|
+
| `publish_custom_chart` | Dry-run or publish a version so every builder can use chart type `custom:<key>` |
|
|
514
|
+
|
|
515
|
+
`custom_chart_upload` and `publish_custom_chart` default to `dry_run` and apply only with `confirm: "APPLY_TO_PRODUCTION"`. Hosted scopes: `mcp:custom-charts:read` and `mcp:custom-charts:write`. Build the bundle with the CLI below.
|
|
516
|
+
</details>
|
|
517
|
+
|
|
518
|
+
---
|
|
519
|
+
|
|
520
|
+
## Custom chart CLI
|
|
521
|
+
|
|
522
|
+
The package also installs a `databrain` binary for chart authors:
|
|
523
|
+
|
|
524
|
+
```bash
|
|
525
|
+
npx -p @databrainhq/mcp-server databrain custom-chart init my-chart
|
|
526
|
+
cd my-chart # read AGENTS.md, edit chart.ts
|
|
527
|
+
databrain custom-chart validate # manifest, icon, css
|
|
528
|
+
databrain custom-chart build # writes dist/index.js, manifest.json, icon.svg, index.css, bundle.zip
|
|
529
|
+
databrain custom-chart dev # local sandbox page on http://127.0.0.1:4174
|
|
530
|
+
DATABRAIN_SERVICE_TOKEN=... databrain custom-chart upload # build, server validate, plan, confirm, upload
|
|
531
|
+
DATABRAIN_SERVICE_TOKEN=... databrain custom-chart upload --publish --yes
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
Problems print as `path code message` and the exit code is 1 when there is any. `upload` needs `DATABRAIN_SERVICE_TOKEN` and, on self-hosted instances, `DATABRAIN_API_URL`. The template's `AGENTS.md` is the full author guide: manifest reference, data shape, theme, interactions, troubleshooting.
|
|
535
|
+
|
|
372
536
|
---
|
|
373
537
|
|
|
374
538
|
## Built-in Knowledge
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
declare const configSchema: z.ZodEffects<z.ZodEffects<z.ZodObject<{
|
|
5
|
+
serviceToken: z.ZodOptional<z.ZodString>;
|
|
6
|
+
apiToken: z.ZodOptional<z.ZodString>;
|
|
7
|
+
oauth: z.ZodOptional<z.ZodObject<{
|
|
8
|
+
issuer: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
|
|
9
|
+
clientId: z.ZodString;
|
|
10
|
+
clientSecret: z.ZodString;
|
|
11
|
+
resource: z.ZodEffects<z.ZodString, string, string>;
|
|
12
|
+
scope: z.ZodOptional<z.ZodString>;
|
|
13
|
+
authMethod: z.ZodDefault<z.ZodEnum<["client_secret_basic", "client_secret_post"]>>;
|
|
14
|
+
}, "strip", z.ZodTypeAny, {
|
|
15
|
+
issuer: string;
|
|
16
|
+
clientId: string;
|
|
17
|
+
clientSecret: string;
|
|
18
|
+
resource: string;
|
|
19
|
+
authMethod: "client_secret_basic" | "client_secret_post";
|
|
20
|
+
scope?: string | undefined;
|
|
21
|
+
}, {
|
|
22
|
+
issuer: string;
|
|
23
|
+
clientId: string;
|
|
24
|
+
clientSecret: string;
|
|
25
|
+
resource: string;
|
|
26
|
+
scope?: string | undefined;
|
|
27
|
+
authMethod?: "client_secret_basic" | "client_secret_post" | undefined;
|
|
28
|
+
}>>;
|
|
29
|
+
apiUrl: z.ZodDefault<z.ZodString>;
|
|
30
|
+
demoDomain: z.ZodDefault<z.ZodString>;
|
|
31
|
+
posthogApiKey: z.ZodOptional<z.ZodString>;
|
|
32
|
+
posthogHost: z.ZodOptional<z.ZodString>;
|
|
33
|
+
}, "strip", z.ZodTypeAny, {
|
|
34
|
+
apiUrl: string;
|
|
35
|
+
demoDomain: string;
|
|
36
|
+
serviceToken?: string | undefined;
|
|
37
|
+
apiToken?: string | undefined;
|
|
38
|
+
oauth?: {
|
|
39
|
+
issuer: string;
|
|
40
|
+
clientId: string;
|
|
41
|
+
clientSecret: string;
|
|
42
|
+
resource: string;
|
|
43
|
+
authMethod: "client_secret_basic" | "client_secret_post";
|
|
44
|
+
scope?: string | undefined;
|
|
45
|
+
} | undefined;
|
|
46
|
+
posthogApiKey?: string | undefined;
|
|
47
|
+
posthogHost?: string | undefined;
|
|
48
|
+
}, {
|
|
49
|
+
serviceToken?: string | undefined;
|
|
50
|
+
apiToken?: string | undefined;
|
|
51
|
+
oauth?: {
|
|
52
|
+
issuer: string;
|
|
53
|
+
clientId: string;
|
|
54
|
+
clientSecret: string;
|
|
55
|
+
resource: string;
|
|
56
|
+
scope?: string | undefined;
|
|
57
|
+
authMethod?: "client_secret_basic" | "client_secret_post" | undefined;
|
|
58
|
+
} | undefined;
|
|
59
|
+
apiUrl?: string | undefined;
|
|
60
|
+
demoDomain?: string | undefined;
|
|
61
|
+
posthogApiKey?: string | undefined;
|
|
62
|
+
posthogHost?: string | undefined;
|
|
63
|
+
}>, {
|
|
64
|
+
apiUrl: string;
|
|
65
|
+
demoDomain: string;
|
|
66
|
+
serviceToken?: string | undefined;
|
|
67
|
+
apiToken?: string | undefined;
|
|
68
|
+
oauth?: {
|
|
69
|
+
issuer: string;
|
|
70
|
+
clientId: string;
|
|
71
|
+
clientSecret: string;
|
|
72
|
+
resource: string;
|
|
73
|
+
authMethod: "client_secret_basic" | "client_secret_post";
|
|
74
|
+
scope?: string | undefined;
|
|
75
|
+
} | undefined;
|
|
76
|
+
posthogApiKey?: string | undefined;
|
|
77
|
+
posthogHost?: string | undefined;
|
|
78
|
+
}, {
|
|
79
|
+
serviceToken?: string | undefined;
|
|
80
|
+
apiToken?: string | undefined;
|
|
81
|
+
oauth?: {
|
|
82
|
+
issuer: string;
|
|
83
|
+
clientId: string;
|
|
84
|
+
clientSecret: string;
|
|
85
|
+
resource: string;
|
|
86
|
+
scope?: string | undefined;
|
|
87
|
+
authMethod?: "client_secret_basic" | "client_secret_post" | undefined;
|
|
88
|
+
} | undefined;
|
|
89
|
+
apiUrl?: string | undefined;
|
|
90
|
+
demoDomain?: string | undefined;
|
|
91
|
+
posthogApiKey?: string | undefined;
|
|
92
|
+
posthogHost?: string | undefined;
|
|
93
|
+
}>, {
|
|
94
|
+
apiUrl: string;
|
|
95
|
+
demoDomain: string;
|
|
96
|
+
serviceToken?: string | undefined;
|
|
97
|
+
apiToken?: string | undefined;
|
|
98
|
+
oauth?: {
|
|
99
|
+
issuer: string;
|
|
100
|
+
clientId: string;
|
|
101
|
+
clientSecret: string;
|
|
102
|
+
resource: string;
|
|
103
|
+
authMethod: "client_secret_basic" | "client_secret_post";
|
|
104
|
+
scope?: string | undefined;
|
|
105
|
+
} | undefined;
|
|
106
|
+
posthogApiKey?: string | undefined;
|
|
107
|
+
posthogHost?: string | undefined;
|
|
108
|
+
}, {
|
|
109
|
+
serviceToken?: string | undefined;
|
|
110
|
+
apiToken?: string | undefined;
|
|
111
|
+
oauth?: {
|
|
112
|
+
issuer: string;
|
|
113
|
+
clientId: string;
|
|
114
|
+
clientSecret: string;
|
|
115
|
+
resource: string;
|
|
116
|
+
scope?: string | undefined;
|
|
117
|
+
authMethod?: "client_secret_basic" | "client_secret_post" | undefined;
|
|
118
|
+
} | undefined;
|
|
119
|
+
apiUrl?: string | undefined;
|
|
120
|
+
demoDomain?: string | undefined;
|
|
121
|
+
posthogApiKey?: string | undefined;
|
|
122
|
+
posthogHost?: string | undefined;
|
|
123
|
+
}>;
|
|
124
|
+
type Config = z.infer<typeof configSchema>;
|
|
125
|
+
|
|
126
|
+
declare const referenceSchema: z.ZodObject<{
|
|
127
|
+
embedId: z.ZodString;
|
|
128
|
+
clientId: z.ZodString;
|
|
129
|
+
widgetId: z.ZodString;
|
|
130
|
+
}, "strict", z.ZodTypeAny, {
|
|
131
|
+
clientId: string;
|
|
132
|
+
embedId: string;
|
|
133
|
+
widgetId: string;
|
|
134
|
+
}, {
|
|
135
|
+
clientId: string;
|
|
136
|
+
embedId: string;
|
|
137
|
+
widgetId: string;
|
|
138
|
+
}>;
|
|
139
|
+
type ChartReference = z.infer<typeof referenceSchema>;
|
|
140
|
+
declare const viewSchema: z.ZodObject<{
|
|
141
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
142
|
+
dateRange: z.ZodOptional<z.ZodEffects<z.ZodObject<{
|
|
143
|
+
from: z.ZodString;
|
|
144
|
+
to: z.ZodString;
|
|
145
|
+
}, "strict", z.ZodTypeAny, {
|
|
146
|
+
from: string;
|
|
147
|
+
to: string;
|
|
148
|
+
}, {
|
|
149
|
+
from: string;
|
|
150
|
+
to: string;
|
|
151
|
+
}>, {
|
|
152
|
+
from: string;
|
|
153
|
+
to: string;
|
|
154
|
+
}, {
|
|
155
|
+
from: string;
|
|
156
|
+
to: string;
|
|
157
|
+
}>>;
|
|
158
|
+
drillId: z.ZodOptional<z.ZodString>;
|
|
159
|
+
}, "strict", z.ZodTypeAny, {
|
|
160
|
+
cursor?: string | undefined;
|
|
161
|
+
drillId?: string | undefined;
|
|
162
|
+
dateRange?: {
|
|
163
|
+
from: string;
|
|
164
|
+
to: string;
|
|
165
|
+
} | undefined;
|
|
166
|
+
}, {
|
|
167
|
+
cursor?: string | undefined;
|
|
168
|
+
drillId?: string | undefined;
|
|
169
|
+
dateRange?: {
|
|
170
|
+
from: string;
|
|
171
|
+
to: string;
|
|
172
|
+
} | undefined;
|
|
173
|
+
}>;
|
|
174
|
+
declare const pageSchema: z.ZodEffects<z.ZodObject<{
|
|
175
|
+
kind: z.ZodEnum<["chart", "kpi"]>;
|
|
176
|
+
title: z.ZodString;
|
|
177
|
+
chartSpec: z.ZodObject<{
|
|
178
|
+
type: z.ZodString;
|
|
179
|
+
}, "strict", z.ZodTypeAny, {
|
|
180
|
+
type: string;
|
|
181
|
+
}, {
|
|
182
|
+
type: string;
|
|
183
|
+
}>;
|
|
184
|
+
rows: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>, "many">;
|
|
185
|
+
columns: z.ZodArray<z.ZodString, "many">;
|
|
186
|
+
svg: z.ZodOptional<z.ZodString>;
|
|
187
|
+
width: z.ZodNumber;
|
|
188
|
+
height: z.ZodNumber;
|
|
189
|
+
points: z.ZodArray<z.ZodObject<{
|
|
190
|
+
key: z.ZodString;
|
|
191
|
+
label: z.ZodString;
|
|
192
|
+
value: z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>;
|
|
193
|
+
x: z.ZodNumber;
|
|
194
|
+
y: z.ZodNumber;
|
|
195
|
+
width: z.ZodNumber;
|
|
196
|
+
height: z.ZodNumber;
|
|
197
|
+
drillId: z.ZodOptional<z.ZodString>;
|
|
198
|
+
}, "strict", z.ZodTypeAny, {
|
|
199
|
+
value: string | number | boolean | null;
|
|
200
|
+
key: string;
|
|
201
|
+
label: string;
|
|
202
|
+
x: number;
|
|
203
|
+
y: number;
|
|
204
|
+
width: number;
|
|
205
|
+
height: number;
|
|
206
|
+
drillId?: string | undefined;
|
|
207
|
+
}, {
|
|
208
|
+
value: string | number | boolean | null;
|
|
209
|
+
key: string;
|
|
210
|
+
label: string;
|
|
211
|
+
x: number;
|
|
212
|
+
y: number;
|
|
213
|
+
width: number;
|
|
214
|
+
height: number;
|
|
215
|
+
drillId?: string | undefined;
|
|
216
|
+
}>, "many">;
|
|
217
|
+
value: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>;
|
|
218
|
+
nextCursor: z.ZodOptional<z.ZodString>;
|
|
219
|
+
}, "strict", z.ZodTypeAny, {
|
|
220
|
+
kind: "chart" | "kpi";
|
|
221
|
+
title: string;
|
|
222
|
+
columns: string[];
|
|
223
|
+
width: number;
|
|
224
|
+
height: number;
|
|
225
|
+
chartSpec: {
|
|
226
|
+
type: string;
|
|
227
|
+
};
|
|
228
|
+
rows: Record<string, string | number | boolean | null>[];
|
|
229
|
+
points: {
|
|
230
|
+
value: string | number | boolean | null;
|
|
231
|
+
key: string;
|
|
232
|
+
label: string;
|
|
233
|
+
x: number;
|
|
234
|
+
y: number;
|
|
235
|
+
width: number;
|
|
236
|
+
height: number;
|
|
237
|
+
drillId?: string | undefined;
|
|
238
|
+
}[];
|
|
239
|
+
value?: string | number | boolean | null | undefined;
|
|
240
|
+
svg?: string | undefined;
|
|
241
|
+
nextCursor?: string | undefined;
|
|
242
|
+
}, {
|
|
243
|
+
kind: "chart" | "kpi";
|
|
244
|
+
title: string;
|
|
245
|
+
columns: string[];
|
|
246
|
+
width: number;
|
|
247
|
+
height: number;
|
|
248
|
+
chartSpec: {
|
|
249
|
+
type: string;
|
|
250
|
+
};
|
|
251
|
+
rows: Record<string, string | number | boolean | null>[];
|
|
252
|
+
points: {
|
|
253
|
+
value: string | number | boolean | null;
|
|
254
|
+
key: string;
|
|
255
|
+
label: string;
|
|
256
|
+
x: number;
|
|
257
|
+
y: number;
|
|
258
|
+
width: number;
|
|
259
|
+
height: number;
|
|
260
|
+
drillId?: string | undefined;
|
|
261
|
+
}[];
|
|
262
|
+
value?: string | number | boolean | null | undefined;
|
|
263
|
+
svg?: string | undefined;
|
|
264
|
+
nextCursor?: string | undefined;
|
|
265
|
+
}>, {
|
|
266
|
+
kind: "chart" | "kpi";
|
|
267
|
+
title: string;
|
|
268
|
+
columns: string[];
|
|
269
|
+
width: number;
|
|
270
|
+
height: number;
|
|
271
|
+
chartSpec: {
|
|
272
|
+
type: string;
|
|
273
|
+
};
|
|
274
|
+
rows: Record<string, string | number | boolean | null>[];
|
|
275
|
+
points: {
|
|
276
|
+
value: string | number | boolean | null;
|
|
277
|
+
key: string;
|
|
278
|
+
label: string;
|
|
279
|
+
x: number;
|
|
280
|
+
y: number;
|
|
281
|
+
width: number;
|
|
282
|
+
height: number;
|
|
283
|
+
drillId?: string | undefined;
|
|
284
|
+
}[];
|
|
285
|
+
value?: string | number | boolean | null | undefined;
|
|
286
|
+
svg?: string | undefined;
|
|
287
|
+
nextCursor?: string | undefined;
|
|
288
|
+
}, {
|
|
289
|
+
kind: "chart" | "kpi";
|
|
290
|
+
title: string;
|
|
291
|
+
columns: string[];
|
|
292
|
+
width: number;
|
|
293
|
+
height: number;
|
|
294
|
+
chartSpec: {
|
|
295
|
+
type: string;
|
|
296
|
+
};
|
|
297
|
+
rows: Record<string, string | number | boolean | null>[];
|
|
298
|
+
points: {
|
|
299
|
+
value: string | number | boolean | null;
|
|
300
|
+
key: string;
|
|
301
|
+
label: string;
|
|
302
|
+
x: number;
|
|
303
|
+
y: number;
|
|
304
|
+
width: number;
|
|
305
|
+
height: number;
|
|
306
|
+
drillId?: string | undefined;
|
|
307
|
+
}[];
|
|
308
|
+
value?: string | number | boolean | null | undefined;
|
|
309
|
+
svg?: string | undefined;
|
|
310
|
+
nextCursor?: string | undefined;
|
|
311
|
+
}>;
|
|
312
|
+
type ChartPage = z.infer<typeof pageSchema>;
|
|
313
|
+
type ChartView = z.infer<typeof viewSchema>;
|
|
314
|
+
|
|
315
|
+
type ChartAction = 'render_chart' | 'refresh_widget' | 'drill_down' | 'change_date_range';
|
|
316
|
+
interface ChartBackend {
|
|
317
|
+
execute(action: ChartAction, reference: ChartReference, view: ChartView): Promise<ChartPage>;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/** Reviewable composition seam; hosted owners must retain their principal-bound client/policy. */
|
|
321
|
+
declare function createChartAppServer(config: Config, backend?: ChartBackend): McpServer;
|
|
322
|
+
|
|
323
|
+
export { createChartAppServer };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
createChartAppServer
|
|
4
|
+
} from "../chunk-N7X762VU.js";
|
|
5
|
+
import "../chunk-5IGP6A6T.js";
|
|
6
|
+
import "../chunk-ERTAKB2H.js";
|
|
7
|
+
import "../chunk-OCBTNAAO.js";
|
|
8
|
+
export {
|
|
9
|
+
createChartAppServer
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
loadConfig
|
|
4
|
+
} from "../chunk-CUPL7CAN.js";
|
|
5
|
+
import {
|
|
6
|
+
createChartAppServer
|
|
7
|
+
} from "../chunk-N7X762VU.js";
|
|
8
|
+
import "../chunk-5IGP6A6T.js";
|
|
9
|
+
import "../chunk-ERTAKB2H.js";
|
|
10
|
+
import "../chunk-OCBTNAAO.js";
|
|
11
|
+
|
|
12
|
+
// src/apps/stdio.ts
|
|
13
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
14
|
+
var server = createChartAppServer(loadConfig());
|
|
15
|
+
await server.connect(new StdioServerTransport());
|
|
16
|
+
//# sourceMappingURL=stdio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/apps/stdio.ts"],"sourcesContent":["import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { loadConfig } from '../utils/config.js';\nimport { createChartAppServer } from './server.js';\n\n// Separate opt-in command until the owners integrate both shared entrypoints.\nconst server = createChartAppServer(loadConfig());\nawait server.connect(new StdioServerTransport());\n"],"mappings":";;;;;;;;;;;;AAAA,SAAS,4BAA4B;AAKrC,IAAM,SAAS,qBAAqB,WAAW,CAAC;AAChD,MAAM,OAAO,QAAQ,IAAI,qBAAqB,CAAC;","names":[]}
|