MCP write path and sessions
The write path lets an agent spend, so its threat model is prompt injection, not user error. A user who sets loose limits and loses money made a choice. A user whose agent read an instruction out of a token name did not. The bounds exist so an instruction injected through attacker-controlled data cannot exceed what the user already authorized out of band. They do not restrict what the user can choose to authorize.
The arb path and this session path are unaudited. CovenSession is the contract standing between an attacker-controlled string and a balance, so review it first.
Authority lives in the contract
Section titled “Authority lives in the contract”CovenSession holds the caps on chain: an expiry, a daily trade count, a maximum price impact and slippage, and a proceeds recipient locked to the owner. Caps on size are per input token, so a buy is bounded in USDC and a sell is bounded in the token’s own units. That direction matters: valuing a sell by the USDC it returns would let an agent dump a whole balance for a few dollars after someone crushed the price, and it would count as a few dollars. Bounding the input closes that. The user’s funds stay in the user’s wallet, approved to the session per token. The contract pulls, swaps through CovenRouter, and returns the proceeds to the owner, holding nothing between transactions. Every trade must have USDC on one side, which is how a cap stays denominated in something measurable.
The session key that the server holds is a hot key. It can trade within the caps and nothing more. It cannot change a limit; there is no tool that edits limits and no tool that reveals the key. Only the owner can change a limit, in a transaction the agent cannot produce. Widening a limit takes effect after a delay, which the contract floors at an hour, so a stolen owner key cannot raise a cap and drain in the same block. Narrowing is immediate. Revocation is immediate and permanent: a revoked session is dead, and resuming means creating a new one.
Slippage is measured against the simulation
Section titled “Slippage is measured against the simulation”The session takes the expected output from the simulation step and enforces the trade against it: the realized output must be within the slippage bound of what the simulation saw. The server fills that value from the simulation handle, so the model never chooses it. This is what makes the slippage bound mean something. Enforcing it against a fresh quote taken in the same transaction as the swap would bound the gap between a quote and its own execution, which is zero by construction, and would let someone who moves the price first walk the trade down with it.
Sessions are created through a factory
Section titled “Sessions are created through a factory”A session is a per-user contract that the user approves tokens to, which makes a lookalike a phishing target. CovenSessionFactory is the trust anchor: it creates every session through CREATE2 keyed on the owner and pins the canonical router and lens, so a factory-created session always points at the real contracts. The MCP server refuses any session the factory did not create. Verify a session with factory.isSession(address) before approving tokens to it.
Creating a session is one transaction the owner sends with their own wallet, factory.create, from the app. There is no per-user contract to deploy and no script to run: the factory is deployed once, and each session is a normal wallet call after that. The @covennetwork/mcp package exports createSession and predictSession for the app to wire behind a button, and predictSession returns the address in advance so the UI can show it before the user signs.
session_statusreports the caps, the remaining allowance for the day, and the expiry.swap_simulateis mandatory and binding. It simulates the exact on-chain call and returns a handle. The result goes back into the model’s context before any commit, which is the step that lets a user or a reviewing model catch an injected trade.swap_executetakes that handle plus explicit token addresses and amounts. It never accepts a symbol, because a symbol is attacker-controlled data. It refuses a handle that is stale, that was already used, or whose parameters differ from the simulation in any field. It refuses and explains rather than clamping silently, so the agent can tell the user something true.
The key comes from an environment variable or a keystore file, never a flag, and is never logged or returned by any tool. Bridging is not in the write surface: a session may swap on Arc and nothing else.