Skip to content
cBioPortalPublic

About

Prototype: cohort-level temporal queries over clinical timeline events (DSL -> ClickHouse SQL)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

645 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cbio-lab

Prototype for cohort-level temporal queries over cBioPortal clinical timeline events (msk_chord_2024). Users define cohorts by relationships between events — "progression within 180 days of starting immunotherapy", "first chemo NOT followed by progression in a year" — and the server compiles that DSL to ClickHouse SQL.

Architecture

  • app/page.js — query-builder UI (selectors, temporal relations, recipes, treatment-lines explorer)
  • app/api/* — API routes; the browser sends DSL JSON only, never SQL
  • lib/compiler.js — DSL → ClickHouse SQL compiler (selectors, BEFORE/DURING/NOT_FOLLOWED_BY relations, occurrence pinning, observability guard, derived treatment-line events)
  • lib/ch.js — server-side ClickHouse HTTP client; credentials come from env and never reach the client

The DSL

The query language is documented in docs/dsl.md — selectors, temporal relations, guards, derived treatment-line events, semantics, and worked examples with real msk_chord_2024 counts. A machine-readable contract is in docs/cohort-query.schema.json (JSON Schema 2020-12).

Environment variables

Every setting is in docs/ENVIRONMENT.md, grouped by what it controls: data, federation, sign-in and saved data, the site, the assistant, performance, building, and the test and check scripts. To run locally you need only CLICKHOUSE_URL, CLICKHOUSE_USER, CLICKHOUSE_PASSWORD and CLICKHOUSE_DB in .env.local; on Vercel they go in Project Settings → Environment Variables.

Federation

One analysis can draw on studies held by more than one cBioPortal database, and the prototype offers that over MCP: the database that holds a study answers aggregate queries (and, opted in, some patient-level ones) through its /api/mcp, and this app never queries it directly. docs/DATA-BOUNDARY.md is the design and its rules.

There are two ways to run it:

  • A simulated peer (the public portal, dev servers, the gate): one deployment holds both databases and serves the second one to itself over MCP (LOOPBACK_PEER). Every query on that database runs only while the app is answering an MCP call as that peer; a direct query on it, or one naming its database on the other connection, is refused (lib/ch.ts). It exercises the real protocol with no second deployment, but it is not separation: one process, one login.
  • A separate peer: a second cbio-lab instance whose own database is the other one, reached at its /api/mcp (PEER_MCP). This instance then holds no connection to that database at all.

Its settings, and how to set it up for the public portal, dev servers and a separate peer, are in docs/ENVIRONMENT.md.

What a federated study supports

Every view either draws over every patient of its cohorts or is not drawn and says why (lib/view-coverage.ts); the add-view buttons and cohort pickers are disabled with the reason.

over MCP, aggregates over MCP, patient-level (timeline, alterations shared)
drawn compare, survival, cooccurrence, coexpression, clinical, hotspots, attrition, course, sequence; Explore, study list, catalog the same, plus timeline and alterations
not drawn over the peer's studies oncoprint, clinical data table, mutation table, cox, logistic, risk model, plot, genome, pathways, enrichment, overlap, incidence, cancer types, clonality, paired, diffexpr, correlates, assays, labs, composition the same

Measured cost (docs/DATA-BOUNDARY.md, "Federation: where it stands"): about +0.3–0.4 s per analysis for aggregate views on a small study, about +2 s for the patient-level views; on a large study the database's own time dominates.

Security notes

  • No caller authentication yet. Anyone who can reach a peer's /api/mcp can call it. On a simulated peer the patient-level tools answer only the app itself (the token); a separate peer answers anyone, so it must not be reachable from outside.
  • The boundary is enforced by the coordinator: a peer's own run_analysis, query_cohort and web API answer patient-level for its own studies to any caller. Fine for public data; a peer serving restricted data needs caller authentication and those closed first.
  • There is no small-cell suppression: counts are exact.

MCP server

The MCP endpoint ships inside the Next.js app at /api/mcp (app/api/[transport]/route.js via mcp-handler), so a Vercel deploy serves it automatically. npm run mcp runs the same tools as a standalone Streamable HTTP server (default 127.0.0.1:3201/mcp). Both expose four tools to LLM clients: describe_study, query_cohort (the DSL), derive_treatment_lines, and render_oncoprint (returns a PNG image block rendered server-side from the OncoprintSpec contract via lib/oncoprint-svg.js). Tool schemas mirror docs/cohort-query.schema.json, and results carry the semantic caveats (observability guard, prior-medication guard, panel-aware denominators) for the model to surface. Register in Claude Code:

claude mcp add --transport http cohort-lab https://<your-deployment>/api/mcp

mcp/test-client.mjs exercises all four tools end to end.

Run locally

npm install
npm run dev        # or: npm run build && npm start

e2e.js is a Playwright suite that exercises the full flow against the live backend (requires a running server on :3100 and a local Chromium).

About

Prototype: cohort-level temporal queries over clinical timeline events (DSL -> ClickHouse SQL)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages