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"]

Tool Description Quality Score

Score is being calculated. Check back soon.

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