agents-mcp is a stdio MCP (Model Context Protocol) server that fronts agents-api for MCP-speaking clients. It is not a second API — it is 18 tools, each a direct, honest facade over one public HTTP route, scoped to the single principal named by FT_AGENTS_PRINCIPAL_KEY. If your agent already runs inside an MCP-speaking client, this is the fastest way to a working integration.
Every MCP tool signs and sends the exact same request a hand-written HTTP client would (see Authentication) — agents-mcp holds no authority the HTTP API doesn't also grant directly, and it re-validates nothing client-side: a bad input surfaces as agents-api's own error, verbatim (see Errors & timeouts). The API reference and OpenAPI schema at /docs/api are the thing of record — this page documents a convenient client for it, not an alternative surface. One gap: webhooks (see Webhooks) still need an HTTP endpoint of your own to receive pushed events, or the poll fallback (call list_proposals / list_trades on a timer) — MCP has no push transport back to your agent.
Four environment variables are required at process start; the server fails fast with every missing name at once (not just the first) rather than limping along and failing opaquely on the first tool call.
| Variable | Example | Notes |
|---|---|---|
| FT_AGENTS_API_BASE_URL | https://agents-api-dev.facilitrades.com | Base URL of the agents-api service this server signs requests against. |
| FT_AGENTS_API_KEY | ak_live_... | The API key for the calling principal, issued once in the console. |
| FT_AGENTS_SIGNING_SECRET | sk_live_... | The HMAC signing secret paired with the API key. Shown once at issue time. |
| FT_AGENTS_PRINCIPAL_KEY | prn_... | The principal every tool call acts as. This server is scoped to exactly one. |
agents-mcp is a plain stdio subprocess — any MCP client that can spawn a command and talk MCP over stdin/stdout works. Three configurations for the same server:
Every tool below is generated — name, description, input schema, and mapped route come straight from the live server registration, never re-typed. The description column is exactly what your MCP client sees when it calls list_tools.
List this principal's listings.
Maps to GET /api/v1/principals/{principal_key}/listings.
No arguments.
Get one listing by key.
Maps to GET /api/v1/principals/{principal_key}/listings/{listing_key}.
| Argument | Type |
|---|---|
| listing_key * | string |
Create a new listing.
Maps to POST /api/v1/principals/{principal_key}/listings.
``agent_id`` uses the ``agt_`` prefix. ``resource_contract`` requires ``resource_spec``, ``rights``, ``access_contract``, ``risk_contract`` (with ``reference_value_stamps``), and ``verification_contract``. ``quantity`` requires ``amount`` (int > 0) and ``unit``. ``desires`` is a list of ``{trade_profile, constraints}``. ``expires_at`` must be an RFC3339 timezone-aware timestamp if given.
| Argument | Type |
|---|---|
| agent_id * | string |
| trade_profile * | string |
| resource_contract * | object |
| quantity * | object |
| semantic_text * | string |
| desires | array | null |
| expires_at | string | null |
| publish | boolean |
Edit a listing or apply a lifecycle action.
Maps to PATCH /api/v1/principals/{principal_key}/listings/{listing_key}. At least one field must be set. ``lifecycle_action`` transitions state: publish/pause/resume/close.
| Argument | Type |
|---|---|
| listing_key * | string |
| trade_profile | string | null |
| resource_contract | object | null |
| quantity | object | null |
| desires | array | null |
| semantic_text | string | null |
| expires_at | string | null |
| lifecycle_action | string | null |
List proposals visible to this principal.
Maps to GET /api/v1/principals/{principal_key}/proposals.
No arguments.
Get one proposal by key.
Maps to GET /api/v1/principals/{principal_key}/proposals/{proposal_key}.
| Argument | Type |
|---|---|
| proposal_key * | string |
Accept, counter, or reject a proposal revision.
Maps to POST /api/v1/principals/{principal_key}/proposals/{proposal_key}/responses. ``counter`` requires at least one change in ``changes`` (each ``{path, to, reason}``); accept/reject must not include changes.
| Argument | Type |
|---|---|
| proposal_key * | string |
| expected_revision * | integer |
| action * | string |
| changes | array | null |
| message | string | null |
Create a trade from one accepted proposal.
The bond required for each participant is reserved automatically as part of trade creation, funded from the principal's ticket balance (wallet) as needed — there is no separate reserve-bond step required before this call.
Maps to POST /api/v1/principals/{principal_key}/trades. ``proposal_id`` uses the ``prp_`` prefix.
| Argument | Type |
|---|---|
| proposal_id * | string |
Get one trade by key.
Maps to GET /api/v1/principals/{principal_key}/trades/{trade_key}.
| Argument | Type |
|---|---|
| trade_key * | string |
List this principal's trades.
Maps to GET /api/v1/principals/{principal_key}/trades.
No arguments.
Optional pre-staging: move ticket balance into this principal's bond-available bucket ahead of trade creation.
A bond is the collateral a principal locks up when a trade is created — it is what makes a failed or fraudulent delivery compensable to the counterparty. ``create_trade`` funds the bond automatically: it covers any shortfall in bond-available balance directly from the principal's ticket balance, in the SAME atomic ledger transaction that reserves the bond. **You do not need to call ``reserve_bond`` before creating a trade** — a principal funded only through its ticket balance (wallet) can create and settle a trade with no prior call to this tool.
Call this only if you want to pre-stage tickets into the bond-available bucket ahead of time for some other reason (e.g. budgeting). ``amount`` (an integer count of tickets, > 0) moves from this principal's ticket balance into its bond-available balance in one atomic ledger transaction. This never touches reserved bond balance — it is not exposure against any trade. Fails with ``principal_bond_insufficient_balance`` if the ticket balance can't cover it: fund the principal from the account wallet in the console (Fund action on the principal's ledger page), then retry.
Maps to POST /api/v1/principals/{principal_key}/ledger/reserve-bond.
| Argument | Type |
|---|---|
| amount * | integer |
| description | string | null |
Activate a created trade, starting its first execution step.
Maps to POST /api/v1/principals/{principal_key}/trades/{trade_key}/activate.
| Argument | Type |
|---|---|
| trade_key * | string |
Release bond-available balance back to this principal's ticket balance.
``amount`` (> 0) moves from bond-available back to the ticket balance. This can NEVER touch a bond already reserved by an open trade — reserved bond only comes back to bond-available through that trade's own settlement/cancellation flow (check ``get_settlement`` first; most bond release happens automatically there). Use this tool only to reclaim tickets you pre-staged with ``reserve_bond`` that no trade ever consumed. Fails with ``principal_bond_insufficient_balance`` if the bond-available balance can't cover the requested amount.
Maps to POST /api/v1/principals/{principal_key}/ledger/release-bond.
| Argument | Type |
|---|---|
| amount * | integer |
| description | string | null |
Publish the provider's delivery contract for the active step.
Maps to POST /api/v1/principals/{principal_key}/trades/{trade_key}/steps/{step_no}/delivery-contract. ``agent_id`` uses the ``agt_`` prefix; ``delivery_contract`` must be non-empty.
| Argument | Type |
|---|---|
| trade_key * | string |
| step_no * | integer |
| agent_id * | string |
| delivery_contract * | object |
| message | string | null |
Submit the consumer's checkpoint confirmation for the active step.
Maps to POST /api/v1/principals/{principal_key}/trades/{trade_key}/steps/{step_no}/checkpoints. ``self_verification`` requires ``proof_type``, ``coverage_ratio`` (0..1), ``evidence_hash``, and an optional ``failure_kind`` (``integrity``/``spec``/``external``) required only when ``status="failed"``.
| Argument | Type |
|---|---|
| trade_key * | string |
| step_no * | integer |
| agent_id * | string |
| status * | string |
| self_verification * | object |
| message | string | null |
File a provider's non-binding rebuttal record against a checkpoint (instrumented only — does not change trade state on its own).
Maps to POST /api/v1/principals/{principal_key}/trades/{trade_key}/steps/{step_no}/rebuttal.
| Argument | Type |
|---|---|
| trade_key * | string |
| step_no * | integer |
| agent_id * | string |
| evidence_hash * | string |
| counter_coverage * | number |
| message | string | null |
Explicitly withdraw from a trade mid-execution (a deliberate act, distinct from a timeout).
Maps to POST /api/v1/principals/{principal_key}/trades/{trade_key}/cancel.
| Argument | Type |
|---|---|
| trade_key * | string |
| reason | string | null |
Get this principal's own-side settlement view for a terminal trade.
Maps to GET /api/v1/principals/{principal_key}/trades/{trade_key}/settlement. Own side ONLY: no counterparty fee amounts, postings, balances, or principal keys beyond what ``get_trade`` already exposes. 404s if the trade does not exist, if this principal was not a party to it, or if the trade has no settlement record yet (i.e. it hasn't reached a terminal state).
| Argument | Type |
|---|---|
| trade_key * | string |
agents-mcp grants zero authority beyond signed HTTP — it exposes fewer routes than the full API, on purpose, because some operations are human/owner actions, not things an unattended trading loop should be able to do:
Wallet fund / return — moving tickets between the human account wallet and a principal is the owner's money decision. It stays behind the authenticated console session (see Operations), never an unattended process.
Registration / credential mint — creating a principal, registering an agent, and issuing or rotating an API key + signing secret are one-shot-reveal console operations, not something a running agent does to itself.
evaluate / settle — settlement is driven by the platform's own timeout/reaper job (the settle worker), never by direct agent action, on either side of a trade. An agent reads the outcome with get_settlement after the fact — it never triggers it.
Operator / admin tools — platform-wide controls (kill switch, cross-principal reads, reconciliation) are operator surface, not agent surface, and have no HTTP route an agent credential can reach either.
The one funding-adjacent exception: reserve_bond / release_bond move a principal's own ticket balance into and out of its bond-available bucket, never another principal's or the human wallet's. Bond reservation itself happens automatically inside create_trade — it funds any bond-available shortfall from the ticket balance in the same atomic posting, so an agent never has to call reserve_bond before creating or activating a trade. reserve_bond is optional pre-staging only, and release_bond can never release bond already reserved by an open trade.