Files
wehub-resource-sync 23f7624596
ADR-166 MCP Bridge Security Lock / Static-source security lock (push) Failing after 0s
ADR-166 MCP Bridge Security Lock / Compose default binds loopback + Mongo has auth (push) Failing after 2s
CodeQL Advanced / Analyze (rust) (push) Failing after 0s
ADR-166 MCP Bridge Security Lock / plugin-agent-federation bindHost default (push) Failing after 1s
ADR-166 MCP Bridge Security Lock / Runtime behavior — 401 + terminal gate + fail-closed (push) Failing after 4s
business-pods-smoke / smoke (push) Failing after 1s
all-plugins-smoke / smoke-all (push) Failing after 2s
CI/CD Pipeline / Security & Code Quality (push) Failing after 1s
CI/CD Pipeline / Test Suite (ubuntu-latest) (push) Failing after 1s
CI/CD Pipeline / Build & Package (macos-latest) (push) Has been skipped
CI/CD Pipeline / Build & Package (ubuntu-latest) (push) Has been skipped
CI/CD Pipeline / Build & Package (windows-latest) (push) Has been skipped
CI/CD Pipeline / Documentation & Examples (push) Failing after 1s
Clone Tracker (14-day rolling) / Snapshot clones for ruflo ecosystem (push) Failing after 1s
CodeQL Advanced / Analyze (actions) (push) Failing after 1s
CodeQL Advanced / Analyze (javascript-typescript) (push) Failing after 1s
federation-peer-rust / stable-noop (push) Failing after 1s
metaharness-ci / score (push) Failing after 1s
metaharness-ci / router-compat (push) Failing after 0s
metaharness-ci / similarity-tests (push) Failing after 0s
no-agentbbs-smoke / smoke-without-agentbbs (push) Failing after 1s
V3 CI/CD Pipeline / Build V3 (windows-latest) (push) Has been skipped
codex-integration-audit / Codex integration audit (push) Failing after 1s
helpers-manifest-guard / guard (push) Failing after 1s
🔗 Cross-Agent Integration Tests / 🤝 Agent Coordination Tests (push) Has been skipped
🔗 Cross-Agent Integration Tests / 🧠 Memory Sharing Integration (push) Has been skipped
🔗 Cross-Agent Integration Tests / 🛡️ Fault Tolerance Tests (push) Has been skipped
🔗 Cross-Agent Integration Tests / ⚡ Performance Integration Tests (push) Has been skipped
metaharness-ci / mcp-scan (push) Failing after 1s
metaharness-ci / eject-dryrun (push) Failing after 1s
metaharness-ci / metaharness-real-data (push) Failing after 0s
no-cli-optdep-bloat-2561 / guard (push) Failing after 1s
no-metaharness-smoke / smoke-without-metaharness (push) Failing after 1s
no-phantom-agentic-flow-subpath / guard (push) Failing after 1s
🔄 Automated Rollback Manager / 🚨 Failure Detection (push) Failing after 1s
V3 CI/CD Pipeline / Plugin hooks smoke / ubuntu-latest / Node 22 (push) Failing after 1s
V3 CI/CD Pipeline / ruflo-graph-intelligence build + test smoke (#2044, ADR-123) (push) Failing after 1s
CVE Audit Gate / Audit root (critical-blocking) (push) Failing after 2s
cost-tracker-smoke / smoke (push) Failing after 3s
oia-audit-weekly / audit (push) Failing after 2s
ruflo-agent-smoke / ruflo-agent structural smoke (push) Failing after 1s
📊 Status Badges Update / 📊 Update Status Badges (push) Failing after 1s
V3 CI/CD Pipeline / Static regression guards (#2267 YAML + (push) Failing after 1s
V3 CI/CD Pipeline / Test V3 Packages (push) Failing after 0s
V3 CI/CD Pipeline / agent_execute provider routing smoke (#2042) (push) Failing after 0s
CVE Audit Gate / Audit v3 (critical-blocking) (push) Failing after 1s
federation-peer-rust / stable-native (push) Failing after 2s
🔗 Cross-Agent Integration Tests / 🚀 Integration Test Setup (push) Failing after 2s
neural-trader-smoke / runtime-smoke (push) Failing after 1s
V3 CI/CD Pipeline / Build V3 (macos-latest) (push) Has been skipped
V3 CI/CD Pipeline / Build V3 (ubuntu-latest) (push) Has been skipped
V3 CI/CD Pipeline / Type Check V3 (push) Failing after 1s
V3 CI/CD Pipeline / Smoke (no better-sqlite3) / ubuntu-latest / Node 24 (push) Failing after 1s
V3 CI/CD Pipeline / Smoke (no better-sqlite3) / ubuntu-latest / Node 22 (push) Failing after 2s
V3 CI/CD Pipeline / browser rvf create flag smoke (#2015) (push) Failing after 0s
V3 CI/CD Pipeline / Dependency review (#2046) (push) Has been skipped
V3 CI/CD Pipeline / Supply-chain audit (#2046) (push) Failing after 0s
V3 CI/CD Pipeline / witness marker drift smoke (#2021) (push) Failing after 1s
V3 CI/CD Pipeline / neural-trader portfolio CG smoke (#2068, ADR-126 Phase 3) (push) Failing after 1s
V3 CI/CD Pipeline / neural-trader backtest signing smoke (#2068, ADR-126 Phase 4) (push) Failing after 1s
V3 CI/CD Pipeline / kg-extract type-import classification smoke (#2049) (push) Failing after 0s
V3 CI/CD Pipeline / witness verify precondition smoke (#1880) (push) Failing after 2s
V3 CI/CD Pipeline / neural-trader pipeline risk-gate smoke (#2068, ADR-126 Phase 5) (push) Failing after 0s
V3 CI/CD Pipeline / neural-trader feature attribution smoke (#2068, ADR-126 Phase 6) (push) Failing after 0s
V3 CI/CD Pipeline / plugin-registry signature verification smoke (#1922, CWE-347) (push) Failing after 4s
V3 CI/CD Pipeline / memory stats legacy-DB smoke (#2120) (push) Failing after 4s
V3 CI/CD Pipeline / github deprecated actions smoke (#2089, ADR-127 Phase 3) (push) Failing after 1s
V3 CI/CD Pipeline / graph query + pathfinder smoke (ADR-130 P2+P5) (push) Has been skipped
V3 CI/CD Pipeline / graph trajectory hooks smoke (ADR-130 P3) (push) Has been skipped
V3 CI/CD Pipeline / graph plugin adapter smoke (ADR-130 P4) (push) Has been skipped
V3 CI/CD Pipeline / graph benchmark (ADR-130 P6) (push) Has been skipped
V3 CI/CD Pipeline / statusline generator delegation smoke (#2195) (push) Failing after 1s
V3 CI/CD Pipeline / wizard init regression guard (#2206 (push) Failing after 1s
V3 CI/CD Pipeline / memory no-stray-db smoke (ADR-125 P7) (push) Failing after 1s
V3 CI/CD Pipeline / github-safe injection smoke (#2089, ADR-127 Phase 1) (push) Failing after 1s
V3 CI/CD Pipeline / github actions pin smoke (#2089, ADR-127 Phase 1) (push) Failing after 1s
V3 CI/CD Pipeline / github attribution opt-in smoke (#2089, ADR-127 Phase 4) (push) Failing after 1s
V3 CI/CD Pipeline / pre-bash hook safety smoke (#2017) (push) Failing after 1s
V3 CI/CD Pipeline / Memory import smoke / ubuntu-latest (push) Failing after 0s
V3 CI/CD Pipeline / MCP protocol smoke / ubuntu-latest (push) Failing after 2s
V3 CI/CD Pipeline / ruvllm WASM auto-init smoke (#2086) (push) Failing after 4s
V3 CI/CD Pipeline / MCP paired-tool round-trip smoke (#1889) (push) Failing after 1s
V3 CI/CD Pipeline / Plugin package install-safety (#1902/#1903/#1904) (push) Failing after 1s
V3 CI/CD Pipeline / Tool description discoverability (ADR-112) (push) Failing after 3s
V3 CI/CD Pipeline / CLI npx-install smoke (#1147 / (22) (push) Failing after 1s
V3 CI/CD Pipeline / CLI npx-install smoke (#1147 / (24) (push) Failing after 1s
V3 CI/CD Pipeline / Windows hook shim smoke (#2132) / ubuntu-latest (push) Failing after 2s
V3 CI/CD Pipeline / Windows hook execution smoke (#2132) / ubuntu-latest (push) Failing after 1s
V3 CI/CD Pipeline / Windows init hooks smoke (#2132) / ubuntu-latest (push) Failing after 1s
V3 CI/CD Pipeline / Vector-index dimension audit (#1947) (push) Failing after 0s
V3 CI/CD Pipeline / Hook-command install safety (#1921) (push) Failing after 1s
V3 CI/CD Pipeline / ToolOutputGuardrail smoke (ADR-131, (push) Failing after 1s
V3 CI/CD Pipeline / init-bundle invariants smoke (#2095, ADR-128 Phase 5) (push) Failing after 1s
V3 CI/CD Pipeline / wasm provider bridge smoke (ADR-129 P1) (push) Failing after 2s
V3 CI/CD Pipeline / wasm gallery CRUD smoke (ADR-129 P3) (push) Failing after 1s
V3 CI/CD Pipeline / wasm plugin bridge smoke (ADR-129 P4) (push) Failing after 0s
V3 CI/CD Pipeline / wasm compose smoke (ADR-129 P2) (push) Failing after 4s
V3 CI/CD Pipeline / graph schema smoke (ADR-130 P1) (push) Failing after 0s
Validate Marketplace / validate (push) Failing after 1s
🔍 Verification Pipeline / 🚀 Setup Verification (push) Failing after 1s
🔍 Verification Pipeline / 🛡️ Security Verification (push) Has been skipped
🔍 Verification Pipeline / 📝 Code Quality (push) Has been skipped
🔍 Verification Pipeline / 🧪 Test Verification (${{ matrix.os }}, Node ${{ matrix.node }}) (push) Has been skipped
🔍 Verification Pipeline / 🏗️ Build Verification (push) Has been skipped
🔍 Verification Pipeline / 📚 Documentation Verification (push) Has been skipped
CVE Audit Gate / High-severity report (warn only) (push) Has been cancelled
🔄 Automated Rollback Manager / 🔄 Execute Rollback (push) Has been cancelled
🔄 Automated Rollback Manager / ✅ Post-Rollback Verification (push) Has been cancelled
🔄 Automated Rollback Manager / 📊 Rollback Monitoring (push) Has been cancelled
V3 CI/CD Pipeline / Windows init hooks smoke (#2132) / windows-latest (push) Has been cancelled
V3 CI/CD Pipeline / Windows hook execution smoke (#2132) / macos-latest (push) Has been cancelled
V3 CI/CD Pipeline / Windows hook execution smoke (#2132) / windows-latest (push) Has been cancelled
🔄 Automated Rollback Manager / ⏳ Manual Rollback Approval (push) Has been cancelled
V3 CI/CD Pipeline / MCP protocol smoke / macos-latest (push) Has been cancelled
V3 CI/CD Pipeline / Memory import smoke / macos-latest (push) Has been cancelled
V3 CI/CD Pipeline / Windows hook shim smoke (#2132) / macos-latest (push) Has been cancelled
V3 CI/CD Pipeline / Windows hook shim smoke (#2132) / windows-latest (push) Has been cancelled
V3 CI/CD Pipeline / Windows init hooks smoke (#2132) / macos-latest (push) Has been cancelled
V3 CI/CD Pipeline / Witness verify (signed manifest) / macos-latest (push) Has been cancelled
V3 CI/CD Pipeline / Witness verify (signed manifest) / ubuntu-latest (push) Has been cancelled
V3 CI/CD Pipeline / Witness verify (signed manifest) / windows-latest (push) Has been cancelled
V3 CI/CD Pipeline / Publish to npm (alpha) (push) Has been cancelled
V3 CI/CD Pipeline / Smoke (no better-sqlite3) / macos-latest / Node 22 (push) Has been cancelled
V3 CI/CD Pipeline / Plugin hooks smoke / macos-latest / Node 22 (push) Has been cancelled
CI/CD Pipeline / Deploy & Release (push) Has been cancelled
CI/CD Pipeline / CI Status (push) Has been cancelled
🔗 Cross-Agent Integration Tests / 📊 Integration Test Report (push) Has been cancelled
🔄 Automated Rollback Manager / 🔍 Pre-Rollback Validation (push) Has been cancelled
🔍 Verification Pipeline / ⚡ Performance Verification (push) Has been cancelled
🔍 Verification Pipeline / 📊 Verification Report (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:02:19 +08:00

16 KiB

MCP Client Guide for CLI Commands

Overview

The MCP Client (mcp-client.ts) provides a thin wrapper for CLI commands to call MCP tools, implementing ADR-005: MCP-First API Design where CLI acts as a thin wrapper around MCP tools.

Architecture

┌─────────────────┐
│  CLI Command    │  ← User interaction & display only
└────────┬────────┘
         │ callMCPTool()
         ▼
┌─────────────────┐
│  MCP Client     │  ← Tool registry & routing
└────────┬────────┘
         │ tool.handler()
         ▼
┌─────────────────┐
│  MCP Tool       │  ← Business logic lives here
│  Handler        │
└─────────────────┘

Quick Start

1. Import the MCP Client

import { callMCPTool, MCPClientError } from '../mcp-client.js';

2. Call an MCP Tool

try {
  const result = await callMCPTool('agent/spawn', {
    agentType: 'coder',
    priority: 'normal',
    config: { timeout: 300 }
  });

  // Handle success - display output
  output.printSuccess(`Agent ${result.agentId} spawned`);
  return { success: true, data: result };

} catch (error) {
  if (error instanceof MCPClientError) {
    output.printError(`Failed: ${error.message}`);
  }
  return { success: false, exitCode: 1 };
}

Available MCP Tools

Agent Tools

Tool Name Description Input Parameters
agent/spawn Spawn a new agent agentType, id?, config?, priority?, metadata?
agent/list List all agents status?, agentType?, limit?, offset?
agent/status Get agent status agentId, includeMetrics?, includeHistory?
agent/terminate Terminate an agent agentId, graceful?, reason?

Swarm Tools

Tool Name Description Input Parameters
swarm/init Initialize swarm topology, maxAgents?, config?, metadata?
swarm/status Get swarm status includeAgents?, includeMetrics?, includeTopology?
swarm/scale Scale swarm targetAgents, scaleStrategy?, agentTypes?, reason?

Memory Tools

Tool Name Description Input Parameters
memory/store Store memory content, type?, category?, tags?, importance?, ttl?
memory/search Search memories query, searchType?, type?, category?, tags?, limit?, minRelevance?
memory/list List memories type?, category?, tags?, sortBy?, sortOrder?, limit?, offset?

Config Tools

Tool Name Description Input Parameters
config/load Load configuration path?, scope?, merge?, includeDefaults?
config/save Save configuration config, path?, scope?, merge?, createBackup?
config/validate Validate config config, strict?, fixIssues?

MCP Client API

Core Functions

callMCPTool<T>(toolName, input, context?): Promise<T>

Call an MCP tool by name and return typed result.

Parameters:

  • toolName: MCP tool name (e.g., 'agent/spawn')
  • input: Tool input parameters (validated by tool's schema)
  • context?: Optional context object

Returns: Promise resolving to tool result

Throws: MCPClientError if tool not found or execution fails

Example:

const result = await callMCPTool<{ agentId: string }>('agent/spawn', {
  agentType: 'coder',
  priority: 'normal'
});
console.log(`Spawned agent: ${result.agentId}`);

getToolMetadata(toolName): ToolMetadata | undefined

Get tool metadata without executing it.

Example:

const metadata = getToolMetadata('agent/spawn');
if (metadata) {
  console.log(`Description: ${metadata.description}`);
  console.log(`Category: ${metadata.category}`);
  console.log(`Schema:`, metadata.inputSchema);
}

listMCPTools(category?): ToolMetadata[]

List all available MCP tools, optionally filtered by category.

Example:

// List all tools
const allTools = listMCPTools();

// List only agent tools
const agentTools = listMCPTools('agent');

hasTool(toolName): boolean

Check if an MCP tool exists.

Example:

if (hasTool('agent/spawn')) {
  console.log('Agent spawn tool is available');
}

validateToolInput(toolName, input): { valid: boolean; errors?: string[] }

Validate input against tool schema before calling.

Example:

const validation = validateToolInput('agent/spawn', {
  agentType: 'coder'
  // missing required field
});

if (!validation.valid) {
  console.error('Validation errors:', validation.errors);
}

getToolCategories(): string[]

Get all unique tool categories.

Example:

const categories = getToolCategories();
console.log('Available categories:', categories);
// Output: ['agent', 'swarm', 'memory', 'config']

Error Handling

MCPClientError

Custom error class for MCP tool failures.

Properties:

  • message: Error message
  • toolName: Name of the tool that failed
  • cause?: Original error if available

Example:

try {
  await callMCPTool('agent/spawn', { ... });
} catch (error) {
  if (error instanceof MCPClientError) {
    console.error(`Tool '${error.toolName}' failed: ${error.message}`);
    if (error.cause) {
      console.error('Caused by:', error.cause);
    }
  }
}

CLI Command Pattern

Standard Pattern

All CLI commands should follow this pattern:

import type { Command, CommandContext, CommandResult } from '../types.js';
import { output } from '../output.js';
import { select, confirm, input } from '../prompt.js';
import { callMCPTool, MCPClientError } from '../mcp-client.js';

const myCommand: Command = {
  name: 'my-command',
  description: 'Command description',
  options: [ /* command options */ ],

  action: async (ctx: CommandContext): Promise<CommandResult> => {
    // STEP 1: Gather input (interactive prompts if needed)
    let param = ctx.flags.param as string;
    if (!param && ctx.interactive) {
      param = await input({
        message: 'Enter parameter:',
        validate: (v) => v.length > 0 || 'Required'
      });
    }

    // STEP 2: Validate required inputs
    if (!param) {
      output.printError('Parameter is required');
      return { success: false, exitCode: 1 };
    }

    // STEP 3: Call MCP tool (business logic)
    try {
      const result = await callMCPTool<ResultType>('tool/name', {
        param,
        // ... other inputs
      });

      // STEP 4: Format and display output
      if (ctx.flags.format === 'json') {
        output.printJson(result);
      } else {
        output.printTable({
          columns: [ /* ... */ ],
          data: [ /* format result for display */ ]
        });
      }

      output.printSuccess('Operation successful');
      return { success: true, data: result };

    } catch (error) {
      // STEP 5: Handle errors
      if (error instanceof MCPClientError) {
        output.printError(`Failed: ${error.message}`);
      } else {
        output.printError(`Unexpected error: ${String(error)}`);
      }
      return { success: false, exitCode: 1 };
    }
  }
};

Key Principles

  1. CLI is thin: Only handles UI/UX, no business logic
  2. MCP tool has logic: All business logic in MCP tool handlers
  3. Type safety: Use TypeScript generics for tool results
  4. Error handling: Always catch and handle MCPClientError
  5. Display formatting: CLI adds visual enhancements only

What Belongs in CLI vs MCP Tool

CLI Command Responsibilities (Display Layer)

Interactive prompts (select, confirm, input) Flag/argument parsing Input validation (basic checks) Output formatting (tables, boxes, colors) Progress indicators Success/error messages JSON output formatting

MCP Tool Responsibilities (Business Logic)

Data validation (schema validation) Business rules enforcement Resource management (agents, swarms, memory) State changes Database operations External API calls Calculations and transformations

Examples

Example 1: Simple Tool Call

// Spawn an agent
const spawnCommand: Command = {
  name: 'spawn',
  action: async (ctx: CommandContext) => {
    const agentType = ctx.flags.type as string;

    try {
      const result = await callMCPTool('agent/spawn', {
        agentType,
        priority: 'normal'
      });

      output.printSuccess(`Spawned agent: ${result.agentId}`);
      return { success: true, data: result };

    } catch (error) {
      if (error instanceof MCPClientError) {
        output.printError(error.message);
      }
      return { success: false, exitCode: 1 };
    }
  }
};

Example 2: Tool Call with Filtering

// List agents with filters
const listCommand: Command = {
  name: 'list',
  action: async (ctx: CommandContext) => {
    try {
      const result = await callMCPTool<{
        agents: Agent[];
        total: number;
      }>('agent/list', {
        status: ctx.flags.status || 'all',
        agentType: ctx.flags.type,
        limit: 100
      });

      // Display results
      output.printTable({
        columns: [
          { key: 'id', header: 'ID', width: 20 },
          { key: 'type', header: 'Type', width: 15 },
          { key: 'status', header: 'Status', width: 10 }
        ],
        data: result.agents
      });

      output.printInfo(`Total: ${result.total} agents`);
      return { success: true, data: result };

    } catch (error) {
      if (error instanceof MCPClientError) {
        output.printError(error.message);
      }
      return { success: false, exitCode: 1 };
    }
  }
};

Example 3: Interactive Input with Tool Call

// Store memory with interactive input
const storeCommand: Command = {
  name: 'store',
  action: async (ctx: CommandContext) => {
    // Get input interactively if not provided
    let content = ctx.flags.content as string;
    if (!content && ctx.interactive) {
      content = await input({
        message: 'Enter content to store:',
        validate: (v) => v.length > 0 || 'Content required'
      });
    }

    if (!content) {
      output.printError('Content is required');
      return { success: false, exitCode: 1 };
    }

    // Select memory type interactively
    let type = ctx.flags.type as string;
    if (!type && ctx.interactive) {
      type = await select({
        message: 'Select memory type:',
        options: [
          { value: 'episodic', label: 'Episodic' },
          { value: 'semantic', label: 'Semantic' },
          { value: 'procedural', label: 'Procedural' }
        ]
      });
    }

    try {
      const result = await callMCPTool('memory/store', {
        content,
        type: type || 'episodic',
        tags: ctx.flags.tags?.split(',') || [],
        importance: ctx.flags.importance
      });

      output.printSuccess(`Stored memory: ${result.id}`);
      return { success: true, data: result };

    } catch (error) {
      if (error instanceof MCPClientError) {
        output.printError(error.message);
      }
      return { success: false, exitCode: 1 };
    }
  }
};

Testing

Unit Testing MCP Client

import { callMCPTool, MCPClientError, hasTool } from '../mcp-client.js';

describe('MCP Client', () => {
  it('should call agent/spawn tool', async () => {
    const result = await callMCPTool('agent/spawn', {
      agentType: 'coder'
    });

    expect(result).toHaveProperty('agentId');
    expect(result).toHaveProperty('agentType', 'coder');
  });

  it('should throw MCPClientError for unknown tool', async () => {
    await expect(
      callMCPTool('unknown/tool', {})
    ).rejects.toThrow(MCPClientError);
  });

  it('should check if tool exists', () => {
    expect(hasTool('agent/spawn')).toBe(true);
    expect(hasTool('unknown/tool')).toBe(false);
  });
});

Integration Testing CLI Commands

import { execute } from '../cli.js';

describe('Agent spawn command', () => {
  it('should spawn agent via MCP tool', async () => {
    const result = await execute(['agent', 'spawn', '--type', 'coder']);

    expect(result.success).toBe(true);
    expect(result.data).toHaveProperty('agentId');
  });
});

Best Practices

1. Type Safety

Always provide type parameters to callMCPTool:

// ✅ Good: Type-safe
const result = await callMCPTool<{ agentId: string }>('agent/spawn', { ... });
console.log(result.agentId); // TypeScript knows this exists

// ❌ Bad: No type safety
const result = await callMCPTool('agent/spawn', { ... });
console.log(result.agentId); // No type checking

2. Error Handling

Always handle MCPClientError:

// ✅ Good: Specific error handling
try {
  const result = await callMCPTool(...);
} catch (error) {
  if (error instanceof MCPClientError) {
    output.printError(`Tool failed: ${error.message}`);
  } else {
    output.printError(`Unexpected error: ${String(error)}`);
  }
  return { success: false, exitCode: 1 };
}

// ❌ Bad: Generic error handling
try {
  const result = await callMCPTool(...);
} catch (error) {
  console.error(error); // User sees raw error
}

3. Input Validation

Validate inputs before calling tools:

// ✅ Good: Validate first
if (!agentId) {
  output.printError('Agent ID is required');
  return { success: false, exitCode: 1 };
}

const result = await callMCPTool('agent/status', { agentId });

// ❌ Bad: Let tool fail
const result = await callMCPTool('agent/status', { agentId }); // Might be undefined

4. Output Formatting

Keep display logic in CLI, not in tool results:

// ✅ Good: CLI formats output
const result = await callMCPTool('agent/list', { ... });
const displayData = result.agents.map(agent => ({
  id: agent.id,
  type: agent.agentType,
  created: new Date(agent.createdAt).toLocaleString() // Format in CLI
}));
output.printTable({ data: displayData });

// ❌ Bad: Expect pre-formatted data from tool
const result = await callMCPTool('agent/list', { ... });
output.printTable({ data: result.formattedAgents }); // Tool shouldn't format

5. Progressive Enhancement

Use feature detection for optional capabilities:

// Check if tool supports feature
const metadata = getToolMetadata('agent/status');
const supportsMetrics = metadata?.inputSchema.properties?.includeMetrics;

const result = await callMCPTool('agent/status', {
  agentId,
  includeMetrics: supportsMetrics ? true : undefined
});

Troubleshooting

Tool Not Found

Problem: MCPClientError: MCP tool not found: xyz/abc

Solutions:

  1. Check tool name spelling
  2. Verify tool is registered in mcp-client.ts
  3. Import tool from correct tools file

Type Errors

Problem: TypeScript errors when calling callMCPTool

Solutions:

  1. Provide correct type parameter: callMCPTool<ResultType>(...)
  2. Match input schema from tool definition
  3. Check tool's TypeScript interfaces

Validation Errors

Problem: Tool execution fails with validation error

Solutions:

  1. Use validateToolInput() before calling
  2. Check tool's input schema requirements
  3. Provide all required parameters

Contributing

When adding new CLI commands:

  1. Import callMCPTool and MCPClientError
  2. Follow the standard CLI command pattern
  3. Keep business logic in MCP tools
  4. Add error handling for MCPClientError
  5. Format output in CLI, not in tool
  6. Add TypeScript types for tool results
  7. Update this guide with new examples

Summary

The MCP Client provides a clean, type-safe way for CLI commands to call MCP tools while maintaining proper separation of concerns:

  • CLI: User interaction & display
  • MCP Client: Tool routing & error handling
  • MCP Tools: Business logic & data management

This architecture ensures maintainability, testability, and consistency across all interfaces to the claude-flow system.