Skip to content

MCP server (agent tools)

faucet can expose itself as an MCP (Model Context Protocol) server, so an LLM agent (Claude Desktop / Code, or any MCP client) can operate faucet: discover connectors, read their config schemas, scaffold and validate a pipeline YAML, preview sample records, and — behind an explicit opt-in — run a pipeline.

MCP is not a data connector (there is no faucet-source-mcp); it is a second front-door onto the operations faucet serve already implements. The MCP layer adds no pipeline capability — it re-exposes existing, schema-introspective surfaces in the shape an agent speaks.

The prebuilt binaries (Homebrew, the curl | sh installer and the release archives — see Installation) include it, so faucet mcp works out of the box. From crates.io it is the mcp feature (off in the default build; included in full):

Terminal window
cargo install faucet-cli --features mcp

For a local agent. Reads newline-delimited JSON-RPC on stdin, writes responses on stdout (logs go to stderr):

Terminal window
faucet mcp # read-only tools
faucet mcp --allow-mutations # also expose run_pipeline
faucet mcp --template-store sqlite:./faucet-templates.db # + the template tools

Claude Desktop config (claude_desktop_config.json):

{
"mcpServers": {
"faucet": { "command": "faucet", "args": ["mcp"] }
}
}

stdio has no bearer/RBAC layer. Without --allow-mutations the server treats every config the client sends as untrusted, because preview builds and reads the source it is handed: configs are screened like a body submitted to faucet serve — subprocess connectors (singer), ${env:} / ${file:} / secret-manager directives and local file paths are refused. Pass --allow-mutations only for a trusted local agent: its configs then run with your user’s access and run_pipeline is exposed. Do not expose stdio remotely — use the HTTP transport with auth for that.

Mounts a /mcp route on the running control plane. It inherits serve’s bearer-auth + RBAC + audit — an MCP request is authenticated, authorized, and recorded exactly like any other API call:

Terminal window
faucet serve --mcp --auth-token "$TOKEN"
faucet serve --mcp --mcp-allow-mutations --auth-config rbac.yaml
Terminal window
curl -s localhost:8080/mcp -H "Authorization: Bearer $TOKEN" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Read-only tools are always available; the mutating run_pipeline tool appears only when the server is started with --allow-mutations and (on HTTP) the caller holds the RunWrite RBAC scope — so a Viewer token can never mutate, even on a mutation-enabled server.

Tool Mutating? What it does
list_connectors no Sources, sinks, transforms, state stores + conformance tier.
get_connector_schema no JSON Schema for a connector / transform config.
scaffold_config no A commented YAML skeleton for a source→sink pair.
validate_config no Full load-time validation (matrix or topology).
preview no Up to 100 sample records from the first source (source side only).
run_pipeline yes Run an inline config. Pass dry_run: true to validate + preview only, and selection ({select, only, skip, tags, status, include_parents}) to run only some matrix rows.
list_templates no Registered pipeline templates and the typed params each takes.
get_template no One template: declared params, stored config body, and its release state (status, stable / previous / newest, channel pointers, launch log).
list_template_rows no A template’s selectable rows — a source template’s streams (write resolution and guarantees against sink when given) or a pipeline’s matrix rows — with status, tags, hierarchy, read/write facts, params used and the last run’s state. With selection, also the run_set a run with it would execute, the ancestors it pulls in, and the rows it blocks. See Running a subset of streams.
register_template yes Register a template document as a new version — kind: source-template, kind: sink-template, or kind: pipeline. Inert by default — pass launch: true to make it live.
run_template yes Run a template with given params / env, at a version or named channel (default stable — the launched version). A source template also takes sink (a registered sink template) + sink_version, and optionally overlay (a registered deployment id or an inline mapping — an inline one is screened under the caller reference policy and refused for a tenant) + overlay_version. dry_run: true materializes + validates only and reports the per-stream write-mode plan. selection runs a subset of the streams / rows (the dry run reports the run_set).

On faucet serve --mcp, run_pipeline and run_template submit through the server exactly as POST /v1/runs / POST /v1/templates/{id}/runs do, as the calling principal — the approval gate, the server --policy, the --default-config, the run queue and the run record all apply — and answer with the run_id (or the pending change request). Poll it with GET /v1/runs/{id}. On stdio they run the pipeline in the MCP process and report its counts. A run_template env override names a variable the template reads (${env:NAME} / ${secret:NAME}) and is literal text: a value containing ${ is refused, and a tenant-scoped principal may not pass env.

The four template tools appear only when a registry is wired — faucet serve --mcp uses its own --history backend; faucet mcp needs --template-store <url>. Without one they are not advertised at all, so an agent never sees a tool it cannot use.

Templates are the ergonomic shape for agent-driven runs: the agent discovers the typed parameter surface with list_templates / get_template and then supplies only the values that change, instead of composing (and possibly mis-composing) a whole config. A secret: true param is echoed back as "***".

Every MCP call over HTTP is written to the audit log; secret material is redacted from any tool output.

A JSON-RPC 2.0 subset: initialize, tools/list, tools/call, resources/list, ping. The advertised protocol version is 2024-11-05.

// → initialize
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}
// ← {"result":{"protocolVersion":"2024-11-05","serverInfo":{"name":"faucet",…}}}
// → discover + generate + check, then (with permission) run
{"jsonrpc":"2.0","id":2,"method":"tools/call",
"params":{"name":"scaffold_config","arguments":{"source":"rest","sink":"bigquery"}}}
  • Read-only by default. run_pipeline, register_template, and run_template are absent from tools/list unless mutations are enabled. preview still executes the source it is given, so without mutations the stdio server screens configs as untrusted (see above).
  • HTTP inherits serve auth. Bearer/RBAC + audit apply to /mcp as to any route; mutations additionally require the RunWrite scope.
  • preview is bounded (≤100 rows) — never a full extract. It reads pages only until the limit is reached and stops after 30 seconds, returning what it has with "timed_out": true; run_pipeline {dry_run: true} previews the same way.
  • Secrets never leak — tool output is run through the same redactor as the rest of the control plane.