Become an Agentic Architect

Leveraging MCP in CrewAI

MCP (Model Context Protocol) lets your agents use external services (MCP servers) as if they were native tools, using a standard protocol. In CrewAI you can plug MCP in with a simple DSL on agents (recommended) or with an advanced adapter for complex setups.


1. Two Ways to Use MCP in CrewAI

CrewAI supports two main integration modes:

Simple DSL on agents (mcps=...)

  • Easiest path, no extra library wiring.
  • You declare MCP servers directly on the agent, CrewAI discovers tools automatically.

Advanced MCPServerAdapter (from crewai-tools)

  • Gives you manual control over starting/stopping servers and selecting tools.
  • Best for complex, multi-server or highly tuned production setups.

You attach MCP servers directly to an agent via the mcps field.

2.1 Quick start with string references

Use string URLs and AMP IDs when you just want to connect and go.

# python
from crewai import Agent, Task, Crew

research_agent = Agent(
    role="Research Analyst",
    goal="Find and analyze information using advanced search tools",
    backstory="Expert researcher with access to multiple data sources",
    mcps=[
        # External HTTPS MCP server (all tools)
        "https://mcp.exa.ai/mcp?api_key=your_key&profile=your_profile",

        # CrewAI AMP marketplace – full service or specific tool
        "crewai-amp:weather-service",                  # all tools from service
        "crewai-amp:weather-service#current_conditions",  # one specific tool
    ],
)

research_task = Task(
    description="Research the latest developments in AI agent frameworks",
    expected_output="Comprehensive research report with citations",
    agent=research_agent,
)

crew = Crew(agents=[research_agent], tasks=[research_task])
result = crew.kickoff()

Patterns you can use:

  • <https://server/mcp> → all tools from that MCP server.
  • <https://server/mcp#get_tool> → only one specific tool.
  • crewai-amp:service → all tools from an AMP service.
  • crewai-amp:service#tool_name → one tool from that service.

CrewAI automatically:

  • Connects to each server.
  • Lists available tools.
  • Exposes them to the agent’s tool-calling system.

2.2 Structured MCP configs on the agent

Use structured objects when you need control over transport, headers, environment, or filtering.

from crewai import Agent, Task, Crew
from crewai.mcp import MCPServerStdio, MCPServerHTTP, MCPServerSSE
from crewai.mcp.filters import create_static_tool_filter

research_agent = Agent(
    role="Advanced Research Analyst",
    goal="Research with full control over MCP connections",
    backstory="Expert researcher with advanced tool access",
    mcps=[
        # Local MCP server via stdio
        MCPServerStdio(
            command="python",
            args=["local_server.py"],
            env={"API_KEY": "your_key"},
            tool_filter=create_static_tool_filter(
                allowed_tool_names=["read_file", "list_directory"],
            ),
            cache_tools_list=True,
        ),

        # Remote HTTP MCP server
        MCPServerHTTP(
            url="https://api.research.com/mcp",
            headers={"Authorization": "Bearer your_token"},
            streamable=True,        # enable streaming responses
            cache_tools_list=True,
        ),

        # Remote SSE MCP server
        MCPServerSSE(
            url="https://stream.example.com/mcp/sse",
            headers={"Authorization": "Bearer your_token"},
            cache_tools_list=True,
        ),
    ],
)

research_task = Task(
    description="Research the latest developments in AI agent frameworks",
    expected_output="Comprehensive research report with citations",
    agent=research_agent,
)

crew = Crew(agents=[research_agent], tasks=[research_task])
result = crew.kickoff()

Key ideas to highlight:

  • Stdio – local processes (python, node, npx) talk over stdin/stdout.
  • HTTP / streamable HTTP – remote servers over HTTPS, optionally streaming.
  • SSE – remote, real‑time, server‑sent events (ideal for live data).
  • tool_filter – lets you whitelist or blacklist tools from a server.
  • cache_tools_list – avoids re‑fetching tool schemas every run.

3. MCP Reference Patterns and Tool Filtering

3.1 Mixed references

You can mix strings and structured configs in one mcps list:

from crewai.mcp import MCPServerStdio, MCPServerHTTP

mcps = [
    "https://external-api.com/mcp",       # external server (all tools)
    "crewai-amp:financial-insights",      # AMP service
    MCPServerStdio(
        command="npx",
        args=["-y", "@modelcontextprotocol/server-filesystem"],
    ),
    MCPServerHTTP(
        url="https://api.example.com/mcp",
        headers={"Authorization": "Bearer token"},
    ),
]

3.2 Static vs dynamic tool filters

Use static filters when you just want allow/block lists.

from crewai.mcp import MCPServerStdio
from crewai.mcp.filters import create_static_tool_filter

static_filter = create_static_tool_filter(
    allowed_tool_names=["read_file", "write_file"],
    blocked_tool_names=["delete_file"],
)

mcps = [
    MCPServerStdio(
        command="npx",
        args=["-y", "@modelcontextprotocol/server-filesystem"],
        tool_filter=static_filter,
    ),
]

Use dynamic filters when you want role‑aware behavior.

from crewai.mcp import MCPServerStdio
from crewai.mcp.filters import create_dynamic_tool_filter, ToolFilterContext

def dynamic_filter(context: ToolFilterContext, tool: dict) -> bool:
    # Example: code reviewers cannot use destructive tools
    if context.agent.role == "Code Reviewer":
        if "delete" in tool.get("name", "").lower():
            return False
    return True

mcps = [
    MCPServerStdio(
        command="npx",
        args=["-y", "@modelcontextprotocol/server-filesystem"],
        tool_filter=dynamic_filter,
    ),
]

4. Advanced Mode: MCPServerAdapter (crewai-tools)

When you need manual control (e.g., connect once, reuse tools across agents, inspect tools programmatically), use MCPServerAdapter from crewai-tools.

4.1 Basic adapter usage

from crewai import Agent
from crewai_tools import MCPServerAdapter
from mcp import StdioServerParameters

server_params = StdioServerParameters(
    command="python3",
    args=["servers/your_server.py"],
    env={"UV_PYTHON": "3.12", **os.environ},
)

with MCPServerAdapter(server_params, connect_timeout=60) as mcp_tools:
    print("Available tools:", [tool.name for tool in mcp_tools])

    my_agent = Agent(
        role="MCP Tool User",
        goal="Utilize tools from an MCP server.",
        backstory="I can connect to MCP servers and use their tools.",
        tools=mcp_tools,   # pass tools directly
        reasoning=True,
        verbose=True,
    )

    # ... create crew and tasks using my_agent ...

You can also:

  • Use SSE or streamable HTTP by passing appropriate server_params.
  • Filter tools by name:
# Only one tool
with MCPServerAdapter(server_params, connect_timeout=60) as mcp_tools:
    my_agent = Agent(
        ...,
        tools=[mcp_tools["tool_name"]],
    )

# Or list of tools via constructor
with MCPServerAdapter(server_params, "tool_1", "tool_2", connect_timeout=60) as mcp_tools:
    my_agent = Agent(
        ...,
        tools=mcp_tools,
    )

The context manager ensures connections are started and stopped cleanly.


5. Using MCP with CrewBase (YAML‑driven crews)

When you build crews with @CrewBase, you can declare MCP servers at the class level and fetch tools via get_mcp_tools().

from crewai import Agent
from crewai.flow import CrewBase, agent
from mcp import StdioServerParameters
import os

@CrewBase
class CrewWithMCP:
    # Multiple servers: HTTP, SSE, stdio, etc.
    mcp_server_params = [
        {
            "url": "http://localhost:8001/mcp",
            "transport": "streamable-http",
        },
        {
            "url": "http://localhost:8000/sse",
            "transport": "sse",
        },
        StdioServerParameters(
            command="python3",
            args=["servers/your_stdio_server.py"],
            env={"UV_PYTHON": "3.12", **os.environ},
        ),
    ]

    # Optional: crew-wide timeout (default 30s)
    mcp_connect_timeout = 60

    @agent
    def your_agent(self):
        return Agent(
            config=self.agents_config["your_agent"],
            tools=self.get_mcp_tools(),   # all available tools
        )

    @agent
    def filtered_agent(self):
        return Agent(
            config=self.agents_config["your_agent"],
            tools=self.get_mcp_tools("tool_1", "tool_2"),  # only some tools
        )

This pattern is ideal for configurable, production crews where MCP endpoints are part of your infra configuration.


6. Reliability, Performance, and Security

Key behaviors:

  • Automatic tool discovery – CrewAI lists tools from servers and namespaces them to avoid collisions.

  • On‑demand connections – servers are contacted when needed; schema can be cached.

  • Graceful failure – if a server is down or slow:

    • errors are logged as warnings,
    • working servers’ tools remain available,
    • default timeout ~30 seconds (configurable).

Security considerations (especially for SSE servers):

  • Validate Origin headers to avoid DNS rebinding.
  • Avoid binding local dev servers to 0.0.0.0; prefer 127.0.0.1.
  • Always require authentication (headers, env vars, or query params).

7. Teaching Angle: MCP as “USB‑C for Tools”

As “Agentic Architect” think about it this way:

  • Without MCP: each tool requires a bespoke Python wrapper.
  • With MCP: tools from many systems conform to one standard protocol; CrewAI just plugs them into agents.

Guidelines:

  1. Start with local tools (crewai tools / custom @tool).
  2. Add MCP via mcps=[...] to reach external services (search, weather, DBs).
  3. Introduce tool filtering & timeouts for governance.
  4. Finish with MCPServerAdapter + CrewBase for large, multi‑server architectures.