Skip to content
Scalekit Docs

Connect Hermes to AgentKit

Connect Hermes to GitHub, Gmail, and Slack through Scalekit. Install the skill, set credentials, and run one tool call.

Hermes is the self-improving AI agent from Nous Research. Hermes runs where you put it: a laptop, a small VPS, or a GPU cluster. You reach Hermes from the command line, or from a messaging app such as Slack or Telegram, and Hermes also runs work on a cron schedule.

Hermes ships with 60+ built-in tools, and the built-in tools stop at the edge of your machine. A Hermes agent that reads your Gmail, posts to your Slack, or opens a GitHub pull request needs an access token for each app. Every access token belongs to one user.

Scalekit holds the connected account for that user, stores the access token, and refreshes the access token. Hermes reaches Scalekit through a skill. A skill is an on-demand instruction set plus scripts, and Hermes loads a skill from ~/.hermes/skills/ when a chat calls for one. The skill tells Hermes how to find the Scalekit connection, how to check that the user finished auth, and how to call the tool with the stored token. The steps below install the skill.

Hermes AgentScalekit AgentKitThird-party servicesOAuth handlerToken vaultGmailSlackSalesforce200+ more Execute tools

The skill runs the following loop when you name an app:

  1. The skill looks up the Scalekit connection you already created for GitHub, Gmail, or another app.
  2. The skill checks the user’s connected account. ACTIVE means auth is complete and Scalekit holds a token.
  3. The skill returns a magic link when the connected account is not ACTIVE.
  4. The skill fetches the tool schema, calls the tool, and returns the result.
  5. The skill calls the Scalekit HTTP proxy when the connector has no named tool.

A magic link is a one-time URL. The hosted page shows OAuth consent, or an API-key form.

Using a coding agent?

  1. Install hermes-delegated-auth from authstack:

    Terminal window
    hermes skills install scalekit-inc/authstack/kits/agentkit/host/hermes-delegated-auth

    Confirm the skill is enabled:

    Terminal window
    hermes skills list
    │ hermes-delegated-auth │ │ local │ local │ enabled │

    Install the Python dependencies:

    Terminal window
    cd "${HERMES_HOME:-$HOME/.hermes}/skills/hermes-delegated-auth"
    uv sync

    New chats load /hermes-delegated-auth. Run /reset in a chat that is already open.

    HERMES_HOME changes the skill path. The commands on this page use ~/.hermes.

  2. Put only Scalekit client credentials in ~/.hermes/.env. Scalekit stores and refreshes the provider tokens for GitHub, Gmail, and Slack. Provider tokens never belong in a Hermes file.

    ~/.hermes/.env
    SCALEKIT_CLIENT_ID=skc_your_client_id
    # Threat: a leaked secret lets anyone call tools as any ACTIVE identifier.
    SCALEKIT_CLIENT_SECRET=your_client_secret
    SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.cloud
    SCALEKIT_IDENTIFIER=usr_8f3a2c
    ParameterDescription
    SCALEKIT_CLIENT_IDYour Scalekit client ID Required
    SCALEKIT_CLIENT_SECRETYour Scalekit client secret Required
    SCALEKIT_ENVIRONMENT_URLYour Scalekit environment URL Required
    SCALEKIT_IDENTIFIERDefault user the host acts as Required

    Copy the client ID, client secret, and environment URL from Dashboard > Developers > Settings > API Credentials.

    SCALEKIT_IDENTIFIER is not a dashboard credential. Pick an opaque id that only your system knows, for example usr_8f3a2c. Every tool_exec.py command needs SCALEKIT_IDENTIFIER, including --list-connections.

  3. Start a chat and ask for a real action. Hermes acts as SCALEKIT_IDENTIFIER by default, and Hermes passes --identifier to the skill when you name another user in the prompt.

    You: Who am I on GitHub?

    Hermes loads the skill and runs these steps:

    1. Hermes looks up the GitHub connection.
    2. Hermes checks that the connected account is ACTIVE, and returns a magic link when the account is not.
    3. Hermes fetches the tool schema.
    4. Hermes calls the tool and returns your GitHub login.

    Name the skill in the prompt to force the same path:

    /hermes-delegated-auth who am I on GitHub?

Confirm all of the following:

  • The skill is listed (hermes skills list or /skills) as hermes-delegated-auth
  • The connected account is ACTIVE after you finish the magic link
  • Hermes returns data from the provider (the GitHub login, or unread mail)

Open the magic link again and retry the same prompt if the account stays inactive.

Slack issues two kinds of token, and the token decides whose name appears on a message. A bot token posts as your Slack app. A user token posts as the person who authorized the app. Authorizing the Hermes gateway grants a bot token, so the gateway alone cannot post as a person.

JobUse
Chat with the agent in a channel or DMHermes Slack gateway. Bot tokens (xoxb- + xapp-) in ~/.hermes/.env. See the Hermes Slack setup.
Read private history, post, or act as a userScalekit Slack connection created with User scope. See the Slack connector.

The gateway bot is a channel into the agent. The gateway bot is not usr_8f3a2c.

Always-on hosts use both identities. The gateway hears the channel. Scalekit acts as the user.

Attach the skill to a Hermes cron job. Each fire is a fresh session. The skill uses Scalekit client credentials. You do not mint a session token.

Terminal window
hermes cron create "0 9 * * *" "List unread emails for usr_8f3a2c and post a 5-line summary" --skill hermes-delegated-auth

Or in chat:

/cron add "every weekday at 9am" "List unread emails for usr_8f3a2c and post a 5-line summary" --skill hermes-delegated-auth

The connected account must already be ACTIVE. Cron cannot click a magic link.

Leave the gateway running on a headless host. A new magic link can then land in Slack or Telegram. Do not put Gmail or Calendar refresh tokens in ~/.hermes/.env.

Three patterns connect Hermes to Scalekit. Pick the one that matches your host.

Pattern A: delegated skill. The default for Hermes. The host holds Scalekit client credentials, and each turn names an identifier. No token sits on the host, so nothing expires.

Pattern B: Virtual MCP on the host. A Virtual MCP server exposes only the tools you list. Hermes reads one bearer token, so the host acts as one operator. You mint the token and reload the host.

Pattern C: Virtual MCP in your app. Your application mints a token before each agent run and passes it to the agent framework. Claude Managed Agents, Mastra, and CrewAI use Pattern C.

QuestionA: delegated skillB: Virtual MCP on the hostC: Virtual MCP in your app
Who runs the agentHermesHermesyour app
How many end usersmany; switch with --identifierone operatormany
Credential on the hostScalekit client ID and secretone session-token bearernone
Anything expires?noyes, about 1 hour by defaultyes, per run
Who mints a replacementnobody; there is no tokenyou, on a schedule, then reloadyour code, before each run
Tool scopingthe full connector catalogonly the tools in the configonly the tools in the config
Best formulti-user hosts and crona scoped, single-operator gatewayshort agent runs

The rest of this page covers Pattern A. For Pattern B, see Run Virtual MCP on a Hermes host. For Pattern C, see Set up and connect a Virtual MCP server.

This is the long-running host setup. One operator. One bearer. You remint.

Use this when you want a scoped tool list on a single-operator Hermes gateway. Create the Virtual MCP config once. Mint a session token with create_session_token. Put the token in Hermes config.yaml. Reload the host before the token expires.

  1. Create the server once per operator role. Save the static mcp_server_url. Do not regenerate the config on each remint.

    See Set up and connect a Virtual MCP server.

  2. Call create_session_token for one identifier. Set expiry above your reload interval.

    from datetime import timedelta
    token_response = scalekit_client.actions.mcp.create_session_token(
    mcp_config_id=config_id,
    identifier="usr_8f3a2c",
    expiry=timedelta(hours=2),
    )
    token = token_response.token

    create_session_token is the remint call. Call it again whenever you need a new token.

  3. Write the token to SCALEKIT_MCP_SESSION_TOKEN in ~/.hermes/.env. Point ~/.hermes/config.yaml at the static URL and that env var.

    ~/.hermes/config.yaml
    mcp_servers:
    scalekit:
    url: "<mcp_server_url>"
    headers:
    Authorization: "Bearer ${SCALEKIT_MCP_SESSION_TOKEN}"

    Do not set auth: oauth. A Scalekit Virtual MCP server takes a bearer token, not MCP OAuth.

    Do not run hermes mcp login against this URL.

  4. Restart Hermes, or run /reload-mcp so Hermes rereads the bearer.

  5. On a cron, mint a new token, write SCALEKIT_MCP_SESSION_TOKEN, then run /reload-mcp. Repeat before the token expires. Set expiry above that interval.

An expired bearer fails at the next tool call, not at startup.

One Hermes host is one operator. Mint per-end-user tokens in your own application. See Set up and connect a Virtual MCP server.

  • Do not put provider tokens in ~/.hermes/.env. Put only Scalekit credentials there.
  • Do not set SCALEKIT_IDENTIFIER to an email or another guessable value.
  • Do not use the bundled Google Workspace skill (~/.hermes/google_token.json) if AgentKit owns the Google user. ~/.hermes/google_token.json is one laptop login, not a per-user identifier.
  • Do not run hermes mcp login against Scalekit Virtual MCP (a Scalekit MCP URL plus a session token). Virtual MCP uses a static bearer session token, and a static bearer token is not MCP OAuth.
  • Do not treat the Slack bot token as “send as usr_8f3a2c”.
  • Do not use one Hermes host as a multi-tenant identity provider. One gateway is one operator. Switch identifiers on the same host with --identifier. Mint per-end-user Virtual MCP session tokens in your own application, not inside Hermes.
How do I authorize a new connection?

The skill returns a magic link if the account is not ACTIVE. Open the link, finish the flow on the hosted page, then return to Hermes and retry.

The hosted page adapts to the connection. An OAuth connector asks for your consent. An API key connector, such as Snowflake, asks for the credential. Hermes never collects the credential in chat.

How do I switch users?

Set SCALEKIT_IDENTIFIER in ~/.hermes/.env as the default.

Name another user in the prompt to override the default for one turn, for example as identifier usr_8f3a2c. Hermes then passes --identifier usr_8f3a2c to the skill, and Scalekit scopes the tools to that user’s connected account.

Why do I see “connection not found”?
  1. Confirm the connection exists in Dashboard > AgentKit > Connections
  2. Confirm the connection is complete, not a draft
  3. Confirm SCALEKIT_ENVIRONMENT_URL matches the environment that holds the connection

Use the connection key_id as the connection name, for example github-connect. Do not use the conn_… id.

The connected account is not ACTIVE

Check the state in Dashboard > AgentKit > Connected accounts:

StateWhat you do
PENDING_AUTHOpen the magic link and finish OAuth
PENDING_VERIFICATIONComplete user verification
EXPIREDOpen a new magic link. Scalekit cannot refresh a dead refresh token
DISCONNECTEDReconnect from the Dashboard, then retry

See Manage connected accounts.

Can I use Virtual MCP with Hermes?

Yes. Pick the pattern that matches your host.

The skill is the default. hermes-delegated-auth calls execute_tool with Scalekit client credentials and an identifier. No token sits on the host, so nothing expires. Use the skill for a host that serves more than one user, and for cron.

Virtual MCP is the scoped alternative. A Virtual MCP server exposes only the tools you list. Tool scoping is the reason to choose it. Hermes reads the bearer from config.yaml as ${SCALEKIT_MCP_SESSION_TOKEN}. Hermes resolves that variable when it connects, and again when you run /reload-mcp. For the host how-to, see Run Virtual MCP on a Hermes host.

Hermes never calls create_session_token. Nothing inside Hermes refreshes the bearer, so you refresh it yourself:

  1. Create the Virtual MCP config once. Save the static mcp_server_url.
  2. Mint a token with create_session_token for one identifier. Set expiry above your reload interval.
  3. Write the token to the environment variable named in config.yaml.
  4. Restart Hermes, or run /reload-mcp.
  5. Repeat step 2 through step 4 before the token expires.

An expired bearer fails at the next tool call, not at startup.

One Hermes host is one operator. Do not mint a session token per end user inside the host. Mint per-user tokens in your own application instead, as in Set up a Virtual MCP server.

Do not set auth: oauth on a Scalekit Virtual MCP server. The server takes a bearer token, not MCP OAuth.

Why does hermes mcp login fail against Scalekit?

hermes mcp login performs MCP OAuth against a vendor’s MCP server. A Scalekit Virtual MCP server does not use MCP OAuth. It takes a static URL plus a session token that your application mints with create_session_token.

Set the bearer header in config.yaml instead. See Set up a Virtual MCP server.