Skip to main content
Hosted MCP serverMCP Streamable HTTP

One URL. 15 money tools for Brazil and Latin America.

CodeSpar runs an MCP server you connect to instead of install. Any agent that speaks MCP gets 15 meta-tools to pay, charge, invoice, ship, message and reconcile over Pix, boleto, NF-e and WhatsApp. Every spend is checked against a signed mandate before a provider is called, and lands in an append-only audit ledger.

Hosted MCP server · canonical URL
https://connect.codespar.dev/mcp
Transport
MCP Streamable HTTP (POST JSON-RPC, SSE for streams)
Auth
Authorization: Bearer csk_test_… or csk_live_…, or OAuth 2.1
Discovery
/.well-known/oauth-protected-resource on the same host (RFC 9728)
Session
Provisioned on the MCP initialize handshake; nothing to mint first

The server is the same runtime that backs the REST API and the SDK. There is no MCP-only behaviour: codespar_pay called from Claude Code and codespar_pay called through the SDK's session.execute() hit the same policy engine, the same mandate check and the same ledger. This page is the door for clients that speak MCP; the tool pages under it describe each tool's arguments and actions.

Connect in 60 seconds

Mint a key at Dashboard → API Keys. A new account already has a test project and a csk_test_ key. Then pick your client.

One command. --transport http is the hosted server; no local process is started.

claude mcp add --transport http codespar https://connect.codespar.dev/mcp \
  --header "Authorization: Bearer csk_test_your_key"

Then open a session and ask for the tool list, or say what you want done: "create a R$49.90 Pix charge for the Pro plan". Claude Code picks codespar_charge from the 15 and runs it.

Claude Desktop connects to remote servers through Settings → Connectors → Add custom connector. Paste the URL and connect; the sign-in that opens in the browser is the server's OAuth 2.1 flow, so there is no key to paste.

Custom connector
Name: CodeSpar
Remote MCP server URL: https://connect.codespar.dev/mcp

There is no header field on that path, so a bearer key cannot be used there. To use a key instead, run the same server as a local process with the @codespar/mcp package and put the key in env:

claude_desktop_config.json
{
  "mcpServers": {
    "codespar": {
      "command": "npx",
      "args": ["-y", "@codespar/mcp", "serve"],
      "env": { "CODESPAR_API_KEY": "csk_test_your_key" }
    }
  }
}

Project-scoped in .cursor/mcp.json, or the same object in Cursor's global MCP settings. Cursor sends headers on every request.

.cursor/mcp.json
{
  "mcpServers": {
    "codespar": {
      "url": "https://connect.codespar.dev/mcp",
      "headers": { "Authorization": "Bearer csk_test_your_key" }
    }
  }
}

Reload the window and the 15 tools appear in agent mode. Keep the file out of git if the key is in it, or reference an environment variable from your shell profile.

Windsurf reads ~/.codeium/windsurf/mcp_config.json. Remote servers use serverUrl.

mcp_config.json
{
  "mcpServers": {
    "codespar": {
      "serverUrl": "https://connect.codespar.dev/mcp",
      "headers": { "Authorization": "Bearer csk_test_your_key" }
    }
  }
}

Restart Windsurf, or refresh the MCP panel, and the tools show up under codespar.

Workspace-scoped in .vscode/mcp.json. VS Code calls the server type http.

.vscode/mcp.json
{
  "servers": {
    "codespar": {
      "type": "http",
      "url": "https://connect.codespar.dev/mcp",
      "headers": { "Authorization": "Bearer csk_test_your_key" }
    }
  }
}

Anything that speaks MCP Streamable HTTP works: the official SDKs, a framework's MCP adapter, or plain HTTP from any language. The server needs the Authorization header on every request and answers JSON-RPC on POST.

TypeScript (@modelcontextprotocol/sdk)
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const transport = new StreamableHTTPClientTransport(
  new URL("https://connect.codespar.dev/mcp"),
  { requestInit: { headers: { Authorization: `Bearer ${process.env.CODESPAR_API_KEY}` } } },
);

const client = new Client({ name: "my-agent", version: "1.0.0" });
await client.connect(transport);

const { tools } = await client.listTools(); // 15 codespar_* tools
const result = await client.callTool({
  name: "codespar_wallet",
  arguments: { action: "balance" },
});
Python (mcp)
import os
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

headers = {"Authorization": f"Bearer {os.environ['CODESPAR_API_KEY']}"}

async with streamablehttp_client("https://connect.codespar.dev/mcp", headers=headers) as (read, write, _):
    async with ClientSession(read, write) as session:
        await session.initialize()
        tools = await session.list_tools()          # 15 codespar_* tools
        balance = await session.call_tool("codespar_wallet", {"action": "balance"})

No SDK at all: the handshake is three POSTs (initialize, notifications/initialized, then tools/list) with Content-Type: application/json and Accept: application/json, text/event-stream. If initialize returns an Mcp-Session-Id header, send it back on the following calls.

What the first call does

The MCP initialize handshake provisions a CodeSpar session for the key; there is no per-user URL to mint. tools/list then returns the 15 meta-tools. Without a valid key the hosted server answers 401 with a WWW-Authenticate header that points at its OAuth discovery document, which is how OAuth-capable clients find the sign-in flow on their own. The local stdio server behaves differently on a bad key: it boots into a setup mode that exposes only codespar_get_started, which walks the agent through fixing the key.

The 15 tools

Each tool is a stable interface over many providers: the agent says what it wants (charge R$249 over Pix, ship 2 kg to Rio, issue an NFS-e) and the router picks the provider, injects the credential server-side and records the call. The tool pages carry the argument table generated from the published schema.

Not sure which one? Ask the server. codespar_discover takes a use case in plain language and returns the tool to call; codespar_get_started returns the ordered happy path for the workspace the key belongs to.

What you need

What it isWhere it comes from
A keycsk_test_ reaches the test environment, csk_live_ reaches production. Same URL; the prefix picks the environment.Dashboard → API Keys. The key must match the environment of its project, otherwise the server answers 401. See Authentication.
A mandate, for anything that spendsA signed spending authority: cap, scope, expiry. codespar_pay, codespar_shop with auto_pay and codespar_crypto_pay are checked against it server-side before any provider is called; a call outside it is refused before money moves.A consent ceremony the person completes in the browser. The server signs the mandate and stores the signature; the agent references it by id and never signs anything. See Wallets and mandates and Directed pay.
A connected provider, for live railsCharges, invoices, shipments and messages dispatch to a provider account you connect (Asaas, Melhor Envio, Z-API and so on).codespar_manage_connections lists what is connected and hands back a dashboard deep link to connect more. Credentials never travel through the agent.

Sandbox

In the test environment the sandbox rails for Pix in, Pix out and the wallet ship pre-connected, so an agent with a csk_test_ key can run the whole buy loop, codespar_shopcodespar_walletcodespar_pay, with no bank connection, CNPJ or KYC, and no real money. Policy, mandate and audit run exactly as in production. Provider-backed tools in test mode dispatch against declared fixtures; Test mode is the reference for that.

Three things called MCP

They share a protocol and nothing else. This page is the first one.

The same 15 tools are also served over stdio by the @codespar/mcp package, for clients that cannot reach a remote server or that want the key in a local environment variable. It is a thin proxy to this server, not a different one.

Next steps

Hosted MCP server | CodeSpar