Koskamo

Nimbus BCI MCP

An MCP server enabling AI agents to build, validate, run, and analyze EEG/BCI pipelines. It supports uploading EEG data, persisting pipelines to studio projects, running experiment campaigns on public datasets like MOABB/BNCI, rendering plots, and exporting BIDS formats via a hosted backend or local deployment.

Endpoint and access

No sign-in to connect and list tools. Individual tools may still need a vendor account, credentials, or permissions; check the documented prerequisites.

Nimbus BCI MCP logo, by Nimbus BCICommunity listingStreamable HTTPNo sign-inEndpoint checked 2026-11-07Published by Nimbus BCI
You need:Custom connectors may require a paid Claude plancreate one on the Studio Account page
MCP endpoint (Streamable HTTP)
https://nimbus-mcp.fly.dev/mcp
Vendor documentation

What its tools do

63 tools, grouped by the hints the server advertises. Hints are self-declared, not verified behavior.

63 of 63 have a description · 63 of 63 declare behavior hints · 59 of 59 with parameters document them all

Checks and signals

Each line is separate evidence, not a trust score.

  • Passed Endpoint answered the live check ·
  • Availability 1 of 1 checks passed in 30 days

What you can do with it

  • Build and validate EEG/BCI pipelines
  • Run experiment campaigns on public datasets
  • Analyze results and render plots
  • Export data in BIDS format

Source and maintenance

Community listingRegistry 0.14.21
Maintenance checked

Protocol and capabilities

Server
nimbus 0.14.21
MCP protocol negotiated in check
2025-11-25
Tools
63 advertised
Resources
0 advertised
Resource templates
0 advertised
Prompts
5 advertised
Server-advertised capabilities
{
  "tools": {
    "listChanged": true
  },
  "logging": {},
  "prompts": {
    "listChanged": true
  },
  "resources": {
    "subscribe": false,
    "listChanged": true
  }
}

Server-provided instructions

Untrusted server output shown for inspection. It is not Koskamo guidance and is excluded from knowledge search.

Nimbus Studio BCI tools. Typical flows: 0) Auth: Local Free needs NO Nimbus Studio login — templates, own data, local execution/plots/stats, BIDS export and local storage work anonymously against the local backend (desktop app / dev backend). account.whoami() shows the mode, account, plan, quota, and (token mode) token expiry. Login is requested ONLY at first cloud value: a tool returning {ok: false, loginRequired: true, trigger} names why and how to authenticate (nimbus-mcp login / NIMBUS_TOKEN) — surface that, do not pre-emptively ask for credentials. {ok: false, tierGate: true} means a hosted Pro feature on a free account. {ok: false, setupRequired: true} now only appears when a credential was rejected or no local identity exists — walk the user through the options in that payload. 1) Explore: catalog.nodes / catalog.node_schema / catalog.templates / catalog.template / catalog.datasets; catalog.leaderboard ranks benchmark pipelines per dataset (meanAccuracyPct desc) — pick templates by ranking there. 1b) INSPECT BEFORE BUILDING: data.inspect_dataset(dataset, subject) or data.inspect_file(path) show channels, class balance, flatlined channels, band powers — class balance drives stratification; units are ASSUMED volts (a µV-native CSV reads 1e6x large; set unitsScale in custom_data config when needed). 2) Build: compose a train graph ({nodes: [{id, type, config}], connections: [{from, to}]}), pipeline.validate it, then execution.run (non-blocking) and poll execution.get. 3) Sweeps: experiment.run (1-25 paced runs, <=2 concurrent) then poll experiment.get for per-run status and aggregated metrics (mean/std/best). 4) Results: execution.results (kappa, ITR, confusion matrix), execution.artifacts / execution.download_artifact, pipeline.export for a standalone zip. 4b) Share/audit: bids.export_dataset / bids.export_execution produce BIDS-layout zips with sha256 manifests. 4c) SEE the results: plots.confusion / plots.dataset / plots.erp / plots.leaderboard render PNG figures you can look at (not just JSON numbers); stats.grouped pools per-subject accuracies across runs into cluster-aware stats (t-interval + t-test vs chance) - the review-grade companion to execution.results. 5) Live (use with care): device.list, device.test, then stream.start(confirm=true) only with the user's explicit go-ahead — it connects an EEG device to a human session. An idle watchdog stops abandoned sessions; polling stream.status keeps them alive. stream.telemetry works with OR without a deployed model: modelless streams report signal quality + focus/relaxation band-power indicators (latestPrediction null). 6) Personal calibration: calibration.start(confirm=true) while the subject wears the device — the Studio app shows cues; calibration.status polls; calibration.train turns the recording into the subject's own classifier. 6b) Neurofeedback protocols: protocol.validate iterates the document (verdict data, no throw), protocol.save(confirm=true) versions it, protocol.list shows saved protocols with versions, protocol.start_assignment(confirm=true) enrolls a subject and prepares the deploy session (yoked sham arms need a donor recording upload); simulated-source sessions are free, live hardware requires Pro. Poll protocol.session_status, pause/resume/stop drive the session, protocol.export_stats gives paired pre/post stats + figure + CSV (inferential from 3 completed sessions). 7) BYO model code: python.validate(script) statically checks a python_model class (fit/predict contract, no execution), then run it via execution.run with the code inline in the node config (runtime auto|local|cloud — desktop app: isolated local worker; hosted web app: ephemeral cloud sandbox with optional per-run pip requirements); leaderboard.submit scores a model class server-side (LOSO). 8) Foundation-model lane: foundation_features(backbone=reve|labram|eegpt|cbramod| biot|steegformer|codebrain) — 7 pretrained EEG backbones; frozen embeddings feed any head. foundation.compare(source/dataset/subject) runs EVERY backbone on YOUR data once (frozen embed + LDA 5-fold CV) and returns a ranked chart with CIs, params, and wall time — pick the backbone by measurement, not vibes. See catalog.leaderboard(track=pretrained_few_trial) for which currently wins at the 100-trial budget. Note: expect filter/ASR warm-up periods and confidence to start low; signal quality matters.

Tools

63 advertised

account.whoami — Who Am I
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

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.

account.whoami input schema
{
  "type": "object",
  "properties": {},
  "additionalProperties": false
}
account.whoami output schema
{
  "type": "object",
  "additionalProperties": true
}
account.whoami annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
catalog.nodes — List Pipeline Nodes
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

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.nodes input schema
{
  "type": "object",
  "properties": {
    "category": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional filter by category id — e.g. \"data\",\n\"preprocessing\", \"feature\", \"model\" (singular ids; plurals such\nas \"models\"/\"features\" are accepted). An unknown category is an\nerror that lists the valid ids."
    }
  },
  "additionalProperties": false
}
catalog.nodes output schema
{
  "type": "object",
  "additionalProperties": true
}
catalog.nodes annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
catalog.node_schema — Node Config Schema
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Full config JSON schema + input/output ports for one node type.

catalog.node_schema input schema
{
  "type": "object",
  "required": [
    "node_type"
  ],
  "properties": {
    "node_type": {
      "type": "string",
      "description": "Node id from catalog.nodes (e.g. \"csp\", \"nimbus_lda\")."
    }
  },
  "additionalProperties": false
}
catalog.node_schema output schema
{
  "type": "object",
  "additionalProperties": true
}
catalog.node_schema annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
catalog.templates — List Pipeline Templates
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

List built-in starter pipelines (MI/P300/SSVEP...). catalog.template(id) returns the graph. Each row carries ``datasetId`` (catalog id, e.g. "BNCI2014_001" — the id catalog.leaderboard and catalog.datasets use) and ``paradigm`` when the template loads a public dataset.

catalog.templates input schema
{
  "type": "object",
  "properties": {
    "dataset": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Only templates on this dataset id (e.g. \"BNCI2014_001\"); case-insensitive."
    },
    "paradigm": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Only templates with this paradigm (e.g. \"motor_imagery\", \"p300\", \"ssvep\")."
    }
  },
  "additionalProperties": false
}
catalog.templates output schema
{
  "type": "object",
  "additionalProperties": true
}
catalog.templates annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
catalog.template — Get Pipeline Template
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Full template incl. the 'train' execGraph needed by execution.run/pipeline.validate.

catalog.template input schema
{
  "type": "object",
  "required": [
    "template_id"
  ],
  "properties": {
    "template_id": {
      "type": "string",
      "description": "Template id from catalog.templates (e.g. \"mi_csp_lda\")."
    }
  },
  "additionalProperties": false
}
catalog.template output schema
{
  "type": "object",
  "additionalProperties": true
}
catalog.template annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
catalog.datasets — List Datasets
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Curated public EEG datasets (MOABB packs) available to pipelines.

catalog.datasets input schema
{
  "type": "object",
  "properties": {
    "only_on_disk": {
      "type": "boolean",
      "default": true,
      "description": "Only return datasets whose data packs are present on this\nbackend (True by default; False also lists known-but-missing sets)."
    }
  },
  "additionalProperties": false
}
catalog.datasets output schema
{
  "type": "object",
  "additionalProperties": true
}
catalog.datasets annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
catalog.leaderboard — Leaderboard
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

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.leaderboard input schema
{
  "type": "object",
  "properties": {
    "dataset_id": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional dataset id. When set, every track is filtered\nto that dataset. Omit it for the full board."
    }
  },
  "additionalProperties": false
}
catalog.leaderboard output schema
{
  "type": "object",
  "additionalProperties": true
}
catalog.leaderboard annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
leaderboard.submit — Submit to Leaderboard
Advertised by the server during the last successful anonymous check.
Open-world

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.

leaderboard.submit input schema
{
  "type": "object",
  "required": [
    "dataset_id",
    "name"
  ],
  "properties": {
    "code": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Python source defining a class with fit(X, y, info) and\npredict(X) (<=256KB; validate first with python.validate).\nRequired unless backbone_repo is set."
    },
    "name": {
      "type": "string",
      "description": "Display name on the board (<=100 chars)."
    },
    "track": {
      "enum": [
        "cross_subject",
        "pretrained_few_trial"
      ],
      "type": "string",
      "default": "cross_subject",
      "description": "\"cross_subject\" (default — full-data leave-one-subject-out,\nseed 42) or \"pretrained_few_trial\" (efficiency track: LOSO with\na protocol-fixed 100-trials-per-subject cap; code that imports\ntorch must declare its trained parameter count as a class\nattribute — PARAMS_TRAINED = <int> — which becomes the row's\nparamsTrained and is cross-checked when computable)."
    },
    "class_name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Contract class to instantiate; omit to auto-detect."
    },
    "dataset_id": {
      "type": "string",
      "description": "A dataset id from catalog.leaderboard\n``submittableDatasets`` (e.g. \"BNCI2014_001\"). A dataset can\nappear under crossSubject and still be closed for submission\n(BNCI2014_008 is scored there and is not in the open set)."
    },
    "requirements": {
      "anyOf": [
        {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional PyPI requirements (e.g. [\"sklearn>=1.4\"])."
    },
    "verification": {
      "enum": [
        "verified",
        "unverified_local"
      ],
      "type": "string",
      "default": "verified",
      "description": "\"verified\" (default; server-side scored, Pro on\nthe hosted backend) or \"unverified_local\" (Account-Free\nlocally-computed lane; see the tool description for its\ncurrent backend status)."
    },
    "backbone_kind": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Checkpoint family for the BYO backbone lane — one\nof the zoo's supported kinds (e.g. \"cbramod\", \"labram\")."
    },
    "backbone_repo": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "HF 'org/name' repo id for the BYO backbone lane."
    },
    "backbone_license": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "License declared for the backbone checkpoint."
    },
    "backbone_revision": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Full 40-char commit SHA pinning the backbone."
    }
  },
  "additionalProperties": false
}
leaderboard.submit output schema
{
  "type": "object",
  "additionalProperties": true
}
leaderboard.submit annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}
leaderboard.status — Leaderboard Submission Status
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

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.status input schema
{
  "type": "object",
  "required": [
    "submission_id"
  ],
  "properties": {
    "submission_id": {
      "type": "string",
      "description": "The submissionId returned by leaderboard.submit."
    }
  },
  "additionalProperties": false
}
leaderboard.status output schema
{
  "type": "object",
  "additionalProperties": true
}
leaderboard.status annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
leaderboard.mine — My Leaderboard Submissions
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

List your leaderboard submissions (newest first), all datasets.

leaderboard.mine input schema
{
  "type": "object",
  "properties": {},
  "additionalProperties": false
}
leaderboard.mine output schema
{
  "type": "object",
  "additionalProperties": true
}
leaderboard.mine annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
pipeline.validate — Validate Pipeline
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

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 input schema
{
  "type": "object",
  "required": [
    "train_graph"
  ],
  "properties": {
    "train_graph": {
      "type": "object",
      "description": "The graph to validate ({nodes, connections}).",
      "additionalProperties": true
    }
  },
  "additionalProperties": false
}
pipeline.validate output schema
{
  "type": "object",
  "additionalProperties": true
}
pipeline.validate annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
pipeline.validate_node — Validate Node Config
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

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).

pipeline.validate_node input schema
{
  "type": "object",
  "required": [
    "node_type",
    "config"
  ],
  "properties": {
    "config": {
      "type": "object",
      "description": "The node's config object to check.",
      "additionalProperties": true
    },
    "dataset": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional MOABB pack id (e.g. \"BNCI2014_001\") so CSP/Nyquist\nchecks can use channel count and sampling rate. Omitted → those\ncontext checks are skipped; inverted-band checks still run."
    },
    "node_type": {
      "type": "string",
      "description": "Node type id from catalog.nodes (e.g. \"csp\", \"bandpass_filter\")."
    }
  },
  "additionalProperties": false
}
pipeline.validate_node output schema
{
  "type": "object",
  "additionalProperties": true
}
pipeline.validate_node annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
execution.run — Run Pipeline
Advertised by the server during the last successful anonymous check.
Open-world

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). The server runs a limited number of executions at once (3 by default); when all slots are busy the call fails immediately with 429 nimbus.execution.queue_full and a retryAfter (seconds) — wait, then retry.

execution.run input schema
{
  "type": "object",
  "required": [
    "train_graph"
  ],
  "properties": {
    "name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Display name for the run (shown in the Runs list)."
    },
    "layout": {
      "anyOf": [
        {
          "type": "object",
          "additionalProperties": true
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional canvas positions {nodes: {id: {x, y}}}; a deterministic\ngrid is synthesized when omitted."
    },
    "subject": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional dataset subject code (e.g. \"S01\") recorded with the run."
    },
    "description": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional longer description of the experiment."
    },
    "train_graph": {
      "type": "object",
      "description": "Pipeline graph {nodes: [{id, type, config}], connections:\n[{from, to}]} as built by catalog.template/pipeline.validate.",
      "additionalProperties": true
    }
  },
  "additionalProperties": false
}
execution.run output schema
{
  "type": "object",
  "additionalProperties": true
}
execution.run annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}
execution.cancel — Cancel Run
Advertised by the server during the last successful anonymous check.
Advertised destructiveOpen-world

Cancel a running execution.

execution.cancel input schema
{
  "type": "object",
  "required": [
    "execution_id"
  ],
  "properties": {
    "execution_id": {
      "type": "string",
      "description": "The run to terminate (from execution.run/execution.list)."
    }
  },
  "additionalProperties": false
}
execution.cancel output schema
{
  "type": "object",
  "additionalProperties": true
}
execution.cancel annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": true
}
execution.delete — Delete Run
Advertised by the server during the last successful anonymous check.
Advertised destructiveOpen-world

Permanently delete one of your finished runs (completed/failed/cancelled) with its results. Running runs must be cancelled first (409 nimbus.execution.delete_not_terminal). Owner only.

execution.delete input schema
{
  "type": "object",
  "required": [
    "execution_id"
  ],
  "properties": {
    "confirm": {
      "type": "boolean",
      "default": false,
      "description": "MUST be true to delete — the explicit user go-ahead."
    },
    "execution_id": {
      "type": "string",
      "description": "The run to delete (from execution.run/execution.list)."
    }
  },
  "additionalProperties": false
}
execution.delete output schema
{
  "type": "object",
  "additionalProperties": true
}
execution.delete annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": true
}
execution.get — Get Run
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Execution status summary (status: running/completed/failed/cancelled). Summary fields: ``dataset`` is the human-readable display label (e.g. "BCIIV2a"); ``datasetId`` is the catalog id (e.g. "BNCI2014_001") accepted by other tools (data.inspect_dataset, public_data.dataset). ``title`` is the run name shown in Studio.

execution.get input schema
{
  "type": "object",
  "required": [
    "execution_id"
  ],
  "properties": {
    "execution_id": {
      "type": "string",
      "description": "The run to check (from execution.run/execution.list)."
    }
  },
  "additionalProperties": false
}
execution.get output schema
{
  "type": "object",
  "additionalProperties": true
}
execution.get annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
execution.list — List Runs
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Recent executions. Optional status filter (running/completed/failed/cancelled). Per-run fields: ``dataset`` is the human-readable display label (e.g. "BCIIV2a"); ``datasetId`` is the catalog id (e.g. "BNCI2014_001") accepted by other tools (data.inspect_dataset, public_data.dataset). ``title`` is the run name shown in Studio.

execution.list input schema
{
  "type": "object",
  "properties": {
    "limit": {
      "type": "integer",
      "default": 20,
      "description": "Maximum number of runs to return (default 20)."
    },
    "status": {
      "enum": [
        "running",
        "completed",
        "failed",
        "cancelled",
        null
      ],
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Filter by run status: running/completed/failed/cancelled."
    }
  },
  "additionalProperties": false
}
execution.list output schema
{
  "type": "object",
  "additionalProperties": true
}
execution.list annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
execution.results — Run Results
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Metrics for a completed run. Trimmed by default (accuracy, kappa, ITR, confusion matrix, per-class); full=True returns the complete result object.

execution.results input schema
{
  "type": "object",
  "required": [
    "execution_id"
  ],
  "properties": {
    "full": {
      "type": "boolean",
      "default": false,
      "description": "Return the backend's complete result object (all fields)."
    },
    "execution_id": {
      "type": "string",
      "description": "The completed run to fetch metrics for."
    }
  },
  "additionalProperties": false
}
execution.results output schema
{
  "type": "object",
  "additionalProperties": true
}
execution.results annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
calibration.start — Start Calibration
Advertised by the server during the last successful anonymous check.
Open-world

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.start input schema
{
  "type": "object",
  "properties": {
    "name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Display name recorded on the execution."
    },
    "port": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Serial/COM port for wired devices."
    },
    "classes": {
      "anyOf": [
        {
          "type": "array",
          "items": {
            "type": "object",
            "additionalProperties": true
          }
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Override class list [{id,label,cue}] (MI default: left/right hand)."
    },
    "confirm": {
      "type": "boolean",
      "default": false,
      "description": "MUST be true — explicit user go-ahead for a session on their head."
    },
    "ip_port": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Port for network devices."
    },
    "paradigm": {
      "type": "string",
      "default": "mi",
      "description": "mi | p300 | sart | target_hit."
    },
    "source_id": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "LSL source id."
    },
    "ip_address": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Device IP for network/wifi devices."
    },
    "device_type": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Device id from device.list (omit → template default synthetic)."
    },
    "mac_address": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Bluetooth MAC (BT devices)."
    },
    "stream_name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "LSL stream name (LSL devices)."
    },
    "serial_number": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Device serial (some BLE stacks)."
    },
    "connection_type": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Device selector when several exist (e.g. serial vs wifi)."
    },
    "trials_per_class": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Override the template's trial count (minimum 5)."
    }
  },
  "additionalProperties": false
}
calibration.start output schema
{
  "type": "object",
  "additionalProperties": true
}
calibration.start annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}
calibration.status — Calibration Status
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

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.status input schema
{
  "type": "object",
  "required": [
    "execution_id"
  ],
  "properties": {
    "execution_id": {
      "type": "string",
      "description": "The calibration run to inspect (from calibration.start)."
    }
  },
  "additionalProperties": false
}
calibration.status output schema
{
  "type": "object",
  "additionalProperties": true
}
calibration.status annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
calibration.pause — Pause Calibration
Advertised by the server during the last successful anonymous check.
Open-world

Pause a running calibration between trials (cues hold; resume anytime).

calibration.pause input schema
{
  "type": "object",
  "required": [
    "execution_id"
  ],
  "properties": {
    "execution_id": {
      "type": "string",
      "description": "The calibration run to pause."
    }
  },
  "additionalProperties": false
}
calibration.pause output schema
{
  "type": "object",
  "additionalProperties": true
}
calibration.pause annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}
calibration.resume — Resume Calibration
Advertised by the server during the last successful anonymous check.
Open-world

Resume a paused calibration session.

calibration.resume input schema
{
  "type": "object",
  "required": [
    "execution_id"
  ],
  "properties": {
    "execution_id": {
      "type": "string",
      "description": "The calibration run to resume."
    }
  },
  "additionalProperties": false
}
calibration.resume output schema
{
  "type": "object",
  "additionalProperties": true
}
calibration.resume annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}
calibration.train — Train Calibration Model
Advertised by the server during the last successful anonymous check.
Open-world

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.

calibration.train input schema
{
  "type": "object",
  "required": [
    "execution_id"
  ],
  "properties": {
    "name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Display name recorded on the training run."
    },
    "paradigm": {
      "type": "string",
      "default": "mi",
      "description": "Paradigm of the recording (mi | p300 | sart | target_hit);\nmi and p300 have default train templates."
    },
    "template_id": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Train template to use (e.g. from catalog.templates);\nrequired for sart/target_hit (mi defaults to mi_headband_csp_lda,\np300 to p300_hardware_xdawn_lda)."
    },
    "train_graph": {
      "anyOf": [
        {
          "type": "object",
          "additionalProperties": true
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Explicit train graph instead of a template; its first\ndata node (custom_data/public_data) is rewired onto the recording."
    },
    "execution_id": {
      "type": "string",
      "description": "The COMPLETED calibration run (from calibration.start)."
    }
  },
  "additionalProperties": false
}
calibration.train output schema
{
  "type": "object",
  "additionalProperties": true
}
calibration.train annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}
experiment.run — Run Experiment
Advertised by the server during the last successful anonymous check.
Open-world

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).

experiment.run input schema
{
  "type": "object",
  "required": [
    "runs"
  ],
  "properties": {
    "runs": {
      "type": "array",
      "items": {
        "type": "object",
        "additionalProperties": true
      },
      "description": "1-25 entries, each {name: str, train_graph: {nodes, connections}}\n(same graph shape as execution.run's train_graph)."
    },
    "max_concurrent": {
      "type": "integer",
      "default": 2,
      "description": "Parallel submissions cap, clamped to 1-2 (default 2)."
    }
  },
  "additionalProperties": false
}
experiment.run output schema
{
  "type": "object",
  "additionalProperties": true
}
experiment.run annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}
experiment.delete — Delete Experiment
Advertised by the server during the last successful anonymous check.
Advertised destructiveOpen-world

Delete one of your experiment records (server + this machine's local cache). Its individual runs are kept — delete them with execution.delete. A still-running experiment cannot be deleted.

experiment.delete input schema
{
  "type": "object",
  "required": [
    "experiment_id"
  ],
  "properties": {
    "confirm": {
      "type": "boolean",
      "default": false,
      "description": "MUST be true to delete — the explicit user go-ahead."
    },
    "experiment_id": {
      "type": "string",
      "description": "The experiment to delete (from experiment.run)."
    }
  },
  "additionalProperties": false
}
experiment.delete output schema
{
  "type": "object",
  "additionalProperties": true
}
experiment.delete annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": true
}
experiment.get — Get Experiment
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

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.get input schema
{
  "type": "object",
  "required": [
    "experiment_id"
  ],
  "properties": {
    "experiment_id": {
      "type": "string",
      "description": "The experiment to inspect (from experiment.run)."
    }
  },
  "additionalProperties": false
}
experiment.get output schema
{
  "type": "object",
  "additionalProperties": true
}
experiment.get annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
execution.artifacts — List Run Artifacts
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Trained artifacts (models/filters, e.g. *.pkl) saved by an execution.

execution.artifacts input schema
{
  "type": "object",
  "required": [
    "execution_id"
  ],
  "properties": {
    "execution_id": {
      "type": "string",
      "description": "Run whose artifacts to list."
    }
  },
  "additionalProperties": false
}
execution.artifacts output schema
{
  "type": "object",
  "additionalProperties": true
}
execution.artifacts annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
execution.download_artifact — Download Run Artifact
Advertised by the server during the last successful anonymous check.
Open-world

Download one artifact file. Local/stdio: saved to NIMBUS_EXPORT_DIR/executions/<id>/ and its path returned. Hosted gateway: returned inline as ``contentBase64`` (up to 1 MB of base64); larger files point to Nimbus Studio. Nothing is written on the gateway.

execution.download_artifact input schema
{
  "type": "object",
  "required": [
    "execution_id",
    "artifact_name"
  ],
  "properties": {
    "execution_id": {
      "type": "string",
      "description": "Run that produced the artifact."
    },
    "artifact_name": {
      "type": "string",
      "description": "File name from execution.artifacts (e.g. \"nimbus_lda.pkl\")."
    }
  },
  "additionalProperties": false
}
execution.download_artifact output schema
{
  "type": "object",
  "additionalProperties": true
}
execution.download_artifact annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
pipeline.export — Export Pipeline
Advertised by the server during the last successful anonymous check.
Open-world

Export the pipeline as a standalone runnable Python bundle (zip). Local/stdio: the zip is saved under NIMBUS_EXPORT_DIR/exports and its path returned. Hosted gateway: the zip is returned inline as ``contentBase64`` (up to 1 MB of base64). UI-only nodes (interactive_application) are left out and listed in ``exportNotes``.

pipeline.export input schema
{
  "type": "object",
  "required": [
    "train_graph"
  ],
  "properties": {
    "name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional name recorded inside the bundle."
    },
    "train_graph": {
      "type": "object",
      "description": "Pipeline graph {nodes, connections} to export.",
      "additionalProperties": true
    }
  },
  "additionalProperties": false
}
pipeline.export output schema
{
  "type": "object",
  "additionalProperties": true
}
pipeline.export annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
bids.export_dataset — Export Dataset as BIDS
Advertised by the server during the last successful anonymous check.
Open-world

Export a Nimbus dataset as a BIDS-layout zip (local: saved to NIMBUS_EXPORT_DIR/bids/; hosted gateway: inline ``contentBase64``, up to 1 MB). 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_dataset input schema
{
  "type": "object",
  "required": [
    "dataset"
  ],
  "properties": {
    "kind": {
      "enum": [
        "auto",
        "pack",
        "upload",
        "recording",
        null
      ],
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional explicit source kind: pack|upload|recording (default auto)."
    },
    "dataset": {
      "type": "string",
      "description": "Dataset id — a MOABB pack id (e.g. \"BNCI2014_001\"), an upload\npath (as returned by data.upload), or a recording name. Auto-detected."
    },
    "subjects": {
      "anyOf": [
        {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Pack exports only — subject filter (e.g. [\"S01\", \"S03\"]) to\nbound zip size; default exports all installed subjects."
    }
  },
  "additionalProperties": false
}
bids.export_dataset output schema
{
  "type": "object",
  "additionalProperties": true
}
bids.export_dataset annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
bids.export_execution — Export Run as BIDS
Advertised by the server during the last successful anonymous check.
Open-world

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). Local: saved to NIMBUS_EXPORT_DIR/bids/. Hosted gateway: inline ``contentBase64`` (up to 1 MB of base64); larger zips point to Nimbus Studio.

bids.export_execution input schema
{
  "type": "object",
  "required": [
    "execution_id"
  ],
  "properties": {
    "execution_id": {
      "type": "string",
      "description": "Run whose results to export (from execution.run)."
    }
  },
  "additionalProperties": false
}
bids.export_execution output schema
{
  "type": "object",
  "additionalProperties": true
}
bids.export_execution annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
device.list — List EEG Devices
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

EEG devices supported by this backend (OpenBCI, Muse, BrainBit, LSL, PiEEG...).

device.list input schema
{
  "type": "object",
  "properties": {},
  "additionalProperties": false
}
device.list output schema
{
  "type": "object",
  "additionalProperties": true
}
device.list annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
device.test — Test EEG Device
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Test a device connection WITHOUT starting a stream (safe, no confirm needed).

device.test input schema
{
  "type": "object",
  "required": [
    "device_type"
  ],
  "properties": {
    "port": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Serial/COM port for wired devices."
    },
    "ip_port": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Port for network devices."
    },
    "source_id": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "LSL source id."
    },
    "ip_address": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Device IP for network/wifi devices."
    },
    "device_type": {
      "type": "string",
      "description": "Device id from device.list (e.g. \"brainbit\", \"muse\")."
    },
    "mac_address": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Bluetooth MAC (BT devices)."
    },
    "stream_name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "LSL stream name (LSL devices)."
    },
    "serial_number": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Device serial (some BLE stacks)."
    },
    "connection_type": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Device-specific selector when several exist (e.g. serial vs wifi)."
    }
  },
  "additionalProperties": false
}
device.test output schema
{
  "type": "object",
  "additionalProperties": true
}
device.test annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
stream.start — Start EEG Stream
Advertised by the server during the last successful anonymous check.
Open-world

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.start input schema
{
  "type": "object",
  "required": [
    "device_type"
  ],
  "properties": {
    "port": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Serial/COM port for wired devices."
    },
    "confirm": {
      "type": "boolean",
      "default": false,
      "description": "MUST be true to start — the explicit user go-ahead for a live\nsession on their head; anything else is refused with zero requests."
    },
    "ip_port": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Port for network devices."
    },
    "source_id": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "LSL source id."
    },
    "chunk_size": {
      "type": "integer",
      "default": 125,
      "description": "Samples per streamed chunk (default 125)."
    },
    "ip_address": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Device IP for network/wifi devices."
    },
    "n_channels": {
      "type": "integer",
      "default": 8,
      "description": "Channel count to open (default 8)."
    },
    "session_id": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional existing session to resume/reuse."
    },
    "device_type": {
      "type": "string",
      "description": "Device id from device.list (e.g. \"brainbit\")."
    },
    "mac_address": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Bluetooth MAC (BT devices)."
    },
    "stream_name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "LSL stream name (LSL devices)."
    },
    "serial_number": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Device serial (some BLE stacks)."
    },
    "connection_type": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Device-specific selector (e.g. serial vs wifi)."
    },
    "idle_timeout_sec": {
      "type": "integer",
      "default": 900,
      "description": "Watchdog: stop+disconnect after this many seconds\nwithout a status poll (default 900; 0 disables)."
    }
  },
  "additionalProperties": false
}
stream.start output schema
{
  "type": "object",
  "additionalProperties": true
}
stream.start annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}
stream.status — EEG Stream Status
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

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.status input schema
{
  "type": "object",
  "required": [
    "session_id"
  ],
  "properties": {
    "session_id": {
      "type": "string",
      "description": "The streaming session to inspect."
    }
  },
  "additionalProperties": false
}
stream.status output schema
{
  "type": "object",
  "additionalProperties": true
}
stream.status annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
stream.stop — Stop EEG Stream
Advertised by the server during the last successful anonymous check.
Advertised destructiveOpen-world

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.stop input schema
{
  "type": "object",
  "required": [
    "session_id"
  ],
  "properties": {
    "session_id": {
      "type": "string",
      "description": "The streaming session to stop."
    }
  },
  "additionalProperties": false
}
stream.stop output schema
{
  "type": "object",
  "additionalProperties": true
}
stream.stop annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": true
}
plots.confusion — Plot Confusion Matrix
Advertised by the server during the last successful anonymous check.
Open-world

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.confusion input schema
{
  "type": "object",
  "required": [
    "execution_id"
  ],
  "properties": {
    "save": {
      "type": "boolean",
      "default": false,
      "description": "Local/stdio: also write the PNG to NIMBUS_EXPORT_DIR/plots/ and return\nits path. Ignored on the hosted gateway (the image is returned inline)."
    },
    "matrix": {
      "type": "string",
      "default": "eval",
      "description": "\"eval\" (held-out, default) or \"train\" (fit-set / cross-validation).\nCV and evaluation-plan runs often have no eval matrix — use \"train\"."
    },
    "execution_id": {
      "type": "string",
      "description": "Run to plot (from execution.run / execution.results)."
    }
  },
  "additionalProperties": false
}
plots.confusion output schema
{
  "type": "object",
  "required": [
    "ok"
  ],
  "properties": {
    "ok": {
      "type": "boolean"
    },
    "meta": {
      "type": "object",
      "description": "Figure sidecar. foundation.compare includes results/best/skipped (also as a JSON text content block).",
      "additionalProperties": true
    },
    "title": {
      "type": [
        "string",
        "null"
      ]
    },
    "mimeType": {
      "type": "string"
    },
    "savedPath": {
      "type": "string",
      "description": "Set when save=true."
    },
    "sizeBytes": {
      "type": "integer",
      "description": "Set when save=true."
    }
  }
}
plots.confusion annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
plots.dataset — Plot Dataset
Advertised by the server during the last successful anonymous check.
Open-world

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.dataset input schema
{
  "type": "object",
  "required": [
    "kind",
    "source"
  ],
  "properties": {
    "band": {
      "enum": [
        "delta",
        "theta",
        "alpha",
        "beta",
        "gamma"
      ],
      "type": "string",
      "default": "alpha",
      "description": "Band for kind=topomap: delta|theta|alpha|beta|gamma (default alpha)."
    },
    "kind": {
      "enum": [
        "psd",
        "topomap",
        "bandpower",
        "spectrogram"
      ],
      "type": "string",
      "description": "Figure type: psd | topomap | bandpower | spectrogram."
    },
    "mode": {
      "enum": [
        "training",
        "evaluation",
        "all"
      ],
      "type": "string",
      "default": "all",
      "description": "Pack split to load: training | evaluation | all (source=dataset)."
    },
    "path": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Upload path (source=upload) or absolute local path (source=local)."
    },
    "save": {
      "type": "boolean",
      "default": false,
      "description": "Local/stdio: also write the PNG to NIMBUS_EXPORT_DIR/plots/ and return\nits path. Ignored on the hosted gateway (the image is returned inline)."
    },
    "source": {
      "enum": [
        "dataset",
        "upload",
        "local"
      ],
      "type": "string",
      "description": "\"dataset\" (MOABB pack), \"upload\" (path from data.upload), or\n\"local\" (absolute path, local backend only)."
    },
    "dataset": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "MOABB dataset id, e.g. \"BNCI2014_001\" (source=dataset)."
    },
    "subject": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Subject id, e.g. \"S01\" (source=dataset)."
    },
    "channel_idx": {
      "type": "integer",
      "default": 0,
      "description": "0-based channel for kind=spectrogram (default 0)."
    }
  },
  "additionalProperties": false
}
plots.dataset output schema
{
  "type": "object",
  "required": [
    "ok"
  ],
  "properties": {
    "ok": {
      "type": "boolean"
    },
    "meta": {
      "type": "object",
      "description": "Figure sidecar. foundation.compare includes results/best/skipped (also as a JSON text content block).",
      "additionalProperties": true
    },
    "title": {
      "type": [
        "string",
        "null"
      ]
    },
    "mimeType": {
      "type": "string"
    },
    "savedPath": {
      "type": "string",
      "description": "Set when save=true."
    },
    "sizeBytes": {
      "type": "integer",
      "description": "Set when save=true."
    }
  }
}
plots.dataset annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
plots.erp — Plot ERP
Advertised by the server during the last successful anonymous check.
Open-world

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.erp input schema
{
  "type": "object",
  "required": [
    "source"
  ],
  "properties": {
    "mode": {
      "enum": [
        "training",
        "evaluation",
        "all"
      ],
      "type": "string",
      "default": "all",
      "description": "Pack split to load: training | evaluation | all (source=dataset)."
    },
    "path": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Upload path (source=upload) or absolute local path (source=local)."
    },
    "save": {
      "type": "boolean",
      "default": false,
      "description": "Local/stdio: also write the PNG to NIMBUS_EXPORT_DIR/plots/ and return\nits path. Ignored on the hosted gateway (the image is returned inline)."
    },
    "source": {
      "enum": [
        "dataset",
        "upload",
        "local"
      ],
      "type": "string",
      "description": "\"dataset\" (MOABB pack), \"upload\" (path from data.upload), or\n\"local\" (absolute path, local backend only)."
    },
    "dataset": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "MOABB dataset id, e.g. \"BNCI2014_001\" (source=dataset)."
    },
    "subject": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Subject id, e.g. \"S01\" (source=dataset)."
    },
    "max_channels": {
      "type": "integer",
      "default": 16,
      "description": "Channels drawn per class subplot (default 16, max 64)."
    }
  },
  "additionalProperties": false
}
plots.erp output schema
{
  "type": "object",
  "required": [
    "ok"
  ],
  "properties": {
    "ok": {
      "type": "boolean"
    },
    "meta": {
      "type": "object",
      "description": "Figure sidecar. foundation.compare includes results/best/skipped (also as a JSON text content block).",
      "additionalProperties": true
    },
    "title": {
      "type": [
        "string",
        "null"
      ]
    },
    "mimeType": {
      "type": "string"
    },
    "savedPath": {
      "type": "string",
      "description": "Set when save=true."
    },
    "sizeBytes": {
      "type": "integer",
      "description": "Set when save=true."
    }
  }
}
plots.erp annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
plots.leaderboard — Plot Leaderboard
Advertised by the server during the last successful anonymous check.
Open-world

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.

plots.leaderboard input schema
{
  "type": "object",
  "required": [
    "dataset_id"
  ],
  "properties": {
    "save": {
      "type": "boolean",
      "default": false,
      "description": "Local/stdio: also write the PNG to NIMBUS_EXPORT_DIR/plots/ and return\nits path. Ignored on the hosted gateway (the image is returned inline)."
    },
    "track": {
      "enum": [
        "within_session",
        "crossSubject",
        "pretrained_few_trial"
      ],
      "type": "string",
      "default": "within_session",
      "description": "\"within_session\" (curated 5-fold), \"crossSubject\" (LOSO,\ncurated + BYO submissions), or \"pretrained_few_trial\" (the\nefficiency track: LOSO at the protocol's fixed per-subject\ntrial budget — the figure also includes the classical LOSO\nbaseline as a muted side panel for comparison)."
    },
    "dataset_id": {
      "type": "string",
      "description": "Dataset to chart, e.g. \"BNCI2014_001\" (see catalog.leaderboard)."
    }
  },
  "additionalProperties": false
}
plots.leaderboard output schema
{
  "type": "object",
  "required": [
    "ok"
  ],
  "properties": {
    "ok": {
      "type": "boolean"
    },
    "meta": {
      "type": "object",
      "description": "Figure sidecar. foundation.compare includes results/best/skipped (also as a JSON text content block).",
      "additionalProperties": true
    },
    "title": {
      "type": [
        "string",
        "null"
      ]
    },
    "mimeType": {
      "type": "string"
    },
    "savedPath": {
      "type": "string",
      "description": "Set when save=true."
    },
    "sizeBytes": {
      "type": "integer",
      "description": "Set when save=true."
    }
  }
}
plots.leaderboard annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
stream.telemetry — EEG Stream Telemetry
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

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.

stream.telemetry input schema
{
  "type": "object",
  "required": [
    "session_id"
  ],
  "properties": {
    "window": {
      "type": "integer",
      "default": 50,
      "description": "How many recent predictions/chunks to include (default 50)."
    },
    "session_id": {
      "type": "string",
      "description": "The streaming session to read telemetry for."
    }
  },
  "additionalProperties": false
}
stream.telemetry output schema
{
  "type": "object",
  "additionalProperties": true
}
stream.telemetry annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
data.upload — Upload Data File
Advertised by the server during the last successful anonymous check.
Open-world

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).

data.upload input schema
{
  "type": "object",
  "required": [
    "file_path"
  ],
  "properties": {
    "format": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Override extension-based detection (auto|mat|csv|tsv|txt|edf|bdf|h5|hdf5)."
    },
    "file_path": {
      "type": "string",
      "description": "Local file to upload (.edf/.bdf/.mat/.csv/.txt/.tsv/.h5/.hdf5, <=500MB)."
    },
    "dataset_name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional label for the uploaded dataset."
    },
    "sampling_rate": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Hz for headerless CSV/TSV/TXT (REQUIRED there, e.g. 250.0)."
    }
  },
  "additionalProperties": false
}
data.upload output schema
{
  "type": "object",
  "additionalProperties": true
}
data.upload annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}
data.delete_upload — Delete Upload
Advertised by the server during the last successful anonymous check.
Advertised destructiveOpen-world

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.delete_upload input schema
{
  "type": "object",
  "required": [
    "path"
  ],
  "properties": {
    "path": {
      "type": "string",
      "description": "Upload path from data.upload (e.g. user_…/file.csv)."
    },
    "confirm": {
      "type": "boolean",
      "default": false,
      "description": "MUST be true to delete — the explicit user go-ahead."
    }
  },
  "additionalProperties": false
}
data.delete_upload output schema
{
  "type": "object",
  "additionalProperties": true
}
data.delete_upload annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": true
}
data.inspect_dataset — Inspect Dataset
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

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 defaults to the dataset's catalog ``defaultSubject`` (see 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_dataset input schema
{
  "type": "object",
  "required": [
    "dataset"
  ],
  "properties": {
    "mode": {
      "enum": [
        "training",
        "evaluation",
        "all"
      ],
      "type": "string",
      "default": "all",
      "description": "Which split to summarize — training | evaluation | all."
    },
    "dataset": {
      "type": "string",
      "description": "Dataset id from catalog.datasets (e.g. \"BNCI2014_001\")."
    },
    "subject": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Subject code (\"S01\") or comma-list cohort (\"S01,S03\"); defaults to\nthe catalog defaultSubject."
    }
  },
  "additionalProperties": false
}
data.inspect_dataset output schema
{
  "type": "object",
  "additionalProperties": true
}
data.inspect_dataset annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
data.inspect_file — Inspect Data File
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

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 with an error that explains how to proceed (upload the file first or switch to a local backend). CSV/TSV/TXT files have no embedded sampling rate: pass sampling_rate (Hz) for them — the backend never assumes 250 Hz. Formats that embed their rate (EDF/BDF/MAT/H5) ignore it.

data.inspect_file input schema
{
  "type": "object",
  "required": [
    "path"
  ],
  "properties": {
    "path": {
      "type": "string",
      "description": "ABSOLUTE filesystem path (`~` is expanded; local backends\nonly) or the RELATIVE upload path returned by data.upload\n(works on any backend)."
    },
    "sampling_rate": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Hz for CSV/TSV/TXT files (REQUIRED there, e.g. 250.0)."
    }
  },
  "additionalProperties": false
}
data.inspect_file output schema
{
  "type": "object",
  "additionalProperties": true
}
data.inspect_file annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
project.create — Create Project
Advertised by the server during the last successful anonymous check.
Open-world

Create a project (container for one pipeline document). Returns projectId.

project.create input schema
{
  "type": "object",
  "required": [
    "name"
  ],
  "properties": {
    "name": {
      "type": "string",
      "description": "Project display name (e.g. \"MI CSP-LDA sweep\")."
    },
    "description": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional longer description shown in the studio."
    }
  },
  "additionalProperties": false
}
project.create output schema
{
  "type": "object",
  "additionalProperties": true
}
project.create annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}
project.list — List Projects
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

List projects owned by the current principal (agent work included).

project.list input schema
{
  "type": "object",
  "properties": {},
  "additionalProperties": false
}
project.list output schema
{
  "type": "object",
  "additionalProperties": true
}
project.list annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
project.save — Save Project Pipeline
Advertised by the server during the last successful anonymous check.
Advertised destructiveOpen-world

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.

project.save input schema
{
  "type": "object",
  "required": [
    "project_id",
    "train_graph",
    "expected_revision"
  ],
  "properties": {
    "name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional pipeline name stored on the document."
    },
    "subject": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional dataset subject code (e.g. \"S01\") for this pipeline."
    },
    "project_id": {
      "type": "string",
      "description": "Target project (from project.create/project.list)."
    },
    "train_graph": {
      "type": "object",
      "description": "Pipeline graph {nodes, connections} to persist.",
      "additionalProperties": true
    },
    "expected_revision": {
      "type": "integer",
      "description": "Optimistic-concurrency base from project.load /\na prior save. Required."
    }
  },
  "additionalProperties": false
}
project.save output schema
{
  "type": "object",
  "additionalProperties": true
}
project.save annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": true
}
project.load — Load Project
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Load a project's saved pipeline (train graph + meta) for editing/re-running.

project.load input schema
{
  "type": "object",
  "required": [
    "project_id"
  ],
  "properties": {
    "project_id": {
      "type": "string",
      "description": "Project whose pipeline document to load."
    }
  },
  "additionalProperties": false
}
project.load output schema
{
  "type": "object",
  "additionalProperties": true
}
project.load annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
project.rename — Rename Project
Advertised by the server during the last successful anonymous check.
Open-world

Rename a project you own (max 200 characters).

project.rename input schema
{
  "type": "object",
  "required": [
    "project_id",
    "name"
  ],
  "properties": {
    "name": {
      "type": "string",
      "description": "New display name."
    },
    "project_id": {
      "type": "string",
      "description": "Project to rename (from project.create/project.list)."
    }
  },
  "additionalProperties": false
}
project.rename output schema
{
  "type": "object",
  "additionalProperties": true
}
project.rename annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
project.delete — Delete Project
Advertised by the server during the last successful anonymous check.
Advertised destructiveOpen-world

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.delete input schema
{
  "type": "object",
  "required": [
    "project_id"
  ],
  "properties": {
    "confirm": {
      "type": "boolean",
      "default": false,
      "description": "MUST be true to delete — the explicit user go-ahead."
    },
    "project_id": {
      "type": "string",
      "description": "Project to delete (from project.create/project.list)."
    }
  },
  "additionalProperties": false
}
project.delete output schema
{
  "type": "object",
  "additionalProperties": true
}
project.delete annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": true
}
protocol.validate — Validate Protocol
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

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.

protocol.validate input schema
{
  "type": "object",
  "required": [
    "spec"
  ],
  "properties": {
    "spec": {
      "type": "object",
      "description": "Wire-format protocol document (camelCase): id, name,\nindicator {name, transform}, armDefaults, blocks\n[{id, kind: assessment|training, durationSec, feedback?}],\nthreshold, sessions, breakCriteria.",
      "additionalProperties": true
    }
  },
  "additionalProperties": false
}
protocol.validate output schema
{
  "type": "object",
  "additionalProperties": true
}
protocol.validate annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
protocol.save — Save Protocol
Advertised by the server during the last successful anonymous check.
Open-world

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.save input schema
{
  "type": "object",
  "required": [
    "spec"
  ],
  "properties": {
    "spec": {
      "type": "object",
      "description": "Wire-format protocol document (validate first to iterate).",
      "additionalProperties": true
    },
    "confirm": {
      "type": "boolean",
      "default": false,
      "description": "MUST be true to write."
    },
    "project_id": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional — bind the version to a project (the project\nprotocol page lists bound ids). Omitted, the id inherits its\nlatest version's binding server-side."
    }
  },
  "additionalProperties": false
}
protocol.save output schema
{
  "type": "object",
  "additionalProperties": true
}
protocol.save annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}
protocol.list — List Protocols
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Every saved protocol id at its latest version.

protocol.list input schema
{
  "type": "object",
  "properties": {
    "project_id": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional — narrow the list to that project's\nprotocols (the project protocol page scope)."
    }
  },
  "additionalProperties": false
}
protocol.list output schema
{
  "type": "object",
  "additionalProperties": true
}
protocol.list annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
protocol.start_assignment — Start Protocol Assignment
Advertised by the server during the last successful anonymous check.
Open-world

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.start_assignment input schema
{
  "type": "object",
  "required": [
    "protocol_id",
    "protocol_version",
    "subject_label",
    "arm"
  ],
  "properties": {
    "arm": {
      "type": "string",
      "description": "active | sham."
    },
    "confirm": {
      "type": "boolean",
      "default": false,
      "description": "MUST be true — explicit go-ahead for a session on a human."
    },
    "protocol_id": {
      "type": "string",
      "description": "Saved protocol id (protocol.save)."
    },
    "execution_id": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Optional completed execution whose stored graph\ncarries a protocol_session node; default clones the template."
    },
    "subject_label": {
      "type": "string",
      "description": "Subject identifier (e.g. \"S01\")."
    },
    "protocol_version": {
      "type": "integer",
      "description": "Immutable version the assignment pins."
    },
    "yoked_donor_upload_id": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Donor recording upload (required when the\narm's blocks resolve to yoked — the backend validates coverage)."
    }
  },
  "additionalProperties": false
}
protocol.start_assignment output schema
{
  "type": "object",
  "additionalProperties": true
}
protocol.start_assignment annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}
protocol.session_status — Protocol Session Status
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

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.session_status input schema
{
  "type": "object",
  "required": [
    "session_id"
  ],
  "properties": {
    "window": {
      "type": "integer",
      "default": 50,
      "description": "How many recent predictions to include (1-200, default 50)."
    },
    "session_id": {
      "type": "string",
      "description": "The deploy session to inspect (from start_assignment)."
    }
  },
  "additionalProperties": false
}
protocol.session_status output schema
{
  "type": "object",
  "additionalProperties": true
}
protocol.session_status annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
protocol.pause — Pause Protocol Session
Advertised by the server during the last successful anonymous check.
Open-world

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.pause input schema
{
  "type": "object",
  "required": [
    "session_id"
  ],
  "properties": {
    "session_id": {
      "type": "string",
      "description": "The deploy session to pause."
    }
  },
  "additionalProperties": false
}
protocol.pause output schema
{
  "type": "object",
  "additionalProperties": true
}
protocol.pause annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}
protocol.resume — Resume Protocol Session
Advertised by the server during the last successful anonymous check.
Open-world

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.resume input schema
{
  "type": "object",
  "required": [
    "session_id"
  ],
  "properties": {
    "chunk_size": {
      "type": "integer",
      "default": 125,
      "description": "Samples per streamed chunk (default 125)."
    },
    "n_channels": {
      "type": "integer",
      "default": 4,
      "description": "Session channel count (the built-in template opens 4)."
    },
    "session_id": {
      "type": "string",
      "description": "The deploy session to resume."
    }
  },
  "additionalProperties": false
}
protocol.resume output schema
{
  "type": "object",
  "additionalProperties": true
}
protocol.resume annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}
protocol.stop — Stop Protocol Session
Advertised by the server during the last successful anonymous check.
Advertised destructiveOpen-world

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.stop input schema
{
  "type": "object",
  "required": [
    "session_id"
  ],
  "properties": {
    "session_id": {
      "type": "string",
      "description": "The deploy session to stop."
    }
  },
  "additionalProperties": false
}
protocol.stop output schema
{
  "type": "object",
  "additionalProperties": true
}
protocol.stop annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": true
}
protocol.export_stats — Export Protocol Stats
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

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.export_stats input schema
{
  "type": "object",
  "required": [
    "assignment_id"
  ],
  "properties": {
    "assignment_id": {
      "type": "string",
      "description": "The assignment to analyze (from start_assignment)."
    }
  },
  "additionalProperties": false
}
protocol.export_stats output schema
{
  "type": "object",
  "additionalProperties": true
}
protocol.export_stats annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
python.validate — Validate Python Model
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

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.

python.validate input schema
{
  "type": "object",
  "required": [
    "code"
  ],
  "properties": {
    "code": {
      "type": "string",
      "description": "Python source of the model class (<=256KB UTF-8)."
    },
    "class_name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Contract class to instantiate; omit to auto-detect the\nfirst class defining fit+predict."
    }
  },
  "additionalProperties": false
}
python.validate output schema
{
  "type": "object",
  "additionalProperties": true
}
python.validate annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
stats.grouped — Grouped Statistics
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

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``. HOW to get grouped stats: in the train graph set ``public_data.subject`` to >= 3 subjects (e.g. "S01,S02,S03", mode "all"), add an ``evaluation_plan`` node wired right after public_data with ``method: "loso"`` and ``evaluationTargetNodeId`` = your model node id, and keep an ``epoching`` node. See catalog.node_schema("evaluation_plan") and the ``mi_bciiv2a_csp_cv`` template for a working plan. 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).

stats.grouped input schema
{
  "type": "object",
  "required": [
    "execution_ids"
  ],
  "properties": {
    "chance": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Chance level in [0, 1]; default 1/nClasses per execution."
    },
    "execution_ids": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "1–25 executions (from execution.run) to pool. Runs\nwithout subject group stats are reported with nulls but do not\nfail the request — unless NONE qualifies\n(``nimbus.stats.insufficient_groups``) or only session groups\nare present (``nimbus.stats.non_subject_groups``)."
    }
  },
  "additionalProperties": false
}
stats.grouped output schema
{
  "type": "object",
  "additionalProperties": true
}
stats.grouped annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
foundation.compare — Compare Foundation Backbones
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

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.

foundation.compare input schema
{
  "type": "object",
  "required": [
    "source"
  ],
  "properties": {
    "mode": {
      "enum": [
        "training",
        "evaluation",
        "all"
      ],
      "type": "string",
      "default": "all",
      "description": "Pack split to load: training | evaluation | all (source=dataset)."
    },
    "path": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Upload path (source=upload) or absolute local path (source=local)."
    },
    "source": {
      "enum": [
        "dataset",
        "upload",
        "local"
      ],
      "type": "string",
      "description": "\"dataset\" (MOABB pack), \"upload\" (path from data.upload), or\n\"local\" (absolute path, local backend only)."
    },
    "dataset": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "MOABB dataset id, e.g. \"BNCI2014_001\" (source=dataset)."
    },
    "subject": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Subject id, e.g. \"S01\" (source=dataset)."
    }
  },
  "additionalProperties": false
}
foundation.compare output schema
{
  "type": "object",
  "required": [
    "ok"
  ],
  "properties": {
    "ok": {
      "type": "boolean"
    },
    "meta": {
      "type": "object",
      "description": "Figure sidecar. foundation.compare includes results/best/skipped (also as a JSON text content block).",
      "additionalProperties": true
    },
    "title": {
      "type": [
        "string",
        "null"
      ]
    },
    "mimeType": {
      "type": "string"
    },
    "savedPath": {
      "type": "string",
      "description": "Set when save=true."
    },
    "sizeBytes": {
      "type": "integer",
      "description": "Set when save=true."
    }
  }
}
foundation.compare annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}

Prompts

5 advertised

mi_csp_lda_bci_iv_2a — Train CSP+LDA on BCI IV 2a

Advertised by the server during the last successful anonymous check.

Run the built-in motor-imagery CSP -> LDA template and show the confusion matrix.

No arguments advertised.

compare_mi_pipelines — Compare MI pipelines

Advertised by the server during the last successful anonymous check.

One paced experiment: CSP+LDA vs FBCSP+LDA vs EEGNet on BCI IV 2a.

No arguments advertised.

foundation_backbones — Pick a foundation backbone

Advertised by the server during the last successful anonymous check.

Benchmark every pretrained EEG backbone on a dataset and pick the best one.

No arguments advertised.

inspect_my_eeg — Inspect my EEG file

Advertised by the server during the last successful anonymous check.

Upload a recording and get an exploratory summary before building a pipeline.

No arguments advertised.

leaderboard_standing — Check the leaderboard

Advertised by the server during the last successful anonymous check.

See the public leaderboard and where your submissions stand.

No arguments advertised.

Resources

0 advertised

No resource definitions available.

90-day uptime

A lightweight connection check about every six hours, sampled on hosts with many listings. It shows the server answered, not that its tools work.

Too few checks for a percentage yet (1 of 1 answered).

  1. 2026-11-07: 1 of 1 checks answered

30-day availability

Aggregated from read-only remote checks; this is not a tool-execution or security guarantee.

Successful checks
1 of 1 (100%)
Average latency
713 ms
95th percentile latency
713 ms

Maintenance history

Public check and source-refresh events. Editorial and ownership records remain private.

  • · probe · passed · 713 ms · metadata changed · 63 tool(s), 0 resource(s), 0 resource template(s), 5 prompt(s)

Connect from your client

Each snippet registers the same endpoint; pick the client you use.

This server is operated by the named third party. Listing and endpoint checks are not an endorsement or a security audit. Review the operator's permissions, terms, and data handling before connecting. How listings are checked and corrected.

Claude Code

Run this once in a terminal. It registers the remote server. Use --scope project to write .mcp.json for the repo.
Claude Code configuration
claude mcp add --transport http nimbus-bci-mcp-fly https://nimbus-mcp.fly.dev/mcp

Codex

Run this once. Codex stores MCP servers in ~/.codex/config.toml (or .codex/config.toml in a trusted project).
Codex configuration
codex mcp add nimbus-bci-mcp-fly --url https://nimbus-mcp.fly.dev/mcp

Cursor

Merge this server into .cursor/mcp.json in your project, then enable nimbus-bci-mcp-fly in your MCP settings.
Cursor configuration
{
  "mcpServers": {
    "nimbus-bci-mcp-fly": {
      "url": "https://nimbus-mcp.fly.dev/mcp"
    }
  }
}

Cline

Merge this into cline_mcp_settings.json (Cline → MCP Servers → Configure).
Cline configuration
{
  "mcpServers": {
    "nimbus-bci-mcp-fly": {
      "type": "streamableHttp",
      "url": "https://nimbus-mcp.fly.dev/mcp",
      "disabled": false
    }
  }
}

VS Code

Merge this server into .vscode/mcp.json. Use MCP: List Servers to start nimbus-bci-mcp-fly and inspect its tools.
VS Code configuration
{
  "servers": {
    "nimbus-bci-mcp-fly": {
      "type": "http",
      "url": "https://nimbus-mcp.fly.dev/mcp"
    }
  }
}

Gemini CLI

Run this once. It writes .gemini/settings.json in the current project; pass --scope user for ~/.gemini/settings.json.
Gemini CLI configuration
gemini mcp add --transport http nimbus-bci-mcp-fly https://nimbus-mcp.fly.dev/mcp

Claude Desktop

Open Claude Settings > Connectors > Add custom connector, enter this server URL and enable it for the conversation. This is a manual remote-connector handoff, not a desktop JSON configuration.
Claude Desktop configuration
https://nimbus-mcp.fly.dev/mcp

Windsurf

Merge this into ~/.codeium/windsurf/mcp_config.json, then refresh MCP in Cascade. Windsurf remote servers use serverUrl, not url.
Windsurf configuration
{
  "mcpServers": {
    "nimbus-bci-mcp-fly": {
      "serverUrl": "https://nimbus-mcp.fly.dev/mcp"
    }
  }
}

Let your agent find its tools

Find servers like Nimbus BCI MCP from your agent. Add Koskamo once to search the index for endpoints, access requirements, and client setup. Public discovery needs no key.