Skip to content

feat: outcomes-first protection tools + MCP annotations, resources, i…#28

Open
grantgumina wants to merge 1 commit into
Commvault:mainfrom
grantgumina:outcomes-first-protection-tools
Open

feat: outcomes-first protection tools + MCP annotations, resources, i…#28
grantgumina wants to merge 1 commit into
Commvault:mainfrom
grantgumina:outcomes-first-protection-tools

Conversation

@grantgumina

@grantgumina grantgumina commented Jun 2, 2026

Copy link
Copy Markdown

Made some edits to the MCP implementation here. Goal was to make the server speak in outcomes rather than 1:1 REST objects so an LLM (incl. autonomous backup agents) states a goal once instead of being walked through a multi-step "wizard".

Changes

  • Per-tool MCP ToolAnnotations via a registration table (src/tool_annotations.py): reads -> readOnlyHint; kill_job/suspend_job/disable_schedule -> destructiveHint; resume/resubmit -> idempotentHint; human-friendly titles. Clients can now self-serve lookups and gate ONLY irreversible actions.
  • Rich SERVER_INSTRUCTIONS operator persona (src/config.py) replacing the one-sentence prompt: resolve IDs yourself, report outcomes, be honest about limits, confirm destructive actions, stop on zero-match.
  • Read-first resources (src/resources.py): commvault://glossary, capabilities (honest about what it cannot do), regions (live from storage pools), objectives.

Also folds in the earlier "look up for jobs jobs" -> "jobs" docstring typo fix.

Verified offline against fastmcp 3.3.1: 58 tools register with correct annotations, 4 resources resolve, and plan_protection returns a complete proposal end-to-end while mutating nothing.

…nstructions

Make the server speak in outcomes rather than 1:1 REST objects so an LLM
(incl. autonomous backup agents) states a goal once instead of being walked
through a multi-step "wizard". Layers 1-2 of the agreed plan; all read-only,
additive, no new write paths.

Layer 1 (conversational ergonomics):
- Per-tool MCP ToolAnnotations via a registration table (src/tool_annotations.py):
  reads -> readOnlyHint; kill_job/suspend_job/disable_schedule -> destructiveHint;
  resume/resubmit -> idempotentHint; human-friendly titles. Clients can now
  self-serve lookups and gate ONLY irreversible actions.
- Rich SERVER_INSTRUCTIONS operator persona (src/config.py) replacing the
  one-sentence prompt: resolve IDs yourself, report outcomes, be honest about
  limits, confirm destructive actions, stop on zero-match.
- Read-first resources (src/resources.py): commvault://glossary, capabilities
  (honest about what it cannot do), regions (live from storage pools), objectives.

Layer 2 (goal-level tools, src/tools/protection_tools.py, all preview/read-only):
- explain_objective: expand 3-2-1/2-copy/1-copy into concrete copies; badge is
  DERIVED from structure, not asserted.
- resolve_scope: collapse the client->id->subclient chain into one call; supports
  client-group/name/type and REFUSES tag/resource-region selection explicitly
  rather than guessing; empty match is reported, never silently treated as all.
- plan_protection: compile scope + objective into one reviewed plan-of-record
  with region-matched pools, open questions, and a deterministic plan_token.
  PREVIEW ONLY -- creates nothing (no provisioning endpoints exist yet).

Also folds in the earlier "look up for jobs jobs" -> "jobs" docstring typo fix.

Verified offline against fastmcp 3.3.1: 58 tools register with correct
annotations, 4 resources resolve, and plan_protection returns a complete
proposal end-to-end while mutating nothing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant