Files
cleveragents-core/docs/api/mcp.md
T
freemo b4ee51c5ad docs: update CHANGELOG, MCP API, plan CLI, and CI/CD docs for recent merged PRs
Document changes from PRs merged 2026-04-03 through 2026-04-05:
- CHANGELOG: add entries for CI artifact capture (#2782), ASV provider
  benchmarks (#3022), CI quality gate restoration (#2629), plan list
  --namespace option (#2616), and MCP 1.4.0 error extraction fix (#2600)
- docs/api/mcp.md: document MCP 1.4.0 error extraction from content[0].text
  in MCPToolAdapter.invoke() with protocol note and usage example
- docs/reference/plan_cli.md: add --namespace/-n option to agents plan list
  options table, update Filters panel description, add usage examples
- docs/development/ci-cd.md: document CI artifact capture for all 8 nox jobs,
  artifact naming convention, retention policy, and agent integration
2026-04-05 06:36:23 +00:00

4.7 KiB

cleveragents.mcp — Model Context Protocol

The mcp package bridges external MCP servers into the CleverAgents ToolRegistry. It handles server lifecycle (lazy start, auto-stop, health monitoring), tool discovery, invocation with JSON Schema validation, sandbox path rewriting, and skill refresh notifications.

See ADR-029 for design rationale.


MCPServerConfig

from cleveragents.mcp import MCPServerConfig

config = MCPServerConfig(
    name="my-server",
    transport="stdio",
    command="python",
    args=["-m", "my_mcp_server"],
    env={"API_KEY": "..."},
)
Field Type Description
name str Server identifier
transport str "stdio" | "sse" | "streamable-http"
command str | None Spawn command (stdio only)
args list[str] Command-line arguments
env dict[str, str] Environment variables
url str | None Server URL (sse/http only)
headers dict[str, str] HTTP headers (sse/http only)

MCPToolAdapter

The primary integration point. Manages the full lifecycle of an MCP server connection.

from cleveragents.mcp import MCPToolAdapter, MCPServerConfig
from cleveragents.tool import ToolRegistry

config = MCPServerConfig(name="bash-tools", transport="stdio",
                         command="uvx", args=["mcp-server-bash"])
adapter = MCPToolAdapter(config)

await adapter.connect()
tools = await adapter.discover_tools()

registry = ToolRegistry()
adapter.register_tools(registry)   # bulk-register with source="mcp"

result = await adapter.invoke("bash", {"command": "ls -la"})
await adapter.disconnect()

Methods

Method Description
connect() Start server process / open HTTP session
disconnect() Clean shutdown
discover_tools(filter) Enumerate tools from the server
invoke(name, arguments) Call a tool with input validation
register_tools(registry, namespace, filter) Discover and bulk-register tools with namespace prefix

Error Handling in invoke()

Protocol note (MCP 1.4.0+): When a server returns isError: true, the error message is embedded in content[0].text — not in a top-level error field. MCPToolAdapter.invoke() reads content[0].text and surfaces it in MCPToolResult.error. Prior to this fix (PR #2600), all server errors were silently replaced with "unknown error".

result = await adapter.invoke("bash", {"command": "invalid-cmd"})
if not result.success:
    print(result.error)   # e.g. "bash: invalid-cmd: command not found"

MCPToolDescriptor

class MCPToolDescriptor(BaseModel):
    name: str
    description: str
    input_schema: dict[str, Any]   # JSON Schema
    annotations: dict[str, Any]

Descriptor for a tool discovered from an MCP server.


MCPToolResult

class MCPToolResult(BaseModel):
    success: bool
    content: Any
    error: str | None = None

MCPCapabilityMetadata

class MCPCapabilityMetadata(BaseModel):
    tools: bool
    resources: bool
    prompts: bool
    raw_capabilities: dict[str, Any]

Full capability information returned during the MCP initialize handshake.


McpClient

Manages a single MCP server connection with lazy start and auto-stop.

from cleveragents.mcp import McpClient, McpClientConfig

client_config = McpClientConfig(server=server_config, auto_stop_idle_secs=60)
client = McpClient(client_config)

async with client:
    tools = await client.list_tools()

McpClientState

Enum: STOPPED, STARTING, RUNNING, STOPPING, ERROR.


McpRegistry

Namespace-isolated registry of McpClient instances. Prevents duplicate server registrations and provides lookup by server name.

from cleveragents.mcp import McpRegistry

reg = McpRegistry()
reg.register("my-server", client)
client = reg.get("my-server")

MCPRefreshHook

Wires MCP notifications/tools/list_changed events to SkillRegistry.refresh_all() so that skill registrations stay in sync when an MCP server's tool list changes at runtime.

from cleveragents.mcp import MCPRefreshHook

hook = MCPRefreshHook(skill_registry)
adapter.on_tools_changed(hook.on_tools_changed)

SandboxPathRewriter

Rewrites absolute host paths in MCP tool arguments and results to sandbox-relative paths, preventing path traversal outside the sandbox root.

from cleveragents.mcp import SandboxPathRewriter, SandboxPathRewriterConfig

rewriter = SandboxPathRewriter(
    SandboxPathRewriterConfig(sandbox_root="/sandbox", host_root="/home/user/project")
)
rewritten_args = rewriter.rewrite_args(tool_args)