Skip to main content
Glama

approve_gate

Approve or reject pending mandatory gate decisions to enforce human-in-the-loop governance. Lists pending gates when no gate ID is given.

Instructions

Approve or reject a pending MANDATORY gate decision. Lists pending gates if no gate_id provided. This is the human-in-the-loop mechanism for MANDATORY classifications.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
actionYesAction to perform
gate_idNoGate ID to approve/reject (required for approve/reject)
approved_byNoIdentity of the approverHUMAN
rationaleNoReason for approval/rejection
webauthn_proofNoOptional WebAuthn passkey proof for cryptographic identity verification

Implementation Reference

  • Handler registration and execution logic for the approve_gate MCP tool. Supports 4 actions: list (show pending gates), approve (approve with optional WebAuthn), reject (reject with optional WebAuthn), break_glass (emergency override). Delegates to engine.gate.approve(), engine.gate.reject(), engine.gate.breakGlassApprove() for core logic.
    export function registerApproveGateTool(server: McpServer, engine: GovernanceEngine): void {
      server.tool(
        'approve_gate',
        'Approve or reject a pending MANDATORY gate decision. Lists pending gates if no gate_id provided. This is the human-in-the-loop mechanism for MANDATORY classifications.',
        {
          action: z.enum(['list', 'approve', 'reject', 'break_glass']).describe('Action to perform'),
          gate_id: z.string().optional().describe('Gate ID to approve/reject (required for approve/reject)'),
          approved_by: z.string().default('HUMAN').describe('Identity of the approver'),
          rationale: z.string().optional().describe('Reason for approval/rejection'),
          webauthn_proof: z.object({
            credentialId: z.string(),
            userId: z.string(),
            verifiedAt: z.string(),
            signatureVerified: z.boolean(),
          }).optional().describe('Optional WebAuthn passkey proof for cryptographic identity verification'),
        },
        { title: 'Approve or Reject Mandatory Gate', readOnlyHint: false, idempotentHint: false, destructiveHint: false, openWorldHint: false, _meta: { ui: { resourceUri: 'ui://gate-approval' } } } as any,
        async (input) => {
          if (input.action === 'list') {
            const pending = engine.gate.getPendingApprovals();
    
            // Tool accountability tracking
            engine.telemetryService.emitToolCall('approve_gate', `gate-list-${Date.now().toString(36)}`, 'INFORMATIONAL', true);
    
            return {
              content: [{ type: 'text' as const, text: JSON.stringify({
                pendingCount: pending.length,
                pending: pending.map(p => ({
                  gateId: p.gateId,
                  operation: p.operation,
                  classification: p.classification,
                  requestedAt: p.requestedAt,
                  ownerRole: p.ownerRole,
                  sla: p.sla,
                })),
              }, null, 2) }],
            };
          }
    
          if (!input.gate_id) {
            return {
              content: [{ type: 'text' as const, text: JSON.stringify({
                error: 'MISSING_GATE_ID',
                message: 'gate_id is required for approve/reject actions.',
              }) }],
              isError: true,
            };
          }
    
          if (input.action === 'break_glass') {
            const entry = engine.ledger.begin(
              'gate-break_glass',
              MaiClassification.MANDATORY,
              GiaLayer.MCP,
              input.approved_by
            );
            entry.addMetadata('gateId', input.gate_id!);
            entry.addMetadata('action', input.action);
            if (input.rationale) entry.addMetadata('rationale', input.rationale);
    
            try {
              const success = engine.gate.breakGlassApprove(
                input.gate_id!, input.approved_by,
                'mcp-break-glass-' + Date.now().toString(36),
                input.rationale ?? 'Break-glass via MCP tool'
              );
    
              const score = engine.scorer.scoreDefault('gate-break_glass');
              const completedEntry = entry.complete(score, {
                classification: MaiClassification.MANDATORY,
                confidence: 1.0,
                rationale: `Gate break_glass: ${input.rationale || 'No rationale provided'}`,
                requiresGate: false,
              });
              engine.ledger.record(completedEntry);
    
              // Auto-emit governance telemetry
              engine.telemetryService.emitGateAction(entry.id, 'break_glass', input.gate_id!, input.approved_by);
              engine.telemetryService.emitToolCall('approve_gate', entry.id, 'MANDATORY', true);
    
              return {
                content: [{ type: 'text' as const, text: JSON.stringify({
                  action: 'BREAK_GLASS_OVERRIDE',
                  gateId: input.gate_id,
                  approvedBy: input.approved_by,
                  success,
                  message: success
                    ? `Gate ${input.gate_id} approved via break-glass emergency override. Mandatory post-review required.`
                    : await enhanceNotFoundMessage(input.gate_id!),
                }, null, 2) }],
                isError: !success,
              };
            } catch (error) {
              engine.telemetryService.emitToolCall('approve_gate', entry.id, 'MANDATORY', false);
              const failedEntry = entry.fail(error instanceof Error ? error : new Error('Gate break_glass failed'), MaiClassification.MANDATORY);
              engine.ledger.record(failedEntry);
              throw error;
            }
          }
    
          if (input.action === 'approve') {
            // Pre-check: is this gate actually pending? Needed to distinguish
            // "not found" from "passkey required" when approve() returns false.
            const pendingBefore = engine.gate.getPendingApprovals().some(p => p.gateId === input.gate_id);
    
            const entry = engine.ledger.begin(
              'gate-approve',
              MaiClassification.MANDATORY,
              GiaLayer.MCP,
              input.approved_by
            );
            entry.addMetadata('gateId', input.gate_id);
            entry.addMetadata('action', input.action);
            if (input.rationale) entry.addMetadata('rationale', input.rationale);
    
            try {
              const success = engine.gate.approve(input.gate_id, input.approved_by, input.rationale, input.webauthn_proof);
    
              const score = engine.scorer.scoreDefault('gate-approve');
              const completedEntry = entry.complete(score, {
                classification: MaiClassification.MANDATORY,
                confidence: 1.0,
                rationale: `Gate approve: ${input.rationale || 'No rationale provided'}`,
                requiresGate: false,
              });
              engine.ledger.record(completedEntry);
    
              // Auto-emit governance telemetry
              engine.telemetryService.emitGateAction(entry.id, 'approve', input.gate_id, input.approved_by);
              engine.telemetryService.emitToolCall('approve_gate', entry.id, 'MANDATORY', true);
    
              // Distinguish failure reasons: gate not found vs passkey required
              let message: string;
              if (success) {
                message = `Gate ${input.gate_id} approved by ${input.approved_by}${input.webauthn_proof ? ' with WebAuthn passkey verification' : ''}.`;
              } else if (pendingBefore) {
                // Gate exists but approve() returned false → passkey enforcement rejected it
                message = `Gate ${input.gate_id} requires WebAuthn passkey proof for approval. Retry with webauthn_proof parameter.`;
              } else {
                message = await enhanceNotFoundMessage(input.gate_id!);
              }
    
              return {
                content: [{ type: 'text' as const, text: JSON.stringify({
                  action: success ? 'APPROVED' : (pendingBefore ? 'PASSKEY_REQUIRED' : 'NOT_FOUND'),
                  gateId: input.gate_id,
                  approvedBy: input.webauthn_proof ? input.webauthn_proof.userId : input.approved_by,
                  passkeyVerified: !!input.webauthn_proof,
                  success,
                  message,
                }, null, 2) }],
                isError: !success,
              };
            } catch (error) {
              engine.telemetryService.emitToolCall('approve_gate', entry.id, 'MANDATORY', false);
              const failedEntry = entry.fail(error instanceof Error ? error : new Error('Gate approve failed'), MaiClassification.MANDATORY);
              engine.ledger.record(failedEntry);
              throw error;
            }
          }
    
          // reject — also pass webauthnProof for identity verification on rejections
          const rejectedBy = input.webauthn_proof ? input.webauthn_proof.userId : input.approved_by;
    
          const entry = engine.ledger.begin(
            'gate-reject',
            MaiClassification.MANDATORY,
            GiaLayer.MCP,
            rejectedBy
          );
          entry.addMetadata('gateId', input.gate_id);
          entry.addMetadata('action', input.action);
          if (input.rationale) entry.addMetadata('rationale', input.rationale);
    
          try {
            const success = engine.gate.reject(input.gate_id, rejectedBy, input.rationale, input.webauthn_proof);
    
            const score = engine.scorer.scoreDefault('gate-reject');
            const completedEntry = entry.complete(score, {
              classification: MaiClassification.MANDATORY,
              confidence: 1.0,
              rationale: `Gate reject: ${input.rationale || 'No rationale provided'}`,
              requiresGate: false,
            });
            engine.ledger.record(completedEntry);
    
            // Auto-emit governance telemetry
            engine.telemetryService.emitGateAction(entry.id, 'reject', input.gate_id, rejectedBy);
            engine.telemetryService.emitToolCall('approve_gate', entry.id, 'MANDATORY', true);
    
            return {
              content: [{ type: 'text' as const, text: JSON.stringify({
                action: 'REJECTED',
                gateId: input.gate_id,
                rejectedBy,
                passkeyVerified: !!input.webauthn_proof,
                success,
                message: success
                  ? `Gate ${input.gate_id} rejected by ${rejectedBy}${input.webauthn_proof ? ' with WebAuthn passkey verification' : ''}.`
                  : await enhanceNotFoundMessage(input.gate_id!),
              }, null, 2) }],
              isError: !success,
            };
          } catch (error) {
            engine.telemetryService.emitToolCall('approve_gate', entry.id, 'MANDATORY', false);
            const failedEntry = entry.fail(error instanceof Error ? error : new Error('Gate reject failed'), MaiClassification.MANDATORY);
            engine.ledger.record(failedEntry);
            throw error;
          }
        }
      );
    }
  • Zod schema defining the input parameters: action (enum: list/approve/reject/break_glass), gate_id (optional string), approved_by (defaults to HUMAN), rationale (optional), webauthn_proof (optional object with credentialId, userId, verifiedAt, signatureVerified).
    {
      action: z.enum(['list', 'approve', 'reject', 'break_glass']).describe('Action to perform'),
      gate_id: z.string().optional().describe('Gate ID to approve/reject (required for approve/reject)'),
      approved_by: z.string().default('HUMAN').describe('Identity of the approver'),
      rationale: z.string().optional().describe('Reason for approval/rejection'),
      webauthn_proof: z.object({
        credentialId: z.string(),
        userId: z.string(),
        verifiedAt: z.string(),
        signatureVerified: z.boolean(),
      }).optional().describe('Optional WebAuthn passkey proof for cryptographic identity verification'),
    },
    { title: 'Approve or Reject Mandatory Gate', readOnlyHint: false, idempotentHint: false, destructiveHint: false, openWorldHint: false, _meta: { ui: { resourceUri: 'ui://gate-approval' } } } as any,
  • Tool is imported and registered in the MCP server's TOOL_REGISTRY with 'operator' tier visibility — meaning it's only exposed to local stdio clients (Claude Code / Claude Desktop), never to external HTTP clients.
    import { registerApproveGateTool } from './tools/approve-gate.js';
    import { registerAgentRightsTool } from './tools/agent-rights.js';
    import { registerPrecedentTools } from './tools/precedent.js';
    import { registerCitizenshipTools } from './tools/citizenship.js';
    import { registerBranchAuthorityTools } from './tools/branchAuthority.js';
    import { registerColonyTools } from './tools/colony.js';
    import { registerMemoryPackTools } from './tools/memory-packs.js';
    import { registerValueMetricsTools } from './tools/value-metrics.js';
    import { registerSRTTools } from './tools/srt.js';
    import { registerVerifyLedgerTool } from './tools/verify-ledger.js';
    import { registerExportLedgerTool } from './tools/export-ledger.js';
    import { registerRemediationPackTools } from './tools/remediation-packs.js';
    import { registerPhoenixRecoveryTools } from './tools/phoenix-recovery.js';
    import { registerGovernedRetrievalTools } from './tools/governed-retrieval.js';
    import { registerContextAuthorityTool } from './tools/context-authority.js';
    import { registerInstitutionTools } from './tools/institution.js';
    import { registerContextReviveTool } from './tools/context-revive.js';
    import { registerGovernedSamplingTool } from './tools/governed-sampling.js';
    import { registerChainOfReasoningTools } from './tools/chain-of-reasoning.js';
    import { GovernedSampling } from '../core/sampling/index.js';
    
    // Runtime accountability instrumentation — wraps server.tool() registrations
    // so every invocation is bookended with startSession()/endSession().
    import { wrapServerWithRuntimeAccountability } from './runtime-accountability-wrapper.js';
    
    // Import resource handlers
    import { registerResources } from './resources/index.js';
    
    // Import prompt handlers
    import { registerPrompts } from './prompts/index.js';
    
    // ============================================================================
    // Tool Visibility Tiers — Tenant Isolation for External MCP Clients
    // ============================================================================
    //
    // Three tiers control which tools are registered per session:
    //   PUBLIC   — stateless scoring/classification tools, safe for any external client
    //   TENANT   — tools that access data, filtered by tenant ID (professional+ tier)
    //   OPERATOR — internal infrastructure tools (local stdio only, never exposed externally)
    //
    // The Smithery gateway and all HTTP clients get PUBLIC by default.
    // Paying customers (professional/enterprise DB keys) get PUBLIC + TENANT.
    // Local stdio (Claude Code / Claude Desktop) gets all tiers (OPERATOR).
    // ============================================================================
    
    export type ToolVisibility = 'public' | 'tenant' | 'operator';
    
    /**
     * Maps each tool registration function to its visibility tier.
     * Grouped by the tier each set of tools belongs to.
     */
    const TOOL_REGISTRY: Array<{
      tier: ToolVisibility;
      register: (server: McpServer, engine: GovernanceEngine) => void;
      description: string;
    }> = [
      // --- PUBLIC: Stateless governance scoring — no data exposure ---
      { tier: 'public', register: registerClassifyDecisionTool, description: 'classify_decision' },
      { tier: 'public', register: registerEvaluateThresholdTool, description: 'evaluate_threshold' },
      { tier: 'public', register: registerScoreGovernanceTool, description: 'score_governance' },
      { tier: 'public', register: registerAssessRiskTierTool, description: 'assess_risk_tier' },
      { tier: 'public', register: registerMapComplianceTool, description: 'map_compliance' },
      { tier: 'public', register: registerVerifyLedgerTool, description: 'verify_ledger' },
    
      // --- TENANT: Data-bearing tools, scoped to authenticated tenant ---
      { tier: 'tenant', register: registerAuditPipelineTool, description: 'audit_pipeline' },
      { tier: 'tenant', register: registerMonitorAgentsTool, description: 'monitor_agents' },
      { tier: 'tenant', register: registerSystemStatusTool, description: 'system_status' },
      { tier: 'tenant', register: registerGenerateReportTool, description: 'generate_report' },
      { tier: 'tenant', register: registerExportLedgerTool, description: 'export_ledger' },
      { tier: 'tenant', register: registerValueMetricsTools, description: 'value_metrics (record_value_metric, record_governance_event, generate_impact_report)' },
      { tier: 'tenant', register: registerMemoryPackTools, description: 'memory_packs (seal, load, transfer, compose, distill, promote)' },
      { tier: 'tenant', register: registerPhoenixRecoveryTools, description: 'phoenix (snapshot, verify_integrity, recovery_health)' },
      { tier: 'public', register: registerContextAuthorityTool, description: 'request_context (governed context authority)' },
      { tier: 'tenant', register: (server, _engine) => registerInstitutionTools(server), description: 'board (list_institutions, list_charters, convene_session, get_session, install_kit)' },
    
      // --- OPERATOR: Internal infrastructure — never exposed to external clients ---
      { tier: 'operator', register: registerApproveGateTool, description: 'approve_gate' },
  • Tool accountability profile registered in GOVERNED_TOOL_REGISTRY with toolClass 'gate', riskTier 'critical', maiDefault 'MANDATORY', requiresHumanApproval true, category 'governance'.
    export const GOVERNED_TOOL_REGISTRY: IToolAccountabilityProfile[] = [
      // ── Core Governance (10 tools) ──
      { toolName: 'classify_decision',   toolClass: 'read',     riskTier: 'moderate', maiDefault: 'ADVISORY',       requiresHumanApproval: false, category: 'governance' },
      { toolName: 'score_governance',    toolClass: 'read',     riskTier: 'moderate', maiDefault: 'ADVISORY',       requiresHumanApproval: false, category: 'governance' },
      { toolName: 'evaluate_threshold',  toolClass: 'read',     riskTier: 'low',      maiDefault: 'INFORMATIONAL',  requiresHumanApproval: false, category: 'governance' },
      { toolName: 'assess_risk_tier',    toolClass: 'read',     riskTier: 'moderate', maiDefault: 'ADVISORY',       requiresHumanApproval: false, category: 'governance' },
      { toolName: 'map_compliance',      toolClass: 'read',     riskTier: 'low',      maiDefault: 'INFORMATIONAL',  requiresHumanApproval: false, category: 'governance' },
      { toolName: 'audit_pipeline',      toolClass: 'read',     riskTier: 'low',      maiDefault: 'INFORMATIONAL',  requiresHumanApproval: false, category: 'forensics' },
      { toolName: 'approve_gate',        toolClass: 'gate',     riskTier: 'critical', maiDefault: 'MANDATORY',      requiresHumanApproval: true,  category: 'governance' },
      { toolName: 'monitor_agents',      toolClass: 'read',     riskTier: 'low',      maiDefault: 'INFORMATIONAL',  requiresHumanApproval: false, category: 'operations' },
      { toolName: 'generate_report',     toolClass: 'read',     riskTier: 'low',      maiDefault: 'INFORMATIONAL',  requiresHumanApproval: false, category: 'reporting' },
      { toolName: 'system_status',       toolClass: 'read',     riskTier: 'low',      maiDefault: 'INFORMATIONAL',  requiresHumanApproval: false, category: 'operations' },
    
      // ── Knowledge Packs (6 tools) ──
      { toolName: 'seal_memory_pack',     toolClass: 'write',    riskTier: 'moderate', maiDefault: 'ADVISORY',       requiresHumanApproval: false, category: 'knowledge' },
      { toolName: 'load_memory_pack',     toolClass: 'read',     riskTier: 'low',      maiDefault: 'ADVISORY',       requiresHumanApproval: false, category: 'knowledge' },
      { toolName: 'transfer_memory_pack', toolClass: 'write',    riskTier: 'high',     maiDefault: 'MANDATORY',      requiresHumanApproval: true,  category: 'knowledge' },
      { toolName: 'compose_memory_packs', toolClass: 'write',    riskTier: 'moderate', maiDefault: 'ADVISORY',       requiresHumanApproval: false, category: 'knowledge' },
      { toolName: 'distill_memory_pack',  toolClass: 'write',    riskTier: 'moderate', maiDefault: 'ADVISORY',       requiresHumanApproval: false, category: 'knowledge' },
      { toolName: 'promote_memory_pack',  toolClass: 'admin',    riskTier: 'high',     maiDefault: 'MANDATORY',      requiresHumanApproval: true,  category: 'knowledge' },
    
      // ── SRT (4 tools) ──
      { toolName: 'srt_run_watchdog',       toolClass: 'read',     riskTier: 'low',      maiDefault: 'INFORMATIONAL',  requiresHumanApproval: false, category: 'srt' },
      { toolName: 'srt_diagnose',           toolClass: 'read',     riskTier: 'moderate', maiDefault: 'ADVISORY',       requiresHumanApproval: false, category: 'srt' },
      { toolName: 'srt_approve_repair',     toolClass: 'gate',     riskTier: 'critical', maiDefault: 'MANDATORY',      requiresHumanApproval: true,  category: 'srt' },
      { toolName: 'srt_generate_postmortem', toolClass: 'read',    riskTier: 'low',      maiDefault: 'ADVISORY',       requiresHumanApproval: false, category: 'srt' },
    
      // ── Value Metrics (3 tools) ──
      { toolName: 'record_value_metric',    toolClass: 'write',    riskTier: 'low',      maiDefault: 'INFORMATIONAL',  requiresHumanApproval: false, category: 'metrics' },
      { toolName: 'record_governance_event', toolClass: 'write',   riskTier: 'low',      maiDefault: 'INFORMATIONAL',  requiresHumanApproval: false, category: 'metrics' },
      { toolName: 'generate_impact_report', toolClass: 'read',     riskTier: 'low',      maiDefault: 'ADVISORY',       requiresHumanApproval: false, category: 'metrics' },
    
      // ── Remediation & Operations (5 tools) ──
      { toolName: 'gia_scan_environment',  toolClass: 'external', riskTier: 'moderate', maiDefault: 'INFORMATIONAL',  requiresHumanApproval: false, category: 'operations' },
      { toolName: 'gia_list_packs',        toolClass: 'read',     riskTier: 'low',      maiDefault: 'INFORMATIONAL',  requiresHumanApproval: false, category: 'operations' },
      { toolName: 'gia_dry_run_pack',      toolClass: 'read',     riskTier: 'moderate', maiDefault: 'ADVISORY',       requiresHumanApproval: false, category: 'operations' },
      { toolName: 'gia_apply_pack',        toolClass: 'external', riskTier: 'critical', maiDefault: 'MANDATORY',      requiresHumanApproval: true,  category: 'operations' },
      { toolName: 'gia_run_patrol',        toolClass: 'external', riskTier: 'moderate', maiDefault: 'ADVISORY',       requiresHumanApproval: false, category: 'operations' },
    
      // ── Forensics (1 tool) ──
      { toolName: 'verify_ledger',         toolClass: 'read',     riskTier: 'low',      maiDefault: 'INFORMATIONAL',  requiresHumanApproval: false, category: 'forensics' },
    ];
  • Helper function that enhances 'not found' error messages by looking up the gate in the PostgreSQL database. Provides detailed messages for TIMED_OUT, APPROVED, or REJECTED states — useful when MCP server restart cleared in-memory gates.
    async function enhanceNotFoundMessage(gateId: string): Promise<string> {
      try {
        const dbRecord = await getGateDbRecord(gateId);
        if (!dbRecord) {
          return `Gate ${gateId} not found in pending approvals or DB. Check the gate_id is correct.`;
        }
        if (dbRecord.status === 'TIMED_OUT') {
          const at = dbRecord.resolvedAt?.toISOString() || 'unknown';
          return `Gate ${gateId} timed out at ${at} (DB status: TIMED_OUT). The in-memory gate was cleared, likely by MCP server restart. Re-issue the original request to create a fresh gate.`;
        }
        if (dbRecord.status === 'APPROVED' || dbRecord.status === 'REJECTED') {
          const at = dbRecord.resolvedAt?.toISOString() || 'unknown';
          const by = dbRecord.approvedBy || 'unknown';
          return `Gate ${gateId} already ${dbRecord.status.toLowerCase()} by ${by} at ${at} (DB status: ${dbRecord.status}). Cannot ${dbRecord.status === 'APPROVED' ? 'approve' : 'reject'} again.`;
        }
        return `Gate ${gateId} not in pending approvals; DB status: ${dbRecord.status}.`;
      } catch {
        return `Gate ${gateId} not found in pending approvals.`;
      }
    }
Behavior3/5

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

Annotations indicate non-destructive, non-idempotent behavior. The description adds that it is a 'human-in-the-loop mechanism' but does not detail side effects, required permissions, or what happens after approval/rejection. With no output schema, the absence of return value info is a gap.

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?

Two sentences, front-loaded with the verb and objective. Every word is meaningful; no redundancy or fluff.

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

Completeness3/5

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

The description is minimal and does not mention return values or additional effects (e.g., confirmation, errors). Given the lack of output schema, more detail on output or post-conditions would improve completeness. However, the tool's simplicity partly compensates.

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

Parameters4/5

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

Input schema has 100% parameter description coverage. The description adds value by clarifying conditional behavior: gate_id is required for approve/reject but not for list (implied by 'Lists pending gates if no gate_id provided'). This goes beyond the schema's static descriptions.

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 explicitly states the tool's purpose: 'Approve or reject a pending MANDATORY gate decision' and 'Lists pending gates if no gate_id provided.' It distinguishes this from siblings like board_approve_gate and srt_approve_repair by highlighting the MANDATORY and human-in-the-loop aspect.

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?

The description provides clear usage context: 'Lists pending gates if no gate_id provided' and implies that approve/reject require a gate_id. However, it does not explicitly mention when to use alternatives or when not to use the tool. The action enum partially covers this, but explicit guidance is missing.

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