MCP
The @codespar/mcp package runs the CodeSpar MCP server locally over stdio, for clients that cannot reach the hosted server or that want the key in a local environment variable. Install, setup mode, config helpers, troubleshooting.
@codespar/mcp is the CodeSpar MCP server as a local process. It speaks stdio to the client that spawns it (Claude Desktop, Cursor, Windsurf, Claude Code, any MCP host) and proxies every call to the same runtime that serves the hosted server: the same 14 meta-tools, the same policy engine, mandate check and audit chain. Only the transport differs.
Connecting? Start at the hosted server.
Most clients do not need this package. The hosted MCP server is one URL, https://connect.codespar.dev/mcp, with a config snippet per client and no process to run. This page is for the cases where a local process is the better fit:
- the client cannot reach a remote MCP server, or speaks stdio only;
- you want the key in a local environment variable instead of a header or an OAuth grant (Claude Desktop, for example, has no header field);
- you are scoping the tool set with
--servers, which only the local server supports.
Installation
npm install -g @codespar/mcppnpm add -g @codespar/mcpyarn global add @codespar/mcpYou do not need to install globally. The configuration below uses npx, which downloads and runs @codespar/mcp on first use. A global install only removes the npx startup delay.
The one config block
Every stdio host takes the same object; only the file it lives in changes.
{
"mcpServers": {
"codespar": {
"command": "npx",
"args": ["-y", "@codespar/mcp@0.5.14", "serve"],
"env": {
"CODESPAR_API_KEY": "csk_test_your_key"
}
}
}
}| Host | Where the block goes | Then |
|---|---|---|
| Claude Desktop | Settings → Developer → Edit Config opens claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/, Windows: %APPDATA%\Claude\, Linux: ~/.config/Claude/) | Restart Claude Desktop. The hammer icon in the chat input lists the 15 codespar_* tools. |
| Cursor | .cursor/mcp.json in the project, or the global MCP settings (Cmd+,, search "MCP") | Reload the window (Cmd+Shift+P, "Developer: Reload Window"). Tools are available in agent mode. |
| Windsurf | ~/.codeium/windsurf/mcp_config.json | Restart Windsurf or refresh the MCP panel. |
| Claude Code | One command instead of a file: claude mcp add codespar --env CODESPAR_API_KEY=csk_test_your_key -- npx -y @codespar/mcp@0.5.14 serve | The tools are in the next session. |
csk_test_ keys reach the test environment, csk_live_ keys reach production; the key prefix picks the environment and the server is otherwise identical. Keep a project-scoped file with a key in it out of git, or reference an environment variable from your shell profile.
First run and codespar_get_started
You do not need a valid API key just to boot the server. If CODESPAR_API_KEY is missing or invalid, the server starts in a guided setup mode instead of crashing: it stays connected to the client and exposes a single tool, codespar_get_started, that walks the agent through minting a key and validating the connection.
In setup mode the agent can:
- Call
codespar_get_startedto learn why the full tool palette is not loaded (no key, or a key the API rejected with401). - Follow the returned steps to mint a key at Dashboard → API Keys.
- Re-validate: once a working
csk_key is in place and the server restarts, the full meta-tool palette replaces the setup tool.
This means a fresh npx @codespar/mcp serve always produces a usable server; the agent itself can guide the user through the remaining setup instead of surfacing a startup crash. The hosted server does not have a setup mode: without a valid key it answers 401.
Scopes: what the key decides
The server opens a session at boot when the key allows it, and since 0.5.11 it tells a rejected key apart from a missing permission. Since 0.5.13 codespar_payables says the same inside a call: a 403 is answered as insufficient permission (403): … with the API's message naming the scope, and a 401 as credential invalid or revoked (401): …, so an agent whose key lacks only payables:pay keeps uploading and reading instead of treating the key as broken. Nothing is widened on the client side; the API enforces every scope.
| Tools | Scope the key needs |
|---|---|
Commerce tools of a session (codespar_pay, codespar_charge, codespar_discover, wallet, mandates, Shop purchases) | sessions:create, plus tools:execute to call them |
codespar_payables with upload, create_batch, get, update_item | payables:read / payables:write |
codespar_payables with pay | payables:pay |
What the API answers to the session decides the palette:
401(wrong, revoked or expired key): the server boots the setup mode, as before.403(a valid key withoutsessions:create): the server runs without a session.codespar_payablesis offered, since it calls the payables routes directly; the session tools are not, and a call to one of them answers that the key lackssessions:createand thatcodespar_payablesstill works.- Within
codespar_payables, a missing scope is the API's403for that one action (for examplepaywithoutpayables:pay); the key stays valid for the rest.
A key with only the payables scopes therefore gets codespar_payables and nothing else. Before 0.5.11 the server read that 403 as a rejected key, so a payables-only key never saw codespar_payables.
API Reference
The package also exports helpers that build the config block for you, for scripts that provision a developer machine or a CI runner.
getMcpConfig(options): McpConfig
Returns a generic MCP server configuration object that can be used with any MCP-compatible client. This is the base function; the client-specific helpers below call it internally.
import { getMcpConfig } from "@codespar/mcp";
const config = getMcpConfig({
apiKey: process.env.CODESPAR_API_KEY,
servers: ["stripe", "mercado-pago", "correios"],
});
console.log(JSON.stringify(config, null, 2));{
"command": "npx",
"args": ["@codespar/mcp@0.5.14", "serve", "--servers", "stripe,mercado-pago,correios"],
"env": {
"CODESPAR_API_KEY": "csk_live_..."
}
}Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
apiKey | string | Yes | Your CodeSpar API key (csk_live_ or csk_test_) |
servers | string[] | No | MCP servers to connect. Omit to connect all available servers. |
getClaudeDesktopConfig(options): ClaudeDesktopConfig
Returns a configuration snippet ready to paste into Claude Desktop's claude_desktop_config.json. The output is the complete mcpServers block.
import { getClaudeDesktopConfig } from "@codespar/mcp";
const config = getClaudeDesktopConfig({
apiKey: "csk_live_your_key_here",
servers: ["stripe", "asaas", "correios", "twilio"],
});
console.log(JSON.stringify(config, null, 2));{
"mcpServers": {
"codespar": {
"command": "npx",
"args": ["@codespar/mcp@0.5.14", "serve", "--servers", "stripe,asaas,correios,twilio"],
"env": {
"CODESPAR_API_KEY": "csk_live_your_key_here"
}
}
}
}getCursorConfig(options): CursorConfig
Returns a configuration snippet for Cursor's MCP settings file (.cursor/mcp.json).
import { getCursorConfig } from "@codespar/mcp";
const config = getCursorConfig({
apiKey: "csk_live_your_key_here",
servers: ["stripe", "twilio"],
});
console.log(JSON.stringify(config, null, 2));{
"mcpServers": {
"codespar": {
"command": "npx",
"args": ["@codespar/mcp@0.5.14", "serve", "--servers", "stripe,twilio"],
"env": {
"CODESPAR_API_KEY": "csk_live_your_key_here"
}
}
}
}Specifying servers
By default the server connects to all available providers. The --servers flag limits which ones the meta-tools may route to, which is useful for scoping the tool set to a domain:
{
"mcpServers": {
"codespar-payments": {
"command": "npx",
"args": ["@codespar/mcp@0.5.14", "serve", "--servers", "stripe,mercado-pago,asaas"],
"env": {
"CODESPAR_API_KEY": "csk_live_your_key_here"
}
}
}
}You can also run multiple CodeSpar MCP servers with different scopes:
{
"mcpServers": {
"codespar-payments": {
"command": "npx",
"args": ["@codespar/mcp@0.5.14", "serve", "--servers", "stripe,mercado-pago"],
"env": {
"CODESPAR_API_KEY": "csk_live_your_key_here"
}
},
"codespar-logistics": {
"command": "npx",
"args": ["@codespar/mcp@0.5.14", "serve", "--servers", "correios,jadlog,melhorenvio"],
"env": {
"CODESPAR_API_KEY": "csk_live_your_key_here"
}
}
}
}Scoping servers improves tool selection accuracy. When the model has fewer providers to choose from, it makes better decisions about which one to call.
Test and live keys
A csk_test_ key puts the server in the test environment: the sandbox rails for Pix in, Pix out and the wallet ship pre-connected, no real money moves, and provider-backed tools dispatch against the fixtures you declare. Test mode is the reference. Test and live share the same tool interface, so moving to production is a single environment variable change:
{
"mcpServers": {
"codespar": {
"command": "npx",
"args": ["-y", "@codespar/mcp@0.5.14", "serve"],
"env": {
"CODESPAR_API_KEY": "csk_live_your_key_here"
}
}
}
}Troubleshooting
Tools do not appear after restart
- Verify the config file location. The table under The one config block lists the path per host.
- Validate JSON syntax. A missing comma or bracket fails silently. Use
python3 -m json.tool < claude_desktop_config.jsonto validate. - Check that
npxis available. Open a terminal and runnpx --version. If it is not installed, install Node.js 20 or later (@codespar/mcpruns on@codespar/sdk, which declaresengines.node >=20). - Check the API key. It starts with
csk_live_orcsk_test_. Keys are case-sensitive, and a key must match the environment of its project.
MCP server crashes on startup
Check the MCP server logs:
- Claude Desktop: open the developer console (
Cmd+Option+Ion macOS) and look for MCP-related errors. - Cursor: check the Output panel (
Cmd+Shift+U) and select "MCP" from the dropdown.
Common causes:
| Symptom | Cause | Fix |
|---|---|---|
ENOENT: npx not found | Node.js not in PATH | Add Node.js to your shell PATH or use the full path to npx in the config |
INVALID_API_KEY | Wrong or missing API key | Verify the key in your dashboard at Dashboard → API Keys |
EACCES: permission denied | npm cache permissions | Run sudo chown -R $(whoami) ~/.npm on macOS/Linux |
TIMEOUT | Network issues | Check your internet connection and verify api.codespar.dev is reachable |
Tool calls return errors
If the server is running but tool calls fail:
- Check what is connected. Not every provider is connected for every account.
codespar_manage_connectionslists what is, andcodespar_discoverrecommends the tool for a use case. - Verify parameters. Tool call errors often come from missing required parameters. Each tool page carries the argument table generated from the published schema.
- Check rate limits. Test keys have lower rate limits than production keys.
Slow startup
The first run with npx downloads the package, which takes a few seconds. Subsequent runs use the cached version. To eliminate the delay, install globally and point the config at the binary:
{
"mcpServers": {
"codespar": {
"command": "codespar-mcp",
"args": ["serve"],
"env": {
"CODESPAR_API_KEY": "csk_live_your_key_here"
}
}
}
}Pix keys of the account: codespar_wallet
The hosted codespar_wallet carries pix_keys_list, pix_keys_register and pix_keys_delete, and this server relays it as the API publishes it, so the three work here with a test or a live key, with no planner in between. The result names keys by key_id and key_tail, never the value; a deletion is sent only after a second call with confirm: true:
{ "name": "codespar_wallet", "arguments": { "action": "pix_keys_list" } }
{ "name": "codespar_wallet", "arguments": { "action": "pix_keys_register" } }
{ "name": "codespar_wallet", "arguments": { "action": "pix_keys_delete", "key_id": "pk_…" } }
{ "name": "codespar_wallet", "arguments": { "action": "pix_keys_delete", "key_id": "pk_…", "confirm": true } }The rules (the account keeps one key, a paused or closed account refuses the writes) are on the meta-tool page.
Documents on demand: codespar_documents
Since @codespar/mcp 0.5.12 the server carries codespar_documents, which runs over REST with the key alone (no session): action: "receipt" downloads the comprovante of a confirmed payment by receipt_id, as pdf (default) or png; action: "statement" downloads the account statement (extrato) of from..to (YYYY-MM-DD, at most 92 days) as an A4 PDF. With out, the file is written to that local path and the result says where; without it, only the reference (filename, content_type, sha256, api_path) is answered, and nothing in it is a public link. Before the payment is confirmed, receipt answers the API's 409 document_not_final on err.code; generating a document never repeats an operation. The hosted codespar_wallet carries the same two documents as receipt_document and statement_document, answered as references for a chat to turn into downloads; this server relays them as the API publishes them.
{ "name": "codespar_documents", "arguments": { "action": "receipt", "receipt_id": "rcpt_…", "format": "png", "out": "/home/me/comprovante.png" } }
{ "name": "codespar_documents", "arguments": { "action": "statement", "from": "2026-09-01", "to": "2026-09-30", "out": "/home/me/extrato-setembro.pdf" } }What each document carries, and the reconciliation the statement asserts, are on the meta-tool page.
Pay documents and batches: codespar_payables
Since @codespar/mcp 0.5.10 the server carries codespar_payables, the tool behind the cookbook Pay documents and batches: a boleto PDF, a Pix QR image, a Pix key in text or a CSV/XLSX list becomes one batch, the agent reviews what the rail resolved, and pay confirms the exact list by version and list_hash. Extracting never pays. The six journeys of the cookbook, as tool calls:
1. A boleto PDF
{ "name": "codespar_payables", "arguments": { "action": "upload", "path": "/home/me/contas/conta-de-luz.pdf" } }
{ "name": "codespar_payables", "arguments": { "action": "create_batch", "file_ids": ["pfile_…"] } }
{ "name": "codespar_payables", "arguments": { "action": "pay", "batch_id": "pbat_…", "version": 1, "list_hash": "…", "mandate_id": "cm_…" } }upload with a local path exists only on this stdio server, which runs where the files are. Anywhere else, upload with POST /v1/payables/files and pass file_ids. No tool fetches a URL.
2. A Pix QR in an image
{ "name": "codespar_payables", "arguments": { "action": "upload", "path": "/home/me/qr-fornecedor.png" } }
{ "name": "codespar_payables", "arguments": { "action": "create_batch", "file_ids": ["pfile_…"] } }3. A Pix key in text, with the amount the person stated
{ "name": "codespar_payables", "arguments": { "action": "create_batch", "items": [{ "pix_key": "pagamentos@fornecedor.com.br", "amount_minor": 5000 }] } }4. One document, several charges, one completed in the review
{ "name": "codespar_payables", "arguments": { "action": "update_item", "batch_id": "pbat_…", "item_id": "pbl_…", "expected_version": 1, "amount_minor": 32000 } }5. A CSV batch
{ "name": "codespar_payables", "arguments": { "action": "upload", "path": "/home/me/fornecedores-outubro.csv" } }A line over the mandate's caps is refused with its code and the others are paid; a change after confirming answers 409 payable_batch_locked and asks for a new confirmation, with the current batch in error.details.batch.
6. One bill printed with a Pix code and a boleto (contract v1.1, @codespar/mcp 0.5.14)
{ "name": "codespar_payables", "arguments": { "action": "upload", "path": "/home/me/contas/dare-sp.pdf" } }
{ "name": "codespar_payables", "arguments": { "action": "create_batch", "file_ids": ["pfile_…"] } }
{ "name": "codespar_payables", "arguments": { "action": "set_rail", "batch_id": "pbat_…", "item_id": "pbl_…", "expected_version": 1, "rail": "boleto" } }The page's one boleto and one Pix code are ONE item with two ways (Pix first), paid once through rail; set_rail (or update_item with rail) chooses the way, and a way the rail refused is answered 409 payable_item_rail_unavailable with error.details.unavailable. The projection the model reads carries rail_chosen_by, each way's rail and unavailable, and the document's title, due_date and amount_minor, never the page's text.