Search / io.github.nimbusbci/nimbus-mcp
Nimbus BCI
R0· no sign-inAI agents build, train, and analyze BCI/EEG pipelines: data, models, experiments, live sessions.
v0.14.11 · active · repository · descriptor JSON · versions
Search / io.github.nimbusbci/nimbus-mcp
R0· no sign-inAI agents build, train, and analyze BCI/EEG pipelines: data, models, experiments, live sessions.
v0.14.11 · active · repository · descriptor JSON · versions
{
"mcpServers": {
"nimbus-mcp": {
"type": "http",
"url": "https://nimbus-mcp.fly.dev/mcp"
}
}
}claude mcp add --transport http nimbus-mcp https://nimbus-mcp.fly.dev/mcp[mcp_servers.nimbus-mcp]
url = "https://nimbus-mcp.fly.dev/mcp"
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"nimbus-mcp": {
"type": "remote",
"url": "https://nimbus-mcp.fly.dev/mcp",
"enabled": true
}
}
}{
"mcpServers": {
"nimbus-mcp": {
"type": "http",
"url": "https://nimbus-mcp.fly.dev/mcp"
}
},
"deeplink": "cursor://anysphere.cursor-deeplink/mcp/install?name=nimbus-mcp&config=eyJ0eXBlIjoiaHR0cCIsInVybCI6Imh0dHBzOi8vbmltYnVzLW1jcC5mbHkuZGV2L21jcCJ9"
}{
"servers": {
"nimbus-mcp": {
"type": "http",
"url": "https://nimbus-mcp.fly.dev/mcp"
}
}
}{
"mcpServers": {
"nimbus-mcp": {
"httpUrl": "https://nimbus-mcp.fly.dev/mcp"
}
}
}extensions:
"nimbus-mcp":
enabled: true
name: "nimbus-mcp"
type: streamable_http
uri: "https://nimbus-mcp.fly.dev/mcp"
timeout: 300
protocol.modernsupports 2026-07-28 (server/discover)protocol.statelessanswers without a sessionprotocol.transportstreamable HTTPprotocol.list_ttltools/list declares ttlMs 0, so clients re-fetch it on every useauth.prm, auth.as_metadata, auth.cimdno remote uses OAuthauth.secret_in_urlno templated URLtools.descriptionsevery tool has a descriptiontools.description_length3 tools have descriptions over 1,024 characters, which crowds the contexttools.schemasevery tool has an object input schematools.annotations60 of 60 tools declare readOnlyHint or destructiveHinttools.directory_hintsevery tool declares readOnlyHint, destructiveHint, idempotentHint and openWorldHinttools.token_costabout 13,129 tokens to load every tooltools.api_dumptools are not a one-to-one API dumpstability.changes135 tool changes in 30 daysstability.rug_pull6 tools kept their name but changed most of their description in 30 days; review before trusting themdeps.known_vulns, deps.mcp_sdk_version, deps.resolvabledependencies not resolved yetexperiment.getchangeddescriptionExperiment snapshot: status (running/completed/failed), per-run rows ({name, executionId, status, error?, metrics?, evaluationKind?}) and, once finished, aggregates over completed runs only: per-metric {mean, std, best, n}, plus ``pooledExecutionIds`` / ``pooledRunNames`` / ``kindBreakdown`` (per-subject vs LOSO etc. — each row has kind, n, mean, std, executionIds, runNames; #470). Pooled headline means are unchanged; kindBreakdown labels what was pooled. std is population; None below 2 values. kindBreakdown is always present when aggregates exist (including single-kind experiments). PORTABILITY: only experiments run through THIS entry point (local stdio vs hosted gateway), on this machine, under the same account/token can be read — records are kept in-process and in the local ~/.nimbus/experiments store, not on the Nimbus server (#518).
Experiment snapshot: status (running/completed/failed), per-run rows ({name, executionId, status, error?, metrics?, evaluationKind?}) and, once finished, aggregates over completed runs only: per-metric {mean, std, best, n}, plus ``pooledExecutionIds`` / ``pooledRunNames`` / ``kindBreakdown`` (per-subject vs LOSO etc. — each row has kind, n, mean, std, executionIds, runNames; #470). Pooled headline means are unchanged; kindBreakdown labels what was pooled. std is population; None below 2 values. kindBreakdown is always present when aggregates exist (including single-kind experiments). PORTABILITY: experiment records are stored on the Nimbus server under your account, so any entry point (local stdio, hosted gateway, another machine) signed in with the same account/token can read them; the serving process and the local ~/.nimbus/experiments store remain as fast-path caches. Experiments run before server-side storage landed exist only in the origin machine's local store and read as unknown elsewhere (#518).
experiment.runchangeddescriptionRun 1-25 pipelines as ONE paced experiment (NON-BLOCKING). Returns an experimentId immediately; a background thread submits at most 2 runs at a time (min(max_concurrent, 2)), retries queue-full up to 3 times per run, and polls each execution to completion. Poll experiment.get() for per-run status and, once finished, aggregated metrics. PORTABILITY: experiment records live in the serving process and in this machine's local store (~/.nimbus/experiments) — they are NOT on the Nimbus server yet. Poll with the SAME entry point that ran the experiment (local stdio vs hosted gateway, same machine, same account/token): an experimentId from another entry point or machine reads as "Unknown experiment" there (#518).
Run 1-25 pipelines as ONE paced experiment (NON-BLOCKING). Returns an experimentId immediately; a background thread submits at most 2 runs at a time (min(max_concurrent, 2)), retries queue-full up to 3 times per run, and polls each execution to completion. Poll experiment.get() for per-run status and, once finished, aggregated metrics. PORTABILITY: the experiment record is written through to the Nimbus server under your account (at start and at completion), so experiment.get works from ANY entry point — local stdio, hosted gateway, another machine — signed in with the same account/token. If the server is unreachable when the experiment starts it still runs and polls locally, but other entry points cannot read it until a write-through succeeds (#518).
leaderboard.submitchangeddescription, input schemaSubmit a BYO python_model to a leaderboard track for server-side scoring. Nimbus scores it server-side under the track's fixed protocol — you submit code, never results. Poll ``leaderboard.status`` with the returned ``submissionId``; scoring takes minutes (classical) to tens of minutes (deep). Requirements must be plain PyPI names/specs (max 20, no URLs). Identical code resubmission is idempotent per track (``deduplicated: true``).
Submit a BYO python_model to a leaderboard track for server-side scoring. Nimbus scores it server-side under the track's fixed protocol — you submit code, never results. Poll ``leaderboard.status`` with the returned ``submissionId``; scoring takes minutes (classical) to tens of minutes (deep). Requirements must be plain PyPI names/specs (max 20, no URLs). Identical code resubmission is idempotent per track (``deduplicated: true``). Verification contract (tier model X10): ``verification="verified"`` (default) is the server-side-scored submission above — on the hosted backend it is Pro-only; free accounts get a structured tier response. ``verification="unverified_local"`` names the designed Account-Free lane for locally-computed results; the backend has no unverified submission kind yet (see the response it returns — nothing is stored, and no row is faked). Anonymous callers get a structured login prompt: a submission needs an identity. Local (desktop/dev) backends keep their existing server-side quota behaviour.
account.whoamichangeddescriptionWho you are authenticated as: account email, plan (isPro / pioneer), this month's free-run quota, and — with a hosted token — the token name and days until it expires. Call this first when setup guidance appears or to check which credential a session uses.
Who you are authenticated as: account email, plan (isPro / pioneer), this month's free-run quota, and — with a hosted token — the token name and days until it expires. Call this first when setup guidance appears or to check which credential a session uses. In anonymous Local Free mode there is no account: the response says so (mode/tier) instead of demanding a login.
foundation.comparechangeddescription, output schemaRun every available pretrained backbone on YOUR data and see which wins — a ranked bar chart with CI whiskers, params, and wall time per backbone. Backbones that can't process your data (window size, channel count) are noted, not silently skipped. Each backbone embeds your trials frozen (the exact foundation_features preprocessing), a LDA is cross-validated on the embeddings, and meta.results carries the per-backbone accuracy, CI, embed dim, params, and time — pick the foundation_features backbone by measurement, not vibes.
Run every available pretrained backbone on YOUR data and see which wins — a ranked bar chart with CI whiskers, params, and wall time per backbone. Backbones that can't process your data (window size, channel count) are noted, not silently skipped. Each backbone embeds your trials frozen (the exact foundation_features preprocessing), a LDA is cross-validated on the embeddings. Returns a PNG image PLUS a JSON text block (and structuredContent.meta.results) with per-backbone accuracy, CI, embed dim, params, and time — pick the foundation_features backbone by measurement, not vibes.
stats.groupedchangeddescription, input schemaCluster-aware group statistics across executions. REQUIREMENT (read first): each execution must have been run with an evaluation plan that STORED per-group (per-subject) accuracies for at least 3 groups — e.g. leave-one-subject-out (LOSO) or grouped CV over >= 3 subjects. A plain single-subject CV run (trials split within one subject, one group) stores no group stats and CANNOT be analysed here. If none of the given executions qualifies, the backend fails with ``nimbus.stats.insufficient_groups`` — that error means exactly this: re-run with a multi-subject / group-wise evaluation plan (>= 3 groups), or pass runs from such a sweep. What it does: pools the per-subject (per-group) accuracies each run's evaluation plan stored, then reports the between-group summary — mean accuracy with a t-interval and a one-sample t-test vs chance. Use this instead of eyeballing pooled accuracy: trials within a subject are not independent, so this is the MOABB-style number that survives review.
Cluster-aware group statistics across executions. REQUIREMENT (read first): each execution must have been run with an evaluation plan that STORED per-SUBJECT accuracies for at least 3 subjects — e.g. leave-one-subject-out (LOSO) or grouped CV over >= 3 subjects. Session groups within one subject (multi-session single-subject runs) are refused with ``nimbus.stats.non_subject_groups`` — those are not independent subjects. A plain single-subject CV run with no subject/session grouping stores no group stats and fails with ``nimbus.stats.insufficient_groups``. What it does: pools the per-subject accuracies each run's evaluation plan stored, then reports the between-group summary — mean accuracy with a t-interval and a one-sample t-test vs chance. Responses label ``groupKind``, real ``groupKeys`` (subject ids like S01 when stamped or recoverable), ``perGroup`` (key + accuracy pairs), ``overall.pooledExecutionIds``, and ``kindBreakdown`` / ``overall.kindBreakdown`` (per_subject vs loso etc. with n + mean — #470; between-group pooled mean is unchanged).
project.savechangeddescription, input schemameaning changedSave a pipeline graph into a project (visible on the studio canvas). Handles revision conflicts automatically (one retry).
Save a pipeline graph into a project (visible on the studio canvas). Always pass expected_revision from the last project.load (or a prior save/create response). When it does not match the current server revision, the save fails with a conflict — it does NOT silently overwrite concurrent edits. Omitting it is rejected so a stale single-writer convenience path cannot wipe another client's work.
data.delete_uploadaddedDelete an uploaded file from your account (disk + registry). Requires confirm=True. Pass the path returned by data.upload (file.path). Only your own uploads can be deleted; missing paths return not-found.
data.uploadchangeddescriptionUpload an EEG file (.edf/.bdf/.mat/.csv/.txt/.tsv/.h5/.hdf5, <=500MB) to the backend and get the registered path for a custom_data node. sampling_rate (Hz, e.g. 250.0) is REQUIRED for plain CSV/TSV/TXT files without embedded metadata — the backend silently assumes 250 Hz otherwise, which mis-times epochs, filters and spectral features. format overrides extension-based detection (auto, mat, csv, tsv, txt, edf, bdf, h5, hdf5).
Upload an EEG file (.edf/.bdf/.mat/.csv/.txt/.tsv/.h5/.hdf5, <=500MB) to the backend and get the registered path for a custom_data node. sampling_rate (Hz, e.g. 250.0) is REQUIRED for plain CSV/TSV/TXT files without embedded metadata — uploads without it are rejected (no silent 250 Hz assumption). format overrides extension-based detection (auto, mat, csv, tsv, txt, edf, bdf, h5, hdf5).
plots.leaderboardchangedoutput schemaShowing the latest 10. Full history: list_changes · trend: quality JSON.
Checks run on what our credential-free, read-only probes observe; tools are never called and no code audit is performed. How it is computed.
+repository +namespace-matches-repo +reachable +uptime-98% +updated-0d-ago
Derived from observable signals (official registry feed and our own credential-free probes); no code audit performed. How it is computed.
[email protected] PyPInot resolved yet; dependencies are read once a day
Dependency graphs from deps.dev; advisories from OSV.dev, including the GitHub Advisory Database and the PyPI Advisory Database; all CC BY 4.0. The graph is what a clean install of this version resolves today; nothing was installed or run. How it is checked.
| remote | auth | reachable | uptime 30d | p50 | protocol | last ok |
|---|---|---|---|---|---|---|
https://nimbus-mcp.fly.dev/mcp streamable-http | none | yes | 98% | 175 ms | 2026-07-28 | 2026-10-20 |
| package | registry | version | runtime | secrets |
|---|---|---|---|---|
nimbus-mcp | pypi | 0.14.11 | – | NIMBUS_TOKEN, NIMBUS_MCP_KEY |
account.whoamiread-only | Who you are authenticated as: account email, plan (isPro / pioneer), this month's free-run quota, and — with a hosted token — the token name and days until it expires. Call this first when setup guidance appears or to check which credential a session uses. In anonymous Local Free mode there is no account: the response says so (mode/tier) instead of demanding a login. |
bids.export_dataset | Export a Nimbus dataset as a BIDS-layout zip saved to NIMBUS_EXPORT_DIR/bids/. Continuous sources (EDF/BDF uploads, stream recordings) export as BIDS-raw (EDF byte-passthrough; recordings converted HDF5→EDF with events.tsv). Epoched sources (MOABB packs, trial-table uploads) export as BIDS-derivatives (data passthrough + descriptive trial_index/label/session/run events — no fabricated onsets). The zip embeds nimbus_export_manifest.json with sha256s. |
bids.export_execution | Export an execution's results as a BIDS-derivative zip (metrics.json, per-subject participants.tsv, protocol.json, full pipeline_snapshot.json, predictions.tsv when stored, provenance/execution.json) saved to NIMBUS_EXPORT_DIR/bids/. |
calibration.pause | Pause a running calibration between trials (cues hold; resume anytime). |
calibration.resume | Resume a paused calibration session. |
calibration.start | Start a guided subject calibration session (NON-BLOCKING; confirm-gated — the device goes on a human's head). The Nimbus Studio app shows the cues on its calibration dashboard automatically; poll calibration.status. Requires a Pro plan (hosted token or Pro session): calibration nodes and custom-data training are gated by the freemium node policy; local X-MCP-Key principals pass only when the desktop app flags the signed-in Pro session (MCP_LOCAL_IS_PRO). |
calibration.statusread-only | Live snapshot of a calibration session (phase, current trial, progress, paused). Once complete, carries the recorded upload — call calibration.train to turn it into the subject's own classifier. |
calibration.train | Train the subject's own classifier from a COMPLETED calibration session (NON-BLOCKING). Fetches the recorded upload, wires it into a train pipeline as a custom_data source, and starts the run. Requires a Pro plan (custom_data training is freemium-gated). The calibrate→train handoff resolves on every backend, desktop-local included; only recordings made before the desktop execution-linkage build resolve no upload — rerun calibration.start for those. |
catalog.datasetsread-only | Curated public EEG datasets (MOABB packs) available to pipelines. |
catalog.leaderboardread-only | Public benchmark leaderboard: pipeline rankings per dataset. Two tracks: the top-level ``within_session`` block (curated suite pipelines) and ``crossSubject`` (leave-one-subject-out — curated pipelines plus BYO ``python_model`` submissions; BYO rows carry ``kind: "byo"`` and an ``owner`` name). Within each dataset, ``rows`` sort desc by ``meanAccuracyPct`` (95% CI in ``ciLoPct``/``ciHiPct``). ``packFingerprint`` identifies the exact dataset pack behind the scores; ``updated`` marks each dataset's most recent run. The ``pretrainedFewTrial`` efficiency track means: accuracy at a protocol-fixed 100-trials-per-subject budget — the frozen-backbone / few-parameter rows that matter when calibration data is scarce (``paramsTrained`` shown per row so cost is readable next to accuracy). ``submittableDatasets`` is the set open for ``leaderboard.submit``; a dataset can appear under ``crossSubject`` and still be closed for new submissions. |
catalog.nodesread-only | List Nimbus pipeline node types (data, preprocessing, features, models...). Use catalog.node_schema(node_type) for one node's full config schema and ports. |
catalog.node_schemaread-only | Full config JSON schema + input/output ports for one node type. |
catalog.templateread-only | Full template incl. the 'train' execGraph needed by execution.run/pipeline.validate. |
catalog.templatesread-only | List built-in starter pipelines (MI/P300/SSVEP...). catalog.template(id) returns the graph. |
data.delete_uploaddestructive | Delete an uploaded file from your account (disk + registry). Requires confirm=True. Pass the path returned by data.upload (file.path). Only your own uploads can be deleted; missing paths return not-found. |
data.inspect_datasetread-only | Exploratory summary of a public EEG dataset (MOABB pack): channels, sampling rate, trial/class balance, per-channel µV stats, band powers and a PSD overview. Look at the data BEFORE building pipelines: class balance drives stratification choices (imbalanced classes skew accuracy), and flatlined channels mean a montage/reference problem worth fixing first. subject is REQUIRED (the backend 400s without it) — get the subject list via catalog.datasets, e.g. "S01"; a comma-list like "S01,S03" loads a cohort. mode: training | evaluation | all. Units note: values are ASSUMED volts by the loader — a µV-native file reads 1e6x too large; set unitsScale in a pipeline's custom_data config when needed. |
data.inspect_fileread-only | Exploratory summary of an EEG file (.edf/.bdf/.mat/.csv/.tsv/.txt/.h5): channels, sampling rate, trial/class balance, per-channel µV stats, band powers and a PSD overview. The path shape picks the source: ABSOLUTE path → read the file from disk (only on a LOCAL backend: desktop app / MCP local mode — no upload needed); RELATIVE path (the one data.upload returns) → describe the uploaded file, which works on ANY backend (hosted or local). Look at the data BEFORE building pipelines: class balance drives stratification choices, and flatlined channels mean a montage/reference problem worth fixing first. Units note: values are ASSUMED volts by the loader — a µV-native CSV reads 1e6x too large; set unitsScale in a pipeline's custom_data config when needed. On a hosted backend absolute paths are refused and this returns guidance (upload the file first or switch to a local backend). |
data.upload | Upload an EEG file (.edf/.bdf/.mat/.csv/.txt/.tsv/.h5/.hdf5, <=500MB) to the backend and get the registered path for a custom_data node. sampling_rate (Hz, e.g. 250.0) is REQUIRED for plain CSV/TSV/TXT files without embedded metadata — uploads without it are rejected (no silent 250 Hz assumption). format overrides extension-based detection (auto, mat, csv, tsv, txt, edf, bdf, h5, hdf5). |
device.listread-only | EEG devices supported by this backend (OpenBCI, Muse, BrainBit, LSL, PiEEG...). |
device.testread-only | Test a device connection WITHOUT starting a stream (safe, no confirm needed). |
execution.artifactsread-only | Trained artifacts (models/filters, e.g. *.pkl) saved by an execution. |
execution.canceldestructive | Cancel a running execution. |
execution.download_artifact | Download one artifact file to NIMBUS_EXPORT_DIR/executions/<id>/ and return its path. |
execution.getread-only | Execution status summary (status: running/completed/failed/cancelled). |
execution.listread-only | Recent executions. Optional status filter (running/completed/failed/cancelled). |
execution.resultsread-only | Metrics for a completed run. Trimmed by default (accuracy, kappa, ITR, confusion matrix, per-class); full=True returns the complete result object. |
execution.run | Start a pipeline run (NON-BLOCKING). Returns executionId — poll with execution.get() until status is completed/failed, then execution.results(). If an identical graph is already running for you, the run still starts but the response carries a ``warning`` + ``duplicateOf`` ids (cancel one with execution.cancel to avoid paying twice). |
experiment.getread-only | Experiment snapshot: status (running/completed/failed), per-run rows ({name, executionId, status, error?, metrics?, evaluationKind?}) and, once finished, aggregates over completed runs only: per-metric {mean, std, best, n}, plus ``pooledExecutionIds`` / ``pooledRunNames`` / ``kindBreakdown`` (per-subject vs LOSO etc. — each row has kind, n, mean, std, executionIds, runNames; #470). Pooled headline means are unchanged; kindBreakdown labels what was pooled. std is population; None below 2 values. kindBreakdown is always present when aggregates exist (including single-kind experiments). PORTABILITY: experiment records are stored on the Nimbus server under your account, so any entry point (local stdio, hosted gateway, another machine) signed in with the same account/token can read them; the serving process and the local ~/.nimbus/experiments store remain as fast-path caches. Experiments run before server-side storage landed exist only in the origin machine's local store and read as unknown elsewhere (#518). |
experiment.run | Run 1-25 pipelines as ONE paced experiment (NON-BLOCKING). Returns an experimentId immediately; a background thread submits at most 2 runs at a time (min(max_concurrent, 2)), retries queue-full up to 3 times per run, and polls each execution to completion. Poll experiment.get() for per-run status and, once finished, aggregated metrics. PORTABILITY: the experiment record is written through to the Nimbus server under your account (at start and at completion), so experiment.get works from ANY entry point — local stdio, hosted gateway, another machine — signed in with the same account/token. If the server is unreachable when the experiment starts it still runs and polls locally, but other entry points cannot read it until a write-through succeeds (#518). |
foundation.compareread-only | Run every available pretrained backbone on YOUR data and see which wins — a ranked bar chart with CI whiskers, params, and wall time per backbone. Backbones that can't process your data (window size, channel count) are noted, not silently skipped. Each backbone embeds your trials frozen (the exact foundation_features preprocessing), a LDA is cross-validated on the embeddings. Returns a PNG image PLUS a JSON text block (and structuredContent.meta.results) with per-backbone accuracy, CI, embed dim, params, and time — pick the foundation_features backbone by measurement, not vibes. |
leaderboard.mineread-only | List your leaderboard submissions (newest first), all datasets. |
leaderboard.statusread-only | Fetch one of your leaderboard submissions (owner-only). Returns status (queued | scoring | done | failed), metrics when done (meanAccuracyPct + CI, same shape as leaderboard rows), or the error that failed it. |
leaderboard.submit | Submit a BYO python_model to a leaderboard track for server-side scoring. Nimbus scores it server-side under the track's fixed protocol — you submit code, never results. Poll ``leaderboard.status`` with the returned ``submissionId``; scoring takes minutes (classical) to tens of minutes (deep). Requirements must be plain PyPI names/specs (max 20, no URLs). Identical code resubmission is idempotent per track (``deduplicated: true``). Verification contract (tier model X10): ``verification="verified"`` (default) is the server-side-scored submission above — on the hosted backend it is Pro-only; free accounts get a structured tier response. ``verification="unverified_local"`` names the designed Account-Free lane for locally-computed results; the backend has no unverified submission kind yet (see the response it returns — nothing is stored, and no row is faked). Anonymous callers get a structured login prompt: a submission needs an identity. Local (desktop/dev) backends keep their existing server-side quota behaviour. |
pipeline.export | Export the pipeline as a standalone runnable Python bundle (zip saved locally). |
pipeline.validateread-only | Validate a pipeline graph before running. ExecGraphSnapshot: {nodes: [{id, type, config}], connections: [{from, to}]}. Build it from catalog.template(id).train or from scratch using catalog.nodes(). |
pipeline.validate_noderead-only | Validate one node's config (schema + semantic checks). Catches the same value errors as pipeline.validate for a single node (inverted bandpass, CSP components vs channel count when dataset is set). |
plots.confusion | Confusion-matrix figure for one execution: heatmap with trial counts + per-class accuracy bars, rendered as a PNG the assistant can see. Use it right after execution.results to eyeball WHICH classes are confused, not just the accuracy number. |
plots.dataset | Figure over an EEG data source — the visual companion to data.inspect_dataset. kind=psd (Welch, channel mean bold), kind=bandpower (channel × band dB heatmap), kind=topomap (band-power scalp map), kind=spectrogram (time-frequency for one channel). Sources are the same ones inspect uses: MOABB packs, uploads, local files. |
plots.erp | ERP butterfly figure from epoched data: one subplot per class, all channel means (thin) + across-channel mean (bold), time-locked to the trial event. Shows whether class-conditioned evoked structure exists BEFORE training anything. |
plots.leaderboard | Leaderboard bar chart for one dataset: accuracy with 95% CI whiskers, best first; BYO python_model submissions highlighted in a distinct color. The visual companion to catalog.leaderboard. On the pretrained_few_trial track the figure also includes the classical LOSO baseline as a muted side panel for comparison. |
project.create | Create a project (container for one pipeline document). Returns projectId. |
project.deletedestructive | Delete a project (and its saved pipeline document) from the studio workspace. Requires confirm=True: this removes the project from the user's project list. Executions already run from it are not affected. Find ids with project.list. |
project.listread-only | List projects owned by the current principal (agent work included). |
project.loadread-only | Load a project's saved pipeline (train graph + meta) for editing/re-running. |
project.save | Save a pipeline graph into a project (visible on the studio canvas). Always pass expected_revision from the last project.load (or a prior save/create response). When it does not match the current server revision, the save fails with a conflict — it does NOT silently overwrite concurrent edits. Omitting it is rejected so a stale single-writer convenience path cannot wipe another client's work. |
protocol.export_statsread-only | Paired pre/post analysis for one assignment's recorded sessions: per-block aggregates (descriptive + CSV), paired t / Wilcoxon / dz (per-statistic minimums: paired t and Cohen's dz need ≥ 3 completed sessions, Wilcoxon needs ≥ 5), specificity notes, the adaptive-threshold trajectory, and a pre/post figure (base64 PNG — render or save it to look at the effect). An assignment with no recordings yet returns the empty payload with a note, never an error. |
protocol.listread-only | Every saved protocol id at its latest version. |
protocol.pause | Pause a running protocol session (blocks freeze; the session and device stay alive — resume with protocol.resume). Simulated and playback sessions only while paused: no data is recorded. |
protocol.resume | Resume a paused protocol session (restarts the server-driven device loop). Live-hardware resume requires a Pro plan; simulated sessions are free. Pass the session's channel count (start_assignment reports it). |
protocol.save | Validate and persist the NEXT VERSION of a protocol document (confirm-gated: each call appends a version row; accidental calls clutter the version history). Edits create a new version — the assignment pins the version it runs. |
protocol.session_statusread-only | Live snapshot of a protocol deploy session: the scheduler block / session progress + threshold state (under ``protocol``) beside the telemetry window (recent indicators, quality, stats). |
protocol.start_assignment | Enroll a subject and prepare their neurofeedback deploy session (confirm-gated — a session runs on a human). Creates the assignment (yoked sham arms REQUIRE yoked_donor_upload_id: a recorded simulated session's upload — mint one by running an active-arm session and data.upload-ing its recording), then persists the protocol graph as a deployable execution. Requires a Pro plan for LIVE hardware sessions; simulated-source sessions (the default template) are free. Graph source: execution_id reuses THAT run's stored graph (it must contain a protocol_session node; no device is pre-connected — the deploy session's data source stays yours). Without execution_id the built-in template graph is cloned — simulated source → bandpass → bandpower_indicator → protocol_session stamped with the protocol refs — and a simulated device is connected to the returned session id. The session starts when a client opens {statusUrl} (the deploy WS), sends init_deployment with modelExecutionId={executionId}, then start; the Studio app shows the feedback panel automatically. Poll protocol.session_status; stop with protocol.stop (the recording's block annotations + assignment progression are written on stop). |
protocol.stop | Stop a protocol session (always safe to call): stops streaming, saves the block-annotated recording, advances the assignment when the scheduler reached its natural end, and disconnects the device (best-effort — a failed disconnect is reported, never raised). |
protocol.validateread-only | Validate a neurofeedback protocol document WITHOUT saving it. Returns {valid: true, spec} on success, or {valid: false, errors: [...]} with the per-violation list (loc/msg) when the document is invalid — the verdict is data, never an exception. |
python.validateread-only | Statically check a python_model script (BYO model class) without running it. Compiles the source and verifies the contract — a class with fit(X, y, info) and predict(X); optional predict_proba(X) unlocks confidence panels. Never executes the code, so it is safe against the hosted backend. Use it before execution.run to catch syntax errors, missing methods, or the wrong class name cheaply. |
stats.groupedread-only | Cluster-aware group statistics across executions. REQUIREMENT (read first): each execution must have been run with an evaluation plan that STORED per-SUBJECT accuracies for at least 3 subjects — e.g. leave-one-subject-out (LOSO) or grouped CV over >= 3 subjects. Session groups within one subject (multi-session single-subject runs) are refused with ``nimbus.stats.non_subject_groups`` — those are not independent subjects. A plain single-subject CV run with no subject/session grouping stores no group stats and fails with ``nimbus.stats.insufficient_groups``. What it does: pools the per-subject accuracies each run's evaluation plan stored, then reports the between-group summary — mean accuracy with a t-interval and a one-sample t-test vs chance. Responses label ``groupKind``, real ``groupKeys`` (subject ids like S01 when stamped or recoverable), ``perGroup`` (key + accuracy pairs), ``overall.pooledExecutionIds``, and ``kindBreakdown`` / ``overall.kindBreakdown`` (per_subject vs loso etc. with n + mean — #470; between-group pooled mean is unchanged). |
stream.start | Connect an EEG device and START a live streaming session on the user's head. Requires confirm=True; call device.test first. Track with stream.status(). Idle watchdog: if no stream.status()/stream.telemetry() poll happens for idle_timeout_sec (default 900), the session is stopped and the device disconnected automatically — an abandoned stream never keeps running on the user's head. Any poll resets the timer; idle_timeout_sec=0 disables the watchdog. |
stream.statusread-only | Live snapshot of a streaming session (running, deviceConnected). Polling this also feeds the idle watchdog: each call resets the session's idle timer (see stream.start's idle_timeout_sec). |
stream.stopdestructive | Stop a streaming session and disconnect the device (always safe to call). Also removes the session from the idle watchdog so it cannot fire after an explicit stop. |
stream.telemetryread-only | Live snapshot of a streaming session: latest prediction + recent window, signal quality (meanChannelQuality, snrDb, artifactProbability), indicators, running stats. Poll this while a session runs. Works with OR without a deployed model: modelless hardware streams (no classifier) report live signal quality + focus/relaxation band-power indicators with latestPrediction null; deployed sessions additionally carry predictions and confidence stats. Expect low confidence during filter/ASR warm-up (first seconds); quality < 0.5 or high artifactProbability means the signal is poor. 404 => session not active in this backend. Each poll also feeds the idle watchdog (see stream.start's idle_timeout_sec), keeping an actively watched session alive. |
Schemas: list_tools.
{
"name": "io.github.nimbusbci/nimbus-mcp",
"title": "Nimbus BCI",
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"remotes": [
{
"url": "https://nimbus-mcp.fly.dev/mcp",
"type": "streamable-http"
}
],
"version": "0.14.11",
"packages": [
{
"version": "0.14.11",
"transport": {
"type": "stdio"
},
"identifier": "nimbus-mcp",
"registryType": "pypi",
"environmentVariables": [
{
"name": "NIMBUS_API_URL",
"format": "string",
"description": "Nimbus backend URL. Defaults to the local backend (http://127.0.0.1:8080) — the desktop app and local key flow expect this; use https://nimbus-studio.fly.dev to run against the hosted API."
},
{
"name": "NIMBUS_TOKEN",
"format": "string",
"isSecret": true,
"description": "Hosted API token (nimb_…) minted in Nimbus Studio → Account → API tokens. Not needed if you already ran `nimbus-mcp login`."
},
{
"name": "NIMBUS_TOKEN_FILE",
"format": "string",
"description": "Path to a 0600 JSON file {\"token\": \"…\"} holding a hosted API token (keeps secrets out of MCP configs)."
},
{
"name": "NIMBUS_MCP_KEY",
"format": "string",
"isSecret": true,
"description": "Local-backend key; must match MCP_LOCAL_KEY on your Nimbus backend (dev server) or the desktop app's key."
},
{
"name": "NIMBUS_MCP_KEY_FILE",
"format": "string",
"description": "Path to a local-backend key file. The desktop app's mcp-key.json is auto-discovered without this."
}
]
}
],
"repository": {
"url": "https://github.com/nimbusbci/nimbus-mcp",
"source": "github"
},
"description": "AI agents build, train, and analyze BCI/EEG pipelines: data, models, experiments, live sessions."
}