All Guides

Developer Guide

Write a Python MCP Server for Hermes Agent

Skills give a Hermes agent knowledge. An MCP server gives it code that runs. This is the short path from an empty Python file to a tool your agent can call — plus the two Hermes-specific details that are not obvious from the SDK docs.

Skill or MCP server?

Decide this first, because it saves building the wrong thing. A skill is a document: it teaches the agent a procedure using tools it already has. An MCP server is executable code: it gives the agent a capability it did not have — reaching an internal API, querying a database, touching a system only your network can see. If the agent already could do it and just does it badly, write a skill.

Install the SDK

pip install "mcp[cli]"
# or, with uv:
uv add "mcp[cli]"

The [cli] extra provides mcp dev and mcp run, which let you exercise the server on its own before Hermes is in the picture.

FastMCP was renamed in mcp 2.x. Nearly every tutorial still opens with from mcp.server.fastmcp import FastMCP. On a current install that raises ModuleNotFoundError — the SDK ships a stub at that path purely to tell you why. The class is now MCPServer, from mcp.server.mcpserver. Pin mcp<2 only if you need to run v1 code unchanged.

The minimal server

# server.py
from mcp.server.mcpserver import MCPServer

mcp = MCPServer("mytools")

@mcp.tool()
def add(a: int, b: int) -> int:
    """Add two numbers and return the result."""
    return a + b

if __name__ == "__main__":
    mcp.run()

Type hints become the input schema. The docstring becomes the tool description, and it is the line that decides whether the agent ever calls your tool — write it as guidance about when to use the tool, not just what it computes.

Async when you wait on something

import httpx
from mcp.server.mcpserver import MCPServer

mcp = MCPServer("mytools")

@mcp.tool()
async def fetch_status(url: str) -> str:
    """Fetch a URL and return its HTTP status code."""
    async with httpx.AsyncClient(timeout=10) as client:
        response = await client.get(url)
        return f"{response.status_code}"
Always set a timeout. This matters more on Hermes than on a desktop agent, because Hermes is typically running unattended as a background process. A tool that hangs forever produces an agent that appears frozen to whoever is messaging it, with nothing in the conversation pointing at your server as the cause.

Register it

hermes mcp add mytools \
  --command python \
  --connect-timeout 60 \
  --args server.py

--args must be the last option. It takes everything that follows, so --args server.py --connect-timeout 60 quietly passes the timeout flag to your script and leaves Hermes on its default. The command reports success either way.

Pass an absolute path to server.py. A relative path resolves against whatever working directory the Hermes process has, which is rarely the one you registered it from — so it can work in your shell and fail as a background service, days later, looking like the server broke by itself.

The full option set is --url, --command, --args, --auth (oauth or header), --preset, --connect-timeout and --env for stdio environment variables as KEY=VALUE.

Remote servers and headers

There is no --header flag, so a remote server that needs an API key is configured in ~/.hermes/config.yaml:

mcp_servers:
  mytools:
    url: "https://tools.example.com/mcp"
    headers:
      authorization: "Bearer YOUR_TOKEN"
    connect_timeout: 60
    enabled: true

The remote schema also accepts auth for OAuth 2.1, client_cert for mTLS, identity_header for per-user identity, and timeout alongside connect_timeout. Restart Hermes after editing the file.

Then prove it works

Do not infer success from a good chat reply. An agent that cannot see a tool will usually answer without it rather than say the tool is missing, so a plausible answer is the most common false positive there is. Ask for something only your tool could produce, and confirm the effect at the far end — a row written, a log line, a real status code from a URL you control.

Writing tools a model uses well

  • Keep the tool count low. Every description competes for context; sixty tools is a worse agent than six.
  • Return prose, not raw payloads. The reader is a language model.
  • Make errors actionable. “Rate limited, retry in 60s” beats a stack trace.
  • Validate inputs. Schemas shape what the model sends; they do not guarantee it is sane.

The same server works on OpenClaw too — MCP is the shared protocol, and only the registration differs. If you would rather not run the agent host yourself, OpenClaw Launch deploys a managed Hermes Agent in about thirty seconds.

Python MCP servers and Hermes Agent FAQ

How do I add a Python MCP server to Hermes Agent?

hermes mcp add mytools --command python --connect-timeout 60 --args server.py. That writes an entry under mcp_servers in ~/.hermes/config.yaml, which you can also edit by hand.

Why must --args come last?

Because it consumes everything after it. A flag written behind --args is passed to your Python script instead of to Hermes, and the command still succeeds — so the server starts with the wrong configuration and nothing reports an error.

How do I pass an auth header to a remote MCP server?

Through config.yaml, not the CLI. hermes mcp add supports --url, --command, --args, --auth, --preset, --connect-timeout and --env — there is no --header flag. Add a headers mapping to the server entry instead.

Do tool functions need to be async?

No. A plain def works and is what the SDK's minimal example uses. Use async def when the tool awaits I/O. Note the SDK runs sync tools in a worker thread, so blocking inside a plain def is safe — the hazard is blocking inside an async def, which stalls the event loop.

Can I use the same server with OpenClaw?

Yes. MCP is the shared protocol, so one server works with both runtimes — only the registration command and config file differ. See the OpenClaw version of this guide.

Related developer guides

Run Hermes Agent around the clock

Deploy a managed Hermes Agent in about 30 seconds and point it at your own MCP server.

Deploy Hermes Agent