Skip to main content
Glama
awictor

flow-agent-mcp

by awictor
README.md
# flow-agent-mcp

An MCP server that exposes Estuary Flow pipeline operations as typed tools, plus
three runnable demo pipelines built on public datasets. It wraps Estuary's
`flowctl` CLI so an agent can drive Flow directly.

## What it does

Each tool wraps a real `flowctl` command with typed, validated inputs and
returns structured JSON. An agent (or a person through Claude Code) can inspect
a pipeline's health, publish captures and materializations, edit and restart
tasks, and read landed documents, all through tool calls rather than hand-typed
CLI commands.

## Tools

Every tool maps to a real `flowctl` invocation, echoed back in the response as
`command` so the underlying call is always visible.

| Tool | Wraps |
|---|---|
| `list_tasks` | `catalog list --captures/--materializations/--collections --output json` |
| `task_status` | `catalog status <task> --output json [--connected]` |
| `task_stats` | `raw stats --task <task> --since <dur>` |
| `task_logs` | `logs --task <task> --since <dur>` (parsed, level-filtered) |
| `task_health` | status + stats + error logs in one call |
| `discover_bindings` | `discover --source flow.yaml` |
| `create_capture` | `catalog publish --source flow.yaml --auto-approve` |
| `create_materialization` | `catalog publish --source flow.yaml --auto-approve` |
| `pull_specs` | `catalog pull-specs --name <task>` |
| `set_task_enabled` | pull specs → toggle `shards.disable` → publish |
| `restart_task` | the disable/verify/enable sequence |
| `read_collection` | `collections read --collection <name> --output json [--since <dur>]` |
| `generate_synthetic_data` | demo record generator (no flowctl) |

Notes on behavior worth knowing:

- **`set_task_enabled` handles the spec surgery.** It pulls the live spec,
  toggles `shards.disable` cleanly, and republishes, so enable/disable is one
  call rather than a manual edit-and-publish loop.
- **Failures return flowctl's own message** as a structured MCP error result
  instead of throwing, so the calling agent gets actionable text.
- **`flowctl` publishes from files**, not inline specs, so specs are written to a
  scratch directory and cleaned up after.

## Setup

```bash
npm install
npm test          # 127 checks, no flowctl or Estuary account needed
```

Add to Claude Code:

```bash
claude mcp add estuary-action -- npx tsx /path/to/estuary-mcp/src/index.ts
```

Real operations need `flowctl` on PATH and `flowctl auth login`. Set
`ESTUARY_DRY_RUN=true` to echo commands without executing them, or
`FLOWCTL_PATH` to point at a specific binary.

## Demo pipelines

Each demo builds a complete catalog — capture, collections, derivation,
materialization — from a public dataset shape.

| Demo | Dataset | Exercises |
|---|---|---|
| `gpu` | [Cloud GPU Price Index](https://gpucloudcompare.com/data/) | HTTP ingest, filter derivation, BigQuery fan-out |
| `weather` | [Open-Meteo](https://open-meteo.com) (live, no API key) | polling an open API, threshold alerts, Postgres |
| `property` | [Property Comps](https://api.nwc-advisory.com/docs) | Postgres CDC, aggregation with reduce annotations, Snowflake |

Generate a catalog and publish it:

```bash
npm run catalog -- gpu acmeCo/gpu > flow.yaml
flowctl catalog publish --source flow.yaml --auto-approve
```

Generate data to feed a pipeline:

```bash
npm run demo:gpu -- 500                 # NDJSON to POST at the ingest endpoint
npm run demo:weather                    # live Open-Meteo readings
npm run demo:weather -- --watch 300     # poll every 5 minutes
npm run demo:property -- 1000 --sql     # INSERTs for the CDC source table
npm run demo:property -- --ddl          # table + replication slot + publication
```

The weather demo pushes directly to Estuary when `WEATHER_INGEST_URL` and
`WEATHER_INGEST_TOKEN` are set. The ingest URL is only shown in the dashboard
after publishing, under the capture's Endpoints section.

### Aggregation correctness

The property rollup sums sales per market. Aggregating derivations emit one
delta document per source row and rely on schema `reduce:` annotations to fold
deltas that share a key. The top-level `reduce: { strategy: merge }` combines
matching deltas and is set alongside the per-field strategies. `aggregateSchema()`
in `src/specs.ts` applies both levels, and `test/catalog.test.mts` asserts they
are present.

## Layout

```
src/
  index.ts          MCP server and tool definitions
  flowctl.ts        subprocess wrapper, NDJSON parsing, scratch spec files
  specs.ts          catalog spec builders (captures, derivations, reductions)
  shards.ts         shards.disable spec surgery
  yaml.ts           literal-block YAML so SQL lambdas survive serialization
  demos/            three end-to-end pipelines
  synthetic/        record generators
test/
  shards.test.mts   disable/enable spec editing
  catalog.test.mts  spec shape, key/schema/reduce invariants
  mcp-client.test.mts  real MCP transport, command construction, validation
```

## Status

**Tested (offline, 127 checks):** tool registration and schema validation over a
real MCP client connection, exact `flowctl` command construction for every tool,
shard spec editing, output parsing, and catalog invariants across all three
demos.

**Verified against a live Estuary tenant.** A full source-to-destination pipeline
was published and run end to end:

- an HTTP-ingest capture landing documents into a collection,
- a SQLite derivation filtering those readings into threshold-based alerts,
- schema inference widening a field's bounds and republishing the task on its own,
- a Postgres materialization writing both collections into an external database,
  confirmed by querying that database directly (8 readings, 3 alerts).

TDQS

A3.6/5.0

Scored across 13 tools

Disambiguation4/5

Most tools have clearly distinct purposes: stats, logs, health, status, create, discover, etc. The health tool intentionally combines status and stats, but its description clearly delineates its role. Minor confusion is possible between task_status and task_health, but each serves a distinct need.

Naming Consistency3/5

Names mix noun-first patterns (task_stats, task_logs, task_health, task_status) with verb-first patterns (discover_bindings, create_capture, list_tasks). While all names use snake_case and are readable, the inconsistent prefix style makes the naming less predictable.

Tool Count5/5

13 tools is a well-scoped count for a Flow management server. It covers monitoring, lifecycle operations, discovery, and data verification without excessive overlap or unnecessary bloat.

Completeness3/5

The toolset covers monitoring, creation, enable/disable, restart, and inspection well. However, there is no explicit delete or general update operation beyond toggling enabled state, which is a notable gap for full task lifecycle management.

Maintenance

ActivityMaintained
ResponsivenessNo issues