Story: Agent validates over MCP with gated destructive operations
Story ID: STORY-002 Status: Revision 1 Created: 2026-10-13
Statement
As an AI agent running a verification loop, I want to call a reviewed set of Xianyun commands over MCP and get structured results back, so that I can check a change against a local cluster without a person copying terminal output, while a person still approves anything that destroys state.
Trigger
An MCP client connects to xianyun-mcp (stdio or Streamable HTTP) and calls a tool.
Acceptance Criteria
Scenario: A read-only tool runs without confirmation
Given a connected MCP client and a valid xianyun.yaml in the working directory
When the client calls the "status" tool
Then the result MUST include the command's exit code and output
And no confirmation MUST be requested
Scenario: A destructive tool needs confirmation first
Given a connected MCP client that supports elicitation
When the client calls "destroy"
Then the first result MUST be input-required and carry a consequence message
And the cluster MUST still exist
When the user answers "accept" and the client retries
Then the cluster MUST be destroyed
Scenario: A declined confirmation changes nothing
Given the client has been asked to confirm "update-etc-hosts"
When the user answers "decline"
Then the exit code MUST be 1
And stderr MUST contain "aborted at the user's request"
And /etc/hosts MUST be unchanged
Scenario: The HTTP transport isn’t reachable from other hosts by default
Given "xianyun-mcp mcp stream --port 18099" is started with no --host
When another host connects to port 18099 on the machine's LAN address
Then the connection MUST be refused
EARS Constraints
- The system shall expose only the commands named in the allowlist.
- If a CLI subcommand isn’t classified as exposed or excluded, then the build shall fail.
- If a client can’t answer elicitation, then the system shall return a tool error and shall not run a gated command.
- While the stdio transport is in use, the system shall write only protocol messages to standard output.
- If a call carries a confirmation answer the server didn’t ask for, then the system shall respond with the challenge and shall not run the command. (Not met: measured 2026-10-13, a forged first-call
acceptranxianyun down; see SR-003.) - When any gated or privileged call completes, the system shall append an audit record naming the command, arguments, and confirmation outcome.
Autonomy Limits
- Maximum actions per cycle: not specified and not enforced. Open decision: pick a number (for example, state-changing calls per session before a fresh human confirmation) and add it as a security requirement. Until then this field is a known gap, not a limit.
- Escalation threshold: any gated tool always escalates to the human; any call whose resolved config contains hooks should (SR-002, not yet met).
- Prohibited actions:
run,tool,kubectl,k9s,stern, andedit-mode-process-supervisoraren’t exposed. - Human oversight: required for the five gated tools. Not required for
up,deploy, andupdate, which is the question SR-002 raises.
Security Mapping
| Concern | Addressed By |
|---|---|
| Spoofing (unauthenticated listener) | Fourth scenario; SR-001 |
| Spoofing (forged confirmation) | EARS constraint on unsolicited answers; SR-003 (not yet met) |
| Elevation of privilege (hooks through ungated tools) | SR-002 (not yet met) |
| Tampering (crafted flag values) | SR-004 (not yet met) |
Denial of service (a client calling up or deploy in a loop; no rate or concurrency limit) | Not specified; tied to the open decision under Autonomy Limits |
| Repudiation (no record of calls) | EARS constraint above; SR-014 (not yet met) |
Information disclosure (config print shows environment values) | SR-007 (not yet met) |
Standards Mapping
- SLSA Level: N/A
- SSDF Practices: PW.1 (secure design) and PW.5 (secure coding), informally
- SCVS Controls: N/A
Dependencies
- Depends on: none. The scenarios use read-only and gated tools; the
upanddeployflows in STORY-001 are reached through the same CLI but aren’t needed to verify the gating. - Blocks: none
- Related ADR: ADR-0005
- Related spec requirement: FR-014, SR-001, SR-002, SR-003
Notes
- Partly covered today.
crates/xianyun-mcp/tests/protocol.rshas three tests: the tool list, an end-to-endversioncall, and a gated call without confirmation not running. Nothing exercises theacceptretry or thedeclinepath of scenarios two and three, and scenario one is checked withversionrather thanstatus.guardrail.rscovers the allowlist constraint. - The fourth scenario fails today. Measured on 2026-10-13: with no
--host, the server listened on0.0.0.0:18099. - Open question for negotiation: should
up,deploy, andupdatemove to the gated tier, or be gated only when hooks are present (the cheaper option that SR-002 proposes)?