Skip to main content
Glama
Pipelex

Pipelex MCP Server

by Pipelex

Pipelex MCP

Pipelex MCP exposes registered-method discovery, MTHDS validation, inputs projection and preparation, and durable method runs to MCP hosts, wrapping the Pipelex API through the @pipelex/sdk PipelexApiClient. It ships as two servers from one repo and one capability core:

  • Hosted console — a Skybridge HTTP server (deployed on Alpic) for remote-connector hosts (ChatGPT, claude.ai, Claude Desktop, Cowork). Registers the Skybridge views.

  • Local workshop — an npm-distributed stdio server (@pipelex/mcp, bin pipelex-mcp) that coding-agent hosts (Claude Code, Codex, Cursor, Cowork) spawn via npx. Its headline feature is the { path } file arm: it reads .mthds files from disk instead of having the model hand-copy their contents.

Get started

Pick one server for a given host — the workshop wherever there is a filesystem, the console everywhere else.

Hosted console — add as a custom connector in ChatGPT, claude.ai or Claude Desktop, then sign in with your Pipelex account. Nothing to install, no key to paste:

https://pipelex-mcp-a3c6a115.alpic.live/mcp

Local workshop — for hosts that can spawn a process (Claude Code, Codex, Cursor). Needs Node.js 24+; hosts fetch it on demand, so there is nothing to install globally:

claude mcp add pipelex --env PIPELEX_API_KEY=plx_sk_... -- npx -y @pipelex/mcp

Then ask it what methods you have, or point it at a .mthds file. Per-host registration snippets are under Local workshop: install & register, and which server belongs on which host is the Host → server matrix.

Both servers register the same MCP tools, with identical names, schemas, and contracts — with one documented exception per shell, marked below:

Tool

What it does

mthds_list_methods

List the active API key's organization catalog as bounded names, descriptions, and canonical ids — never method source or stored inputs/outputs.

mthds_validate

Validate submitted .mthds files, or a registered method by catalog id; on a valid verdict, ship the dry-run method graph to the run-graph view (hosted only).

mthds_inputs_template

Project a pipe's declared inputs as a fill-in template for a run.

mthds_codegen

Generate typed code for a method's concepts — TypeScript (ts-zod) or Python (python-pydantic, python-structures) — stamped and locked, to write verbatim into the project. On the local workshop, output_dir writes the tree straight to disk.

mthds_prepare_inputs

Turn filled inputs run-ready: upload file-bearing values to Pipelex storage and rewrite them to pipelex-storage:// (workshop uploads; console is pass-through only).

mthds_upload_attachments

Hosted console only. Turn a file the user attached in the chat into a run-ready pipelex-storage:// reference (ChatGPT only — see Chat attachments).

mthds_run

Start a durable run on the hosted Pipelex API; returns a durable run_id immediately.

mthds_run_status

Check a durable run's coarse lifecycle state by run_id.

mthds_run_results

Fetch a durable run's terminal outcome by run_id.

mthds_download_artifacts

Local workshop only. Save the files a completed run produced (images, PDFs, documents) under the directory the server was started in — see Saving run artifacts.

The two exceptions mirror each other. mthds_upload_attachments takes a host-substituted attachment reference, and the host gates that substitution on the declared JSON Schema, so on the workshop the tool would be structurally unreachable rather than merely unused. mthds_download_artifacts writes files under the server's working directory, which the console does not have — its users download run outputs from the app's UI. The invariant that still holds is that no tool name means different things on the two shells.

SPEC.md is the source of truth for the full tool contracts, verdict discipline, and view behavior. This README covers what you need to install, register, and run the servers. docs/readme.html is an illustrated overview of the same ground — the two shells, the tool surface, the flow a method takes, and the sharp edges — for reading in a browser.

Related MCP server: Model Context Shell

The two deployments, and the { path } arm

MCP tool arguments are generated token-by-token by the host LLM — there is no other channel from the conversation to the server. So submitting a bundle's .mthds contents to the hosted server means the model re-emits every file as output tokens (slow on large bundles, re-paid every repair-loop iteration and every tool in the chain, and not guaranteed byte-identical to what's on disk). The local server sidesteps this: the host spawns it in your workspace, so it can read files from disk given only a path.

The shared submitted-files shape accepts two item forms — inline content or a file path:

type SubmittedFileInput = { content: string; uri?: string | null } | { path: string };

Both servers register this same union, so the tool contract never forks; what differs is behavior:

  • The workshop resolves { path } from disk before invoking the capability — near-constant token cost regardless of bundle size, byte-accurate reads, and real provenance (the resolved item carries uri = the submitted path, so diagnostics locate to files you can open and edit). Inline { content, uri? } items stay accepted for parity.

  • The console rejects { path } items with an instructive input_domain error located at files[i].path: this deployment cannot read files; resubmit as { content, uri? }, or use the local workshop (npx @pipelex/mcp).

An item is one arm or the other; on a malformed item carrying both keys, content wins (first-match union semantics) and path is ignored.

Path trust boundary (workshop). { path } values resolve relative to the server's working directory. The arm is contracted to .mthds files, so a non-.mthds extension is rejected before any filesystem access (a prompt-injected .env or key-file path is never opened), and the resolved target (symlinks followed) must live inside the working-directory subtree. Non-.mthds paths, escapes, missing files, and non-regular files come back as input_domain errors located at files[i].path.

Local workshop: install & register

The workshop is published as @pipelex/mcp. Hosts spawn it on demand with npx -y @pipelex/mcp (bin pipelex-mcp); you do not install it globally. It needs Node.js 24+ and a PIPELEX_API_KEY (a plx_sk_ platform key) for the run tools; validation and inputs work without one against a key-less API.

The registration name is yours to choose; these snippets use pipelex (which yields mcp__pipelex__mthds_validate-style tool names).

Claude Code

claude mcp add pipelex --env PIPELEX_API_KEY=plx_sk_... -- npx -y @pipelex/mcp

Codex~/.codex/config.toml

[mcp_servers.pipelex]
command = "npx"
args = ["-y", "@pipelex/mcp"]
env = { PIPELEX_API_KEY = "plx_sk_..." }

Cursor~/.cursor/mcp.json

{
  "mcpServers": {
    "pipelex": {
      "command": "npx",
      "args": ["-y", "@pipelex/mcp"],
      "env": { "PIPELEX_API_KEY": "plx_sk_..." }
    }
  }
}

Cowork / Claude Desktop (builder mode)claude_desktop_config.json

{
  "mcpServers": {
    "pipelex": {
      "command": "npx",
      "args": ["-y", "@pipelex/mcp"],
      "env": { "PIPELEX_API_KEY": "plx_sk_..." }
    }
  }
}

Environment

  • PIPELEX_API_KEY — a plx_sk_ platform key. Required for mthds_list_methods because the returned catalog is the key's active, workspace-shared organization catalog. Optional for mthds_validate / mthds_inputs_template / mthds_codegen calls that submit files against a key-less API; effectively required for the run family and for any method_id call on any tool, since the catalog is org-scoped (a missing/invalid key is a config no-verdict).

  • PIPELEX_BASE_URL — defaults to the hosted Pipelex API (https://api.pipelex.com). Set it to http://localhost:8081 to develop against a local OSS pipelex-api runner. Durable runs need the hosted API; a bare runner has no run lifecycle.

The working directory matters. The host spawns the workshop in your project, and that directory is the boundary for everything the server touches on disk: files: { path } items resolve inside it, mthds_download_artifacts saves under it, and mthds_codegen's output_dir writes under it. Nothing outside it is ever read or written — an absolute path, a .., or a symlink pointing out of the tree is refused.

Hosted console: sign in with your Pipelex account

The hosted console holds no server-side API key and there is nothing to paste. Add the connector by its URL and your host walks you through signing in with your Pipelex account:

https://pipelex-mcp-a3c6a115.alpic.live/mcp

That is the production console. The hostname is assigned by Alpic, and the OAuth Resource Indicator registered with WorkOS is pinned to it, so it moves only behind a deliberate migration — if it ever does, every existing connector has to be re-added anyway.

Sign-in is OAuth through WorkOS AuthKit, which the console's MCP host drives for you — ChatGPT, claude.ai, Claude Desktop/Cowork and Cursor all handle the handshake themselves, including picking the organization you want to work in. Your verified session is what authorizes every call the console makes on your behalf, so the catalog you see and the runs you spend are your own. The token never travels through tool arguments, so it never enters the model's context.

There is no keyless mode: every tool call requires a signed-in session. If one expires or is revoked, calls come back as a config no-verdict at authorization telling you to reconnect the connector and sign in again.

Upgrading from a ?api_key= connector. Bring-your-own-key has been removed. A connector still registered with ?api_key=plx_sk_... (or an Authorization: Bearer plx_sk_... header) no longer connects at all — remove it and re-add it by the plain URL above. ChatGPT in particular caches a connector's configuration at add-time, so re-adding is the only path.

(That said, prefer the local workshop on hosts that can spawn it — see the matrix below.)

Chat attachments (ChatGPT only)

The workshop gets the user's actual file through the { path } arm. The console has no filesystem, so it gets it a different way: ChatGPT's Apps runtime rewrites the model's reference to an attached file into a signed-URL object before the call reaches the server. mthds_upload_attachments takes that channel — it fetches the bytes server-side and uploads them to Pipelex storage under your signed-in account, returning only small URI strings. The bytes never enter the model's context, which is the whole reason console-side upload is allowed here at all.

The flow, on the console:

user attaches a PDF in the chat
  → mthds_upload_attachments   → pipelex-storage://… uris
  → fill the uris into the mthds_inputs_template output
  → mthds_run

mthds_prepare_inputs can be skipped — a pipelex-storage:// value is already run-ready. Nothing else in the flow changes.

Three things to know:

  • Re-add the connector to get it. ChatGPT caches a connector's tool list at add-time and never refreshes it, so a newly shipped tool (or a changed tool description) stays invisible to an existing installation until you remove and re-add the connector.

  • 7 MiB per attachment. This is a transport ceiling, not a product choice: POST /v1/upload takes a base64 body behind an AWS API Gateway HTTP API, whose 10 MiB request quota divides by base64's 4/3 inflation to ~7.5 MiB decoded. (The app-level 50 MiB MAX_UPLOAD_MIB is unreachable through the public gateway — don't quote it.) ChatGPT hands over much larger files happily, so expect to meet this; the refusal fires before any bytes are fetched and names the limit.

  • ChatGPT only. claude.ai injects no file reference into a connector call, and MCP has nothing in-spec (SEP-2631 is an open draft). On any other host the model can only fabricate a URL, which the fetch boundary refuses — that refusal is also the "this host cannot attach files, ask for an http(s) URL" diagnostic.

Attachment fetch boundary. Fetching a host-supplied URL from a public endpoint is an SSRF surface, so the fetch is a deny-by-default policy: https: only; the host must be oaiusercontent.com at the apex or on any subdomain (OpenAI's own locked domain — where live attachment traffic is served), or oaisdmntpr<azure-region>.blob.core.windows.net (where it used to be, and where the oaisdmntpr prefix stays required, because that suffix is multi-tenant and a suffix-only rule would admit any Azure customer's storage account); no credentials in the URL, no non-default port; redirects refused; the size cap enforced from content-length before the body is read and again mid-stream; a bounded timeout; no headers forwarded; non-2xx refused. Because these hosts are undocumented vendor infrastructure that changes without notice — it already has once — the cap, the timeout, and the no-redirect rule hold on their own; the host check is a filter, not the defence.

Host → server matrix

Connect each host to exactly one Pipelex server — the local workshop wherever there's a filesystem, the hosted console everywhere else.

Host

Server

How to connect

ChatGPT (web)

Hosted console

Apps directory

claude.ai (web + mobile)

Hosted console

Connector (custom URL)

Claude Desktop (chat mode)

Hosted console

Connector / marketplace plugin

Claude Code

Local workshop

claude mcp add, or the pipelex plugin from the pipelex-plugins marketplace (its manifest spawns the workshop)

ChatGPT desktop (Codex mode)

Local workshop

~/.codex/config.toml

Cursor

Local workshop

~/.cursor/mcp.json

Claude Desktop (Cowork mode)

Dual — console for consumers, workshop for builders

Connector, or stdio in claude_desktop_config.json

Mistral Vibe (TUI)

Local workshop

pending Vibe's MCP mechanics

Mistral Vibe (web)

Hosted console

Connector / config

On views: the hosted console ships the run-graph and run-follow views, which render on view-capable hosts (ChatGPT, claude.ai, Cowork) and degrade to text on Claude Code. The local workshop is tools-first — it ships no views on any host today, so it reports structured results and text summaries directly. (Codex and Cowork are view-capable hosts and would render workshop views if local view delivery lands in a later increment.)

One host, one server

A host should be connected to one Pipelex server, never both. Same tool names on both means a both-installed host has ambiguous routing (nothing guarantees the model picks the local one), contradictory schemas under identical names (the workshop accepts { path }, the console rejects it), and doubled tool registrations for no added capability.

The trap that gets you there without choosing it: a claude.ai Pipelex connector syncs into Claude Code automatically. A user signed into claude.ai with the connector enabled gets the hosted tools in coding sessions alongside a locally-registered workshop. When you run the local workshop, disable the connector for those sessions:

  • In Claude Code, /mcp is the entry point. A connector you haven't signed into is collapsed behind a "Show unused connectors" row (Claude Code v2.1.161+) — expand it to find Pipelex.

  • Config alternatives: per-project deniedMcpServers in .claude/settings.json, or global disableClaudeAiConnectors: true in user settings.

Tools at a glance

Full contracts (verdict discipline, _meta channels, view behavior) live in SPEC.md. The shapes below use SubmittedFileInput from the two deployments.

mthds_list_methods

// input
{
  query?: string;   // trimmed, case-insensitive; matched SERVER-side over name/description
  limit?: number;   // integer 1..50; default 20
  cursor?: string;  // opaque next_cursor from a previous call
}

// structuredContent — success
{
  status: "ok";
  returned_count: number;
  next_cursor: string | null;
  methods: Array<{
    method_id: string;
    name: string;
    name_truncated: boolean;
    description: string | null;
    description_truncated: boolean;
    created_at: string;
  }>;
}

Both shells expose this read-only, no-view catalog entry point. Search and paging are the server's job: query is applied across the whole organization catalog rather than over one page, and rows arrive already ordered newest first by the immutable created_at the catalog pages on. Continue a listing by passing the returned next_cursor back as cursor. Names are bounded to 200 Unicode code points and descriptions to 500, with explicit truncation flags. Empty catalogs and no-match queries are successful empty results.

There is deliberately no total: counting a catalog means reading all of it, which is the cost paging exists to avoid.

The projection is deliberately source-free: mthds, Python, stored inputs and outputs, organization ids, and creator ids never enter structuredContent, content, _meta, or logs — and the index projection no longer carries them at all. A malformed row fails the whole result as a non-retryable runtime contract error rather than returning a misleading partial list.

Name-to-run flow:

mthds_list_methods({ query: "invoice" })
  → choose/disambiguate method_id
  → mthds_validate({ method_id })                 # optional current-content check
  → mthds_inputs_template({ method_id })
  → fill inputs; prepare/upload assets if needed
  → mthds_run({ method_id, inputs })

No method source crosses the conversation in this flow.

mthds_validate

// input — exactly ONE of files / method_ref / method_id
{
  files?: SubmittedFileInput[];
  method_ref?: string;         // published method address — github.com/<owner>/<repo>[/<selector>][@<tag>]
  method_id?: string;          // catalog id (mt_…) of a registered method
  include_graph?: boolean;
}

// structuredContent
{
  status: "ok" | "error";
  is_valid: boolean;
  is_runnable: boolean;
  pending_signatures: string[];
  available_view_specs: Array<"dry_run_graph" | "input_form">;
  validation_errors?: unknown[];
  errors?: ToolError[];
}

The graph (graph_spec) and the form's per-pipe artifact pair — the IO contracts (pipe_io_contracts) and the input-form descriptor (input_form, requested from the API via the opt-in views: ["input_form"] token) — ride the tool result's view-only _meta channel for the run-graph view — never structuredContent, so the model never pays their tokens. On the hosted console that view renders the method graph and, on a runnable verdict that carries both artifacts, an input form for the main pipe (its fields derived from the wire descriptor) whose Run button starts the method from the view. available_view_specs is how the model learns which views exist to surface; include_graph defaults to true. The MCP content text carries the human-readable summary. The three source forms are mutually exclusive — supply exactly one. method_ref validates a published method by its address (github.com/<owner>/<repo>[/<selector>][@<tag>], e.g. github.com/Pipelex/methods/documents@v0.1.0); method_id validates a registered method by its catalog id (requires an API key, since the catalog is org-scoped). Both are server pass-throughs: the selector rides the /v1/validate body and the hosted API resolves it — no method source enters the conversation. The graph view works identically whichever source form the verdict came from.

mthds_inputs_template

// input — exactly ONE of files / method_ref / method_id
{
  files?: SubmittedFileInput[];
  method_ref?: string;         // published method address — github.com/<owner>/<repo>[/<selector>][@<tag>]
  method_id?: string;          // catalog id (mt_…) of a registered method
  pipe_ref?: string;
  explicit?: boolean;
  format?: "json" | "toml";
}

// structuredContent
{
  status: "ok" | "error";
  is_valid: boolean;
  pipe_ref?: string;
  format?: "json" | "toml";
  explicit?: boolean;
  inputs?: Record<string, unknown>;
  inputs_toml?: string;
  validation_errors?: unknown[];
  errors?: ToolError[];
}

pipe_ref is a qualified domain.pipe_code; omit it to default to the closure's declared main_pipe. explicit (default true) emits the ceremonial {concept, content} envelope per input — the declared concept ref plus the canonical content shape; pass false for the light shape (bare example values). format (default "json") chooses the template encoding. The three source forms are mutually exclusive — supply exactly one. method_ref projects a published method by address, resolved server-side on the build envelope; method_id projects a registered method's current stored content (requires an API key, since the catalog is org-scoped). No Skybridge view — the template is small structured data the model reads directly, and the content summary repeats it in a fenced block.

mthds_codegen

// input — exactly ONE of files / method_ref / method_id, plus the required target
{
  files?: SubmittedFileInput[];
  method_ref?: string;         // published method address — github.com/<owner>/<repo>[/<selector>][@<tag>]
  method_id?: string;          // catalog id (mt_…) of a registered method
  target: "ts-zod" | "python-pydantic" | "python-structures";
  output_dir?: string;         // LOCAL WORKSHOP ONLY — write the tree here instead of returning its content
}

// structuredContent
{
  status: "ok" | "error";
  is_valid: boolean;
  target?: "ts-zod" | "python-pydantic" | "python-structures";
  kind?: "types";
  crate_fingerprint?: string;
  engine_version?: string;
  artifacts?: Array<{ path: string; bytes: number; content?: string; written_to?: string }>;
  lock?: { filename: string; bytes: number; content?: string; written_to?: string };
  truncated?: boolean;
  // the written arm (output_dir):
  output_dir?: string;
  is_current?: boolean;
  orphans?: string[];
  orphans_truncated?: boolean;
  drifts?: unknown[];
  validation_errors?: unknown[];
  errors?: ToolError[];
}

Projects the method's concept set into typed models through the Pipelex codegen engine (POST /v1/codegen). target is required and has no default — the tool description carries the decision rule, so the assistant picks it from the project (the user's explicit request wins): ts-zod for a TypeScript or JavaScript project (types.ts with zod schemas and inferred types, plus binder.ts with a parse/serialize pair per concept — keep both), python-pydantic for a Python consumer with no Pipelex runtime (models.py), python-structures for a Pipelex host or a @pipe_func implementation (structures.py). Field keys stay snake_case in every target. The three selectors are server pass-throughs — no bundle enters the conversation.

On the local workshop, pass output_dir — a dedicated generated directory relative to the working directory, such as src/generated/<method>/. The tool writes the artifacts and codegen.lock there verbatim and returns no file content at all: output_dir, written_to per file, is_current and any orphans instead. It overwrites files it generated (they carry a codegen stamp) and the lock beside them, and refuses the whole write rather than touch anything else — a symlink, a directory, or a file it did not write. Orphans, a stamped file the new lock does not list, are reported and never deleted, so a directory holding two generations stays non-current by design; give each generation its own directory. The hosted console takes no output_dir and refuses it instructively.

Without output_dir, write every artifact at its path and the lock as codegen.lock beside them, verbatim, into a dedicated generated directory; pipelex codegen check (or runCodegenCheck from @pipelex/sdk) then passes on that tree. The content summary repeats each file in a fenced block tagged for its language. A large set is withheld by whole file rather than cut (truncated: true, content absent on the withheld entries; the lock's bytes are reserved first, so the trust anchor always rides). No Skybridge view.

mthds_prepare_inputs

// input — exactly ONE of files / method_id, plus the filled inputs (no method_ref — see below)
{
  files?: SubmittedFileInput[];
  method_id?: string;               // catalog id (mt_…) of a registered method
  pipe_ref?: string;
  inputs: Record<string, unknown>;  // the FILLED mthds_inputs_template output
}

// structuredContent
{
  status: "ok" | "error";
  is_valid: boolean;
  pipe_ref?: string;                // echoed only when the caller supplied it
  inputs?: Record<string, unknown>; // the prepared (rewritten) inputs — ready for mthds_run
  uploads?: string[];               // the pipelex-storage:// uris uploaded this call ([] when all pass-through)
  errors?: ToolError[];
}

Sits between mthds_inputs_template (produces the empty template) and mthds_run (executes the filled inputs): it makes file-bearing inputs run-ready. The pipe's declared signature identifies which values are assets; each is uploaded to Pipelex storage and rewritten to pipelex-storage://. http(s) URLs and existing pipelex-storage:// references pass through unchanged, so an inputs set that is already all pass-through can skip this step. Per-deployment asset boundary: the local workshop uploads local paths, data: URLs, and inline bytes with your API key; the hosted console is pass-through only and refuses any upload-needing input up front with an input_domain error at inputs, naming the workshop. No Skybridge view — the prepared inputs are small structured data the model reads directly, repeated in the content summary. Unlike the other tools this has no produced-invalid arm: an unresolvable closure is a no-verdict status: "error" (recover via mthds_validate / mthds_inputs_template). See SPEC.md → "Prepare Inputs Scope" for the full contract.

mthds_upload_attachments — hosted console only

// input — the host fills this in; never construct one yourself
{
  attachments: Array<{
    download_url: string;   // required — the host's signed HTTPS URL
    file_id: string;        // required — e.g. "sediment://file_0000…"
    mime_type?: string;
    file_name?: string;
  }>;
}

// structuredContent
{
  status: "ok" | "error";
  is_valid: boolean;                  // true only when EVERY attachment ingested
  attachments?: Array<{
    file_id: string;
    file_name?: string;
    uri?: string;                     // the pipelex-storage:// reference, on success
    content_type?: string;
    size?: number;                    // decoded bytes
    error?: ToolError;                // per-item failure
  }>;
  uploads?: string[];                 // the successful uris
  errors?: ToolError[];               // no-verdict only
}

Registered on the hosted console only, and populated by ChatGPT only — see Chat attachments for the flow, the 7 MiB cap, and the fetch boundary. The four-field attachment shape is mandated, not chosen: OpenAI's app review requires exactly these properties with exactly this required/optional split, and the host's runtime substitution is gated on the same schema — so a deliberately lenient variant would never be populated. Partial success is a produced verdict: status: "ok" with is_valid: false, the successful uploads returned alongside per-item errors rather than discarded. No Skybridge view — the returned URIs are small structured data the model reads directly, repeated in the content summary.

mthds_run / mthds_run_status / mthds_run_results

Durable (async) method execution on the hosted Pipelex API. mthds_run starts a run — from submitted files (files?, plus pipe_code? and inputs?), from a published method's address (method_ref?github.com/<owner>/<repo>[/<selector>][@<tag>], resolved server-side with the resolved commit SHA echoed back as method_provenance), or from a registered method's catalog id (method_id?, mt_…) — and returns a durable run_id immediately (never blocks); mthds_run_status is a cheap read of the coarse lifecycle state; mthds_run_results fetches the terminal outcome (main output on success, failure message otherwise) along with a compact run-level usage object — total USD cost (null-aware), tokens, and inference-call count. The per-pipe rollup and the full per-call record list ride the view-only _meta (_meta.usage_by_pipe / _meta.tokens_usages) for a future detailed-cost surface, and usage never appears in the prose. A by-id run executes the method's current stored content (methods are not versioned) and requires an API key; when both files and method_id are supplied, the files run and the id is recorded as run-history linkage on the platform. method_ref is a complete run source of its own and pairs with nothing — beside files or method_id the request is refused. All run state lives behind the durable run_id on the platform, so the flow survives conversation gaps — days later, the same id still answers. On the hosted console, mthds_run ships the run-follow live-status view; on the workshop these are plain tools. See SPEC.md → "Run Scope" for the full contract.

The pipe selector is pipe_code here and pipe_ref on mthds_inputs_template / mthds_prepare_inputs — the same qualified domain.pipe_code value under the name each underlying route uses; each description names the other, so copying the value across the two calls is expected.

Saving run artifacts (local workshop only)

mthds_download_artifacts is the download counterpart of mthds_prepare_inputs: where prepare pushes local files into Pipelex storage, this brings a run's produced files back out, onto disk.

// input
{
  run_id: string;   // the durable run id from mthds_run
  dir?: string;     // where to save, relative to the server's working directory (created if missing; must stay inside it)
}

// structuredContent (state = "completed")
{
  status: "ok";
  run_id: string;
  state: "completed";
  artifacts: Array<{ uri: string; path?: string; content_type?: string | null; size?: number; error?: ToolError }>;
  saved_paths: string[];   // relative to the working directory
  all_saved: boolean;      // every referenced file saved
}

A completed run's results carry a produced image, PDF or document with a pipelex-storage:// reference beside a presigned public_url that expires within the hour. Pass the run id here instead of racing that link: every reference in the run's full output is resolved to a fresh link through the API and streamed into a file under the working directory — so the same call still works days later. Filenames come from the storage key, sanitized; files are never overwritten (a collision gets a numeric suffix); dir cannot escape the working directory (no absolute paths, no .., no symlink out). A running or failed run is a produced verdict with nothing to save; partial success is a produced verdict with the failures on their items. On the workshop, a mthds_run_results summary whose output references stored files names this tool. See SPEC.md → "Artifact Download Scope" for the full contract and the reasoning behind a companion tool rather than a flag on mthds_run_results.

Success and verdict discipline

A successful catalog page is status: "ok" with counts and methods (there is no is_valid field). For tools that produce a method verdict, a produced verdict is always status: "ok" — discriminate on is_valid (and, for validation, is_runnable); an invalid bundle or unresolvable closure is a produced is_valid: false verdict, not an error. status: "error" is reserved for no result/verdict could be produced and carries an errors[] array, each tagged input_domain (bad request), config (env/auth/unreachable API), or runtime (server fault), plus a retryable flag. Every errors[] entry's location, message, and hint are also surfaced in the content text.

Hosted console: local development

The hosted server is a Skybridge app. During early development this repo also supports the local OSS pipelex-api runner so the MCP can be exercised before the hosted path is fully wired — temporary; the production target is the hosted Pipelex API only.

Prerequisites:

  • Node.js 24+

  • A Pipelex API serving POST /v1/validate and POST /v1/build/inputs (a local OSS pipelex-api during development)

  • A WorkOS AuthKit tenant — the console has no keyless mode and refuses to start without one (see below)

The console requires two WorkOS variables. Per-user OAuth is its only auth posture, so the server throws at startup unless both are set:

Variable

Value

WORKOS_AUTHKIT_DOMAIN

the AuthKit domain, e.g. <tenant>.authkit.app

PIPELEX_MCP_RESOURCE_INDICATOR

the server origin with a trailing slashhttp://localhost:3000/, not .../mcp

The Resource Indicator must also be registered in the WorkOS dashboard (Connect → Configuration), along with Dynamic Client Registration. It becomes the issued token's aud, and the server verifies it byte-for-byte — registering the /mcp path or dropping the trailing slash yields tokens that never validate. The startup check rejects both mistakes with a message naming the fix, rather than letting every tool call fail later at audience verification.

If you only need to work on the capability core, use make dev-local instead — the workshop shell shares the same capabilities, authenticates with a plain PIPELEX_API_KEY, and needs no WorkOS setup at all.

Install dependencies, start the API, then the Skybridge dev server:

npm install

cd ../pipelex-api && make run          # serves http://localhost:8081
npm run dev
# .env at the repo root (gitignored)
WORKOS_AUTHKIT_DOMAIN=<tenant>.authkit.app
PIPELEX_MCP_RESOURCE_INDICATOR=http://localhost:3000/
PIPELEX_BASE_URL=http://localhost:8081

PIPELEX_BASE_URL defaults to the hosted Pipelex API when unset — set it to http://localhost:8081 to develop against a local runner. PIPELEX_API_KEY has no effect on the console: the caller's verified OAuth token always overrides it. .env is dev-only and loaded via nodemon.json (tsx --env-file-if-exists=.env); it is not watched, so restart the dev server after editing it.

If port 3000 is taken, Skybridge falls back to another port and prints it — the Resource Indicator then has to match that port too, both in .env and in the WorkOS dashboard.

The MCP endpoint is at http://localhost:3000/mcp, with Skybridge DevTools at http://localhost:3000.

To poke the local workshop stdio server during development:

make dev-local       # run the stdio server from TypeScript (tsx)
make inspect-local   # open MCP Inspector against it

Build

npm run build        # Skybridge app (regenerates .skybridge/views.d.ts first)
npm run build:local  # tsup → dist/local/main.js (the npm-distributed bin)
npm run check        # lint + format:check + build + build:local + typecheck

mthds_validate registers the run-graph view (src/views/run-graph.tsx), which satisfies Skybridge's "≥1 view entry" production-build requirement. The Skybridge build scans src/views/ and regenerates .skybridge/views.d.ts (the view-name registry) as its first step, so npm run check runs build before the standalone typecheck — the registry must exist for tsc to resolve the registered view name. The local build follows and prepack rebuilds it, so a pack/publish can never ship a stale or absent bin.

Tests

make test         # the default suite — hermetic, no network
make agent-test   # the same suite for an agent — quiet unless it fails
make test-e2e     # the live suite — real client, real Pipelex API
make smoke        # the workshop stdio server, end to end, against the live API
make test-all     # all of the above plus the run family — SPENDS INFERENCE CREDIT

make test fakes every API client, so it proves the projections and never touches the network; make all and CI run only that. The live targets are the drift detector: the faked seams mean a wire-shape change on the API side fails nothing at all in the hermetic suite, so make test-e2e calls each capability with the real PipelexApiClient and make smoke drives the whole shell over stdio. Both need PIPELEX_API_KEY (a gitignored .env at the repo root is enough), and neither spends inference credit — the run family that does only fires under make test-e2e-run. Their codegen legs need one thing more against the hosted API: /v1/codegen sits behind the FF_PLAYGROUND feature flag as well as the plan, so a perfectly valid key whose organization is not enabled for it gets a 403 that reddens the whole run — ask for the flag, or point PIPELEX_BASE_URL at a local runner, which does not gate the route. make smoke is entirely read-only; make test-e2e has one write, the workshop arm of mthds_prepare_inputs, which uploads a 1x1 PNG to your organization's Pipelex storage to prove the upload path still rewrites values to pipelex-storage://. The SDK exposes no delete, so that object persists.

make test-all chains all three in cost order and adds the run family, so a single command covers every test in the repo; it spends inference credit, which is why make all does not reach it. make agent-test is the same hermetic suite as make test with its output captured and replayed only on failure, plus a heartbeat while it runs — meant for coding agents, whose context a few hundred lines of green vitest output would otherwise fill.

The by-id paths need one durable fixture method in the API key's organization; make seed-e2e-fixture creates or refreshes it, idempotently. See CLAUDE.md → "Detecting API drift".

Versioning

pipelex-mcp follows Semantic Versioning; version in package.json is tagged (vX.Y.Z) on release, and npm publish and the Alpic deploy ship together at one version. See CHANGELOG.md for what has shipped. 0.1.0 is the first tagged release.

Available Tools

4 tools
healthA

Simple health check

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.6/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden. 'Simple health check' provides minimal behavioral detail—does not disclose what the check entails, whether it is idempotent, or what side effects (if any) exist. For a read-only operation, this is acceptable but not informative.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four words with no extraneous information. Perfectly concise for a simple health check tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no parameters, an output schema exists, and the tool is a simple health check, the description is sufficient to understand its purpose. The agent can rely on the output schema for return values.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters and schema coverage is 100%, so the description does not need to explain parameters. Baseline is 4 for zero parameters, and the description adds nothing extra, which is acceptable.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description 'Simple health check' clearly indicates the tool performs a health check operation. It is distinct from sibling tools (list_available_pipes, pipe_builder, pipe_runner) which deal with pipeline management, so an agent can easily differentiate.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use this tool versus alternatives. Sibling tools suggest different purposes, but the description offers no explicit context or restrictions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_available_pipesA

List all available pipes in the Pipelex library

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description bears full responsibility. It indicates a read-only listing operation, which is obvious, but lacks details on authentication, rate limits, or side effects.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence with no unnecessary words, efficiently communicating the tool's purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no parameters and no annotations, the description is minimal but functional. Given an output schema exists, it does not need to specify return values, but it could mention what information is returned (e.g., names or IDs).

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so the description does not need to add parameter information. Baseline score of 4 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb 'List' and identifies the resource 'available pipes in the Pipelex library', clearly distinguishing it from sibling tools like 'pipe_builder' and 'pipe_runner'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use this tool versus alternatives; it simply states what it does without context or exclusion criteria.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pipe_builderC

Build a Pipelex pipeline from a natural language request, do not modify it

ParametersJSON Schema
NameRequiredDescriptionDefault
untouched_user_requestYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
plx_contentYes
inputs_format_to_runYes

TDQS

C2.8/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description carries full burden. It only states 'do not modify it', hinting at a non-modifying behavior but does not disclose side effects, errors, or idempotence. Minimal behavioral info.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Short and to the point, but the 'do not modify it' clause is somewhat confusing. Could be slightly more front-loaded, but overall efficient.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite having an output schema, description does not clarify return value or process. Parameter 'untouched_user_request' is unexplained. Insufficient for a tool that builds pipelines from NL.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% and description does not explain the sole parameter 'untouched_user_request'. No hint about what to provide or format. Baseline compensation not met.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action: 'Build a Pipelex pipeline from a natural language request'. It uses a specific verb and resource, and is distinct from siblings like 'health', 'list_available_pipes', and 'pipe_runner'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit guidance on when to use this tool versus alternatives. The 'do not modify it' part is vague and not helpful for selection. Lacks context such as prerequisites or exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

pipe_runnerD

Run a Pipelex pipeline (optionally with PLX content)

ParametersJSON Schema
NameRequiredDescriptionDefault
plx_contentYes
specific_pipe_code_if_plx_content_has_no_main_pipeYes
inputs_jsonYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

D1.7/5.0
Behavior1/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, description carries full burden but only provides a vague action. Contradicts schema about optionality, and no disclosure of side effects, permissions, or outcomes.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is very short (10 words), but conciseness is undermined by inaccuracy and lack of necessary information. Front-loads purpose but not effectively.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness1/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite an output schema existing, the description fails to provide essential context for a 3-param tool with required inputs. No behavioral or usage context, and schema contradiction makes it unreliable.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, and description fails to explain the three required parameters (plx_content, specific_pipe_code_if_plx_content_has_no_main_pipe, inputs_json). The one mention of PLX content contradicts the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose2/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states 'Run a Pipelex pipeline (optionally with PLX content)', but the input schema lists plx_content as required, creating a contradiction. This misleads about whether PLX content is mandatory.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use this tool versus siblings like pipe_builder or list_available_pipes. No context about prerequisites or scenarios.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 4 tool updatesv0.1.7
    • First observedhealth
    • First observedlist_available_pipes
    • First observedpipe_builder
    • First observedpipe_runner

TDQS

B3.1/5.0

Scored across 4 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: health check, listing pipes, building a pipeline, and running a pipeline. No overlap between any pair.

Naming Consistency4/5

Most tools use snake_case with verb_noun or noun_verb pattern (list_available_pipes, pipe_builder, pipe_runner). 'health' is a single noun without underscore, creating slight inconsistency but still clear.

Tool Count5/5

4 tools is well-scoped for a pipeline management server: health, list, build, run. Each tool serves a necessary function without redundancy.

Completeness4/5

Covers the core lifecycle: listing available pipes, building a pipeline, and running it. Missing possibly a tool to inspect a specific pipe or delete one, but not essential for basic operation.

Maintenance

ActivityActive
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers