Skip to content

MCP Client

ipybox supports the invocation of MCP servers in containers via generated MCP client code. An application first calls generate_mcp_sources to generate a Python function for each tool provided by an MCP server, using the tool's input schema. This needs to be done only once per MCP server. Generated functions are then available on the container's Python path.

Generated function

The example below generates a fetch function from the input schema of the fetch tool provided by the Fetch MCP server.

from ipybox import ExecutionClient, ExecutionContainer, ResourceClient

server_params = {  # (1)!
    "command": "uvx",
    "args": ["mcp-server-fetch"],
}

async with ExecutionContainer(tag="ghcr.io/gradion-ai/ipybox") as container:
    async with ResourceClient(port=container.resource_port) as client:
        tool_names = await client.generate_mcp_sources(  # (2)!
            relpath="mcpgen",
            server_name="fetchurl",
            server_params=server_params,
        )
        assert tool_names == ["fetch"]  # (3)!

    async with ExecutionClient(port=container.executor_port) as client:
        result = await client.execute("""
            from mcpgen.fetchurl.fetch import Params, fetch
            print(fetch(Params(url="https://www.gradion.ai"))[:375])
        """)  # (4)!
        print(result.text)  # (5)!
  1. Configuration of the Fetch MCP server.
  2. Generate MCP client code from an MCP server config. One MCP client function is generated per MCP tool.
  3. List of tool names provided by the MCP server. A single fetch tool in this example.
  4. Execute code that imports and calls the generated MCP client function.
  5. Prints
    ```
                             ___                    _
       ____ __________ _____/ (_)___  ____   ____ _(_)
      / __ `/ ___/ __ `/ __  / / __ \/ __ \ / __ `/ /
     / /_/ / /  / /_/ / /_/ / / /_/ / / / // /_/ / /
     \__, /_/   \__,_/\__,_/_/\____/_/ /_(_)__,_/_/
    /____/
    ```
    

Calling a generated MCP client function, executes the corresponding MCP tool. Tools of stdio based MCP servers are always executed inside the container, while streamable-http or legacy sse based MCP servers are expected to run elsewhere. Generated MCP client code can be downloaded from the container with get_mcp_sources (not shown).

Application example

freeact agents use the ipybox MCP integration for calling MCP tools in their code actions.

Remote MCP servers

In addition to stdio based MCP servers that run inside the container, ipybox also supports connecting to remote MCP servers running with streamable-http or legacy sse transports. This is demonstrated below with an example MCP server that is part of the project. Start the server in a separate terminal on the host machine:

python tests/mcp_server.py --transport streamable-http --port 8000

Then connect to it from your Python script:

from ipybox import ExecutionClient, ExecutionContainer, ResourceClient


server_params = {  # (1)!
    "type": "streamable_http",
    "url": "http://[YOUR-HOST-IP-ADDRESS]:8000/mcp",
}

async with ExecutionContainer(tag="ghcr.io/gradion-ai/ipybox") as container:
    async with ResourceClient(port=container.resource_port) as client:
        tool_names = await client.generate_mcp_sources(  # (2)!
            relpath="mcpgen",
            server_name="test_server",
            server_params=server_params,
        )
        assert tool_names == ["tool_1", "tool_2"]  # (3)!

    async with ExecutionClient(port=container.executor_port) as client:
        result = await client.execute("""
            from mcpgen.test_server.tool_1 import Params, tool_1
            response = tool_1(Params(s="Hello from ipybox!"))
            print(response)
        """)  # (4)!
        print(result.text)  # (5)!
  1. Configuration of the test MCP server running on the host machine. Replace [YOUR-HOST-IP-ADDRESS] with your host machine's IP address.
  2. Generate MCP client code from an MCP server config. One MCP client function is generated per MCP tool.
  3. List of tool names provided by the test server: tool_1 and tool_2
  4. Execute code that imports and calls the generated tool_1 function
  5. Prints: You passed to tool 1: Hello from ipybox!