***

title: MCPClient
slug: /reference/python/agents/mcp-gateway/mcp-client
description: Manage a single MCP server subprocess with JSON-RPC communication.
max-toc-depth: 3
---------------------

For a complete index of all SignalWire documentation pages, fetch https://signalwire.com/docs/llms.txt

[mcpmanager-create-client]: /docs/server-sdks/reference/python/agents/mcp-gateway/mcp-manager/create-client

[mcpservice]: /docs/server-sdks/reference/python/agents/mcp-gateway/mcp-manager

MCPClient manages a single MCP server subprocess. It handles starting the process,
initializing the MCP session via JSON-RPC, calling tools, and stopping the process
with cleanup.

<Warning>
  MCPClient instances are created internally by
  [`MCPManager.create_client()`][mcpmanager-create-client].
  You should not instantiate them directly in most cases.
</Warning>

```python
from signalwire.mcp_gateway import MCPClient
```

## **Properties**

<ParamField path="process" type="subprocess.Popen" toc={true}>
  The underlying subprocess object. `None` before `start()` is called.
</ParamField>

<ParamField path="tools" type="list[dict[str, Any]]" toc={true}>
  List of tool definitions retrieved from the MCP server after initialization.
</ParamField>

***

## **start**

**start**() -> `bool`

Spawn the MCP server process, initialize the MCP session, and retrieve the list
of available tools. Returns `True` on success, `False` if initialization fails.
The process runs in a sandboxed environment according to the service's
`sandbox_config`.

### Returns

`bool` -- `True` if the process started and initialized successfully.

***

## **stop**

**stop**() -> `None`

Stop the MCP server process. Attempts a graceful JSON-RPC shutdown first, then
falls back to `SIGTERM`, and finally `SIGKILL` if needed. Cleans up the sandbox
directory after the process stops.

***

## **call\_tool**

**call\_tool**(`tool_name`, `arguments`) -> `dict[str, Any]`

Call a tool on the MCP server and return the result.

### Parameters

<ParamField path="tool_name" type="str" required={true} toc={true}>
  Name of the tool to invoke.
</ParamField>

<ParamField path="arguments" type="dict[str, Any]" required={true} toc={true}>
  Arguments to pass to the tool.
</ParamField>

### Returns

`dict[str, Any]` -- The tool result from the MCP server.

***

## **call\_method**

**call\_method**(`method`, `params`) -> `Any`

Send a JSON-RPC request to the MCP server and wait for the response. Raises
`TimeoutError` after 30 seconds if no response is received. Raises
`RuntimeError` if the client is shutting down.

### Parameters

<ParamField path="method" type="str" required={true} toc={true}>
  The JSON-RPC method name (e.g., `"tools/call"`, `"tools/list"`).
</ParamField>

<ParamField path="params" type="dict[str, Any]" required={true} toc={true}>
  Parameters for the JSON-RPC request.
</ParamField>

### Returns

`Any` -- The `result` field from the JSON-RPC response.

***

## **get\_tools**

**get\_tools**() -> `list[dict[str, Any]]`

Return a copy of the tool definitions retrieved during initialization.

### Returns

`list[dict[str, Any]]`

***

## **Example**

```python
from signalwire.mcp_gateway import MCPManager

config = {
    "services": {
        "todo": {"command": ["python3", "todo_mcp.py"], "description": "Todo list", "enabled": True}
    }
}

manager = MCPManager(config)
client = manager.create_client("todo")
tools = client.get_tools()
print(f"Tools: {[t['name'] for t in tools]}")
result = client.call_tool("add_todo", {"text": "Buy groceries"})
print(result)
client.stop()
manager.shutdown()
```