dagster-mono-mcp
# dagster-mono-mcp
A single-tool [MCP](https://modelcontextprotocol.io/) server for [Dagster](https://dagster.io). One tool, five actions, minimal token overhead.
Dagster has an [official MCP server](https://github.com/dagster-io/dagster/tree/master/python_modules/libraries/dagster-mcp), but I couldn't get it working easily. This is a minimal alternative that covers the actions you actually need when debugging pipelines with an LLM: listing runs, inspecting run details, reading logs, and raw GraphQL for everything else.
Supports [Cloudflare Access](https://developers.cloudflare.com/cloudflare-one/applications/configure-apps/self-hosted-apps/) for Dagster instances behind Zero Trust — an easy, free way to secure your Dagster instance.
## Install
### Claude Code
Project-scoped (`.mcp.json` in your project root):
```json
{
"mcpServers": {
"dagster": {
"command": "npx",
"args": ["-y", "github:pjatx/dagster-mono-mcp"],
"env": {
"DAGSTER_GRAPHQL_URL": "https://dagster.example.com/graphql",
"CF_ACCESS_CLIENT_ID": "your-client-id",
"CF_ACCESS_CLIENT_SECRET": "your-client-secret"
}
}
}
}
```
Global (`~/.claude.json` — available in all projects):
```json
{
"mcpServers": {
"dagster": {
"command": "npx",
"args": ["-y", "github:pjatx/dagster-mono-mcp"],
"env": {
"DAGSTER_GRAPHQL_URL": "https://dagster.example.com/graphql"
}
}
}
}
```
### Cursor
Add to `.cursor/mcp.json` in your project root:
```json
{
"mcpServers": {
"dagster": {
"command": "npx",
"args": ["-y", "github:pjatx/dagster-mono-mcp"],
"env": {
"DAGSTER_GRAPHQL_URL": "https://dagster.example.com/graphql",
"CF_ACCESS_CLIENT_ID": "your-client-id",
"CF_ACCESS_CLIENT_SECRET": "your-client-secret"
}
}
}
}
```
### Windsurf
Add to `~/.codeium/windsurf/mcp_config.json`:
```json
{
"mcpServers": {
"dagster": {
"command": "npx",
"args": ["-y", "github:pjatx/dagster-mono-mcp"],
"env": {
"DAGSTER_GRAPHQL_URL": "https://dagster.example.com/graphql",
"CF_ACCESS_CLIENT_ID": "your-client-id",
"CF_ACCESS_CLIENT_SECRET": "your-client-secret"
}
}
}
}
```
## Environment Variables
| Variable | Default | Required |
|----------|---------|----------|
| `DAGSTER_GRAPHQL_URL` | `http://localhost:3000/graphql` | No |
| `CF_ACCESS_CLIENT_ID` | — | No (required if behind CF Access) |
| `CF_ACCESS_CLIENT_SECRET` | — | No (required if behind CF Access) |
## Usage
Single tool `dagster` with action dispatch:
### List runs
```json
{"action": "runs"}
{"action": "runs", "status": "FAILURE"}
{"action": "runs", "job": "my_job", "limit": 5}
```
### Run details
```json
{"action": "run", "id": "<run-id>"}
```
### Event logs
```json
{"action": "logs", "id": "<run-id>"}
{"action": "logs", "id": "<run-id>", "limit": 100}
```
### Raw GraphQL
```json
{"action": "graphql", "query": "{ version }"}
{"action": "graphql", "query": "query($id: ID!) { runOrError(runId: $id) { __typename } }", "variables": {"id": "abc123"}}
```
### Help
```json
{"action": "help"}
```
Returns full documentation including available statuses, all parameters, and example queries.
## Design
This project follows the mono-tool pattern: one MCP tool with action dispatch instead of many small tools. Fewer tools means less token overhead for the LLM and simpler tool selection — the model doesn't have to choose between a dozen similar-sounding tools. Inspired by Cloudflare's [Code Mode](https://blog.cloudflare.com/code-mode/) post on rethinking how LLMs interact with MCP servers.
## Development
```bash
npm install
npm run build # esbuild bundle -> dist/index.js
npm start # run the MCP server (stdio transport)
```
## License
MIT
TDQS
Scored across 1 tool
The single tool 'dagster' has clearly distinct actions (runs, run, logs, graphql, help) with no overlap in purpose. Each action targets a specific operation within the Dagster domain, making misselection impossible.
The tool naming is perfectly consistent as there is only one tool, 'dagster', and its actions follow a clear, uniform pattern (e.g., 'runs', 'run', 'logs') without any mixing of conventions or styles.
With only one tool, the server feels thin for a Dagster monitoring/debugging domain, as it bundles multiple distinct operations (e.g., querying runs, fetching logs, GraphQL) into a single tool. This may limit clarity and usability compared to a more granular tool set.
The tool covers core operations like retrieving runs, logs, and GraphQL queries, but lacks obvious lifecycle actions such as triggering new runs, pausing/resuming, or managing assets. This creates notable gaps for a full Dagster debugging workflow.