Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 accept ran xianyun 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, and edit-mode-process-supervisor aren’t exposed.
  • Human oversight: required for the five gated tools. Not required for up, deploy, and update, which is the question SR-002 raises.

Security Mapping

ConcernAddressed 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 up and deploy flows 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.rs has three tests: the tool list, an end-to-end version call, and a gated call without confirmation not running. Nothing exercises the accept retry or the decline path of scenarios two and three, and scenario one is checked with version rather than status. guardrail.rs covers the allowlist constraint.
  • The fourth scenario fails today. Measured on 2026-10-13: with no --host, the server listened on 0.0.0.0:18099.
  • Open question for negotiation: should up, deploy, and update move to the gated tier, or be gated only when hooks are present (the cheaper option that SR-002 proposes)?