Skip to main content
Glama

mcp_client

Test and interact with MCP servers by connecting via HTTP or stdio transport, listing available tools, and calling tools from within a Strands Agent.

Instructions

Test and interact with MCP servers.

This tool provides a complete MCP client implementation for testing and using MCP servers from within a Strands Agent.

Returns: Result dictionary with status and content

Examples: # Connect to HTTP server mcp_client( action="connect", connection_id="my-server", transport="http", server_url="http://localhost:8000/mcp" )

# Connect to stdio server
mcp_client(
    action="connect",
    connection_id="stdio-server",
    transport="stdio",
    command="python",
    args=["mcp_server_stdio.py"]
)

# List tools from connection
mcp_client(action="list_tools", connection_id="my-server")

# Call a tool
mcp_client(
    action="call_tool",
    connection_id="my-server",
    tool_name="calculator",
    tool_args={"expression": "2 + 2"}
)

# List all connections
mcp_client(action="list_connections")

# Disconnect
mcp_client(action="disconnect", connection_id="my-server")

Notes: - stdio transport: Server must be launchable as subprocess - HTTP transport: Server must be already running - Connections are maintained in global state for reuse

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
actionYesAction to perform - "connect", "disconnect", "list_tools", "call_tool", "list_connections"
connection_idNoUnique identifier for this connection
transportNoTransport type - "http", "stdio", or "sse"
server_urlNoURL for HTTP/SSE transport (e.g., "http://localhost:8000/mcp")
commandNoCommand for stdio transport (e.g., "python")
argsNoArguments for stdio command (e.g., ["mcp_server_stdio.py"])
tool_nameNoName of tool to call (for call_tool action)
tool_argsNoArguments to pass to tool (for call_tool action)

Implementation Reference

  • The primary handler function for the 'mcp_client' tool, decorated with @tool. It dispatches based on the 'action' parameter to connect/disconnect/list/call tools on remote MCP servers.
    @tool
    def mcp_client(
        action: str,
        connection_id: Optional[str] = None,
        transport: Optional[str] = None,
        server_url: Optional[str] = None,
        command: Optional[str] = None,
        args: Optional[list[str]] = None,
        tool_name: Optional[str] = None,
        tool_args: Optional[dict[str, Any]] = None,
    ) -> dict[str, Any]:
        """Test and interact with MCP servers.
    
        This tool provides a complete MCP client implementation for testing and using
        MCP servers from within a Strands Agent.
    
        Args:
            action: Action to perform - "connect", "disconnect", "list_tools", "call_tool", "list_connections"
            connection_id: Unique identifier for this connection
            transport: Transport type - "http", "stdio", or "sse"
            server_url: URL for HTTP/SSE transport (e.g., "http://localhost:8000/mcp")
            command: Command for stdio transport (e.g., "python")
            args: Arguments for stdio command (e.g., ["mcp_server_stdio.py"])
            tool_name: Name of tool to call (for call_tool action)
            tool_args: Arguments to pass to tool (for call_tool action)
    
        Returns:
            Result dictionary with status and content
    
        Examples:
            # Connect to HTTP server
            mcp_client(
                action="connect",
                connection_id="my-server",
                transport="http",
                server_url="http://localhost:8000/mcp"
            )
    
            # Connect to stdio server
            mcp_client(
                action="connect",
                connection_id="stdio-server",
                transport="stdio",
                command="python",
                args=["mcp_server_stdio.py"]
            )
    
            # List tools from connection
            mcp_client(action="list_tools", connection_id="my-server")
    
            # Call a tool
            mcp_client(
                action="call_tool",
                connection_id="my-server",
                tool_name="calculator",
                tool_args={"expression": "2 + 2"}
            )
    
            # List all connections
            mcp_client(action="list_connections")
    
            # Disconnect
            mcp_client(action="disconnect", connection_id="my-server")
    
        Notes:
            - stdio transport: Server must be launchable as subprocess
            - HTTP transport: Server must be already running
            - Connections are maintained in global state for reuse
        """
        if action == "connect":
            return _connect(connection_id, transport, server_url, command, args)
        elif action == "disconnect":
            return _disconnect(connection_id)
        elif action == "list_tools":
            return _list_tools(connection_id)
        elif action == "call_tool":
            return _call_tool(connection_id, tool_name, tool_args)
        elif action == "list_connections":
            return _list_connections()
        else:
            return {
                "status": "error",
                "content": [
                    {
                        "text": f"❌ Unknown action: {action}\n\n"
                        "Available actions: connect, disconnect, list_tools, call_tool, list_connections"
                    }
                ],
            }
  • Core helper implementing connection establishment for different transports, session testing, and global state management.
    def _connect(
        connection_id: Optional[str],
        transport: Optional[str],
        server_url: Optional[str],
        command: Optional[str],
        args: Optional[list[str]],
    ) -> dict[str, Any]:
        """Connect to an MCP server.
    
        This function establishes a connection to an MCP server using the specified
        transport type. The connection is stored in global state for reuse.
    
        Follows patterns from:
        - Strands MCPClient: sdk-python/src/strands/tools/mcp/mcp_client.py
        - MCP client transports: python-sdk/src/mcp/client/
        """
        try:
            if not connection_id:
                return {
                    "status": "error",
                    "content": [{"text": "❌ connection_id is required"}],
                }
    
            if not transport:
                return {
                    "status": "error",
                    "content": [{"text": "❌ transport is required (http, stdio, or sse)"}],
                }
    
            if connection_id in _client_connections:
                return {
                    "status": "error",
                    "content": [{"text": f"❌ Connection '{connection_id}' already exists"}],
                }
    
            # Import MCP client components
            from mcp.client.session import ClientSession
            from mcp.client.stdio import StdioServerParameters, stdio_client
            from mcp.client.streamable_http import streamablehttp_client
    
            if transport == "http":
                if not server_url:
                    return {
                        "status": "error",
                        "content": [{"text": "❌ server_url is required for HTTP transport"}],
                    }
    
                logger.debug(f"Connecting to HTTP server: {server_url}")
    
                # Create transport callable following Strands MCPClient pattern
                def transport_callable():
                    return streamablehttp_client(server_url)
    
                connection_info = {
                    "transport": "http",
                    "server_url": server_url,
                    "transport_callable": transport_callable,
                    "session": None,  # Will be initialized on first use
                }
    
            elif transport == "stdio":
                if not command:
                    return {
                        "status": "error",
                        "content": [{"text": "❌ command is required for stdio transport"}],
                    }
    
                logger.debug(f"Connecting to stdio server: {command} {args or []}")
    
                # Create stdio server parameters
                server_params = StdioServerParameters(command=command, args=args or [], env=None)
    
                # Create transport callable
                def transport_callable():
                    return stdio_client(server_params)
    
                connection_info = {
                    "transport": "stdio",
                    "command": command,
                    "args": args,
                    "transport_callable": transport_callable,
                    "session": None,
                }
    
            elif transport == "sse":
                if not server_url:
                    return {
                        "status": "error",
                        "content": [{"text": "❌ server_url is required for SSE transport"}],
                    }
    
                logger.debug(f"Connecting to SSE server: {server_url}")
    
                from mcp.client.sse import sse_client
    
                def transport_callable():
                    return sse_client(server_url)
    
                connection_info = {
                    "transport": "sse",
                    "server_url": server_url,
                    "transport_callable": transport_callable,
                    "session": None,
                }
    
            else:
                return {
                    "status": "error",
                    "content": [{"text": f"❌ Unknown transport: {transport}\n\nSupported: http, stdio, sse"}],
                }
    
            # Test the connection by listing tools
            logger.debug(f"Testing connection by listing tools...")
            tools = []
            try:
                # Create a temporary session to test and get tool count
                import asyncio
    
                async def test_connection():
                    async with connection_info["transport_callable"]() as (
                        read_stream,
                        write_stream,
                        get_session_id,  # StreamableHTTP returns 3 values
                    ):
                        async with ClientSession(read_stream, write_stream) as session:
                            await session.initialize()
                            result = await session.list_tools()
                            return result.tools
    
                tools = asyncio.run(test_connection())
                logger.debug(f"Successfully connected, found {len(tools)} tools")
    
            except Exception as e:
                logger.exception("Failed to connect to MCP server")
                return {
                    "status": "error",
                    "content": [{"text": f"❌ Failed to connect: {str(e)}"}],
                }
    
            # Store connection
            _client_connections[connection_id] = connection_info
    
            # Build response
            tool_list = "\n".join(f"  • {tool.name}" for tool in tools[:10])
            if len(tools) > 10:
                tool_list += f"\n  ... and {len(tools) - 10} more"
    
            transport_info = (
                f"URL: {server_url}" if transport in ["http", "sse"] else f"Command: {command} {' '.join(args or [])}"
            )
    
            message = (
                f"✅ Connected to MCP server '{connection_id}'\n\n"
                f"📊 Transport: {transport}\n"
                f"🔗 {transport_info}\n"
                f"🔧 Available tools ({len(tools)}):\n"
                f"{tool_list}"
            )
    
            return {"status": "success", "content": [{"text": message}]}
    
        except Exception as e:
            logger.exception("Error in connect action")
            return {
                "status": "error",
                "content": [{"text": f"❌ Error: {str(e)}"}],
            }
  • Helper to list available tools from a connected MCP server, including descriptions and input schemas.
    def _list_tools(connection_id: Optional[str]) -> dict[str, Any]:
        """List tools from a connected MCP server.
    
        This creates a temporary session to query the server for its available tools.
        """
        try:
            if not connection_id:
                return {
                    "status": "error",
                    "content": [{"text": "❌ connection_id is required"}],
                }
    
            if connection_id not in _client_connections:
                return {
                    "status": "error",
                    "content": [{"text": f"❌ Connection '{connection_id}' not found"}],
                }
    
            connection_info = _client_connections[connection_id]
            logger.debug(f"Listing tools from '{connection_id}'")
    
            # Create session and list tools
            import asyncio
    
            from mcp.client.session import ClientSession
    
            async def list_tools_async():
                async with connection_info["transport_callable"]() as (
                    read_stream,
                    write_stream,
                    get_session_id,  # StreamableHTTP returns 3 values
                ):
                    async with ClientSession(read_stream, write_stream) as session:
                        await session.initialize()
                        result = await session.list_tools()
                        return result.tools
    
            tools = asyncio.run(list_tools_async())
            logger.debug(f"Found {len(tools)} tools")
    
            # Build detailed tool list
            tool_details = []
            for tool in tools:
                details = f"**{tool.name}**"
                if tool.description:
                    details += f"\n  Description: {tool.description}"
                if tool.inputSchema:
                    # Show required parameters
                    schema = tool.inputSchema
                    if "required" in schema:
                        details += f"\n  Required: {', '.join(schema['required'])}"
                    if "properties" in schema:
                        details += f"\n  Parameters: {', '.join(schema['properties'].keys())}"
                tool_details.append(details)
    
            tools_text = "\n\n".join(tool_details)
    
            message = f"📋 **Tools from '{connection_id}'**\n\n" f"Found {len(tools)} tools:\n\n" f"{tools_text}"
    
            return {"status": "success", "content": [{"text": message}]}
    
        except Exception as e:
            logger.exception("Error listing tools")
            return {
                "status": "error",
                "content": [{"text": f"❌ Error: {str(e)}"}],
            }
  • Helper to execute remote tools on connected MCP servers via ClientSession.call_tool().
    def _call_tool(
        connection_id: Optional[str],
        tool_name: Optional[str],
        tool_args: Optional[dict[str, Any]],
    ) -> dict[str, Any]:
        """Call a tool on a connected MCP server.
    
        This establishes a session, calls the specified tool with provided arguments,
        and returns the result.
        """
        try:
            if not connection_id:
                return {
                    "status": "error",
                    "content": [{"text": "❌ connection_id is required"}],
                }
    
            if not tool_name:
                return {
                    "status": "error",
                    "content": [{"text": "❌ tool_name is required"}],
                }
    
            if connection_id not in _client_connections:
                return {
                    "status": "error",
                    "content": [{"text": f"❌ Connection '{connection_id}' not found"}],
                }
    
            connection_info = _client_connections[connection_id]
            logger.debug(f"Calling tool '{tool_name}' on '{connection_id}' with args: {tool_args}")
    
            # Call the tool
            import asyncio
    
            from mcp.client.session import ClientSession
    
            async def call_tool_async():
                async with connection_info["transport_callable"]() as (
                    read_stream,
                    write_stream,
                    get_session_id,
                ):
                    async with ClientSession(read_stream, write_stream) as session:
                        await session.initialize()
                        result = await session.call_tool(tool_name, tool_args or {})
                        return result
    
            result = asyncio.run(call_tool_async())
            logger.debug(f"Tool call complete, got {len(result.content)} content items")
    
            # Extract result content
            result_text = []
            for content in result.content:
                if hasattr(content, "text"):
                    result_text.append(content.text)
                else:
                    result_text.append(str(content))
    
            combined_result = "\n".join(result_text)
    
            message = f"✅ **Tool '{tool_name}' executed on '{connection_id}'**\n\n" f"Result:\n{combined_result}"
    
            return {"status": "success", "content": [{"text": message}]}
    
        except Exception as e:
            logger.exception(f"Error calling tool '{tool_name}'")
            return {
                "status": "error",
                "content": [{"text": f"❌ Error: {str(e)}"}],
            }
  • Package-level registration: imports mcp_client and adds to __all__, making it directly importable as 'from strands_mcp_server import mcp_client' for use in Agents.
    from strands_mcp_server.mcp_client import mcp_client
    from strands_mcp_server.mcp_server import mcp_server
    
    __version__ = "0.1.3"
    __all__ = ["mcp_server", "mcp_client"]
Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/cagataycali/strands-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server