Skip to main content
Glama
PaymanAI

genie-mcp-stdio

Official
by PaymanAI

genie-mcp-stdio

Genie for any MCP host that runs local stdio servers.

Using an AI coding agent? Don't read this — hand it over. Paste this into Claude Code, Codex, Cursor, or whatever you use:

Integrate Genie (Payman's payments agent) into my MCP host by following the
"For agents" section of https://raw.githubusercontent.com/PaymanAI/genie-mcp-stdio/main/README.md
exactly. Detect which host I use, add the server, run the sign-in, and verify.

Your agent will add one server entry, open your browser once for you to sign in to Genie, and confirm the connection. Nothing to copy, no keys to obtain.

For agents

You are integrating Genie into the user's MCP host. Follow these steps in order. Do not improvise credentials: there are no API keys, tokens or client ids to obtain or ask the user for. The sign-in is a browser flow the bridge runs itself.

1. Check prerequisites

node --version   # must print v20 or newer

If Node is missing or older than 20, install Node 20+ (or tell the user to) before continuing. Nothing else is needed; npx fetches the bridge on first run.

2. Detect the host and add the server

Look for the host's config in this order; use the first that exists on the machine (or the one the user named). Add the genie entry, merging into any existing mcpServers object rather than replacing the file. Add no env block.

Host

Config file

Entry

OpenMausBot

~/.openmausbot/config.json

JSON below, under mcpServers

Claude Desktop (macOS)

~/Library/Application Support/Claude/claude_desktop_config.json

JSON below, under mcpServers

Claude Desktop (Windows)

%APPDATA%\Claude\claude_desktop_config.json

JSON below, under mcpServers

Claude Code

run claude mcp add genie -- npx -y @paymanai/genie-mcp-stdio

Cursor

~/.cursor/mcp.json (global) or <project>/.cursor/mcp.json

JSON below, under mcpServers

Windsurf

~/.codeium/windsurf/mcp_config.json

JSON below, under mcpServers

Codex CLI

~/.codex/config.toml

TOML below

Anything else that launches stdio MCP servers

its MCP config

command npx, args -y @paymanai/genie-mcp-stdio, no env

JSON entry:

{
  "mcpServers": {
    "genie": {
      "command": "npx",
      "args": ["-y", "@paymanai/genie-mcp-stdio"]
    }
  }
}

TOML entry (Codex CLI):

[mcp_servers.genie]
command = "npx"
args = ["-y", "@paymanai/genie-mcp-stdio"]

Claude Code, Claude Desktop and Codex CLI can also add https://genie.paymanai.com/mcp directly as a remote server with OAuth. That only works once Payman has registered the host's OAuth client, because Genie has no dynamic client registration; see Integrating Genie without the bridge. Until then, or when in doubt, use the bridge above; it works everywhere.

3. Sign the user in

Run this in a terminal the user can see, and tell them a browser window will open:

npx -y @paymanai/genie-mcp-stdio login

It prints Signed in to Genie. and Sign-in stored in …/genie-mcp-stdio/credentials.json on success. If no browser opens, give the user the URL printed after Sign in to Genie in your browser:. It waits up to fifteen minutes. You can skip this step — the bridge signs in on the first tool call instead — but running it now means the user's first message doesn't stall on a browser.

4. Verify

Restart the host (or reload its MCP servers). Confirm a server named genie exposing the tool ask_genie (and the four *_genie_agent / *_genie_access self-service tools) appears. Its single argument is request — the person's ask, in plain words ({"request": "what can you help me with?"}). Have the user (or the host's agent) send Genie a harmless request like that and check that a reply comes back. On first use Genie asks the user to connect a finance provider — that is expected and happens in Genie's own UI, not in the host. If the request fails, see Troubleshooting.

5. Report back

Tell the user, in one or two lines: which config file you changed, that they are signed in to Genie, and that npx -y @paymanai/genie-mcp-stdio logout signs them out everywhere.

Do not

  • Do not set GENIE_ACCESS_TOKEN, GENIE_INTEGRATION_KEY, GENIE_OAUTH_CLIENT_ID or any other GENIE_* variable. They exist for Payman's own deployments and integrators; a person's setup uses none of them, and asking the user for such values is a red flag.

  • Do not copy credentials.json into the host's config or anywhere else.

  • Do not ask the user for their Genie password; the bridge never sees it either.


Related MCP server: GenieOS MCP Server

What this is

Genie is Payman's payments agent. It is reachable as a remote MCP server (https://genie.paymanai.com/mcp, Streamable HTTP) exposing one tool, ask_genie. Some hosts, like OpenMausBot, only launch local stdio MCP servers. Others, like Claude Code, Claude Desktop and Codex CLI, can connect to remote MCP URLs, but Genie only accepts OAuth clients that Payman has registered. This package works for both today: a local process that speaks stdio to the host and Streamable HTTP to Genie, forwarding tools verbatim and relaying Genie's elicitation prompts back to the host when the host supports them.

It decides nothing. You sign in to your own Genie account once in the browser; the bridge keeps that sign-in in a private file and never puts a secret in a host's configuration, tool output or logs.

Commands

Command

What it does

npx -y @paymanai/genie-mcp-stdio

Serve Genie over stdio. This is what hosts run.

npx -y @paymanai/genie-mcp-stdio login

Sign in now: opens the browser, waits up to fifteen minutes for the callback, stores the sign-in.

npx -y @paymanai/genie-mcp-stdio logout

Revoke the sign-in at Genie and delete the local copy.

All diagnostics go to stderr, prefixed [genie-mcp-stdio]; stdout is reserved for MCP.

How the sign-in works

The bridge is a preregistered native OAuth client at Genie (genie-mcp-stdio): authorization code with S256 PKCE, a loopback redirect on a random port (RFC 8252), and a refresh token that Genie rotates on every use and lets live for 90 days from the last use. Access tokens last one hour and are renewed silently; you only see the browser again if you have not used Genie for 90 days, sign out, or Genie revokes the sign-in.

The browser has fifteen minutes to finish. If it takes longer, the bridge stops waiting but keeps its loopback port open, so a late browser sees "This sign-in expired" with what to do next rather than a refused connection; and if the port is gone (a login command that already exited), Genie's own page notices you came back and explains the same thing. Either way nothing was connected, and asking the agent again starts a fresh sign-in.

The refresh token is stored in ~/.config/genie-mcp-stdio/credentials.json ($XDG_CONFIG_HOME respected), mode 0600, keyed by Genie URL. It is never written to a host's configuration, tool output or logs. logout revokes it at Genie (RFC 7009) before deleting it, so a copied file stops working too.

Configuration (you almost certainly don't need this)

A person's setup uses no environment variables at all. These exist for Payman's own local Genie stacks, CI, and organizations integrating on their own behalf rather than as a person:

Variable

Meaning

GENIE_MCP_URL

Defaults to https://genie.paymanai.com/mcp. Must be https; plain http is accepted only for loopback (local Genie stacks).

GENIE_OAUTH_CLIENT_ID

Leave unset. Defaults to genie-mcp-stdio, the bridge's own preregistered public client id (not a secret). Only a self-hosted Genie, or a fork we registered separately, sets this.

GENIE_BROWSER_COMMAND

Command (space-separated) that receives the sign-in URL; defaults to the OS opener.

GENIE_CREDENTIALS_FILE

Where the sign-in is stored; defaults as above.

GENIE_ACCESS_TOKEN

Bypass the account sign-in with a Genie OAuth access token you obtained elsewhere (expires; no refresh).

GENIE_INTEGRATION_KEY + GENIE_CUSTOMER_ID (+ GENIE_CUSTOMER_EMAIL)

Bypass the account sign-in with a managed integration key; this identifies an organization's integration acting for a customer, not a person's own account.

Setting both bypass variables is refused, because Genie refuses a request that carries both.

What the host sees

  • Tools: whatever Genie lists — today ask_genie, which takes one argument, request: what the person wants, in plain words, plus four self-service tools the assistant uses to manage its own Genie record (get_genie_agent, rename_genie_agent, grant_genie_read_access, request_genie_access) — read-only access it can grant itself; full access it asks for and the person approves on Genie's Agents page. Sign-ins made by bridge 0.3.x carry only genie:ask; run npx -y @paymanai/genie-mcp-stdio logout, then sign in again, to pick up genie:self. tools/list_changed is forwarded.

  • Elicitation: Genie asks the person to connect their account and pick a finance provider on first use. If the host declared the elicitation capability the prompt is relayed to it; otherwise Genie's reply explains what to do instead.

  • Errors: a rejected credential surfaces as an MCP error naming what to check, never a token value. The bridge starts even when Genie is unreachable, so a problem shows up on the first call rather than as a silent missing server. If Genie stops accepting the stored sign-in, the bridge opens the browser again rather than failing.

Troubleshooting

OpenMausBot on macOS: every bot reply fails with "MCP server could not start"

The full message is MCP server could not start; check its command and installation, and it appears even though the server's Test button in OpenMausBot lists ask_genie. OpenMausBot's chat starts MCP servers without the user's shell PATH, so it cannot find npx; its Test button adds that PATH, which is why the test passes.

The fix is an env that holds only PATH on the genie entry. This is the one exception to "Add no env block" above. Print the value in the user's shell:

printf '%s:/usr/bin:/bin:/usr/sbin:/sbin\n' "$(dirname "$(command -v npx)")"

Add it to the entry in ~/.openmausbot/config.json:

"env": { "PATH": "<the line printed above>" }

Then have the user quit OpenMausBot (Cmd+Q) and open it again, without changing MCP servers in the app first: a hand edit needs the restart, and an in-app MCP change before then writes the old entry back. People doing this by hand can follow docs/hosts/openmausbot.md.

Security notes

  • One session per bridge process, bound by Genie to the authenticated caller. Restarting the host restarts the session.

  • Genie never returns a bank credential to a model; the bridge never sees one either. This package only moves JSON-RPC.

  • The bridge collapses concurrent token refreshes into one request: the MCP session's POST and its notification stream can both meet a 401 at the same moment, and Genie treats a second use of a rotated refresh token as a replay that revokes the sign-in.

  • logout when you stop using a machine; the sign-in is then dead at Genie, not just deleted locally.

Integrating Genie without the bridge

If you maintain a host and want to connect to Genie's remote MCP server directly — the better long-term answer, and the one OpenMausBot has on its roadmap — here is what Genie expects. It is standard MCP authorization; nothing here is Genie-specific except the client registration.

  1. Transport. Streamable HTTP at https://genie.paymanai.com/mcp. POSTs answer with JSON; notifications and elicitation requests arrive on the standalone GET SSE stream, so open it after initialize. Sessions are bound to the authenticated caller via Mcp-Session-Id; a new process needs a new session.

  2. Discovery. An unauthenticated request returns 401 with WWW-Authenticate: Bearer resource_metadata="https://genie.paymanai.com/.well-known/oauth-protected-resource/mcp", scope="genie:ask genie:self" (RFC 9728). That document names the authorization server, whose RFC 8414 metadata lists the authorize, token, revocation and JWKS endpoints.

  3. Authorization. Authorization code with S256 PKCE, token_endpoint_auth_method: none, scope genie:ask genie:self (genie:ask alone still works, without the self-service tools), and the resource parameter set to the MCP URL (RFC 8707). There is no dynamic client registration: ask us to preregister your host with its client_id, display name and exact redirect URIs (open an issue on this repository). Registered loopback redirects for native apps match on any port; everything else matches exactly. Native clients receive a refresh token (90 days sliding, rotated on every use — send the new one back next time, and never reuse an old one, which Genie treats as a replay and revokes the sign-in). Access tokens are one-hour ES256 JWTs.

  4. Elicitation. Declare the elicitation capability if you can render a form: Genie uses it once per account to have the person connect a finance provider, and carries a connectionUrl in _meta you may open for them. Without it, ask_genie replies with instructions instead.

  5. Test against the real thing. This bridge's test/fixture.ts and test/fakeAuthServer.ts are a faithful local stand-in for the above if you want an offline test; the production server behaves the same way.

Development

nvm use            # Node 24
npm install
npm test           # builds, then node:test against an in-process fake Genie

test/fixture.ts is a small Streamable HTTP MCP server with Genie's admission rule (exactly one credential or 401 with a Bearer challenge) and an ask_genie that can elicit on the standalone stream, the way Genie does. test/fakeAuthServer.ts is the slice of Genie's authorization server the sign-in uses — discovery, PKCE, refresh rotation, revocation — and test/browser.ts stands in for the person's browser.

License

MIT.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    Not graded
    maintenance
    Bridges STDIO-based MCP clients with SSE-based MCP servers, allowing applications like Claude Desktop to connect to remote MCP servers that use SSE transport.
    9
    -
  • A
    license
    B
    quality
    A
    maintenance
    Enables local MCP clients to access the hosted Asyntai MCP server by bridging stdio to HTTPS and handling OAuth sign-in, giving assistants the same 52 tools as the Asyntai dashboard.
    54
    40 npm
    1
    MIT