mcp server
Calane
Inspectable execution kernel for recurring analytical LLM workflows: versioned, schema-validated, multi-model pipelines with traceable run bundles
Set up
Runs on your computer. Pick your agent and operating system.
This project does not publish an install method we can turn into a config. Follow the README instead.
README
synced Oct 24, 2026llm-pipeline-kernel
A small, inspectable execution kernel for recurring analytical LLM workflows.
It runs versioned, schema-validated, multi-model analysis pipelines and exports traceable run bundles. The core defensible artifact is a traceable, versioned, schema-validated reasoning run.
This is a kernel, not a platform. See the non-goals below.
What it is
A caller — a human, an LLM, an agent, an MCP client, a REST client, or an OpenAI-style tool caller — can:
- execute a named pipeline,
- resolve its prompts/specs (filesystem or Git registry),
- run channels across providers or delegated agents,
- validate structured outputs against JSON Schema,
- store the run (metadata, raw + parsed outputs, validation reports),
- emit telemetry (pluggable; no-op by default),
- synthesize results (synthesis is just another channel),
- optionally recurse (bounded, explicit — never model-decided), and
- export the full, reproducible run bundle.
Non-goals (binding)
- No visual builder.
- No hosted SaaS.
- No authentication UI.
- No billing.
- No marketplace.
- No general-purpose agent framework.
- No LangGraph clone.
- No Langfuse clone.
- No prompt-management product.
- No enterprise policy engine.
Plus, for the first implementation: no UI, no multi-tenant SaaS, no enterprise auth.
What's new since the initial public snapshot
Calane is a single-author project: it is developed in a private working
repository and published here — this public repo is the canonical release
surface, not a fork of third-party work. Each item below is visible as a
commit in this repo's git log.
security— vitest patched (GHSA-5xrq-8626-4rwp / CVE-2026-47429). Bumps the test runner tovitest@^4.1.0(resolved to4.1.8) and addspackages/core/tests/security-pins.test.ts— a regression guard that resolves the installedvitest/package.jsonand asserts>= 4.1.0, so any future downgrade fails the suite instead of silently re-introducing the vuln.examples— multi-model distillation pipelines.examples/pipelines/distillation.pipeline.yamldistils a subject across Claude / GPT / Mistral / Gemini in parallel, then synthesises on Anthropic with bounded depth-2 recursion (synthesis_onlycarry-forward).examples/pipelines/distillation_2key.pipeline.yamlis a trimmed variant that completes end-to-end with onlyMISTRAL_API_KEY+GEMINI_API_KEY(synthesis on Mistral, free-tier Gemini model). Shared prompts underexamples/prompts/distillation/, schemas underexamples/schemas/distillation.*.schema.json.docker— multi-stage Dockerfile +.dockerignorefor the combined entrypoint. Mirrorsrender.yamlbyte-for-byte (same port, same env defaults, same volume, same boot model) so the two deployment paths share one boot story. Seedocs/deploy-docker.md.fix— Node engine range aligned with vitest.package.jsonengines.nodeandrender.yamlNODE_VERSIONoriginally claimed Node 20, but the pinnedpnpm@11.3.0requires Node ≥22.13 (it importsnode:sqlite, a Node-22 built-in) — a from-scratchpnpm installon Node 20 failed immediately. Discovered while running the first independentdocker buildof the pre-publication development tree. Both are now declared as"^22.0.0 || >=24.0.0"/"22", matchingvitest@4.1.8's own engines range and dropping the non-LTS Node 23 line (EOL 2026-06-01) from the support matrix.
Architecture
Caller
-> Gateway (CLI | REST | MCP | openai.json)
-> PipelineExecutor
-> PromptRegistryPlugin (filesystem | git)
-> ExecutionPlan (explicit channels, providers, depth, synthesis)
-> ChannelExecutor (direct_provider | delegated_agent)
-> ProviderAdapter / DelegatedAgent
-> JsonSchemaValidator (Ajv)
-> ResultStorePlugin (filesystem)
-> TelemetrySink (no-op by default)
-> RunBundleExporter
See docs/architecture.md for detail, and
docs/plugin-model.md for the functional vs.
observational plugin split.
Monorepo layout
| Package | Purpose |
|---|---|
packages/core | Specs (TypeBox), executor, renderer, validator, bundle exporter, plugin interfaces |
packages/providers/mock | Deterministic mock provider (offline/tests) |
packages/providers/anthropic | Anthropic Messages API provider via the official SDK |
packages/providers/openai-compatible | Fetch-based OpenAI-compatible provider + delegated-agent placeholder |
packages/registries/filesystem | Filesystem prompt/pipeline/schema registry |
packages/registries/git | Minimal Git registry (records commit SHA) |
packages/stores/filesystem | Filesystem result store |
packages/stores/sqlite | SQLite result store with relational schema |
packages/telemetry/otel | OpenTelemetry sink (no-op by default) |
packages/cli | llm-pipe CLI |
packages/server | Fastify REST API + public/openai.json + OAuth discovery + /mcp |
packages/mcp-server | MCP server (stdio + Streamable HTTP), 8-tool surface |
Getting started
Requires Node 22 LTS (or 24+) and pnpm — the engine range is
"^22.0.0 || >=24.0.0". The pinned pnpm@11.3.0 requires Node ≥22.13 (it
imports node:sqlite); vitest@4.1.8 declares the same engines range. See
"What's added" §4 above for the discovery story.
pnpm install
pnpm build
pnpm test
Run the example SWOT pipeline (offline, mock provider)
node packages/cli/dist/index.js run swot_recursive \
examples/inputs/sample-topic.md --providers mock --depth 1 --export run_bundles
Other CLI commands:
node packages/cli/dist/index.js list-pipelines
node packages/cli/dist/index.js validate-pipeline swot_recursive
node packages/cli/dist/index.js get-run <run-id>
node packages/cli/dist/index.js export-run <run-id> --out run_bundles
By default the CLI reads pipelines from examples/ (override with --registry
or $LLM_PIPE_REGISTRY) and writes runs to .runs/ (override with --store
or $LLM_PIPE_STORE).
Every CLI command, flag, and exit code is documented in
docs/cli-reference.md.
REST server
PORT=8787 node packages/server/dist/server.js
curl localhost:8787/pipelines
curl localhost:8787/openai.json
Every HTTP route (params, responses, status codes, auth) is documented in
docs/rest-reference.md.
MCP server
node packages/mcp-server/dist/server.js # speaks MCP over stdio
See docs/mcp.md and docs/openai-json.md.
Docker (combined entrypoint)
docker build -t calane:latest .
docker run --rm -p 8787:8787 \
-e ANTHROPIC_API_KEY -e OPENAI_API_KEY \
-v calane-data:/data calane:latest
# then: curl http://localhost:8787/health
Same boot model as render.yaml (runs packages/server/dist/combined.js —
REST + OpenAPI + OAuth discovery + MCP Streamable HTTP at /mcp — on one
port, with persistent state on /data). Full setup, env vars, smoke tests,
and known issues in docs/deploy-docker.md.
End-to-end scenarios
Practical, runnable walkthroughs that pair the per-surface references with real
use-cases (run → sign → verify; resume/diff/replay/stats; REST/MCP/A2A;
connecting an external or GitHub registry) live in
docs/scenarios/. Each runnable block is exercised
by pnpm test (via packages/cli/tests/scenarios.test.ts) so the docs can't
silently rot.
The 8-tool surface
To respect the OpenAI tool/action surface limit (~30 tools), both MCP and
openai.json expose exactly 8 coarse-grained tools — never one tool per
internal function: run_pipeline, get_run_result, list_pipelines,
validate_pipeline, export_run_bundle, rerun_channel, list_runs,
get_pipeline_spec.
Schema rule
TypeBox is the single source of truth; Ajv validates. No Zod anywhere in the
codebase. See docs/schema-rule.md.
Providers
Shipped:
mock— deterministic, schema-synthesizing (offline + tests).anthropic— Anthropic Messages API via the official SDK; forces structured output through a singleemit_structured_outputtool when anoutputSchemais set. Pricing table bundled (USD / 1M tokens);costUsdisnullfor unknown models, never silently0.openai-compatible— any OpenAI-style/chat/completionsendpoint; key from the env var named byapiKeyEnv(defaultOPENAI_API_KEY). Used for OpenAI itself and for Mistral, Gemini's OpenAI-compatible endpoint, Groq, Together, OpenRouter, local Ollama, etc. — setbaseUrlper provider.delegated-agent— placeholder fordelegated_agentexecution mode.
The adapter interface is designed to admit future Ollama-native, LiteLLM, Portkey, MCP-agent, and custom HTTP providers without core changes.
Run bundles
See docs/run-bundle.md for the exact bundle layout.