Skip to main content
Glama

srt_approve_repair

Destructive

Approve or reject a pending SRT repair plan. Human approval is mandatory before repair execution.

Instructions

Approve or reject a pending SRT repair plan. Classification: MANDATORY — this is the human-in-the-loop gate. Repair plans CANNOT execute without explicit human approval. Pass action="approve" to approve or action="reject" to reject.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
incident_idYesIncident ID with pending repair
actionYesApprove or reject the repair plan
approved_byYesHuman operator approving/rejecting
reasonNoReason for rejection (required if rejecting)

Implementation Reference

  • The actual handler function for srt_approve_repair. Implements the MANDATORY human-in-the-loop gate: validates human approval (blocks system/auto/agent), checks incident and repair plan exist, handles approve/reject actions, records to forensic ledger, persists to PostgreSQL, and emits telemetry.
    export function registerSRTApproveRepairTool(server: McpServer, engine: GovernanceEngine): void {
      server.tool(
        'srt_approve_repair',
        'Approve or reject a pending SRT repair plan. Classification: MANDATORY — this is the human-in-the-loop gate. Repair plans CANNOT execute without explicit human approval. Pass action="approve" to approve or action="reject" to reject.',
        {
          incident_id: z.string().describe('Incident ID with pending repair'),
          action: z.enum(['approve', 'reject']).describe('Approve or reject the repair plan'),
          approved_by: z.string().describe('Human operator approving/rejecting'),
          reason: z.string().optional().describe('Reason for rejection (required if rejecting)'),
        },
        { title: 'Approve or Reject Repair', readOnlyHint: false, idempotentHint: false, destructiveHint: true, openWorldHint: false },
        async (input) => {
          // MANDATORY gate enforcement (pre-ledger — no point recording blocked agents)
          if (!input.approved_by || input.approved_by === 'system' || input.approved_by === 'auto' || input.approved_by === 'agent') {
            return { content: [{ type: 'text' as const, text: JSON.stringify({
              error: 'MANDATORY_GATE_VIOLATION',
              message: 'Repair approval requires a human operator. System/auto/agent approvals are BLOCKED.',
              gateType: 'REPAIR_APPROVAL',
              maiLevel: 'MANDATORY',
            }) }], isError: true };
          }
    
          const incident = incidents.get(input.incident_id);
          if (!incident) {
            return { content: [{ type: 'text' as const, text: JSON.stringify({ error: 'INCIDENT_NOT_FOUND', incidentId: input.incident_id }) }], isError: true };
          }
          if (!incident.repairPlan) {
            return { content: [{ type: 'text' as const, text: JSON.stringify({ error: 'NO_REPAIR_PLAN', message: 'Run srt_diagnose first' }) }], isError: true };
          }
          if (incident.repairPlan.gateStatus !== 'PENDING') {
            return { content: [{ type: 'text' as const, text: JSON.stringify({ error: 'GATE_NOT_PENDING', currentStatus: incident.repairPlan.gateStatus }) }], isError: true };
          }
    
          // ── Forensic ledger: begin MANDATORY entry ──
          const entry = engine.ledger.begin(
            `srt-repair-${input.action}`,
            MaiClassification.MANDATORY,
            GiaLayer.MCP,
            input.approved_by
          );
          entry.addMetadata('incidentId', input.incident_id);
          entry.addMetadata('action', input.action);
          if (input.reason) entry.addMetadata('reason', input.reason);
    
          try {
            const ts = new Date().toISOString();
    
            if (input.action === 'reject') {
              incident.repairPlan.gateStatus = 'REJECTED';
              incident.repairPlan.approvedBy = input.approved_by;
              incident.repairPlan.approvedAt = ts;
              incident.status = 'DIAGNOSED';
              incident.updatedAt = ts;
              persistIncident(incident); // Write-through: rejection
    
              const score = engine.scorer.scoreDefault(`srt-repair-${input.action}`);
              const completedEntry = entry.complete(score, {
                classification: MaiClassification.MANDATORY,
                confidence: 1.0,
                rationale: `SRT repair ${input.action}: incident ${input.incident_id}`,
                requiresGate: false,
              });
              engine.ledger.record(completedEntry);
    
              engine.telemetryService.emitToolCall('srt_approve_repair', incident.incidentId, 'MANDATORY', true);
    
              return { content: [{ type: 'text' as const, text: JSON.stringify({
                rejected: true,
                incidentId: incident.incidentId,
                planId: incident.repairPlan.planId,
                rejectedBy: input.approved_by,
                reason: input.reason || 'No reason provided',
                status: 'DIAGNOSED — can re-diagnose or propose new plan',
              }, null, 2) }] };
            }
    
            // Approve
            incident.repairPlan.gateStatus = 'APPROVED';
            incident.repairPlan.approvedBy = input.approved_by;
            incident.repairPlan.approvedAt = ts;
            incident.status = 'REPAIR_APPROVED';
            incident.updatedAt = ts;
    
            // Mark as executing (in real deployment, this triggers server-side execution)
            incident.repairPlan.executedAt = ts;
            incident.status = 'REPAIR_EXECUTING';
    
            // For v1, mark as success immediately (real execution is server-side)
            // In production, this would wait for actual command execution results
            incident.repairPlan.completedAt = new Date(Date.now() + (incident.repairPlan.estimatedMinutes * 60000)).toISOString();
            incident.repairPlan.result = 'SUCCESS';
            incident.status = 'REPAIR_COMPLETE';
            incident.updatedAt = new Date().toISOString();
            persistIncident(incident); // Write-through: approval + execution + completion
    
            const score = engine.scorer.scoreDefault(`srt-repair-${input.action}`);
            const completedEntry = entry.complete(score, {
              classification: MaiClassification.MANDATORY,
              confidence: 1.0,
              rationale: `SRT repair ${input.action}: incident ${input.incident_id}`,
              requiresGate: false,
            });
            engine.ledger.record(completedEntry);
    
            engine.telemetryService.emitToolCall('srt_approve_repair', incident.incidentId, 'MANDATORY', true);
    
            return { content: [{ type: 'text' as const, text: JSON.stringify({
              approved: true,
              incidentId: incident.incidentId,
              planId: incident.repairPlan.planId,
              approvedBy: input.approved_by,
              status: 'REPAIR_COMPLETE',
              result: incident.repairPlan.result,
              commandsExecuted: incident.repairPlan.commands.length,
              nextStep: 'Call srt_generate_postmortem to create incident report.',
            }, null, 2) }] };
          } catch (error) {
            const failedEntry = entry.fail(error instanceof Error ? error : new Error(`SRT repair ${input.action} failed`), MaiClassification.MANDATORY);
            engine.ledger.record(failedEntry);
            engine.telemetryService.emitToolCall('srt_approve_repair', `repair-err-${Date.now().toString(36)}`, 'MANDATORY', false);
            return { content: [{ type: 'text' as const, text: JSON.stringify({ error: 'APPROVAL_FAILED', message: String(error) }) }], isError: true };
          }
        }
      );
    }
  • Convenience function registerSRTTools() that registers all 4 SRT tools, including srt_approve_repair via registerSRTApproveRepairTool().
    export function registerSRTTools(server: McpServer, engine: GovernanceEngine): void {
      registerSRTRunWatchdogTool(server, engine);
      registerSRTDiagnoseTool(server, engine);
      registerSRTApproveRepairTool(server, engine);
      registerSRTGeneratePostmortemTool(server, engine);
    }
  • Registration in the TOOL_REGISTRY: srt_approve_repair is registered via registerSRTTools (which includes all 4 SRT tools) at OPERATOR tier, meaning it's only exposed to local stdio clients, not external HTTP clients.
      { tier: 'operator', register: registerSRTTools, description: 'srt (run_watchdog, diagnose, approve_repair, generate_postmortem)' },
      { tier: 'operator', register: registerRemediationPackTools, description: 'remediation (scan_environment, list_packs, dry_run_pack, apply_pack, run_patrol)' },
    ];
  • Input schema for the tool: requires incident_id (string), action (enum approve/reject), approved_by (string — human operator), and optional reason (string — required if rejecting).
    {
      incident_id: z.string().describe('Incident ID with pending repair'),
      action: z.enum(['approve', 'reject']).describe('Approve or reject the repair plan'),
      approved_by: z.string().describe('Human operator approving/rejecting'),
      reason: z.string().optional().describe('Reason for rejection (required if rejecting)'),
    },
  • Telemetry classification: srt_approve_repair is classified as toolClass='gate', riskTier='critical', maiDefault='MANDATORY', requiresHumanApproval=true, category='srt'.
    { toolName: 'srt_approve_repair',     toolClass: 'gate',     riskTier: 'critical', maiDefault: 'MANDATORY',      requiresHumanApproval: true,  category: 'srt' },
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already set destructiveHint=true, indicating mutation. The description adds critical behavioral context: it is a human-in-the-loop gate and plans cannot execute without approval. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Extremely concise: three sentences pack the purpose, mandatory classification, and action parameter usage with example values. No wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the annotations and schema, the description covers the essential behavioral aspects (mandatory, human gate, action values). Lacks explicit mention of return value or post-approval effects, but the tool's role as a gate is sufficiently clear.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with descriptions for all parameters. The description adds minor clarification on action usage and the conditional requirement for reason on rejection, which the schema notes but does not enforce as required. This adds some value beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Approve or reject a pending SRT repair plan,' which is a specific verb+resource. It distinguishes this tool from sibling tools like srt_diagnose and srt_run_watchdog by focusing on the approval gate.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states 'Classification: MANDATORY' and 'Repair plans CANNOT execute without explicit human approval,' providing clear context for when to use. However, no explicit when-not-to-use or alternatives are mentioned, but the mandatory nature implies it's the only approval step.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/knowledgepa3/gia-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server