hermes atlas
168·repos hermes·v0.15.2 ★ star this repo
dev tutorial · module 6 of 7 · reach & building

Reaching out: MCP, the gateway & cron

So far the agent has lived in your terminal, used the tools you gave it, and remembered you between sessions. This module is about reach — three ways to push the same agent loop further out into the world: more tools (MCP), more places (the gateway), and more time (cron).

Hermes Atlas dev tutorial · ~13 min · for builders, no CS degree assumed

Here's the frame to carry through this whole module. The loop from Module 2 doesn't change — it's still think → call a tool → see the result → repeat. What changes is the blast radius:

MCP — more tools, no tool code

In Module 3 you wrote tools as Python functions. That's great when the capability is yours and specific. But for the big, common integrations — GitHub, Slack, a Postgres database, a filesystem — someone has already written and battle-tested the tool code. MCP is how you borrow it.

MCP — the Model Context Protocol — is an open standard for plugging tool "servers" into any AI host. A server exposes a set of tools over a well-defined protocol; any MCP-aware host can consume them. Think of it as USB for AI tools: one plug shape, many devices.

A way to picture it — writing a Python tool is like building an appliance from parts. Adding an MCP server is like buying one and plugging it in — it already works, the cord fits the socket, and you didn't have to understand its wiring. Hermes is the wall socket; the MCP server is the appliance.

Hermes is an MCP client (also called a host): you point it at an MCP server, and it gains that server's tools — surfaced to the model exactly like the built-in ones from Module 3. The model can't even tell the difference, and that's the point.

Configuring a server

MCP servers are declared in ~/.hermes/config.yaml under mcp_servers. Each entry is, at heart, a command to launch plus its args and env. Most public servers ship as an npx one-liner, so adding them is a few lines of YAML:

# ~/.hermes/config.yaml
mcp_servers:
  # A local filesystem server — gives the agent read/write tools
  # scoped to one directory.
  filesystem:
    command: npx
    args: ["-y", "@modelcontextprotocol/server-filesystem", "/home/me/projects"]

  # A GitHub server — issues, PRs, repo search, etc.
  github:
    command: npx
    args: ["-y", "@modelcontextprotocol/server-github"]
    env:
      GITHUB_PERSONAL_ACCESS_TOKEN: "${GITHUB_TOKEN}"   # pulled from ~/.hermes/.env

That's the whole integration. Two servers, a dozen lines, and the agent now has GitHub and filesystem tools it never had before — with zero Python written by you.

What happens under the hood

The mechanics live in tools/mcp_tool.py. On startup it opens a background connection to each configured server, asks the server for its tool list (the protocol has a standard "list tools" handshake), and registers those tools into the same toolbox the model already sees. From the loop's perspective, an MCP tool is just another callable — name, description, schema, go.

Builder's takeaway — MCP is the fastest way to add a big batch of capabilities — Slack, GitHub, a database, Google Drive, a browser — with zero Python. Someone already wrote the server; you just declare it. Before you write a custom tool, check whether an MCP server already exists. See the MCP feature docs and the "Use MCP with Hermes" guide.

Hermes can also BE a server

The arrow points both ways. Hermes can expose itself as an MCP server with hermes mcp serve (see mcp_serve.py), so other AI hosts — a desktop chat app, another agent — can reach into Hermes' conversations and messaging as tools. You become the appliance someone else plugs in.

The messaging gateway — more places to live

An agent trapped in your terminal can only help you, and only when you're at the keyboard. The gateway fixes that. One Hermes process can serve Telegram, Discord, Slack, WhatsApp, Signal, Email, and roughly twenty more channels at once — same brain, many faces.

Glossary: adapter — an adapter is a thin translator for one platform. It knows how to receive that platform's messages and how to format and send replies back in that platform's shape (Slack blocks vs. Telegram markdown vs. a plain email body). The gateway keeps one adapter per platform in a registry — the gateway/ directory uses a registry pattern (see gateway/platform_registry.py and the per-platform code under gateway/platforms/).

The crucial design choice: adapters only handle the edges — receiving and formatting. The thinking is identical no matter where the message came from. Every platform funnels into the same agent loop (run_conversation) you've been reading about since Module 2. Here's the path a single message travels:

Telegram message: "what's on my calendar today?"
        |
        v
  +----------------------------------------------+
  |  THE GATEWAY                                 |
  |                                              |
  |   adapter receives  -->  find / create session  |
  |   (Telegram)                       |          |
  |                                    v          |
  |              run the SAME agent loop          |
  |               (run_conversation)              |
  |                                    |          |
  |   adapter formats   <--  stream the reply       |
  |   for Telegram                                |
  +----------------------------------------------+
        |
        v
Telegram reply: "You have 2 events: …"

Read that flow as: platform message → adapter receives → look up or create the right session → run the same loop → stream the reply → adapter formats it for that platform → send back. The session lookup is what makes a Discord thread feel continuous and keeps your DMs separate from a group chat. Everything in the middle is the agent you already know.

Standing it up

# turn your agent into a multi-platform assistant
hermes gateway setup     # wizard: pick platforms, paste their tokens
hermes gateway start     # one process now serves all of them

This is the step that turns a personal tool into a product: you ship the assistant to real users on the channels they already live in, instead of asking them to learn yours. Full setup details are in the messaging docs.

Cron — more time (it works while you sleep)

MCP gave the agent more tools; the gateway gave it more places. Cron gives it more time — the ability to run on a schedule, unattended, with no human in the loop. Hermes ships a built-in scheduler (cron/ plus the tools in tools/cronjob_tools.py), and the jobs you create are stored in ~/.hermes/cron/jobs.json.

The lovely part: you don't write code for a job. You describe it in plain English and Hermes runs that description on a schedule. A job is built from these fields:

FieldWhat it isExample
scheduleWhen to run. A cron expression or natural language.0 9 * * *  or  "every 30 minutes" / "daily at 9am"
promptWhat to do, in plain English. This is the instruction the agent runs."Check HN for Hermes mentions and summarize"
skillsOptional skills (Module 4) to attach for this run.research-summary
toolsetOptional restricted set of tools the job is allowed to use.web_search, send_message
deliveryWhere the result goes: back to origin, saved locally, or to a platform.telegram:<chat-id>

Notice how this stacks on everything earlier in the module: a cron job's delivery target can be a gateway platform, and its prompt can lean on MCP tools and skills. The three reach mechanisms compose.

What happens on each tick

The scheduler (cron/scheduler.py) checks the clock. When a job is due, it spawns a fresh agent, runs the job's prompt through the normal loop, and then hands the result to the configured delivery target. Fresh agent per run means jobs don't pollute each other's context — each wakes up clean, does its task, and reports.

⚠ Heads up: scheduled prompts are attack surface — a cron prompt runs without you watching, so a malicious instruction smuggled into one is dangerous. Hermes scans job prompts for prompt-injection patterns (the guards live in cron/scheduler.py) and flags sketchy ones. Still, treat any job whose prompt ingests outside content ("summarize this webpage", "read my inbox") with the same caution you'd give an untrusted email — restrict its toolset, and don't give an unattended job more power than the task needs.

A concrete job

Say you want a research briefing every morning before you're awake. You'd create a job whose schedule is 0 7 * * * (7am daily), whose prompt is "Research the latest on <topic> and write me a tight summary," and whose delivery is telegram:<your-chat-id>. At 7am a fresh agent spins up, does the research, and the summary lands in your Telegram before coffee.

That exact pattern is walked end-to-end in the daily-briefing-bot guide. For the full feature reference and more recipes, see the cron docs and the "Automate with cron" guide.

Builder's takeaway — cron turns Hermes into a fleet of natural-language automations that run unattended — morning reports, uptime monitors, scrape-and-notify pipelines, weekly digests. You describe the task once in English; the scheduler keeps doing it forever. No glue scripts, no separate cron daemon to babysit.

How the three fit together

These aren't three unrelated features — they're three axes of the same idea, and they multiply. Picture a single assistant you ship to a Discord community (gateway), that answers questions using a GitHub MCP server (MCP), and that posts an automated weekly changelog every Friday (cron). One agent loop, three kinds of reach, one product.

Key takeaways
Quick check — You want your agent to query a Postgres database, and you'd rather not write or maintain SQL-execution tool code yourself. Which of the three reach mechanisms is the right starting point, and what do you actually have to do?

Answer: MCP. A Postgres MCP server almost certainly already exists. You add it as an entry under mcp_servers in ~/.hermes/config.yaml — a command (usually npx), its args, and an env with your connection string — and restart. tools/mcp_tool.py connects in the background, asks the server for its tools, and registers them. No Python, no SQL plumbing of your own. (The gateway is about where the agent lives; cron is about when it runs — neither adds the database tools.)
Pair with your AI — get hands-on with all three before Module 7. Try: "In my cloned hermes-agent repo, walk me through three things and cite the files: (1) how tools/mcp_tool.py turns an entry under mcp_servers in config.yaml into tools the model can call; (2) how a message goes from gateway/platforms/<platform> into run_conversation and back out via an adapter; (3) what fields a cron job in ~/.hermes/cron/jobs.json has and where cron/scheduler.py scans the prompt for injection. I'm a product builder — keep it conceptual but point me at the exact functions."

← Module 5 · Memory

Module 7 · Building on Hermes →

↩ Dev tutorial index