@barivia/barsom-mcp
v0.21.0
Published
barSOM MCP proxy — connect any MCP client to the barSOM cloud API for Self-Organizing Map analytics
Maintainers
Readme
@barivia/barsom-mcp
MCP proxy for the Barivia Analytics Engine — connects any stdio MCP client (Cursor, Claude Desktop, etc.) to the barSOM cloud API. The npm package is @barivia/barsom-mcp; many configs label the server analytics-engine (the MCP server name in the client JSON). guide_barsom_workflow is the canonical bootstrap: it loads plan-scoped workflow text from the Barivia API when online (tool map, async rules, training modes, SOP). If the API is unreachable, it returns a short offline stub. Core tools are datasets, train (map, siom_map, impute, floop_siom where entitled), jobs (status/list/compare/cancel/delete — lifecycle only), results (get/export/download/recolor), and inference (predict/batch_predict/impute_column/compare/project_columns/transition_flow/report). Optional MCP App tools (training_monitor, results_explorer) add embedded or localhost viz; they are not required to complete upload → train → poll → results, though results_explorer is the preferred way to browse figures.
Pre-training help (pick one): prepare_training prompt = narrative checklist (tier-scoped from the API when online); training_guidance tool = structured presets and parameter hints (including the resolved per-column normalization). Review either, then submit with train.
Installation
Published on the public npm registry as @barivia/barsom-mcp. No GitHub token or scoped .npmrc is required for installs.
MCP clients typically run it with npx (downloads on first use):
{
"mcpServers": {
"analytics-engine": {
"command": "npx",
"args": ["-y", "@barivia/barsom-mcp"],
"env": {
"BARIVIA_API_KEY": "bv_your_key",
"BARIVIA_API_URL": "https://api.barivia.se"
}
}
}
}Verify: npm view @barivia/barsom-mcp version
Audit logging (0.10.3+): Each tool invocation emits a structured mcp_tool_call line on stderr for support correlation — not sent to the Barivia API. Fields: tool, action, duration_ms, outcome, rid (matches API X-Request-ID), job_id / dataset_id when the action returns or accepts them, scale hints grid_x / grid_y on training submits, and timeout_hit / output_truncated when proxy fetch/output limits apply. No API keys or file paths. Grep client stderr alongside API/worker logs by rid; see docs/OPERATIONS_MANUAL.md §5b.
Hosted HTTP MCP paused (2026-06): https://mcp.barivia.se/mcp returns 503 (hosted_mcp_paused). Use this npm package only.
Cursor / multi-account note: Cursor's tool dispatcher resolves tools under a serverIdentifier (e.g. user-barivia-bbb-maps), which can differ from the key you wrote in mcp.json (e.g. barivia-bbb-maps). If a tool call fails with "server does not exist" or similar, list the resolved identifier with your client's tool inspector (mcp.list-tools or equivalent) and use that identifier — not the mcp.json key.
Future: A private npm org scoped package is an option later (paid npm teams/orgs; users authenticate with npm, usually simpler than GitHub Packages for pure npm consumers).
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
| BARIVIA_API_KEY | Yes | -- | API key (starts with bv_) |
| BARIVIA_API_URL | No | https://api.barivia.se | API base URL |
| BARIVIA_WORKSPACE_ROOT | No | process.cwd() or PWD | Directory for relative file_path and save_to_disk. In Cursor MCP, process.cwd() is often the MCP install dir — add BARIVIA_WORKSPACE_ROOT to your MCP config env with your project path (e.g. /home/user/myproject). Absolute paths and file:// URIs work without it. |
| BARIVIA_FETCH_TIMEOUT_MS | No | 60000 | Per-request HTTP timeout (ms) to the API. Increase (e.g. 120000) on slow networks or when the API does long-running work. Large dataset uploads use a separate longer timeout internally, and datasets(analyze) runs asynchronously (auto-polled) so it is not bound by this. A timeout is not auto-retried (re-firing slow work would only multiply load / risk duplicates). |
| BARIVIA_VIZ_PORT | No | OS-assigned | When the client has no MCP Apps support, the proxy may start a local viz server on 127.0.0.1. The port is assigned per MCP session and changes when the proxy restarts, so standalone …/viz/… URLs from a previous session go stale (the page then can't reach /api/* and shows a "stale session — re-run the tool" message). Set a fixed port for stable bookmark URLs. Diagnostic: GET http://127.0.0.1:<port>/api/health?job_id=<id> reports the port, API reachability, and the job's status. |
| BARIVIA_ENFORCE_WORKSPACE_SANDBOX | No | 1 (enabled) | File uploads are constrained to the MCP workspace root by default. Set to 0 or false to allow absolute paths anywhere on the machine (high trust). Changed in v0.x: previously defaulted to off; now on for security. If uploads fail with "paths outside the workspace are disabled", either set BARIVIA_WORKSPACE_ROOT to cover your data directory, or opt out with BARIVIA_ENFORCE_WORKSPACE_SANDBOX=0. |
Legacy BARSOM_API_KEY / BARSOM_API_URL / BARSOM_WORKSPACE_ROOT are also accepted as fallbacks.
Trust model (who are we trusting?)
- API key — Anyone with your key can access your tenant on the Barivia API like any other HTTP client. The proxy does not add a separate authorization layer.
- Local machine — The process runs with your OS user. File uploads are now sandboxed to the workspace root by default (
BARIVIA_ENFORCE_WORKSPACE_SANDBOX=1). SetBARIVIA_WORKSPACE_ROOTto your project directory; useBARIVIA_ENFORCE_WORKSPACE_SANDBOX=0only if you need unrestricted absolute-path access. - Logs — stderr may include API paths and tool activity; do not log secrets in MCP client configs.
Supported stack: Node 18+ (see engines in package.json). Built with @modelcontextprotocol/sdk ^1.x — if a major MCP client upgrade breaks tools, check SDK release notes alongside this package version.
Local viz fallback: If the IDE does not advertise MCP Apps, the proxy starts an HTTP server bound to 127.0.0.1 only (not exposed to the LAN). It serves built-in HTML for training prep / monitor / results explorer and proxies read-only API calls with your existing API key. Responses may include http://127.0.0.1:<port>/viz/... links. Browser Access-Control-Allow-Origin: * applies only to that localhost origin so the embedded pages can load data.
Tools and prompts (15 tools + 2 prompts)
All multi-action tools follow the datasets / jobs / results / inference / account pattern: a required action enum routes to the correct operation.
Prompts (not tools): info (short orientation; prefer guide_barsom_workflow for depth), prepare_training (requires dataset_id; checklist text from API when online).
Flattened catalog (optional grouping in UIs)
| Section | Items |
|--------|--------|
| Bootstrap | guide_barsom_workflow, prompts info, prepare_training |
| Data | datasets |
| Train & poll | train, jobs, training_monitor (optional) |
| Results | results, results_explorer (optional) |
| Inference | inference |
| Account | account |
| Optional UI | training_monitor, results_explorer |
| Advanced | training_guidance |
Agents should not call _fetch_figure from chat; it exists for the Results Explorer MCP App host. Use results(action=get) or results_explorer instead.
guide_barsom_workflow
Call at the start of mapping work (or when the user asks what the MCP can do). Returns plan-scoped orientation from the Barivia API when online. No parameters. training_guidance returns JSON presets and hints with the same entitlement filtering.
datasets(action)
| Action | Use when |
|--------|----------|
| upload | Adding a new CSV — returns dataset_id and stage_job_id when staging is enqueued. Accepts .csv/.tsv and pre-gzipped .csv.gz/.tsv.gz (compress big tables locally to transfer ~3× less). Large files stream directly to object storage; multi-GB uploads are supported. |
| preview | Before training — inspect columns, stats, cyclic/datetime hints |
| analyze | Pre-training recommendations (correlation, columns to consider dropping, etc.) |
| list | Finding dataset IDs |
| get | One dataset by id — status, staging fields, stage_job_id, ingest errors |
| subset | Creating a filtered/sliced copy (row_range, filter conditions) |
| add_expression | Add a derived column from an expression (formula → new column on the dataset) |
| reduce_spectral | Pre-training reducer for long ordered numeric blocks (spectra, time series, sensor fingerprints, gene panels). Methods: pca (top-k principal components), log_sample (k columns at log-spaced indices — scattering, audio bands), uniform_sample (k columns at evenly-spaced indices — regularly-sampled time series), stats (6 fixed per-row summary columns). All produce one feature vector per row; appends derived columns to the dataset. |
| delete | Removing a dataset |
train(action)
All training is submitted via the train tool; every action is async and returns a job_id (poll with jobs(action=status, job_id=...)).
| Action | Use when |
|--------|----------|
| map | New map training job — full control: model type, grid, epochs, cyclic/temporal features, transforms. Complete-case data only (no NaNs in training columns). |
| impute | Sparse training: missSOM / SIOM missSOM — map + imputed.csv. Supports transforms, temporal_features, cyclic_features, normalization_methods (zscore/mad/sigmoidal/none — not sepd or rank). Defaults: model=auto, cv_folds=5. Valid parent for inference(impute_column). |
| siom_map | Self-interacting map — same grid-map workflow plus SIOM controls such as gamma, siom_decay, and penalty selection. |
| floop_siom | FLooP-SIOM — growing node-budget manifold; default topology=free (CHL); optional topology=chain for strict 1D linked list. Requires Premium/Enterprise (all_algorithms). |
For a quick first map, use train(action=map, preset=quick) (or normalize=mad with a grid sized from the preview row count) — see the baseline_explore preset in training_guidance.
jobs(action) — lifecycle
| Action | Use when |
|--------|----------|
| status | Polling after any async job — every 10–15s; map jobs expose progress_phase (ordering, convergence, cv, artifacts) |
| list | Finding job IDs, checking pipeline state |
| compare | Picking the best run from a set (QE, TE, silhouette table) |
| cancel | Stopping a running job |
| delete | Permanently removing a job + its S3 files |
jobs is lifecycle only. Submit training with the train tool and run scoring / post-training map ops with inference. (The old jobs(action=train_*/run_baseline_study/batch_predict) forwarders were removed in 0.17.0 — see Migration notes.)
results(action)
| Action | Sync | Use when |
|--------|------|----------|
| get | instant | First look after training — combined view + quality metrics |
| export | instant | Learning curve (training_log), weight matrix (weights), node stats (nodes) |
| download | instant | Saving figures to a local folder |
| recolor | async | Changing colormap or output format without retraining |
Temporal state-transition analysis moved to inference(action=transition_flow) in 0.17.0 (read the resulting figure with results(action=get/download)).
All visualizations and metrics come from results(action=get). Grid-map jobs return combined map figures, component planes, and quality metrics; FLooP-SIOM jobs return structure/coverage figures, occupation/profile views, and metrics. Use figures=all or export_type=... for more. There is no separate analyze tool.
inference(action)
All actions use a frozen trained map — no retraining. Derived columns use datasets(action=add_expression); overlaying columns on the map uses inference(action=project_columns).
| Action | Output | Timing |
|--------|--------|--------|
| predict | Score rows against the trained map. Inputs: dataset_id (defaults to the parent training dataset) or inline rows (≤500). Output style (output param): "compact" → predictions.csv (row_id, bmu_x/y, bmu_node_index, cluster_id [+ QE / qe_p95 / potential_anomaly when scoring new data]); "annotated" → annotated.csv (original CSV + BMU columns appended). Regime auto-detected: when the resolved dataset matches the training dataset, QE columns are intentionally omitted in compact output (training-set fit ≠ generalisation; the p95 anomaly flag would be circular). Prefer dataset_id for batches and SIOM/irregular maps. | 5–120s |
| batch_predict | Fan out many predict jobs at once against one parent training job_id: pass inputs (array of { dataset_id? , rows? }). Returns the list of submitted job_ids (does not auto-poll — poll each with jobs(action=status)). | submits N jobs |
| impute_column | Fill a numeric target_column not used in training: requires dataset_id + target_column. Parent job: completed train(action=map) or train(action=impute). Dataset must contain all training features plus the target. Pools observed target values from rows mapped to this row's BMU and topology neighbors (BMU + neighbors, often 7 nodes on hex interior; fewer on borders unless the map is periodic). only_missing (default true); impute_aggregation: mean or median. Not held-out validated — map-local estimate. Output imputed.csv. For holes across many training columns, prefer train(action=impute) first. | 5–120s |
| compare | density-diff heatmap + top gained/lost nodes — drift, A/B, cohort | 30–120s |
| project_columns | Project one or more dataset columns onto the trained map (component planes) | async |
| transition_flow | Temporal state-transition arrows on the trained map (time-ordered rows only). Pass the training job_id; returns a new result job_id for results(get/download). lag/min_transitions/top_k tune it. | 30–60s |
| report | Report manifest (figure names, download URLs, metrics, cluster summary) — sync; use with results(download) on the training job_id for report.pdf when present; build custom PDFs in Quarto/Jupyter | immediate |
account(action)
| Action | Use when |
|--------|----------|
| status | Before large jobs — plan tier, GPU availability, queue depth, credit balance, training time estimates |
| request_compute | Upgrading to cloud burst. Leave tier blank to list options. |
| compute_status | Checking active lease time remaining |
| release_compute | Manually stopping a lease to stop billing |
| history | Viewing recent compute usage and spend |
| add_funds | Getting instructions to add credits |
MCP App tools (optional UIs)
| Tool | Role |
|------|------|
| training_monitor | Live QE + panel topographic-error curves (ordering/convergence, dual y-axis); Panel TE and Map TE scalars at kernel end; FLooP step progress when applicable; optional — jobs(action=status) is enough |
| results_explorer | Browse metrics and figures after training completes |
| _fetch_figure | Host / App only — Results Explorer invokes this for one raster figure; not for agent chat |
When the client does not advertise MCP Apps support, the proxy starts viz-server on 127.0.0.1 (localhost-only). Tool responses can include http://127.0.0.1:PORT/viz/... links. See Local viz fallback under Environment Variables.
Choosing where to view results
The right viewer depends on (MCP App support) and (can the human reach the proxy's 127.0.0.1) — not on whether the agent is "text" or "GUI".
| Path | When to use | Caveats |
|------|-------------|---------|
| Embedded MCP App (ui://barsom/results-explorer) | Client supports MCP Apps (Cursor, Claude Desktop with App support). Preferred default. | None of the topology issues below — transported over the MCP channel. Works for local proxy, remote SSH proxy, or container. |
| Localhost viz-server link | MCP Apps unsupported AND the human user is on the same host as the proxy (typical local Cursor + local stdio proxy). | Ephemeral port (lost on proxy restart). Unreachable when the proxy runs on a remote SSH host while the user is elsewhere, in a container with no port forwarding, or behind a strict host firewall. Pure text agents on the same host CAN use this path — the user just clicks the link. |
| results(action=get) text-only path | Always works. Use when (a) the agent is headless / autonomous (no human to click anything) or (b) proxy and user are on different hosts and MCP Apps is unsupported. With figures="none" it's also the leanest path for parameter sweeps and LLM clients (no image payloads). | Returns metrics text and inline images via MCP content; never starts a server. |
Migration notes
- Fixed-panel live TE (0.20.4): mid-training TE curves use a fixed evaluation panel (
te_panel_sizeontrain). Monitors show Panel TE and Map TE separately; curve tail no longer snaps to map TE. - Features (0.20.0, non-breaking):
- FLooP-SIOM maps are now projectable.
inference(action=project_columns),inference(action=predict), anddatasets(action=add_expression, project_onto_job=<floop_job>)work on FLooP-SIOM (free/chain) maps — values render onto the FLooP Voronoi layout instead of failing. Grid-only ops (inference(action=transition_flow | impute_column | render_variant)) return a clearunsupported_topology_for_inferencemessage; use a fixed-grid SOM/SIOM for those. No client change required. datasets(action=reduce_spectral)column selectors. New optionalcolumns_range([first, last], the server expands the inclusive numeric block — preferred for wide spectra over sending thousands of names) andcolumns_except(drop non-frequency columns like id/label/target from the block, or use alone for "all numeric except these").columns_exceptcomposes withcolumns_blockorcolumns_range;columns_blockandcolumns_rangeare mutually exclusive. Existingcolumns_blockcallers are unaffected.- Minimum dataset size for train/analyze relaxed from 50 to 10 rows (10–49 allowed with a small-N stability caveat).
- FLooP-SIOM maps are now projectable.
- Surface cleanup (0.19.0, breaking):
training_prepandsubmit_prepared_trainingremoved. The interactive prep UI is retired; for pre-train help use theprepare_trainingprompt (narrative checklist) ortraining_guidance(presets + resolved per-column normalization), then submit directly withtrain(action=map | siom_map | impute | floop_siom).- The unused
data-previewandmap-explorerview scaffolds were deleted (they were never wired to a tool). The two shipped MCP App UIs are nowtraining_monitorandresults_explorer, both enhanced (auto-resize, earlier render, and silent model-context sync of what the user is viewing).
- Fixes (0.17.1, non-breaking):
datasets(action=list/get)no longer printsingest_error=missingfor healthy datasets (a SQLNULLwas serialized as the literal"missing"; fixed server-side, and the proxy now also ignores themissing/nullsentinels).file_pathupload help now states that relative paths resolve against the MCP workspace root — in Cursor/IDE clients that root is often the MCP install dir, so setBARIVIA_WORKSPACE_ROOT(or pass an absolute path) if a relative path is "not accessible".- Preprocessing failures now name the offending column(s) (e.g. missing cells in a
train(action=map)column) instead of a generic error.
- Surface cleanup (0.17.0, breaking):
train(action=baseline_study)removed — usetrain(action=map, preset=quick)(thebaseline_explorepreset intraining_guidance).results(action=transition_flow)removed — it is nowinference(action=transition_flow)(a frozen-map operation). Read the resulting figure withresults(action=get/download)on the returned job_id.- The deprecated
jobs(action=train_map | train_siom_map | train_impute | train_floop_siom | run_baseline_study | batch_predict)forwarders are removed. Submit training viatrain; run scoring / map ops viainference.jobsis lifecycle-only and no longer accepts training parameters.
- Training moved to the
traintool (0.14.0): submit training viatrain(action=map | siom_map | impute | floop_siom);jobsnow covers lifecycle only (status/list/compare/cancel/delete).batch_predictisinference(action=batch_predict). (The 0.14.0–0.16.x deprecatedjobs(train_*)forwarders were removed in 0.17.0; see above.) Update Cursor / Claude Desktop configs and prompts to the new tools. explore_mapremoved (0.13.0): the deprecated alias ofresults_exploreris gone. Update any Cursor / Claude Desktop / MCP config or call site to useresults_explorer.train_floop_chainremoved (0.13.0): the deprecated alias ofjobs(action=train_floop_siom)is gone. Usetrain(action=floop_siom).- Shorter
infoprompt: Clients that relied on the old longinfotext should useguide_barsom_workflowor server instructions for the full story.
send_feedback
Submit feedback or feature requests (max 1400 characters, ~190 words).
Tool Design Guidelines
When adding or refining tools, follow MCP best practices:
- Single responsibility — One clear purpose per tool; avoid kitchen-sink tools
- Specific, actionable descriptions — State purpose, constraints, and side effects; include usage guidance and follow-up steps
- Explicit parameter descriptions — Each parameter should describe format, constraints, and when to use it
- Bounded capability — Focused tools with specific contracts; prefer narrow, testable actions over broad ones
Data preparation
To train on a subset of your data (e.g. first 2000 rows, or rows where region=Europe) without re-uploading: use datasets(action=subset) with row_range and/or filter to create a new dataset, then train with train(action=map, dataset_id=...), train(action=siom_map, dataset_id=...), or train(action=floop_siom, dataset_id=...) on the new dataset_id; or pass row_range in the training job params for a one-off slice.
How It Works
The proxy implements the MCP stdio transport locally and translates tool calls into REST API requests to the Barivia backend. Results are returned as rich MCP content with text summaries, inline base64 images, and resource links.
MCP Client (Cursor/Claude) ←stdio→ @barivia/barsom-mcp ←HTTPS→ api.barivia.seTroubleshooting
| Symptom | What to check |
|--------|----------------|
| 401 / invalid key | BARIVIA_API_KEY in MCP config; check your email or manage your key in the account dashboard. Error text includes a request id for support. |
| Request timed out | Raise BARIVIA_FETCH_TIMEOUT_MS (e.g. 120000). Large uploads already use an extended timeout; datasets(analyze) is async (auto-polled). Timeouts are not auto-retried, so re-running a timed-out upload is safe — an idempotency key reconciles it to the original dataset instead of duplicating. |
| Path must be within the workspace / upload can’t find file | Set BARIVIA_WORKSPACE_ROOT to your project directory, or use an absolute path / file:///... URI. |
| Job stuck “running” | Poll jobs(action=status) every 10–15s; large grids or FLooP-SIOM can take several minutes—not an MCP error. Staged datasets enqueue prepare_training_matrix (or impute prepare) first — train submit returns prepare_job_id; MCP auto-polls prepare when present. CFD mesh submit may return prepare_job_id for prepare_training_matrix (barmesh auto-polls). |
| 429 | Rate limit—wait and retry. |
| Standalone …/viz/… page stuck at "running 0%" or "Loading…" | The link is stale: the viz port is assigned per MCP session and changes when the proxy restarts. Re-run training_monitor / results_explorer for a fresh URL, or set BARIVIA_VIZ_PORT for a persistent port. Confirm with GET /api/health?job_id=<id>. |
| Embedded results explorer: switching figures shows nothing | Fixed in 0.18.0 — earlier versions pointed embedded figures at a localhost URL the webview can't load. Update the package; the embedded view now lazy-loads figures over the MCP App bridge. |
| Malformed MCP / client errors | Ensure nothing writes to stdout except MCP JSON-RPC (the proxy logs API traffic to stderr only). |
Development
cd apps/mcp-proxy
npm install
npm run dev # Run with tsx (hot reload)
npm run build # Compile to dist/
npm test # VitestPost-change spot-check (real MCP client): confirm guide_barsom_workflow appears near the top of the tool list, the removed explore_map / train_floop_chain aliases are no longer listed, and Results Explorer can still load figures (it uses _fetch_figure internally — agents should rely on results / results_explorer).
For local development against a local API stack:
BARIVIA_API_URL=http://localhost:8080 BARIVIA_API_KEY=bv_test_key npm run devPublishing
The npm tarball is runtime-only: minified dist/**/*.js, the three embedded view HTML files, LICENSE, package.json, and README.md. It does not include TypeScript source, .map, .d.ts, tests, or src/. CI runs build:publish (clean dist, compile without source maps, views, minify entrypoint) via prepublishOnly.
License
Proprietary — Barivia AB. The package is published as UNLICENSED on npm (no permissive open-source grant). See the LICENSE file in this package. Use is subject to your agreements with Barivia; copying, redistribution, or derivative works are not permitted except as stated there or in writing by Barivia AB. (Any semver already published to npm under MIT stays MIT for that published artifact only; newer versions use the proprietary LICENSE.)
Published to registry.npmjs.org via GitHub Actions when you push tag mcp-proxy-v* (version in package.json must match the tag, e.g. tag mcp-proxy-v0.7.10 for version 0.7.10):
git tag mcp-proxy-v0.7.10
git push origin mcp-proxy-v0.7.10The repository needs a NPM_TOKEN secret (npm automation/publish token with access to the @barivia scope).
Checking local vs published
From the platform root:
cd barivia-platform
bash scripts/checks/check-mcp-proxy-publish.shCompares local build:publish output to the tarball on public npm. Exit 0 = match; exit 1 = diff. VERBOSE=1 for a full dist/ diff.
