MCP Server
@solidus-network/mcp is an MCP (Model Context Protocol) server that exposes Solidus as run-time tools an agent can call — resolve a did:solidus DID, verify a credential, and check, create, or authorize a scoped spend mandate. Point any MCP-compatible client (Claude Code, Cursor, Windsurf, or a custom agent loop) at it over stdio and those become ordinary tool calls.
This is the run-time half of agent-native distribution. The CLI is the install-time half — solidus init --with-mcp wires this server into a project’s .mcp.json in one step.
Install
You don’t install this globally — an MCP client launches it on demand with npx:
npx @solidus-network/mcpClaude Code (.mcp.json)
{
"mcpServers": {
"solidus": {
"command": "npx",
"args": ["-y", "@solidus-network/mcp"],
"env": {
"SOLIDUS_API_KEY": "<your operator key, only needed for create_mandate>"
}
}
}
}Any other MCP client (Cursor, Windsurf, a custom StdioClientTransport) works the same way — it’s a standard stdio MCP server, command: npx, args: ["-y", "@solidus-network/mcp"].
Tools
5 tools, 3 read (no side effects, no auth) and 2 write (side effects; a human should confirm the terms before an agent calls them):
| Tool | Type | What it does |
|---|---|---|
resolve_did | read | Resolve a did:solidus DID document from the Solidus chain. |
verify_credential | read | Verify a Solidus verifiable credential by id against the chain. |
check_mandate | read | Check whether a spend-mandate envelope authorizes a given amount/currency/rail. Pure — no auth, moves nothing. This is the counterparty refusal check. |
create_mandate | write | Issue a scoped spend_mandate credential (bounded by maxAmount/currency/rail/expiresAt) for an agent, on behalf of a principal DID. Returns the checkable envelope — never the private key or credential bundle. |
agent_pay | write | Authorize a payment under a mandate and return the envelope for the caller’s own rail. Settles nothing — a refusal short-circuits and does no further work. |
check_mandate calls the same POST /v1/mandates/check route documented on the Agents API page — the mandate-check flow — and passes authorized/reason through verbatim.
Configuration
All optional except where noted; the server has working defaults for every read tool out of the box.
| Env var | Default | Used by |
|---|---|---|
SOLIDUS_RPC_URL | https://rpc.solidus.network | resolve_did, verify_credential (chain SDK) |
SOLIDUS_AGENTS_URL | https://agents.solidus.network | check_mandate, create_mandate, agent_pay (agents backend) |
SOLIDUS_API_KEY | — | create_mandate only — an operator bearer token. The other four tools need no auth. |
SOLIDUS_SDK_MODE | testnet | Chain SDK mode: testnet (public chain, no key needed for reads), mainnet, or stub (local Postgres-backed simulation for development). |
Quickstart: resolve, refuse, raise, authorize
A mandate bounds what an agent can spend; check_mandate is the refusal a counterparty runs before accepting a payment. This walks resolving a DID, hitting the refusal, then raising the mandate and authorizing:
// 1. Resolve the paying agent's DID
resolve_did({ "did": "did:solidus:testnet:<addr>" })
// → { "did": "did:solidus:testnet:<addr>", "document": { ... }, "resolved": true }
// 2. Issue a mandate capped at 500 TRY
create_mandate({
"agentId": "<agent-id>",
"principalDid": "did:solidus:testnet:<principal-addr>",
"maxAmount": "500",
"currency": "TRY",
"rail": "moka",
"expiresAt": "2026-08-01T00:00:00.000Z"
})
// → { "mandateId": "...", "envelope": "<base64url envelope>", "expiresAt": "2026-08-01T00:00:00.000Z" }
// 3. The counterparty checks a 750 TRY charge against it — over the cap, refused
check_mandate({ "envelope": "<envelope from step 2>", "amount": 750, "currency": "TRY", "rail": "moka" })
// → { "authorized": false, "reason": "amount exceeds mandate limit" }
// 4. Raise the mandate to 1000 TRY
create_mandate({ /* same as step 2, "maxAmount": "1000" */ })
// → { "mandateId": "...", "envelope": "<new envelope>", "expiresAt": "..." }
// 5. agent_pay authorizes the same 750 TRY charge under the raised mandate
agent_pay({ "envelope": "<envelope from step 4>", "amount": 750, "currency": "TRY", "rail": "moka" })
// → { "authorized": true, "envelope": "<same envelope>", "header": "x-solidus-mandate" }Step 5’s envelope and header are what the caller sends to their own payment rail — Solidus’s part ends at authorization. agent_pay settles nothing; no money moves through this package or through Solidus at any point.
Trust boundary
This package is a thin adapter over @solidus-network/sdk (chain reads) and @solidus-network/agent-identity (mandates, credentials). It holds no issuer keys and does no cryptography of its own — credential signing happens in the Solidus backend; trust in a credential is trust in the issuer key, not in this code.
Status
- First release (0.1.0). New package, testnet-grade.
- Solidus L1 is testnet-only — there is no mainnet. DIDs resolve as
did:solidus:testnet:<addr>. Treat anything you create through these tools (DIDs, credentials, mandates) as sandbox data, not a durable production record. - Credential signing (BBS+) has no external security audit yet. Do not protect production-grade value with it.
Next steps
- CLI —
solidus init --with-mcpwires this server into.mcp.jsonfor you - Agents API — the HTTP surface
check_mandate,create_mandate, andagent_paycall underneath - SDK Reference — the packages this server wraps