Files
app/docs/code/agents.md
T

146 lines
5.6 KiB
Markdown

# Agents over MCP
The engine exposes the flow API to agents over the
[Model Context Protocol](https://modelcontextprotocol.io). Point Claude Code,
Claude Desktop, Codex or anything else that speaks MCP at it, and it can read,
build, publish and run flows.
## Switching it on
```sh
MCP_ENABLED=true
```
It is off by default: switching it on opens client registration to whoever can
reach the host.
The endpoint is `https://api.${DOMAIN}/mcp`, or `http://api.localhost/mcp` on a
local stack.
## Connecting a client
```sh
claude mcp add --transport http fluksio https://api.${DOMAIN}/mcp
```
The OAuth flow does the rest: the client registers itself, you approve it in
the browser, and it exchanges the grant for a token. Nothing to paste.
## What an agent may do
An agent acts as **the person who approved it**, and only through the same REST
API the dashboard uses. It cannot do anything you could not do in the browser,
and it cannot do anything *you* cannot do. An agent approved by a non-superuser
is not one either.
Its tokens are signed with a keypair of their own, kept beside the flow store.
Deleting that file revokes every agent's access without logging anyone out of
the dashboard.
Registered clients are managed under **Admin**.
## The tools
Read-only:
| Tool | Returns |
|---|---|
| `list_flows` | every flow with its node count and state |
| `get_flow` | one flow's definition, node status and issues |
| `get_node_source` | a node's Python |
| `list_node_types` | every type and its parameter schema |
| `get_flow_state` | the current value of each of a flow's messages |
| `get_message_history` | one message's recent numeric values |
| `get_graph` | every flow as one graph |
| `list_shared_nodes` | the shared library and its usages |
| `list_secrets` | secret **names**, never values |
| `get_modules` | the packages node code can import |
| `get_health` | flows, nodes, queue and loop lag |
| `get_metrics` | executions, errors and timings per minute |
| `list_failures` | what went wrong recently |
| `list_runs` | recent cascades |
Editing:
| Tool | Does |
|---|---|
| `save_flow` | write a draft |
| `save_node_source` | write a node's code into the draft |
| `validate_flow` | the issues, without saving |
| `publish_flow` | put the draft live (takes the version it saw) |
| `discard_draft` | throw the draft away |
| `delete_flow` | delete it |
| `apply_modules` | replace the package manifest |
Operating:
| Tool | Does |
|---|---|
| `run_flow` | run every node once from the values given |
| `trigger_node` | feed one node and run what is downstream |
| `start_flow` / `stop_flow` | activate or tear down |
| `pause_flow` / `resume_flow` | hold messages, or let them through |
| `cancel_node` | kill a node's code while it runs |
## Why it is shaped this way
The tools do not reach into the engine. Each one calls the same REST endpoint
the dashboard calls, over an in-process transport.
That keeps exactly one description of what a flow is and how it may be changed:
the validation, the draft/publish split, and the version check that stops two
clients overwriting each other. An agent saving a flow through a private back
door could write one the canvas cannot open.
The caller's token rides along on every hop, so the API sees the agent's own
identity rather than a service account. The audit trail on Home names it.
## The assistant
The same tools drive the chat inside the dashboard. An operator sets a
provider under **Settings → Assistant** (anything OpenAI-compatible: OpenAI,
Anthropic, OpenRouter, a local Ollama), and an **Assistant** entry appears in
the sidebar for everyone. The panel opens on any screen and keeps its place
from screen to screen; on a flow, it knows which one you are looking at.
The model calls the tools above, in-process, as **you**: every call carries
your own token, so the chat can do nothing you could not do yourself, and its
edits show up in the editor as drafts the moment they are saved. It is told to
publish only when asked, but it has the tool, so read what it did before
saying so. The trace under each answer lists every call it made.
The conversation is one per person, kept on the instance beside the
configuration, and the bin in the panel's header starts it over. `MCP_ENABLED`
is not needed for it: the endpoint is for agents outside, the chat for the
one inside.
## Control
Where a live flow has a [`wren` node](../reference/node-types.md#wren) with
its `prompt` and `actions` wired, the chat gains a **Control** tab, and Home a
chat button at the top right of the brain graph (in the header, on a phone)
that opens it. No provider is needed for this one: the model is the node.
A command is published to the node's `prompt` message as a value from the
chat, and the answer is the next value of its `actions`: each call, the
message it went to, whether it was applied, and how sure the model was. A
failing node answers with its error, and one that says nothing for fifteen
seconds is reported as such. With several nodes, a picker in the header
chooses. The conversation is kept in the browser only, and a reload clears
it.
## A note on working this way
The pattern that works is the same one that works with a person: let the agent
read the flow and its issues, let it write a **draft**, and publish yourself
once you have looked. `validate_flow` before `publish_flow` is cheap and tells
you what the canvas would have told you.
## Limits
- MCP is not currently reachable through a [portal](../interface/portal.md)
tunnel: the proxy forwards `/api/v1/` only. Connect an agent on the same
network as the instance.
- Secrets are never readable, by an agent or by anyone else. `list_secrets`
returns names.