For the complete documentation index, see llms.txt. This page is also available as Markdown.

Signer service

@kumbaya_xyz/onchain-signer is the key-custody component of the Kumbaya Agent Kit. It's a standalone HTTP service that holds every agent's private key and signs token-authenticated requests, so agent processes never hold a raw key. Run it when you're operating a fleet of agents in one framework; for a single wallet you don't need it - onchain-mcp signs directly.

Field
Value

Package

@kumbaya_xyz/onchain-signer (npm)

Bin

kumbaya-onchain-signer

Transport

HTTP (Hono)

Default port

8787

License

MIT

Why it exists

The kit's security rule is that whatever holds a key does nothing else. With a fleet, you don't want every agent process carrying a raw key. The signer isolates key custody to one trusted host:

  • Keys never enter agent processes. Each agent's onchain-mcp runs keyless and delegates signing over HTTP.

  • Tokens, not keys, are the agent credential. A leaked token is revoked or rotated by editing the keystore; the underlying key is untouched.

  • Per-agent policy. Each token can be scoped to allowed chains, a native-value cap, a recipient allowlist, and a typed-data allowlist. Requests that violate the policy are rejected before signing.

  • One identity per agent. Each token maps to one address, so every agent signs as itself.

Run it

SIGNER_KEYS_FILE=/secure/keys.json PORT=8787 npx @kumbaya_xyz/onchain-signer

Then point each agent's onchain-mcp at it:

Keystore

The signer loads a JSON map of token → key (or token → { key, label, policy }). Prefer SIGNER_KEYS_FILE over the inline SIGNER_KEYS so keys don't show up in the process list.

A value can be a bare private-key string (no label, no policy) or an object. Policy fields are all optional:

Field
Effect

allowChains

If set, tx.chainId must be in this list, else the request is rejected.

maxValueWei

If set, tx.value must not exceed this cap.

allowTo

If set, tx.to must be in this allowlist (case-insensitive).

allowTypedData

Allowed EIP-712 shapes for /v1/sign/typed-data, matched on primaryType / name / version / verifyingContract / chainId, each with an optional spenderField + allowSpenders. When unset, only the FuelVault GiftPermit is signed.

Configuration

Env var
Default
Purpose

SIGNER_KEYS_FILE

(none)

Path to the keystore JSON. Preferred.

SIGNER_KEYS

(none)

Inline keystore JSON. Use only where a file isn't practical.

PORT

8787

Listen port.

If neither keystore variable is set, the signer starts empty and rejects every request.

HTTP API

All signing endpoints require Authorization: Bearer <token>. Bigints in transaction and typed-data payloads are transported as hex strings and revived server-side.

Method
Path
Body
Returns

GET

/health

-

{ ok, agents } (count of loaded tokens)

GET

/v1/address

-

{ address, label } for the token

POST

/v1/sign/transaction

{ transaction }

{ signedTransaction } - policy-checked first

POST

/v1/sign/typed-data

{ typedData }

{ signature } - policy-checked (default: GiftPermit only)

POST

/v1/sign/message

{ message }

{ signature }

Policy is enforced on /v1/sign/transaction and /v1/sign/typed-data; a violating request returns 403 with a policy: <reason> error and is never signed.

How onchain-mcp delegates

When onchain-mcp sees SIGNER_URL set, it skips local key loading and builds a viem account whose signing methods call the signer:

  • signTransactionPOST /v1/sign/transaction

  • signTypedDataPOST /v1/sign/typed-data

  • signMessagePOST /v1/sign/message

The signer signs with the key mapped to the request's token and returns the signature; onchain-mcp then broadcasts the signed transaction itself. The signer only signs - it never touches the chain.

Operating notes

  • Run the signer on a trusted host and treat SIGNER_KEYS_FILE as a secret.

  • Give each agent its own token and a policy scoped to what it actually needs (e.g. testnet-only, capped value, router + position-manager recipients).

  • Rotate a token by replacing it in the keystore; the underlying key is unaffected.

Where to next

Last updated