Skip to main content

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.

1 min read
View MarkdownEdit on GitHub
@codespar/mcpv0.5.14

@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/mcp
pnpm add -g @codespar/mcp
yarn global add @codespar/mcp

You 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 block
{
  "mcpServers": {
    "codespar": {
      "command": "npx",
      "args": ["-y", "@codespar/mcp@0.5.14", "serve"],
      "env": {
        "CODESPAR_API_KEY": "csk_test_your_key"
      }
    }
  }
}
HostWhere the block goesThen
Claude DesktopSettings → 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.jsonRestart Windsurf or refresh the MCP panel.
Claude CodeOne command instead of a file: claude mcp add codespar --env CODESPAR_API_KEY=csk_test_your_key -- npx -y @codespar/mcp@0.5.14 serveThe 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:

  1. Call codespar_get_started to learn why the full tool palette is not loaded (no key, or a key the API rejected with 401).
  2. Follow the returned steps to mint a key at Dashboard → API Keys.
  3. 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.

ToolsScope 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_itempayables:read / payables:write
codespar_payables with paypayables: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 without sessions:create): the server runs without a session. codespar_payables is offered, since it calls the payables routes directly; the session tools are not, and a call to one of them answers that the key lacks sessions:create and that codespar_payables still works.
  • Within codespar_payables, a missing scope is the API's 403 for that one action (for example pay without payables: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));
Output
{
  "command": "npx",
  "args": ["@codespar/mcp@0.5.14", "serve", "--servers", "stripe,mercado-pago,correios"],
  "env": {
    "CODESPAR_API_KEY": "csk_live_..."
  }
}

Parameters:

ParameterTypeRequiredDescription
apiKeystringYesYour CodeSpar API key (csk_live_ or csk_test_)
serversstring[]NoMCP 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));
Output
{
  "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));
Output
{
  "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:

Payments only
{
  "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:

Multiple scoped servers
{
  "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:

Production
{
  "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

  1. Verify the config file location. The table under The one config block lists the path per host.
  2. Validate JSON syntax. A missing comma or bracket fails silently. Use python3 -m json.tool < claude_desktop_config.json to validate.
  3. Check that npx is available. Open a terminal and run npx --version. If it is not installed, install Node.js 20 or later (@codespar/mcp runs on @codespar/sdk, which declares engines.node >=20).
  4. Check the API key. It starts with csk_live_ or csk_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+I on macOS) and look for MCP-related errors.
  • Cursor: check the Output panel (Cmd+Shift+U) and select "MCP" from the dropdown.

Common causes:

SymptomCauseFix
ENOENT: npx not foundNode.js not in PATHAdd Node.js to your shell PATH or use the full path to npx in the config
INVALID_API_KEYWrong or missing API keyVerify the key in your dashboard at Dashboard → API Keys
EACCES: permission deniednpm cache permissionsRun sudo chown -R $(whoami) ~/.npm on macOS/Linux
TIMEOUTNetwork issuesCheck your internet connection and verify api.codespar.dev is reachable

Tool calls return errors

If the server is running but tool calls fail:

  1. Check what is connected. Not every provider is connected for every account. codespar_manage_connections lists what is, and codespar_discover recommends the tool for a use case.
  2. Verify parameters. Tool call errors often come from missing required parameters. Each tool page carries the argument table generated from the published schema.
  3. 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.

Next steps

MCP | CodeSpar