12 KiB
id, title, sidebar_label
| id | title | sidebar_label |
|---|---|---|
| mcp | Agent access (MCP) | Agent access (MCP) |
The Model Context Protocol is how an LLM agent - Claude, or any other MCP client - talks to a tool server over a defined wire format instead of a one-off integration. Connecting Vantage to an agent this way lets it answer questions about your fleet and, if you choose to let it, act on it: run a workflow, apply updates, or draft a step for you to review.
:::info Requires the MCP feature on your licence
Agent access is a per-instance feature you enable on a paid plan. Without it,
/api/mcp answers feature_unavailable and the token form refuses to mint a
token carrying an mcp:* scope. See
Licensing and entitlements.
:::
Minting a token
An agent authenticates the same way any script does: with an
API token. Two scopes govern what it can reach
on the MCP endpoint specifically, on top of whatever resource scopes
(servers:read, workflows:write, and so on) it also needs:
mcp:read- permission to reach the MCP endpoint at all and use its read-only tools.mcp:write- permission to use its write tools: running a workflow, applying updates, assigning a key, or creating a step, workflow or monitor.
Without mcp:write, write tools are not merely refused when called - they
are left out of the tool listing entirely, so a read-only agent never learns
they exist. A tool it cannot see is not one it can talk a user into asking
for.
Each tool additionally needs the ordinary resource scope for what it touches
run_workflowneedsworkflows:write,list_serversneedsservers:read, and so on, exactly as the scopes table describes for any other token.mcp:readormcp:writedecides whether the MCP surface is open to this token at all; the resource scope decides what it can do once there.
Restricting a token by tag
An agent token benefits from the same tag
restriction every API token
can carry, and it is the main lever for keeping an agent's blast radius
small. A token restricted to env=staging sees only staging hosts from
list_servers, gets a not-found error asking about a production host by ID,
and cannot run a workflow that would touch one.
Worked example: a staging-only agent token. Create a token with
mcp:read, mcp:write, servers:read, workflows:read and
workflows:write, restrict it to env=staging, and give it to your agent.
It can list and inspect staging servers and run a workflow already
configured to target them. Point it at a workflow whose saved targets
include even one production host, though, and run_workflow refuses the
call outright - see what an agent cannot do
below for why that refusal is all-or-nothing rather than "run on the
servers it can see."
Connecting a client
Agent access lives at /api/mcp on your instance, over the streamable HTTP
transport, and takes a bearer token the same way the REST API does. It has
no separate authentication of its own - a browser tab with a signed-in
session does not count, only a real API token does.
Point an MCP client at it with a configuration block like this:
{
"mcpServers": {
"vantage": {
"type": "http",
"url": "https://YOUR-INSTANCE/api/mcp",
"headers": { "Authorization": "Bearer vt_your_token_here" }
}
}
}
The endpoint is stateless and answers POST requests only: it holds no
per-connection session, so each call is self-contained and there is nothing
to resume. A GET request - a client probing for the endpoint, or a browser
navigating to it directly - gets a 405, by design, rather than a page. That
is the protocol-correct response from a server that does not offer the
GET/SSE half of MCP, not a misconfiguration.
The tool list
Every tool below calls the same service code the REST API and the Vantage UI call. Nothing in this list has its own path to the database - the MCP surface is a presentation layer over existing authority, not a new one.
| Tool | What it does | Scope required |
|---|---|---|
list_servers |
List servers in the fleet, optionally filtered by tags. | mcp:read, servers:read |
get_server |
Get one server's OS, online state and tags. | mcp:read, servers:read |
list_monitors |
List monitors and their current state. | mcp:read, monitors:read |
get_monitor_status |
Get one monitor's up/down/pending state, last check and last error. | mcp:read, monitors:read |
list_incidents |
List monitor incidents (outages), most recent first. | mcp:read, monitors:read |
get_monitor_samples |
Get one monitor's recent raw check results. | mcp:read, monitors:read |
list_workflows |
List workflows with step count, target count and whether each is scheduled. | mcp:read, workflows:read |
get_workflow |
Get one workflow's ordered steps, targets and schedule. | mcp:read, workflows:read |
get_run |
Get one workflow run's status and per-server counts. | mcp:read, workflows:read |
get_run_logs |
Get the ordered log lines for one server within one run. | mcp:read, workflows:read |
list_pending_updates |
List outstanding package updates, fleet-wide or for one server. | mcp:read, servers:read |
list_vulnerabilities |
List known CVEs affecting the fleet, one row per CVE/package pair. | mcp:read, vulns:read |
get_server_packages |
List installed packages on one server, optionally filtered by name. | mcp:read, vulns:read |
search_fleet |
Search every server's installed packages by name across the fleet. | mcp:read, vulns:read |
list_audit_events |
List recent audit log events. | mcp:read, settings:read |
list_secret_names |
List secret group and key names - metadata only, never a value. | mcp:read, secrets:read |
run_workflow |
Run a workflow against the servers it is already saved to target. | mcp:write, workflows:write |
cancel_run |
Cancel an in-progress workflow run. | mcp:write, workflows:write |
apply_updates |
Apply pending OS package updates on real servers. | mcp:write, servers:write |
update_agent |
Trigger the Vantage agent on real servers to update itself. | mcp:write, servers:write |
assign_key |
Assign an SSH key to real servers. | mcp:write, keys:write |
create_step |
Create a reusable workflow step. | mcp:write, workflows:write |
create_workflow |
Create a workflow from existing step IDs. | mcp:write, workflows:write |
create_monitor |
Create a monitor, saved disabled. | mcp:write, monitors:write |
A known limitation worth calling out on search_fleet: its version_below
argument is not implemented. Passing it gets you an error explaining that
correct version ordering depends on each host's own package manager
(dpkg, rpm, apk each order versions differently), which the tool has no way
to resolve, so it refuses rather than guess with a naive string comparison.
Omit version_below and it returns every matching install instead, for you
or the agent to filter.
Running a workflow: targets are fixed, not chosen
run_workflow does not take a target list. A workflow runs the servers and
tags it was already saved with - an agent cannot redirect it at a different
part of the fleet on the fly. Before starting the run, Vantage checks that
those saved targets sit entirely inside the calling token's tag
restriction. If even one of them falls outside it, the whole call is
refused; there is no partial run against just the servers the token happens
to be able to see. A token scoped to env=staging cannot use a
production-and-staging workflow to touch only the staging half - it has to
be pointed at a workflow whose saved targets are staging-only from the
start.
What an agent can create
Three tools let an agent propose new work rather than only look at existing
work: create_step, create_workflow and create_monitor. Nothing they
create is armed:
- A created workflow cannot be given a schedule.
create_workflowrefuses outright if ascheduleargument is present at all, so scheduling stays a separate, later decision a human makes in the UI. - A created monitor is always saved disabled, regardless of any
enabledargument. It checks nothing and alerts nobody until a human turns it on. - A created step may not reference a secret.
create_steprefuses asecret_refsargument, because a script an agent wrote is not something you want run with credentials attached before a person has read it.
create_workflow applies the same two checks run_workflow applies before
a run: it refuses to save a workflow whose targets are not entirely inside
the token's tag scope, and it refuses (absent confirm:true) to save one
whose targets exceed the 25-server fan-out limit. A workflow this token
could not later run is never created in the first place.
Steps an agent creates are marked with a source of mcp, which the
Vantage UI uses to badge them, so a human reviewing the step library can
tell at a glance which scripts came from an agent rather than a person.
There is no tool to update or delete an existing step, workflow or monitor. An agent can add to your instance; it cannot change or remove anything that was already there.
What an agent cannot do
This is the section to read before turning the feature on.
- It cannot see a secret's plaintext.
list_secret_namesreturns group and key names only; no tool anywhere in the MCP surface returns a secret's value to a model. - It cannot open a console or a shell. There is no MCP tool for the browser console, SSH, RDP or VNC. An agent can trigger a workflow step that runs a script, but it cannot open an interactive session on a machine.
- It cannot exceed its tag restriction. Every tool that resolves
servers - by ID, by tag, or through a saved workflow - resolves them
through the token's own scope. A server outside that scope is invisible
to
list_serversandget_server, not-found to anything asking about it by ID, and excluded from what a write tool will act on. - It cannot act at all without
mcp:write. Every write tool needs it, on top of its own resource scope, and a token that lacks it never even sees those tools in the listing. - It cannot touch more than 25 servers in one call without saying so
explicitly. Any write tool that would affect more than 25 servers is
refused with a message asking for
confirm:truebefore it will proceed - cheap insurance against a mis-parsed tag selector reaching the whole fleet on one badly phrased instruction. - It cannot edit or delete anything that already exists. The creation tools only add; there is no MCP tool that updates or removes a step, workflow or monitor a person defined.
A monitor whose runner server sits outside a token's scope is not hidden
from that token - it still appears in list_monitors. The REST API reaches
that outcome by redacting: it replaces the runner with a
RunnerRestricted placeholder when the runner falls outside the caller's
visible servers. The MCP tools reach the same outcome a different way -
list_monitors and get_monitor_status project a monitor onto a summary
that never carries a runner field for any caller, restricted or not, so
there is nothing there to redact in the first place. Two mechanisms, chosen
so the two surfaces cannot end up disagreeing about what a restricted token
learns. A workflow's target list is filtered more directly: servers outside
the token's scope are dropped from what get_workflow reports, and a
targets_restricted flag says that some were held back, without saying how
many.
Every call is audited
Every tool call reaches the audit log, whether it read something or changed something:
- A successful call - read or write - is recorded as
mcp.tool_call. - A call refused by policy - missing scope, an out-of-scope target, or a
fan-out over 25 servers without confirmation - is recorded as
mcp.tool_denied, naming the specific gate that refused it, so a human reading the log can tell "the agent was stopped" from "the agent tried and the underlying action failed." - A write tool that reached the underlying service and that service
rejected is recorded as
mcp.tool_failed. - Creating a step, workflow or monitor is recorded separately as
mcp.created, naming what was made and its ID - a question like "what has this agent added to my instance" should not require digging through hundreds of read rows to answer.
See the audit log for how to read these alongside everything else on the instance.