Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 8 additions & 10 deletions docs/MCP_TOOLS.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ The `devops-cli` FastMCP server exposes DevOps automation and AI review capabili
| [`argo_fleet_sync`](#argo-fleet-sync) | `false` | Synchronize an application across a fleet of Kubernetes clusters with bounded concurrency. |
| [`argo_rollouts_analyze`](#argo-rollouts-analyze) | `false` | Evaluate metric rollback gates and trigger automated rollback on threshold violation. |
| [`branches_list`](#branches-list) | `true` | List branches across all repos. |
| [`ci`](#ci) | `true` | Run tests, linting, formatting, and type-checks. A run that selects test, security or typecheck first waits for a free gate slot, so the gates of parallel agents take turns. ci.gate_slots sets how many run at once. |
| [`ci`](#ci) | `false` | Run tests, linting, formatting, and type-checks. A run that selects test, security or typecheck first waits for a free gate slot, so the gates of parallel agents take turns. ci.gate_slots sets how many run at once. |
| [`config_audit_keys`](#config-audit-keys) | `true` | Audit OS Keyring token health, backend status, and zero-plaintext secret compliance. The audit scans each config file that the settings merge: the global config file and the project config file. It also scans config.yaml and .devops/config.yaml in the current directory. Exits 0 only when the audit is compliant. Exits 1 when a config file holds a plaintext secret, or when a config file cannot be read or parsed, reporting it unaudited. The full report prints before the exit. The alert of a leak names two commands. `devops config set <key>` stores a credential in the keyring. Add `--from-file <path>` for a multi-line credential, such as a PEM key. `DEVOPS_CLI_CONFIG=<file> devops config unset <key>` removes the value from the file of the leak. |
| [`config_output`](#config-output) | `true` | Output environment variables available for devops-cli configuration. |
| [`config_show`](#config-show) | `true` | Print every setting that a variable sets and every credential. A credential shows as set or not set, never its value. |
Expand Down Expand Up @@ -89,7 +89,7 @@ The `devops-cli` FastMCP server exposes DevOps automation and AI review capabili
| [`k8s_teardown_stack`](#k8s-teardown-stack) | `false` | Uninstall the k8s infrastructure / LLM stack and delete namespaces. |
| [`k8s_tempo_info`](#k8s-tempo-info) | `true` | Retrieve Tempo distributed tracing HTTP API URL and OTLP trace endpoints. |
| [`k8s_validate`](#k8s-validate) | `true` | Validate Kubernetes YAML manifests against OpenAPI schemas using Kubeconform. |
| [`pr_check_readiness`](#pr-check-readiness) | `true` | Validate PR merge readiness: conflicts, draft state, checks, review threads, grounding and draft readiness. Grounding applies where the base holds openspec/changes/. The PR targets the default branch. It closes exactly one issue, an open issue of its own repository that holds a priority/* label: a roadmap item. GitHub closes that issue when the PR merges. The PR adds openspec/changes/archive/\<date\>-\<issue\>-\<slug\>/, which uv run devops openspec archive writes for that issue's change. Only that archive writes openspec/specs/ and openspec/changes/archive/. An implement pull request must have every task group ticked. |
| [`pr_check_readiness`](#pr-check-readiness) | `false` | Validate PR merge readiness: conflicts, draft state, checks, review threads, grounding and draft readiness. Grounding applies where the base holds openspec/changes/. The PR targets the default branch. It closes exactly one issue, an open issue of its own repository that holds a priority/* label: a roadmap item. GitHub closes that issue when the PR merges. The PR adds openspec/changes/archive/\<date\>-\<issue\>-\<slug\>/, which uv run devops openspec archive writes for that issue's change. Only that archive writes openspec/specs/ and openspec/changes/archive/. An implement pull request must have every task group ticked. |
| [`pr_checks`](#pr-checks) | `true` | Check remote CI quality gate status on a pull request. |
| [`pr_close`](#pr-close) | `false` | Close a pull request. |
| [`pr_describe`](#pr-describe) | `true` | Print the title and the body of the pull request that delivers an issue. The first line is the title, then a blank line, then the body. |
Expand All @@ -112,8 +112,8 @@ The `devops-cli` FastMCP server exposes DevOps automation and AI review capabili
| [`review_pr`](#review-pr) | `false` | Review a GitHub pull request. |
| [`review_stats`](#review-stats) | `true` | Compute and display review accuracy statistics across saved sessions. |
| [`roadmap_intake`](#roadmap-intake) | `false` | Turn each open issue with no priority label into a roadmap item, or file a new candidate: intake sets the labels, adds a reason comment and names a possible duplicate for a person to close. It writes nothing without --confirm. Details: docs/roadmap/intake.md. |
| [`roadmap_refine`](#roadmap-refine) | `true` | Refine roadmap items to Ready: investigate open questions with tools that read the code and the documentation, then write the design, tasks and acceptance criteria to GitHub. Without --confirm, refine prints its plan only. Details: docs/roadmap/refine.md. |
| [`roadmap_run`](#roadmap-run) | `true` | Run the roadmap jobs that are due, in order: metrics, then intake, refine and the alternatives check, and record each one's last success. Intake is due on an issue reopened, and decides at most 5 candidates a run and keeps a record of those it left beside the schedule; refine is due every 31 minutes, on a first run, and after an intake that placed a critical fix or a P0 item; the alternatives check is due every 719 minutes and on a first run, and checks at most roadmap.alternatives.first_pass_limit items while an item has no check, and roadmap.alternatives.limit items after. Without --confirm, or with --dry-run, prints the due list and runs nothing. |
| [`roadmap_refine`](#roadmap-refine) | `false` | Refine roadmap items to Ready: investigate open questions with tools that read the code and the documentation, then write the design, tasks and acceptance criteria to GitHub. Without --confirm, refine prints its plan only. Details: docs/roadmap/refine.md. |
| [`roadmap_run`](#roadmap-run) | `false` | Run the roadmap jobs that are due, in order: metrics, then intake, refine and the alternatives check, and record each one's last success. Intake is due on an issue reopened, and decides at most 5 candidates a run and keeps a record of those it left beside the schedule; refine is due every 31 minutes, on a first run, and after an intake that placed a critical fix or a P0 item; the alternatives check is due every 719 minutes and on a first run, and checks at most roadmap.alternatives.first_pass_limit items while an item has no check, and roadmap.alternatives.limit items after. Without --confirm, or with --dry-run, prints the due list and runs nothing. |
| [`sandbox_deploy`](#sandbox-deploy) | `false` | Deploy an isolated background container sandbox with security containment. |
| [`sandbox_exec`](#sandbox-exec) | `false` | Execute a command inside an active sandbox container. |
| [`sandbox_network_policy`](#sandbox-network-policy) | `true` | Generate declarative Kubernetes NetworkPolicy YAML for workload sandbox isolation. |
Expand Down Expand Up @@ -640,7 +640,7 @@ List branches across all repos.

Run tests, linting, formatting, and type-checks. A run that selects test, security or typecheck first waits for a free gate slot, so the gates of parallel agents take turns. ci.gate_slots sets how many run at once.

**Annotations:** `readOnlyHint: true`
**Annotations:** `readOnlyHint: false`

**Parameters:**

Expand Down Expand Up @@ -1443,7 +1443,7 @@ adds openspec/changes/archive/\<date\>-\<issue\>-\<slug\>/, which uv run devops
writes for that issue's change. Only that archive writes openspec/specs/ and
openspec/changes/archive/. An implement pull request must have every task group ticked.

**Annotations:** `readOnlyHint: true`
**Annotations:** `readOnlyHint: false`

**Parameters:**

Expand Down Expand Up @@ -1884,7 +1884,7 @@ Turn each open issue with no priority label into a roadmap item, or file a new c

Refine roadmap items to Ready: investigate open questions with tools that read the code and the documentation, then write the design, tasks and acceptance criteria to GitHub. Without --confirm, refine prints its plan only. Details: docs/roadmap/refine.md.

**Annotations:** `readOnlyHint: true`
**Annotations:** `readOnlyHint: false`

**Parameters:**

Expand All @@ -1901,7 +1901,7 @@ Refine roadmap items to Ready: investigate open questions with tools that read t

Run the roadmap jobs that are due, in order: metrics, then intake, refine and the alternatives check, and record each one's last success. Intake is due on an issue reopened, and decides at most 5 candidates a run and keeps a record of those it left beside the schedule; refine is due every 31 minutes, on a first run, and after an intake that placed a critical fix or a P0 item; the alternatives check is due every 719 minutes and on a first run, and checks at most roadmap.alternatives.first_pass_limit items while an item has no check, and roadmap.alternatives.limit items after. Without --confirm, or with --dry-run, prints the due list and runs nothing.

**Annotations:** `readOnlyHint: true`
**Annotations:** `readOnlyHint: false`

**Parameters:**

Expand Down Expand Up @@ -2057,7 +2057,6 @@ Scan target files for prompt-injection smuggling vectors and canary tokens.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| `target` | `string` | No | `.` | Target file or directory to scan for prompt-injection smuggling vectors. |
| `sarif` | `string` | No | - | Write findings to this path as a SARIF 2.1.0 document. |
| `min_severity` | `string` | No | - | Drop findings below this severity (CRITICAL|HIGH|MEDIUM|LOW|INFO). |
| `suppress` | `string` | No | - | Suppression policy file; inherited policies are resolved via 'extends'. |
| `show_suppressed` | `boolean` | No | `False` | List findings hidden by the suppression policy and the rule that hid them. |
Expand Down Expand Up @@ -2314,7 +2313,6 @@ Generate and show an OpenTofu execution plan.
|---|---|---|---|---|
| `directory` | `string` | No | `.` | Target directory containing OpenTofu configuration. |
| `var_file` | `string` | No | - | Path to variable definitions file. |
| `out` | `string` | No | - | Write generated plan to file. |
| `destroy` | `boolean` | No | `False` | Generate a plan to destroy all resources. |
| `dry_run` | `boolean` | No | `False` | Preview execution plan without mutating external state. |

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-11-05
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Design

## Decisions

- **The test scans the description of each option in the published schema of each read-only tool.**: It looks for `resolve`, `write`, `delete` and `create` in the base, `-s` and `-ing` forms. The issue names these verbs and names the help text as the signal. The generator copies the help text into the description of the published parameter. So the schema is what a model reads. The test names the tool and the option.
- **A past form of a verb does not match.**: `resolved` in `sandbox_network_policy.public_whitelist`, `sandbox_network_policy.local_whitelist` and `scan_injection.suppress` describes a result. `wrote` in `roadmap_refine.item` does the same. A match on them would need an exempt list. An exempt list hides the error that the test must show.
- **`pr check-readiness`, `roadmap refine`, `roadmap run` and `ci` are marked not read-only. Each command keeps its option.**: `--auto-resolve` and `--confirm` write to GitHub. `--fix` rewrites files, and it is on by default. The flag then says what the tool can do. No job role table names these tools, so no role loses a tool. The rule finds the first two. A person finds the other two by reading the options, so the table test names them.
- **`scan_injection` and `tf_plan` stay read-only. Their schemas drop `sarif` and `out`.**: Each command prints its result, so the model needs no file. SECURITY.md rule 11 says that a tool publishes no option for a path that the command writes, unless a path helper confines it. Nothing confines `sarif` or `out`. The dry-run class of `scan injection` is `no-external-request`, and the ratchet test requires a read-only tool for that class. The restriction follows the rule of `ai_ast_graph` and `scan_sbom`.
- **The verb pattern is a private constant of the test.**: Only the test reads it, so CONTRIBUTING.md section 5 puts it in that module.
- **The test builds a one-tool server for each case of the rule, with the signature that the generator makes.**: The rule then runs on the same kind of object that the repository check reads. No double replaces a tool.

## Out of scope

- **Tools that write local state.**: `ai_quiesce`, `ai_resume`, `ai_failover`, `ai_gateway_failover` and `review_export_feedback` write local state or a file. Dropping an option does not make them read-only, because the whole command writes. A flag that is not read-only fails the requirement `mcp-read-only-hint-agrees-with-no-external-request` and its ratchet test. Issue #3642 decides what the class means for the flag.
- **The words of `tf_notify_plan`.**: The command prints the comment and posts nothing, so the flag is right. Issue #3644 fixes the help text.
- **Paths with no confinement decision.**: `scan_injection.suppress` reads a path and `review_export_feedback.output` writes a path. Both stay as before. Issue #3480 gives each a decision.

## Rejected alternatives

- **Keep `tf_plan` not read-only and publish `out`.**: The tool then publishes a path that the command writes, and nothing confines it. SECURITY.md rule 11 and the requirement "Write path confinement" of `mcp-tool-path-confinement` forbid that.
- **Mark only `pr check-readiness` and add no general check.**: The scan finds more tools of the same kind. Acceptance criterion 1 of the issue says that no tool with a write option is read-only.
- **Remove `auto_resolve` from the published schema of `pr_check_readiness`.**: `_PATH_PARAM_RESTRICTIONS` takes an `allowed` list only. The entry must list the seven other options, and it drops each option that the command adds later. The option is also useful for a model that has the write right.
- **Scan option names, not descriptions.**: `--confirm`, `--out`, `--fix` and `--sarif` have names with no write verb. The check would miss four of the tools.
- **Widen the verbs to `post`, `execute`, `apply`, `restore` and `close`.**: These words find `roadmap_run.confirm` (`Execute`), `tf_notify_plan.pr_number` (`post`) and `ai_gateway_failover.reset` (`Restore`). The first is a write. The second is not, because the command posts nothing. The words also match text with no write: `sandbox_status.all_instances` (`Apply operation across all registered sandbox instances`), `ci.check` (`applying`), `gh_issues_list.state` (`closed`) and `pr_describe.issue` (`closes`). A word list cannot tell the groups apart. A person must read each flag. So the test keeps the four verbs of the issue, and the table holds the result of that reading.
- **Mark `scan_injection` not read-only.**: The dry-run ratchet test fails with that flag (see Feasibility in the proposal).
- **Mark the five local writers not read-only.**: The requirement `mcp-read-only-hint-agrees-with-no-external-request` and its ratchet test fail. A change to them needs a decision of its own, which issue #3642 holds.
- **Keep the old flag and rely on the description of the tool.**: A role server reads the flag and not the text, so the text does not stop a write.
Loading
Loading