Ctrl K
ComunidadGuías…

specs/020-mcp-server.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Spec: MCP Server

Status: Draft.

## Scope

This spec defines the MCP endpoint, authentication contract, API-key surface
acceptance, and `dagu://` resource reads exposed by Dagu.

This spec does not define the MCP tool specs (`dagu_read`, `dagu_change`, or
`dagu_execute`), prompts, subscriptions, audit events, Web UI behavior, storage
internals, or MCP SDK internals.

## Goal

Dagu exposes MCP through one authenticated endpoint. MCP clients read Dagu
objects through `dagu://` resource URIs instead of depending on REST paths,
local files, or generated API structs.

## Behavior

### Endpoint

Dagu exposes MCP over Streamable HTTP.

Rules:

- The MCP endpoint path is `/mcp` when the Dagu HTTP server has no base path.
- When the Dagu HTTP server is mounted under a base path, the MCP endpoint path
  is that base path followed by `/mcp`.
- The MCP endpoint belongs to the same Dagu server origin as the REST API and
  Web UI.
- Requests sent to any other path are outside this spec.
- The endpoint must not expose filesystem paths or storage paths as MCP route
  structure.
- While a standalone event stream (`GET`) is open, the server writes an SSE
  comment immediately after the response headers and again at intervals of no
  more than 30 seconds. Clients ignore SSE comments.

### Authentication

MCP requests use the Dagu server's configured authentication mode.

Rules:

- MCP requests are authenticated by the Dagu HTTP server before MCP request
  handling.
- When authentication is disabled for the Dagu server, the MCP endpoint accepts
  requests without credentials.
- `Authorization` is the canonical credential carrier.
- Built-in authentication uses `Authorization: Bearer <token>`, where
  `<token>` is a Dagu login token or a Dagu API key.
- Basic authentication uses
  `Authorization: Basic <base64(username:password)>`.
- For clients that cannot send headers, the server may accept `?token=<token>`
  as a bearer-token fallback when no `Authorization` header is present.
- An accepted credential establishes identity only. Requested Dagu operations
  still apply normal authorization checks.

This spec does not define token issuance, token internals, API-key storage,
OIDC login flow, or exact HTTP challenge bodies.

### API-Key Surface

API keys can restrict which server surfaces accept them.

Rules:

- The MCP endpoint accepts an API key only when that key is valid and includes
  the `mcp` surface.
- An API key that includes only the `rest_api` surface is not accepted by the
  MCP endpoint.
- An API key that includes only the `mcp` surface is not accepted by REST API
  routes solely because it is valid for MCP.
- Surface acceptance is checked by the Dagu HTTP server before an MCP request
  is handled.

### Resource URI Model

Dagu MCP resources use the `dagu` URI scheme.

URI identity rules:

- Resource URIs must use the `dagu` scheme.
- The URI host identifies the resource family.
- Path segments identify a resource inside that family.
- DAG names, DAG-run IDs, and reference topic names that contain URI-reserved
  characters must be percent-encoded as path segments.
- A resource URI identifies current Dagu state at read time. It is not a
  historical snapshot unless the named Dagu object is itself historical.
- Resource reads are read-only. Resource URIs do not define mutation or run
  control behavior.

Collection resource rules:

- Collection resource reads enumerate resources visible to the caller. They
  remain resource reads and are not tool calls.
- Collection resources may accept query parameters supported by the
  corresponding Dagu list API.

Query parameter rules:

- Query parameters are unsupported unless a resource family explicitly allows
  them.
- Query strings use normal URL query encoding.
- Unknown or malformed query parameters fail with `invalid_resource_uri`.
- Query parameters must not change the identity of a singular resource.

Invalid URI rules:

- Unsupported URI hosts, unsupported path shapes, and malformed URIs fail with
  `invalid_resource_uri`.

Supported resource families:

| Family | URI shape | MIME type | Content |
| --- | --- | --- | --- |
| Reference collection | `dagu://reference` | `application/json` | Available built-in MCP reference resources. |
| Reference topic | `dagu://reference/{topic}` | `text/markdown` | Built-in MCP reference text for a server-advertised topic. |
| DAG collection | `dagu://dags` | `application/json` | DAG summaries visible to the caller. |
| DAG spec | `dagu://dags/{name}/spec` | `application/yaml` | Current YAML specification for the named DAG. |
| Run collection | `dagu://runs` | `application/json` | DAG-run summaries visible to the caller. |
| Run details | `dagu://runs/{name}/{dagRunId}` | `application/json` | Current DAG-run details for the named DAG run. |
| Run logs | `dagu://runs/{name}/{dagRunId}/logs` | `application/json` | Current log data for the named DAG run. |
| Step log | `dagu://runs/{name}/{dagRunId}/steps/{stepName}/logs` | `application/json` | Current stdout and stderr data for one DAG-run step. |
| Child run details | `dagu://runs/{name}/{dagRunId}/sub/{subRunId}` | `application/json` | Current details for a child DAG run addressed under its root run. |
| Child step log | `dagu://runs/{name}/{dagRunId}/sub/{subRunId}/steps/{stepName}/logs` | `application/json` | Current stdout and stderr data for one child-run step. |
| Foreach items | `dagu://runs/{name}/{dagRunId}/steps/{stepName}/foreach` | `application/json` | Items of a foreach step with the status each body run reached. |
| Foreach item | `dagu://runs/{name}/{dagRunId}/steps/{stepName}/foreach/{item}` | `application/json` | One foreach item with the status of each body step. |
| Foreach step log | `dagu://runs/{name}/{dagRunId}/steps/{stepName}/foreach/{item}/steps/{bodyStepName}/logs` | `application/json` | Current stdout and stderr data for one body step of a foreach item. |
| Child foreach items, item, and step log | The three foreach shapes under `dagu://runs/{name}/{dagRunId}/sub/{subRunId}` | `application/json` | The same for a foreach step of a child run. |
| Wiki collection | `dagu://wiki` and `dagu://wiki/{workspace}` | `application/json` | Wiki pages visible to the caller. |
| Wiki page | `dagu://wiki/{workspace}/{path}` | `text/markdown` | Current Markdown content for the named Wiki page. |

### Resource Content

Rules:

- Reference collection resources return the available reference resource URIs
  and titles or descriptions when available.
- The built-in reference topic set includes `authoring`, `tools`, `apps`,
  `read-tool`, `change-tool`, `execute-tool`, and `notifications`.
- Reference topic resources return Markdown text owned by the Dagu MCP server.
- DAG collection resources return a paginated or bounded list of DAG summaries
  visible to the caller.
- DAG spec resources return a YAML document representing the current stored DAG
  specification.
- Run collection resources return a paginated or bounded list of DAG-run
  summaries visible to the caller.
- Run detail resources return JSON using Dagu's run-inspection model.
- Run log resources return JSON using Dagu's run-log model.
- This spec does not freeze the exact JSON field set or generated schema for
  collection, run detail, or run log resources.
- Run log and step log resources may accept query parameters supported by the
  Dagu log reader.

## Errors

Server-level failures and resource-read failures return a Dagu MCP error
object, not resource content:

```json
{
  "code": "invalid_resource_uri",
  "message": "Resource URI is malformed.",
  "resourceUri": "dagu://runs/example/run-id/logs",
  "operation": "resources/read",
  "details": {
    "field": "uri"
  }
}
```

`resourceUri`, `operation`, and `details` are omitted when they do not apply.

Clients must branch on `code`, not parse `message`.

Required error codes for this spec:

`unauthenticated`, `unauthorized`, `invalid_api_key_surface`,
`invalid_resource_uri`, `unsupported_resource`, `resource_not_found`,
`resource_unavailable`, `internal_error`.

Common conditions map to codes as follows:

| Condition | Code |
| --- | --- |
| Authentication is required and the request is not authenticated. | `unauthenticated` |
| The accepted credential is not authorized for the requested operation. | `unauthorized` |
| A valid API key is not accepted for the `mcp` surface. | `invalid_api_key_surface` |
| The resource URI is malformed, uses the wrong scheme, or has an unsupported path shape. | `invalid_resource_uri` |
| The resource URI host is not a supported resource family. | `unsupported_resource` |
| The named resource does not exist. | `resource_not_found` |
| The resource exists but cannot currently be read. | `resource_unavailable` |
| The server fails unexpectedly while handling the request. | `internal_error` |

## Examples

Default endpoint:

```text
http://localhost:8080/mcp
```

Endpoint under a server base path:

```text
https://dagu.example.com/dagu/mcp
```

Built-in reference collection:

```text
dagu://reference
```

Built-in reference topic:

```text
dagu://reference/authoring
```

Detailed tool reference topics:

```text
dagu://reference/read-tool
dagu://reference/change-tool
dagu://reference/execute-tool
```

DAG collection with list filters:

```text
dagu://dags?name=nightly&perPage=20
```

DAG spec resource:

```text
dagu://dags/nightly-report/spec
```

Run collection with list filters:

```text
dagu://runs?name=nightly-report&limit=20
```

Run detail resource:

```text
dagu://runs/nightly-report/20260701T010000Z
```

Run log resource with a log-reader query:

```text
dagu://runs/nightly-report/20260701T010000Z/logs?tail=100
```

An API key with only this accepted surface can be used at the MCP endpoint:

```json
["mcp"]
```

An API key with only this accepted surface is rejected by the MCP endpoint:

```json
["rest_api"]
```