Skip to main content
Publish one or more agents to any MCP client as ask_{name} tools with a single serve_agents([...]) call.
Same thing via launch(). Agent.launch(protocol="mcp") and PraisonAIAgents.launch(protocol="mcp") both delegate to serve_agents(...), so the tools, endpoint, and session model are identical:
Pick whichever idiom fits your code — see Agents MCP.

Quick Start

1

Install

pip install praisonai-mcp alone is enough for the default http-stream transport. Add praisonai-mcp[all] only if you need extra transports.
2

Serve One Agent

Pass a single agent — serve_agents wraps it in a list for you.
3

Serve Multiple Agents

Pass a list to publish every agent on one endpoint.
4

Serve Over stdio

Use stdio when the MCP client launches your process locally (Claude Desktop).

How It Works

Each ask_* call loads that session’s transcript, runs one turn on an isolated copy of your agent, appends the turn, and returns the reply. Pick a transport based on where the client runs.

Configuration Options

Under transport="stdio", host and port are ignored — the client owns the process over stdin/stdout. Any value other than "http-stream" or "stdio" raises ValueError.
serve_agents(...) returns the underlying MCPServer instance, which is handy for tests and orchestration.

Published Tools

serve_agents([...]) registers one ask_{agent_name} tool per agent plus a single list_agents() discovery tool.

ask_

Input schema:
Return value:

list_agents

Returns the agents available on the endpoint:
The description falls back through agent.role → the first line of agent.instructions"Ask the {name} agent.".

Session Model

Sessions are opaque, isolated, and server-owned — the client controls continuity by echoing back the session_id, nothing more.
  • session_id is opaque and client-supplied. When present, the adapter loads that session’s transcript, applies it to an isolated per-call agent copy, runs one turn, and appends the user + assistant turns.
  • Omitting session_id mints a fresh id per call. It never falls back to a shared sticky session, so history never leaks across clients. Verified by test_omitted_session_mints_fresh_id_and_no_shared_history.
  • Transcripts are namespaced per tool. The internal store key is f"{tool_name}:{session_id}", so reusing one session_id across ask_support and ask_billing does not mix their histories. Verified by test_same_session_id_across_agents_does_not_leak_history.
  • Per-session serialization. Each session holds a threading.Lock, so overlapping calls to the same session can’t clobber each other’s saved turn. Different sessions never contend.
  • Per-turn agent isolation. Each turn runs on a shallow copy.copy(agent) with the session’s history swapped in; the original Agent is never mutated by concurrent sessions.
  • Server-owned persona. There is no tool parameter that lets the client set instructions or persona. Verified by test_no_client_instructions_parameter.
  • AgentOS /chat now uses the same per-request clone model as serve_agents, but drops back to the shared template when the agent has handoffs. See AgentOS Chat Session Isolation.
Omit session_id to start a fresh session — do not pass an empty string. Every call without the field gets a brand-new minted id.
Client-side continuity pattern — store the returned session_id and send it back on the next turn:

Naming and Disambiguation

Agent names become tool suffixes deterministically. Collisions get a numeric suffix. Verified by test_normalized_name_collision_registers_distinct_tools and test_unnamed_agents_do_not_collide.

What Clients See

With support and billing served, list_agents() returns:
and the tool list contains ask_support, ask_billing, and list_agents. Call an agent over the http-stream endpoint:

Client Integration

serve_agents_app.py:

Best Practices

Use serve_agents([...]) for your product agents. The praisonai.agent.chat tool is a generic, server-owned assistant proxy that intentionally cannot be repersonalised by the client.
The name becomes the ask_{name} tool suffix the client sees. Unnamed agents collapse to ask_agent, ask_agent_2, and so on.
Keep the returned session_id on the client side and pass it back on every follow-up turn for the same conversation. Omitting it always starts a fresh session — that is by design.
Prefer transport='http-stream' for shared deployments. Use transport='stdio' only when the MCP client launches your process (Claude Desktop).

Agents MCP

launch(protocol='mcp') — the same code path, delegating here

PraisonAI MCP

Umbrella praisonai mcp serve

MCP

Connect agents to MCP servers (client side)

praisonai-mcp Package

Standalone host package guide

MCP Memory Tools

Expose memory over MCP alongside your agents