agentlane/ docs
On this page

MCP

MCPToolsShim adds tools from Model Context Protocol (MCP) servers to an AgentLane agent. It supports Streamable HTTP and local stdio servers. Install the optional dependency:

uv add 'agentlane[mcp]'

Connect an agent

Attach the shim through AgentDescriptor.shims. Replace the server URL and use your configured AgentLane model:

from agentlane.harness import AgentDescriptor
from agentlane.harness.agents import DefaultAgent
from agentlane.harness.mcp import (
    MCPServer,
    MCPStreamableHTTPTransport,
    MCPToolsShim,
)

notes = MCPServer(
    name="notes",
    transport=MCPStreamableHTTPTransport(url="https://notes.example.com/mcp"),
)

agent = DefaultAgent(
    descriptor=AgentDescriptor(
        name="Notes assistant",
        model=model,
        shims=(MCPToolsShim(servers=(notes,)),),
    ),
)

result = await agent.run("Find the latest launch decision in the notes.")
print(result.final_output)

The shim opens and closes connections for each run. For a runnable local example, see the MCP meeting assistant.

HTTP servers require HTTPS. For development HTTP, set MCPStreamableHTTPTransport(..., allow_insecure_http=True). Supply credentials through an authorization provider, not the URL. Legacy SSE, MCP resources, and MCP prompts are not supported as model capabilities.

Use a local server

Replace the HTTP transport with MCPStdioTransport. Set the command, working directory, and environment for your server:

from agentlane.harness.mcp import MCPStdioTransport

notes = MCPServer(
    name="notes",
    transport=MCPStdioTransport(
        command="python",
        args=("-m", "my_notes_mcp"),
        cwd="/srv/my-product",
        env={"NOTES_DATABASE": "/data/notes.db"},
    ),
)

Stdio inherits only the MCP SDK’s allowed environment variables plus explicit env values. Pass the variables your server needs.

Select tools

The model sees names such as notes__list_meetings. Use these names in RESTRICT_TOOLS, OVERRIDE_TOOLS, and ExcludeToolsShim policies. Names are normalized; use simple, unique server names to avoid collisions.

To expose only selected tools, set MCPServer.tools. Filter patterns match the original names reported by the server:

from agentlane.harness.mcp import MCPToolFilter

notes = MCPServer(
    name="notes",
    transport=MCPStreamableHTTPTransport(url="https://notes.example.com/mcp"),
    tools=MCPToolFilter(include=("list_*", "get_*"), exclude=("*_transcript",)),
)

Place MCPToolsShim before SkillsShim when skill tool rules must cover MCP tools. For subagent and handoff policies, see shims.

Authorization

Your app handles OAuth consent, credential storage, refresh, and revocation. Implement MCPAuthorizationProvider with two async methods:

  • get_access_token(server, context) returns a valid MCPAccessToken with token and optional expires_at and scopes.
  • invalidate_access_token(server, context, token) invalidates a token that the server rejected.

Attach your provider to the HTTP server and pass the user’s identity:

from agentlane.harness.mcp import MCPAuthorizationContext

authorized_notes = MCPServer(
    name="notes",
    transport=MCPStreamableHTTPTransport(url="https://notes.example.com/mcp"),
    authorization=provider,
)

shim = MCPToolsShim(
    servers=(authorized_notes,),
    authorization_context=MCPAuthorizationContext(key=user_id, value=user_id),
)

Use a stable, non-secret context key for each authorized user or connection. Different keys keep connections and tool catalogs separate. The optional value passes application data to your provider.

The provider is called repeatedly; reuse valid tokens until refresh is needed. On HTTP 401, AgentLane invalidates the token and retries once with a token from the provider. AgentLane does not store refresh tokens.

Reuse connections

For multiple agents or runs, share one application-scoped MCPClientManager:

from agentlane.harness.mcp import MCPClientManager

async with MCPClientManager() as manager:
    shim = MCPToolsShim(servers=(notes,), client_manager=manager)
    # Attach this shim to agents and run them inside this context.

If your app manages shutdown explicitly, call await manager.aclose(). Finish active runs before closing the manager. For authorized servers, also pass the user’s authorization_context to each shim.

Set MCPClientManager(limits=MCPClientLimits(...)) to change the defaults: 64 connections, 300 seconds of idle time, and a 10-second shutdown timeout. Both classes are exported from agentlane.harness.mcp.

Configure limits

Set these options on MCPServer:

OptionDefaultUse
requiredTrueStop the run if discovery fails. Set False to continue without that server’s tools.
connect_timeout_seconds30Limit connection setup and the MCP handshake.
discovery_timeout_seconds30Limit tool discovery.
tool_timeout_seconds120Limit each tool call.
catalog_ttl_seconds300Limit how long the tool list can stay cached.

Timeouts and catalog TTL must be finite and greater than zero. Optional servers retry transient discovery failures on later turns. AgentLane does not automatically repeat a tool call after a transport failure or timeout.

To change output limits, set MCPServer.result_policy=MCPResultPolicy(...). The inline defaults are 32 content blocks and 51,200 characters. Servers repeat structured content in text blocks for clients that cannot read it. If a successful result has structured content, the model gets the structured content and the other content blocks, but not the text blocks. A failed result keeps its text blocks, because they contain the failure details. Set include_structured_content=False to omit structured results and keep all content blocks. Image, audio, and resource bodies are returned as metadata.

JSON text that exceeds parser limits or contains duplicate keys is omitted and marks the result as incomplete. This applies with and without storage; an incomplete result is not saved as a full result.

Store full results

Pass an existing FileWriter and a directory to MCPToolsShim. Give the native read tool the same filesystem:

shim = MCPToolsShim(
    servers=(notes,),
    result_writer=filesystem,
    result_directory="/workspace/tool-results",
)
reader = read_tool(reader=filesystem)
shims = (shim, HarnessToolsShim((reader,)))

Import HarnessToolsShim and read_tool from agentlane.harness.tools, and pass shims to AgentDescriptor. Use a directory that the filesystem can resolve. See File I/O interfaces for mounts and backends.

With storage enabled, AgentLane sanitizes the selected content once with its existing renderer. Saved content includes all supported text blocks and embedded resource text. include_structured_content controls structured content in both the saved file and the inline response. Image, audio, and blob bodies remain metadata.

max_text_chars and max_content_blocks limit the inline response. If the selected content fits both limits, the result returns inline. Otherwise, AgentLane saves one UUID-named .txt file. The file retains text beyond both inline limits. Inline responses keep the structured-content and resource metadata behavior described above.

A saved result returns a preview and [Full MCP result: "<path>"]. The model calls read(path="<path>", offset=1, limit=200) and follows the reader’s next offset. Text lines wrap at 4,096 characters so large strings remain readable. The file contains serialized MCP text with JSON escaping; line wrapping means it is not a stable JSON format. “Full” means the complete supported text representation selected by policy.

The response, including its path, stays within max_text_chars. Storage uses the existing write and cancellation handling. If a write fails, the preview reports [Full MCP result unavailable.]. The provider call is not repeated. The host owns write deadlines and file retention.

Configure both storage options together. With neither option set, the existing response and processing limits are unchanged.

MCPToolsShim checks that the resolved directory, UUID filename, and reference format fit each server’s max_text_chars, including JSON escaping. Direct calls to MCPClientLease.tools() check the supplied directory before tool discovery. If the reference cannot fit, configuration raises ValueError. Use a shorter directory or increase max_text_chars.

Storage preparation has separate processing limits: depth 32, 4,096 nodes, 8 Mi characters processed, and 8 Mi serialized characters. These internal limits bound renderer work. They are independent of the inline limits and application storage quotas. If a processing limit is reached, AgentLane writes no file and returns a bounded preview with [MCP processing limit exceeded; full result not saved.].

Troubleshooting

Use the symptom or error to choose the next step:

Symptom or errorAction
MCPDependencyErrorInstall agentlane[mcp] in the environment that runs the agent.
Connection or discovery failsCheck the endpoint or local command, server availability, and credentials. Use MCPDiscoveryError.failure_kind to distinguish authorization, transport, timeout, capacity, and protocol failures.
A tool is missingCheck the server’s tool list, MCPToolFilter, and agent tool policies. Filters use original names; agent policies use names such as notes__list_meetings.
ToolNameCollisionErrorGive servers distinct names and check for duplicate tool names after normalization.
HTTP 401 or 403Check token validity and required scopes. Ensure invalidation lets the provider return a fresh token.
A tool call times outCheck whether the server completed the operation before retrying. Increase tool_timeout_seconds only if the operation needs more time.
MCPPoolCapacityErrorReduce concurrent runs or increase MCPClientLimits.max_connections.
MCPShutdownTimeoutErrorCheck for a server that does not stop. Increase shutdown_timeout_seconds if needed; call aclose() again to wait for ongoing cleanup.
Results contain truncated or omittedBlocksConfigure result_writer and result_directory, request less data, or increase the relevant MCPResultPolicy limit. max_text_chars must be at least 128.

Tool execution failures return ToolFailure. Treat server results as untrusted input, and keep secrets out of tool arguments and results.