Skip to the content
TAPEHOUSE

Agents

MCP server

Run @tapehouse/mcp so an AI agent can read the band, margin accounts, shorts and gap cover, and prepare unsigned transactions.

@tapehouse/mcp is a Model Context Protocol server. An agent connected to it reads Tapehouse's band, its feeds, the Morpho oracles, the baskets, the margin accounts, the short positions and the gap cover, and gets back unsigned calls for a wallet to sign. The server never holds a key. The published version is 0.1.1.

It is built on the official TypeScript SDK, @modelcontextprotocol/server, for the 2026-07-28 specification, and serves clients of the 2025 revisions too. Every read and call goes through @tapehouse/sdk.

Run it#

Over stdio, the server is launched by the host. This is the configuration, in the mcpServers format that hosts such as Claude Desktop, Claude Code, Cursor and VS Code read:

JSON
{
  "mcpServers": {
    "tapehouse": {
      "command": "npx",
      "args": ["-y", "@tapehouse/mcp"],
      "env": {
        "TAPEHOUSE_RPC_URL": "https://rpc.testnet.chain.robinhood.com",
        "TAPEHOUSE_NETWORK": "46630"
      }
    }
  }
}

Where each host keeps this file and how it names the key are in that host's own documentation. Claude Code users can skip it with the plugin, which writes the same server definition.

To run from a clone of the repository:

Shell
make build-apps
TAPEHOUSE_RPC_URL=https://rpc.testnet.chain.robinhood.com TAPEHOUSE_DEPLOYMENTS=deployments/46630.json node packages/mcp/dist/main.js

Environment#

VariableWhat it is
TAPEHOUSE_RPC_URLThe chain's JSON-RPC endpoint, http or https. It may carry an API key. The server never shows it to a client, not even in an error.
TAPEHOUSE_NETWORKThe chain: 4663 (Robinhood Chain), 46630 (its testnet) or 42161 (Arbitrum One). The package carries each chain's registry as it was when published, so a redeploy of a chain's contracts is a new release of the package.
TAPEHOUSE_DEPLOYMENTSThe path of a registry, deployments/<chainId>.json, used instead of TAPEHOUSE_NETWORK. The server refuses an endpoint that serves another chain.
TAPEHOUSE_MAX_SLIPPAGE_BPSThe most slippage a sale or buy-back may state, from 0 to 10,000 basis points. Default 100.
TAPEHOUSE_MAX_CALLS_PER_MINUTEThe most tool calls the server answers in a minute, from 1 to 100,000. Default 120. A call beyond it is refused before it reads anything.

Transports#

Stdio is the default. tapehouse-mcp --http <port> serves Streamable HTTP on the loopback interface; 0 picks a free port and prints it on stderr. It answers 127.0.0.1 only and refuses any other Host or Origin with 403, which stops DNS rebinding and requests from a web page. Any process on the machine can still reach it, and its calls count against the same rate limit. Serving it beyond the machine needs TLS, authentication and a front of your own. createServer, exported by the package, builds the same server for any createMcpHandler deployment.

Conventions#

Every tool is read-only: reads take the chain's state at one block and name it, and the transaction tools return unsigned calls.

  • Amounts are whole numbers of base units as decimal strings. USDG has 6 decimals, WETH and the Stock Tokens 18.
  • Band prices are USD with 8 decimals. Equity and requirements are USD with 18.
  • A position is CROSS or an asset's symbol such as NVDA.
  • Each result is structured content matching the tool's output schema, and the same JSON as text.
  • A prepared transaction names its signer and lists its calls in order, each with to, data, value, the function and its arguments by name. A deposit or repayment is preceded by an approval where the allowance is short.

Tools#

Registry and band#

ToolWhat it returns
registryThe chain's registry: every address the other tools use
band_quote, band_session, band_haltAn asset's band (state, live legs, centre, half-width, edges), the 24/5 session, and its trading halt
band_latest_band, band_sealedThe whole band from the asset's BandFeed, and the band it sealed before a reopen
chainlink_roundA .chainlink feed's latest round, refused where it prices the share and the caller expects the token, or the reverse
morpho_oracleThe price an asset's Morpho Blue oracle answers, or no price and why (stale, halted or sequencerNotSettled), never zero; with its band, tokens, scale, owner and the asset's halt

Baskets#

ToolWhat it returns
baskets_components, baskets_target, baskets_pending_targetA basket's Stock Tokens and address, the target in effect (base units of each token per share), and a target proposed with its seven days' notice
baskets_preview_mint, baskets_preview_redeemWhat minting shares takes of each Stock Token, rounded up, and what redeeming them gives, rounded down
baskets_mint, baskets_redeemA mint of a basket's shares paid in kind, its maxAssets what baskets_preview_mint reads, each Stock Token approved for exactly its part where the allowance is short; and a redemption in kind, with what it gives

Margin accounts: reads#

ToolWhat it returns
accounts_health, accounts_in_basketsA position's equity, requirement and surplus over it; and what it holds of each Stock Token through its baskets
accounts_collateral, accounts_leverageWhat a position holds of a token or of a basket's shares, and its leverage
accounts_liquidation_price, accounts_repayment, accounts_is_authorizedThe price at which a position falls short once it borrows more, what repays it, and whether an address may act for an account
accounts_mandateThe mandate an account gave an agent and where the agent stands against a position. See Mandates
accounts_recoveryWhen the accounts last recorded an asset halted or with a multiplier change pending, and until when a position holding it cannot borrow or withdraw against it

Margin accounts: transactions#

ToolWhat it prepares
accounts_set_authorizationThe call with which an account lets an address act for it, with grants saying everything that lets it do; or the call that stops it
accounts_set_mandateThe call with which an account gives an address a bounded authority until a time, with limits saying what that lets it do; or the call that ends it
accounts_deposit, accounts_withdraw, accounts_borrow, accounts_repayThe margin accounts' calls. A basket's key deposits and withdraws its shares, in the cross position alone
accounts_unwrapThe call that redeems a basket's shares in a cross position into the Stock Tokens they hold, which the position then holds at the same equity and requirement

Shorts#

ToolWhat it returns
shorts_position, shorts_health, shorts_restrictionA short, its health at the band's high edge, and the short-sale restriction after a 10% fall
shorts_deposit, shorts_withdrawThe USDG of a short, in and out
shorts_sell, shorts_coverA short sale and a buy-back. Their limits are Uniswap QuoterV2's quote less or plus the slippage the caller states, within the server's cap. max buys back all a short owes

Gap cover#

ToolWhat it returns
gap_cover_sales, gap_cover_quoteWhether gap cover is on sale, for which closure and until when; and a cover's premium with the writers' USDG it reserves, its smallest deductible, and the weekend gap it prices at
gap_cover_series, gap_cover_position, gap_cover_vaultA series as open, settled with its reference and reopening prices, or void; a cover with what its release credits and the holder's unclaimed USDG; and the writers' vault, with a writer's shares and what it may deposit and redeem now
gap_cover_buyA purchase of gap cover, its maxPremium the quote at the block it reads, the premium approved in USDG for exactly that where the allowance is short. Refused with SalesClosed outside the sales
gap_cover_release, gap_cover_claimThe release of a settled or void cover, which anyone may send, with the payout or refund it credits; and the holder's claim of its credits
gap_cover_deposit, gap_cover_redeemA writer's deposit, approved for exactly its USDG, and redemption. Each is refused beyond what the vault takes now: deposits close at the sales' end, redemptions wait for every cover's release
gap_cover_measureThe measurement of an asset's week for the closure on sale, which anyone may send. Refused with SalesClosed outside the sales and with TooEarlyToMeasure before the week's last day has passed

Trust model#

  • No key. The server signs nothing and reads no key.
  • An authorization grants everything. Once an account signs the call from accounts_set_authorization, the operator can withdraw every collateral token of every margin position and the USDG of every short to any address, borrow USDG to any address, and sell or buy back the account's shorts, until the account signs setAuthorization(operator, false). The tool says so in its description and returns it as grants. Authorize only an address the account controls, and prefer a mandate for an agent.
  • The data is not instructions. Everything a tool returns is a value read from the chain or the registry, and the server's instructions tell the agent so. A revert's text, such as the router's reason, is quoted cut to 200 characters. Any other failure's message, such as a node's, is stripped of control characters and cut to 300. An agent should still treat tool output as untrusted, and a host should keep showing the user what the agent sends.
  • The signer checks the call. A prepared call is only as good as the registry and the RPC behind it. Before signing, check that to is the registry's contract or token, that the function and arguments are what was asked, and simulate it. A wallet that shows decoded calldata shows the same arguments the server lists.
  • Input is validated before any call. Addresses must carry their checksum in mixed case, amounts are whole numbers below 2^256, symbols are at most 32 letters, digits, dots, dashes or underscores, unknown arguments are refused, and slippage stays within the cap the operator sets.
  • Calls are limited. The server answers at most TAPEHOUSE_MAX_CALLS_PER_MINUTE calls a minute over every client together, so an agent caught in a loop cannot spend the endpoint's quota. A call beyond it is a tool error.
  • Annotations are hints. MCP's tool annotations, such as readOnlyHint, are the server's own claims. A host should trust them only as far as it trusts the server.

An agent that borrows, withdraws or trades for an account needs the account's setAuthorization or setMandate first. Without either, the margin accounts and the shorts revert with Unauthorized(caller, account), and the server explains every revert by name and arguments.

Tested with two clients#

packages/mcp/examples/devnode.ts drives the server over Streamable HTTP with the official TypeScript client on the 2026-07-28 protocol, and signs and sends every call it prepares. examples/devnode.py drives it over stdio with the official Python client on the 2025-11-25 protocol. make test-mcp-devnode runs both against a local Nitro dev node. Neither passes the account's key to the server.

Next#