Skip to content
🐋Cetacean

MCP tools and resources

This page is the catalog an agent sees over Cetacean’s MCP server: 14 resources, 27 tools, 6 prompts, and 5 widgets. For enabling the server, authorization, and configuration, see MCP server.

Everything here is filtered per identity. A tool above the configured operations level isn’t registered at all; a tool or resource the identity holds no grant for is hidden from the listing and refused at call time.

Tools

Tools are gated by operations level (mcp.operations_level, inheriting server.operations_level) and by per-resource write grants. Every MCP tool requires the same operations level as the API route for the same operation, so there’s no MCP-specific scheme to learn.

Each tool advertises the behavioral hints (readOnlyHint, destructiveHint, idempotentHint, openWorldHint) clients use to gate confirmation prompts and an output schema the server validates results against. A mutating tool returns an error when someone else changed the resource first, so re-read it and retry.

Caution

Removals are irreversible: no spec history is retained after a service removal, and a config, secret, or volume payload can’t be recovered.

Orientation

Where to start, and how to turn a name into something you can act on. find and describe attach links to the resources they returned, so a host can offer somewhere to go next.

get_cluster_status

Answers whether the cluster is healthy and, when it’s not, names the services not in their desired state or restarting in a loop, the nodes down or draining, the rollouts in flight, and reserved against total CPU and memory. Start here.

arguments
none
level
0 (read-only)

find

Locates resources. With type it enumerates that type, paged by offset and capped at the same 200 the default sets. Without type it searches every type at once: offset is ignored, and the result carries counts, the per-type breakdown behind total.

arguments
type (plural: nodes, services, tasks, stacks, configs, secrets, networks, volumes), query, state, stack, node, image, label, limit (200 typed, 3 per type otherwise), offset, raw
level
0 (read-only)

describe

Returns one resource as a Digest. id takes an ID or a name—a hostname for a node, the rendered {service}.{slot} for a task, the plain name for everything else—and a name matching more than one resource is refused, naming the matching IDs.

arguments
type (singular, required: service, node, task, stack, config, secret, network, volume), id (required), raw
level
0 (read-only)

get_topology

Projects the cluster as a graph: network joins services to the overlay networks they attach to, placement joins nodes to the services they run, and drain-impact joins the services on one node to the nodes that could take them.

In drain-impact a service with no edges is stranded, and its detail names the placement constraint that blocked it; a global service reports as global, since draining stops its task rather than relocating it. Constraints are evaluated the way Swarm enforces them; spare capacity isn’t considered, since get_cluster_status already reports reserved against total. Where grants hid candidate nodes, the graph carries a note saying what the assessment was narrowed to.

arguments
view (network, placement, drain-impact), node (for drain-impact)
level
0 (read-only)

Observation

What the cluster is doing now, and what it did recently.

get_logs

Fetches recent log lines from one scope.

A task reads one replica and is the only way to reach one that has already exited—the form to reach for after a crash, and the most perishable, since Swarm discards a task’s output with the task record, five per replica slot by default. A service in a restart loop may hold seconds of history, so read it first. stack and cluster merge server-side and attribute each line to its service, so grepping the cluster with contains costs one call; a wide read covers at most 25 services and reports what it couldn’t reach in errors rather than failing.

arguments
exactly one of service, task, stack, cluster; plus contains, tail (100 per replica), since, level (debug, info, warn, error, fatal)
level
0 (read-only)

get_events

The change timeline, newest first. resource takes a name as readily as an ID, resolved against types when exactly one is given and otherwise only where no other type claims the name. A service’s timeline includes its tasks’ entries unless types leaves out task.

arguments
since, until, types, resource, limit
level
0 (read-only)

get_metrics

Charts or ranks CPU, memory, or network use. It takes a target and a metric rather than PromQL, resolves the service or node against Cetacean’s cache, and checks the caller’s read grant before querying.

Asking for top turns it into a ranking: target: "cluster" ranks the busiest services, or nodes with by: "node", and target: "node" with an id ranks the services on that host, which answers why a node is hot.

Metrics need Prometheus, plus cAdvisor for service metrics and node-exporter for node metrics; without them the tool says metrics are unavailable rather than returning empty series.

arguments
target (required: service, node, cluster), id, metric (cpu, memory, network), range (1h, 6h, 24h, 7d), top (5, capped at 10), by
level
0 (read-only)

get_recommendations

The recommendation engine’s current findings, the same ones cetacean://recommendations returns, with totals counting what the caller may read. A finding with a remedy carries it as fix, naming the tool to call, for example {"tool": "update_service", "section": "resources"}. A finding whose REST fixAction route has no MCP tool behind it reports no fix.

arguments
severity
level
0 (read-only)

watch

Blocks until a service has settled, then reports whether it did. It exposes the same convergence rule the converging mutations use, as a read; the wait can’t be canceled once started.

arguments
service (required), timeout (60 seconds, capped at 300)
level
0 (read-only)

Service lifecycle

Running services: how many replicas, which image, and starting over. All four converging tools accept task augmentation and return a summary of where the service ended up rather than its full spec:

{
    "id": "web",
    "name": "web",
    "image": "nginx:1.27",
    "mode": "replicated",
    "replicas": 5,
    "running": 5,
    "state": "running",
    "version": 42
}

running is the live count, state is the same derivation the dashboard and the API report, and version is the Swarm version index for a caller doing its own concurrency checks. replicas is omitted for a global service.

scale_service

Sets the desired replica count. 0 stops every task without removing the service.

arguments
id, replicas
level
1 (operational)

update_service_image

Sets the container image, triggering a rolling deploy per the service’s update policy.

arguments
id, image
level
1 (operational)

rollback_service

Reverts to the previous spec. Only one previous spec is retained, so calling twice doesn’t unwind further.

arguments
id
level
1 (operational)

restart_service

Forces a rolling restart by bumping ForceUpdate. No other spec field changes.

arguments
id
level
1 (operational)

remove_task

Deletes a task; Swarm reschedules a replacement, so this is a forced reschedule.

arguments
id
level
3 (impactful)

remove_service

Deletes a service and stops every task. Doesn’t delete the volumes, networks, configs, or secrets it referenced.

arguments
id
level
3 (impactful)

Service configuration

Editing a service’s spec. These tools return the section they changed rather than the whole service:

{
    "id": "web",
    "name": "web",
    "version": 42,
    "section": "resources",
    "details": {
        "cpuLimitCores": 2,
        "memoryLimitBytes": 1073741824
    }
}

details reports the edited section as describe would, naming environment variables and log driver options without their values—so raising a CPU limit never hands back the service’s credentials.

update_service_secrets, update_service_configs, and update_service_mounts replace their set wholesale: pass every entry the service should end up with, because one left out is detached—and a container may lose data it was writing to a dropped mount.

update_service

Changes one section of a service’s spec. section takes one of ten names, and value that section’s new value:

SectionValueSemantics
envMerge-patch objectA string sets a key, null deletes it, an omitted key is preserved
labelsMerge-patch objectSame as env; the only service section that doesn’t trigger a rolling deploy, along with the two policies
resourcesResourceRequirementsCPU and memory limits and reservations
placementPlacementConstraints, preferences, max replicas per node, platforms; may reschedule tasks
portsArray of PortConfigDrops connections to any port it removes or remaps
update-policyUpdateConfigApplies to the next spec change
rollback-policyUpdateConfigApplies to rollback_service
log-driverDriverName plus options; routes subsequent log lines
healthcheckProbetest as an array (["CMD-SHELL", "curl -f localhost || exit 1"]), plus interval, timeout, startPeriod, retries. Durations are strings such as "10s". An empty test removes the check
commandcommand plus argsThe entrypoint and what follows it, the split Docker makes. Omitting one clears it

Every section other than env and labels replaces its section wholesale: a field you omit is cleared.

Secrets, configs, and mounts aren’t sections here. Each takes a list rather than a spec fragment, and attaching a secret checks a read grant on the secret as well as a write grant on the service, so each is a tool of its own. Passing one as a section is refused with the name of the tool to use.

arguments
id, section, value
level
2 (configuration)

update_service_secrets

Replaces the complete set of secrets a service receives.

arguments
id, secrets
level
2 (configuration)

update_service_configs

Replaces the complete set of configs a service receives.

arguments
id, configs
level
2 (configuration)

update_service_mounts

Replaces the complete set of mounts: named volumes, host bind mounts, tmpfs.

Caution

A bind mount hands the container the host’s filesystem at that path, and binding /var/run/docker.sock gives it control of the whole cluster, and a volume with driver options can bind the host too. Below level 3 a bind mount the service doesn’t already have is refused, and so is a named volume the manager doesn’t hold as a plain local volume; at level 3, update_service_mounts does it if asked.

The tool can’t set bind options, so a bind the service has with a propagation mode reads as changed: below level 3 it’s refused, and at level 3 resending it drops the mode.

arguments
id, mounts
level
2 (configuration)

Cluster resources

Configs, secrets, networks, and volumes. Swarm secrets and configs are immutable, so rotating one is three calls in order: create_secret for the replacement, update_service_secrets to repoint each service that uses it (describe the secret first, its related array names them), then remove_secret once nothing references it. Configs follow the same sequence, and unlike a secret a config’s content can be read back, so use a secret for anything sensitive.

create_secret

Creates a Swarm secret.

arguments
name, data, encoding (utf8, base64), labels
level
2 (configuration)

create_config

Creates a Swarm config.

arguments
name, data, encoding (utf8, base64), labels
level
2 (configuration)

remove_secret

Deletes a secret. Fails if any service still references it.

arguments
id
level
3 (impactful)

remove_config

Deletes a config. Fails if any service still references it.

arguments
id
level
3 (impactful)

remove_network

Deletes an overlay network. Fails if a service is attached; ingress and docker_gwbridge can’t be removed.

arguments
id
level
3 (impactful)

remove_volume

Deletes a volume by name. Fails if a container is using a local volume, even with force, which there only overrides an error from the volume driver. On a cluster volume, force deletes it even while it is in use.

arguments
name, force
level
3 (impactful)

Nodes

Where work is allowed to run, and who votes in Raft.

update_node_labels

Patches a node’s labels (JSON Merge Patch).

arguments
id, labels
level
2 (configuration)

update_node

Changes a node’s availability or role.

Draining a manager may destabilize the swarm, so prefer draining workers. Promoting a node adds a Raft voter and demoting removes one: never reduce the manager count below the quorum threshold, and on a three-manager cluster demote at most one at a time. Node labels stay a tool of their own, update_node_labels, at level 2, so a deployment that lets an agent relabel a node doesn’t also let it demote a manager.

arguments
id, section (availability, role), value (active, pause, drain—or worker, manager)
level
3 (impactful)

Resources

Resources are read-only views returned as application/json. Three are static, eleven are URI templates.

URIContents
cetacean://cluster
Node, service, task, and stack counts, node readiness, task counts by state, total and reserved CPU and memory, the largest node’s capacity, converged and degraded service counts, last sync time
cetacean://recommendations
Current recommendation engine findings, each with severity, category, target resource, and rationale
cetacean://history
The most recent create, update, and delete events across every resource type, newest first, up to 100. A task event is named after its service (demo_flaky.3) rather than by task ID; resourceId still carries the ID

Every numeric field in cetacean://cluster names its unit: totalCPUCores, reservedCPUCores, maxNodeCPUCores, totalMemoryBytes, reservedMemoryBytes, maxNodeMemoryBytes. Both CPU figures are in cores.

Templated resources return the same compact digest the describe tool builds. The exceptions are services/{id}/logs, a raw log stream, and the two compose documents, which are YAML rather than JSON.

URI templateContents
cetacean://nodes/{id}
Node digest, by ID or hostname
cetacean://services/{id}
Service digest, by ID or name, with cross-references
cetacean://services/{id}/logs
Service logs merged across replicas, subscribable; not a digest
cetacean://services/{id}/compose
The service as a one-service Compose file; everything it references is external
cetacean://tasks/{id}
Task digest; the parent service and node are in related, not top-level fields
cetacean://stacks/{name}
Stack digest, rolling up its member resources
cetacean://stacks/{name}/compose
The stack as a Compose file; secrets and configs are referenced, never exported
cetacean://configs/{id}
Config digest; the payload’s size in bytes, never the payload
cetacean://secrets/{id}
Secret digest; the payload is never read, not even its length
cetacean://networks/{id}
Network digest, with the attached services
cetacean://volumes/{name}
Volume digest, keyed by name

Subscriptions

Clients call resources/subscribe with a URI. When the underlying cluster state changes, the server sends notifications/resources/updated for that URI and the client re-reads. notifications/resources/list_changed fires when resources are created or removed. Both are filtered by grants per notification: a client is only notified about resources its identity can read.

Argument completion

Templated resource URIs and prompt arguments complete, offering resource names rather than IDs. Matching is a case-insensitive substring, so typing prometheus offers monitoring_prometheus. Completions are capped at 100 values and are filtered by the caller’s grants like every other read.

Compact resource shapes

Tools and resource reads never return raw Docker objects—they’re enormous, and they don’t carry the field a caller actually wants, since a service’s health is derived from its tasks. Every read returns one of two shapes.

Row is one entry in a list, returned by find. Every row carries id, name, and type (singular: service, node, task, and so on). stack, state, and detail (the most identifying secondary fact, such as a service’s image, a node’s role, or a network’s driver) are omitted where they don’t apply. desired and running are populated only where a replica count means something:

  • services set both, the desired replica count and how many are running
  • stacks set desired alone, counting member services rather than replicas
  • nodes, tasks, configs, secrets, networks, and volumes set neither

Digest is the detail view of one resource, returned by describe and by every templated cetacean://<type>/{id} read. Alongside id, name, type, and state it adds:

FieldContents
reason
The cause Swarm gave for a non-healthy state; omitted when the state is healthy
since
When the current state began: the oldest still-live failing task’s timestamp, or the resource’s own last-updated time
details
A type-specific map of facts, such as a service’s image, replica counts, reserved CPU and memory, ports, and placement constraints, or a node’s role and capacity
related
Always an array, even when empty: the resources this one references or is referenced by
recentFailures
Always an array: the task failures behind a failing state, newest first, capped at 5. Only a service digest populates it
restarts
A service’s involuntary task terminations as lastHour and lastWeek counts. Services only

restarts is the only field that reveals a restart loop. state reads running whenever a replica happens to be up, and recentFailures drops tasks the orchestrator has already replaced, so a service crash-looping every few seconds otherwise describes as healthy. lastHour answers whether it’s failing now; the ratio between the two windows answers whether the fault is new.

Every numeric field in details names its unit, such as cpuLimitCores (a float, in cores) and memoryLimitBytes, or is reported as a duration string like "10s" (healthcheckInterval, an update policy’s delay and monitor). Docker’s own types express these as unlabeled NanoCPU or nanosecond integers. Environment variables are reported as envNames: names only, never values.

The raw: true option

Both find (when type is given) and describe accept raw: true, adding the untouched Docker record to the result under raw. Use it only when a specific field a row or digest omits is needed; the compact shapes exist to avoid handing an agent a several-hundred-line object.

Raw records ride beside the compact shape rather than replacing it: find adds a raw array with one record per row, describe a raw object beside the digest.

Prompts

Prompts are named sequences a client offers from a menu. Picking one seeds the conversation with an investigation or a runbook. A prompt only seeds the conversation; every read and write it then describes goes through the normal tools, grant checks included.

A prompt’s level is the highest level of the tools it walks, so it’s never offered where one of its steps would be refused. At the default level 0 you get the three diagnostic prompts; level 1 adds roll_back_service.

Prompts are filtered by grants too, all or nothing: you are offered a prompt only if you can use every tool it walks and can read every resource type in its Reads column. A caller whose grants match nothing is offered none.

diagnose_service
Walks tasks, the failing task’s logs, metrics, and recent changes to find why a service is unhealthy
Level0ArgumentserviceReadsservice
explain_unschedulable
Separates the causes of an unplaced task: placement constraints, node labels and platform, node availability and state, per-node replica caps, reservations
Level0ArgumentserviceReadsservice, node
review_capacity
Joins node capacity, reservations, real usage, and sizing findings to say where the cluster is constrained
Level0ArgumentnoneReadsnode
roll_back_service
Confirms a service is degraded, then rolls it back and waits for the replicas to run
Level1ArgumentserviceReadsservice
right_size_service
Checks a sizing recommendation against measured use, then corrects the reservations
Level2ArgumentserviceReadsservice
drain_node
Checks quorum and that the work can be placed elsewhere, then drains the node and confirms the tasks moved
Level3ArgumentnodeReadsnode, service

Apps

A host that supports the MCP Apps extension can render Cetacean’s data as an interactive view instead of JSON. Cetacean advertises io.modelcontextprotocol/ui and serves each widget as a resource. Each tool names its widget in _meta, so a host knows which view fits the result; the same tool called from a client without app support returns ordinary JSON.

MCP Apps are self-contained: they load nothing from the network and read data only through Cetacean’s MCP tools, so a widget shows exactly what the calling identity’s grants allow.

Picking a finding in the recommendations widget sends the model a message in the user’s name, and that message quotes resource names and finding text from the cluster. Whoever can name a service or node chooses part of it. The widget passes those fields as one JSON value marked as cluster data, but the model still reads them, so treat a follow-up from a widget as you would any output that quotes the cluster.

ui://cetacean/table
Searchable, sortable table of one resource type, showing how many records it holds when the page is a subset
RendersA find result
ui://cetacean/topology
Graph to pan, zoom, and drag; switching view re-runs the tool under the same identity and grants
RendersA get_topology result
ui://cetacean/logs
Live tail, re-reading from the cursor the previous read returned; level and search filtering happens over the lines already fetched
RendersA get_logs result
ui://cetacean/metrics
Line chart with a range picker; changing the range re-runs the tool. Every series is named in a legend with its latest value
RendersA get_metrics result
ui://cetacean/recommendations
Findings grouped by severity, most serious first. Picking one asks the host to send the model a follow-up, which a host may decline
RendersA get_recommendations result