> ## Documentation Index
> Fetch the complete documentation index at: https://hub.hcompany.ai/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> H Platform has four products: the Agents API (managed computer-use agents, base URL https://agp.eu.hcompany.ai/api/v2 or https://agp.hcompany.ai/api/v2 for the US), the Models API (OpenAI-compatible Holo vision-language models at https://api.hcompany.ai/v1), HoloDesktop CLI (Holo on the user's own desktop), and HoloTab (a free no-code Chrome extension that runs Holo in the user's browser, with recordable routines and schedules).
> Authenticate with a bearer API key from the HAI_API_KEY environment variable. SDKs: `pip install hai-agents` (Python, `from hai_agents import Client`) and `npm install hai-agents` (TypeScript, `import { HaiAgentsClient } from "hai-agents"`). CLI: `hai`.
> Agents do work in a browser or on a desktop; describe the task as an imperative instruction. To run a task quickly, prefer the pre-built agent `h/web-surfer-flash`. Read results from the session's `latest_answer` after it reaches a terminal status.
> Sessions are the unit of work; wait for a terminal status (completed, failed, timed_out, interrupted) before reading the answer. Use webhooks or the `changes` long-poll endpoint to follow progress.

# MCP agent

> Connect Holo to any MCP server: list its tools, pass them as OpenAI functions, and route each tool call back through the MCP session.

This is the [browser agent](/models-api/cookbooks/browser-agent) loop with the screen swapped for an MCP server. MCP tools already carry JSON schemas, so one conversion function turns them into `tools`, and each call goes back through `session.call_tool`. This example uses the reference [fetch server](https://github.com/modelcontextprotocol/servers/tree/main/src/fetch), which reads web pages as Markdown. Any stdio server works the same way.

<Steps titleSize="h3">
  <Step title="Save the agent">
    Install with `pip install openai "mcp>=2"` and export `HAI_API_KEY`. The fetch server runs through `uvx`, which ships with [uv](https://docs.astral.sh/uv/).

    ```python mcp_agent.py expandable theme={"system"}
    import asyncio
    import json
    import os

    from mcp import ClientSession, StdioServerParameters
    from mcp.client.stdio import stdio_client
    from openai import AsyncOpenAI

    client = AsyncOpenAI(base_url="https://api.hcompany.ai/v1/", api_key=os.environ["HAI_API_KEY"])
    MODEL = "holo4-35b-a3b"


    def fn(name: str, description: str, parameters: dict) -> dict:
        return {"type": "function", "function": {"name": name, "description": description, "parameters": parameters}}


    ANSWER_TOOL = fn("answer", "Provide a final answer", {
        "type": "object",
        "properties": {"content": {"type": "string", "description": "The answer content"}},
        "required": ["content"],
    })


    async def run(task: str, max_steps: int = 10) -> str:
        server = StdioServerParameters(command="uvx", args=["mcp-server-fetch"])
        async with stdio_client(server) as (read, write), ClientSession(read, write) as session:
            await session.initialize()
            mcp_tools = (await session.list_tools()).tools
            tools = [fn(t.name, t.description or "", t.input_schema) for t in mcp_tools] + [ANSWER_TOOL]

            messages = [
                {"role": "system", "content": "You are a research agent. Use your tools to gather facts, then answer."},
                {"role": "user", "content": task},
            ]
            for _ in range(max_steps):
                resp = await client.chat.completions.create(
                    model=MODEL,
                    messages=messages,
                    tools=tools,
                    tool_choice="required",
                    temperature=0.8,
                    extra_body={"chat_template_kwargs": {"enable_thinking": True}},
                )
                msg = resp.choices[0].message
                messages.append({"role": "assistant", "content": msg.content, "tool_calls": msg.tool_calls})
                if not msg.tool_calls:
                    continue
                call = msg.tool_calls[0]
                args = json.loads(call.function.arguments)
                if call.function.name == "answer":
                    return args["content"]
                print(f"--- {call.function.name}({args})")
                result = await session.call_tool(call.function.name, args)
                text = "\n".join(c.text for c in result.content if c.type == "text")
                messages.append({"role": "tool", "tool_call_id": call.id, "content": text[:8000]})
        return "Step budget exhausted"


    if __name__ == "__main__":
        print(asyncio.run(run("Fetch https://docs.python.org/3/whatsnew/3.13.html and list the three headline features of Python 3.13.")))
    ```
  </Step>

  <Step title="Run it">
    ```bash theme={"system"}
    python mcp_agent.py
    ```

    ```text Output theme={"system"}
    --- fetch({'url': 'https://docs.python.org/3/whatsnew/3.13.html'})
    --- fetch({'url': 'https://docs.python.org/3/whatsnew/3.13.html', 'raw': True})
    ...
    --- fetch({'url': 'https://docs.python.org/3/whatsnew/3.13.html', 'raw': True, 'start_index': 20000})
    The three headline features of Python 3.13 are:

    1. **A new interactive interpreter** - A greatly improved REPL with enhanced features and color support
    2. **Experimental free-threaded mode** - Support for running CPython without the Global Interpreter Lock (GIL), enabling true parallel execution of threads (PEP 703)
    3. **A Just-In-Time (JIT) compiler** - A basic JIT compiler was added to improve performance (PEP 744), though it is disabled by default
    ```

    Holo pages through the document on its own, using the `raw` and `start_index` arguments from the server's tool schema.
  </Step>
</Steps>

## How it works

* **Tool names come from the server**, so each call goes straight back through `session.call_tool`. Add `answer` yourself: MCP servers do not provide it.
* **Results are text.** The loop keeps the text content blocks and caps them at 8,000 characters.
* **Several servers.** Open one `ClientSession` per server, merge their tool lists, and map each tool name to its session.
* **Remote servers.** Swap `stdio_client` for `streamable_http_client` from `mcp.client.streamable_http`. The loop stays the same.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.