Skip to main content
MCP connections in PraisonAI Agents support context managers and explicit shutdown() so subprocesses, streams, and sockets close reliably.
MCP(...) accepts three equivalent construction forms — see Three equivalent forms.
The user runs an agent inside an MCP context manager; connections shut down cleanly when the session ends.

Quick Start

1

Simple Usage

2

With Configuration

How It Works

Agent-Managed Cleanup

When you pass an MCP client through the constructor (tools=[MCP(...)]), agent.close() and agent.aclose() now walk the agent’s tools and shut down anything exposing .shutdown() / .aclose() — so the MCP subprocess and its background thread are cleaned up with the agent.
Constructor-pattern MCP clients (tools=[MCP(...)]) are now auto-shut-down by agent.close() / agent.aclose() — you don’t need remove_mcp_server() any more just for cleanup. aclose() prefers a tool’s aclose() and falls back to shutdown().

Manual Cleanup

For cases where a context manager is not suitable:

Request Cancellation

An MCP client can abort an in-flight request by sending a notifications/cancelled notification naming the requestId it wants to stop.
1

Send the request

The client calls a tool with a JSON-RPC id it can reference later.
2

Cancel it

The client sends a cancellation notification with the same id as requestId.
3

Receive the cancelled response

The server cancels the running task and replies with a JSON-RPC error.
Only id-bearing requests can be cancelled. Fire-and-forget notifications have no id to reference and return nothing.

Lifecycle Methods

Authenticating the HTTP transport

When api_key is configured on the MCP HTTP-stream server, all of GET, POST, and DELETE require:
Comparison uses constant-time hmac.compare_digest (timing-attack resistant). Missing or wrong tokens return 401 Unauthorized with {"error": "Unauthorized"}. DELETE returning 401 instead of 405 prevents information disclosure about whether sessions exist.

__enter__ / __exit__

Context manager protocol for automatic resource management:

shutdown()

Explicitly close all connections and cleanup resources:
shutdown() dispatches to the right teardown call per transport. HTTP-stream and WebSocket clients expose close() (not shutdown()), so shutdown() falls back to close() for them — previously these two transports leaked on shutdown.
Since PraisonAI #4423, a failed construction (handshake timeout or init error) invokes an internal MCPToolRunner.stop() — a best-effort teardown that joins the background thread so a failed handshake does not leak a stdio subprocess. It runs automatically inside MCP.__init__; it is not a public API. Public shutdown stays mcp.shutdown() or the context-manager form. See MCP → Errors on construction.

__del__

Destructor ensures cleanup even if shutdown() was not called:

Connection Types

MCP supports multiple connection types, all with proper cleanup:
All four transports now close uniformly on shutdown(). HTTP-stream and WebSocket close via the close() fallback inside MCP.shutdown() — previously these two leaked subprocesses/threads on shutdown, while stdio and SSE cleaned up correctly.

Best Practices

Prefer with MCP(...) as mcp: — cleanup runs even when an exception is raised.
Wrap tool calls in try/except inside the with block; __exit__ still closes the connection.
Open each MCP in its own with block or nest them — both instances shut down in reverse order.
Use the env= parameter with os.getenv(...) rather than hard-coding API keys in recipe files.

MCP CLI

Run and inspect MCP servers from the terminal

MCP Transports

Stdio, SSE, HTTP stream, and WebSocket options

Agent Lifecycle Cleanup

How agent.close() shuts down MCP tools and breakers