Troubleshooting & FAQ

Troubleshooting & FAQ

If your question isn't here, the Tool Call Logs are usually faster than support — every tool call has the full request and response captured.


FAQ

About Rutter Connect

What is an MCP server?

Model Context Protocol is an open spec from Anthropic that lets an LLM call tools on a remote server using a standard JSON-RPC interface. Instead of bolting custom function-calling into every app, the model speaks one protocol and the server advertises its tools, schemas, and results.

How is this different from the Rutter REST API?

The REST API is a normalized HTTP interface — write code against one schema, read data from many accounting and commerce platforms. Rutter Connect is an MCP server that exposes the same surface area as tools an AI agent can call directly.

For data sync, integration, or analytics: REST API. For agents that take actions: Rutter Connect. Some teams use both.

What problems does an MCP server have to solve?

A naive MCP server has to solve six things, and Rutter Connect solves all six:

  • Auth — proving the user is who they say they are, and binding the session to the right tenant. Rutter Connect uses Rutter Link for merchant auth and binds connections into MCP sessions automatically.
  • Tool discovery & schemas — advertising what tools exist and their argument shapes.
  • Normalization — when one MCP fronts many backends (e.g. QuickBooks vs. Xero), the model shouldn't see platform quirks. Rutter's unified schema handles this.
  • Rate limits & abuse — the model can call tools in a loop; the server has to throttle.
  • Audit & compliance — every tool call is captured.
  • Write safety — read calls are forgiving; mutations (post a bill, refund an order) are not. Rutter Connect requires explicit confirmation on every write.

Can I use Rutter Connect with non-Anthropic models?

Yes. Rutter Connect exposes tools via MCP, which is model-agnostic. Anthropic's Claude has native MCP support; OpenAI, Gemini, Llama, and others can use MCP through any of the open-source MCP client libraries. The model doesn't matter — what matters is that the agent runtime speaks MCP.


Connections and authentication

Why doesn't the agent re-prompt for auth in chat?

Pre-binding. The merchant authenticates once via Rutter Link in the dashboard. When chat starts, Rutter Connect silently binds those existing connections into a fresh upstream MCP session, so the model never has to interrupt the conversation with a Link flow.

Why two connection slots in one session?

A single MCP session holds two independent active connections — accounting and commerce. This lets an agent answer cross-domain questions in one turn ("compare last month's Shopify orders against what posted in QuickBooks") without juggling auth.

Re-authing replaces only the slot for that domain. The other slot stays intact.

The login_to_rutter response includes a domain_mismatch field if the user picked a platform in the other domain than requested_domain. The slot is still filled; the agent should surface the mismatch and offer a retry on the correct domain.

Is data freshness exposed to the model?

Yes. Sync recency is cached per merchant for ~2 minutes and injected into the system prompt, so the model can say "from QuickBooks, synced 2h ago" without spending a tool call to find out.


Security and compliance

How is auth scoping enforced?

Every chat turn mints a short-lived (5 min) AES-GCM-encrypted bind token containing the merchant ID, scoped to the proxy URL. Anthropic's MCP connector can't proceed without it — no session-cookie reuse, no cross-tenant bleed.

There is no fallback to a default access token on Rutter API calls — that prevents cross-tenant leaks. Every response includes a connection { company_name, connection_id, platform } envelope so the agent can attribute results.

How does the tool allowlist work?

Before any tool call reaches Rutter's upstream, Rutter Connect checks it against an explicit allowlist. Unknown or off-pattern tools get rejected with JSON-RPC -32601. Prompt injection can't smuggle in a tool that isn't on the list.

How does write safety work?

Mutations require an explicit confirmation step. The model is prompted to summarize the action ("Post a $2,140 bill to QuickBooks?") and emit a confirmation sentinel; the write only fires after the user clicks Approve. This is enforced in the system prompt and in tool policy — belt-and-suspenders.

Every write tool is also annotated readOnlyHint: false, with destructiveHint: true for delete/void. Hosts that honor MCP annotations bucket tools automatically.

Are credentials encrypted?

Yes. All stored OAuth tokens, refresh tokens, and platform credentials are encrypted with AES-256 at rest and decrypted only at the moment of injection into outbound calls. Your code (and the model) never sees them.

Where is my data stored?

Tool Call Logs, Audit Trail, credentials, and configuration are stored in encrypted databases in AWS US-East. Encrypted in transit (TLS 1.2+), encrypted at rest (AES-256). Enterprise plans can pin storage to other regions.


Operations

Are there rate limits?

Yes. Sliding-window limits per merchant: 30 chat requests/min, 120 tool calls/min. Returns 429 with Retry-After.

What's captured in the audit log?

Every tool call is logged with 90-day retention:

  • Read args → SHA-256 hash (privacy-preserving)
  • Write args → AES-256-GCM ciphertext, merchantId as AAD (recoverable for incident review)
  • Also streamed to stderr → Vercel Logs → Datadog

Why is my tool call slow?

The Tool Call Logs show a latency breakdown per call — auth resolution, dual-slot session lookup, mapper dispatch, platform round-trip. Most of the time, "slow" is the platform itself. Rutter Connect typically adds 50–200ms over the platform's response time.

Pre-binding has a 15-min upstream cache so the first call eats the 1–3s login_to_rutter cost and subsequent calls reuse the session.

How long are tool calls retained?

90 days on standard plans, longer on Business and Enterprise. Beyond retention, the only path to longer history is bulk CSV export.

How do I rotate the MCP bearer token?

Rutter Connect → Rotate. The old token stops working immediately on rotation — propagate the new token to every agent client before clicking.


Troubleshooting

The errors below cover most of the support volume we see, grouped by where in the flow you'll hit them.

Setup

MCP bearer token returns 401 on every request

Symptom. Calls to https://mcp.rutterapi.com/v1/sse return 401 Unauthorized, or Claude Desktop shows "0 tools".

Cause. Three things to check, in order:

  1. The header format is Authorization: Bearer <TOKEN> — the word Bearer is required and case-sensitive.
  2. The token has been rotated; the dashboard shows the active set under Rutter Connect.
  3. The token is from the wrong environment — sandbox tokens only work against sandbox connections, production tokens only against production.

Fix. Re-copy the token from the dashboard. If you rotated recently, propagate the new value to every agent client that uses it. If you're moving from sandbox to production, swap to a production token and re-bind connections in production.

RUTTER_MCP_URL or ENCRYPTION_KEY missing

Symptom. The proxy fails with "missing environment variable" instead of starting.

Cause. Each environment variable maps to a distinct failure surface — RUTTER_MCP_URL is the upstream Rutter Connect endpoint, ENCRYPTION_KEY is what the proxy uses to mint bind tokens.

Fix. Each gets a distinct error rather than a generic "something went wrong." Pull the missing key from the dashboard's setup page and add it to your env. Restart the proxy.


Authentication

Symptom. The agent calls login_to_rutter(domain="accounting") and gets back a link_url instead of a filled slot.

Cause. The merchant doesn't have an active connection for that domain, so Rutter Connect falls back to opening Link.

Fix. Confirm the merchant linked the platform via Rutter Link in your dashboard before chat started. The dashboard's Connections page shows what's bound for each merchant.

domain_mismatch in the login_to_rutter response

Symptom. The response has requested_domain: "accounting" but domain: "commerce", with domain_mismatch set.

Cause. The merchant picked a platform in the other domain than the agent requested. The slot is still filled; this is a hint, not a hard error.

Fix. The agent should surface the mismatch ("Looks like you linked Shopify but I asked for accounting — want to retry?") and offer a re-call to login_to_rutter for the correct domain.

Connection shows as expired

Symptom. Tool call returns an error indicating the connection's OAuth refresh failed.

Cause. The user's OAuth refresh token is invalid — either expired (rare; most providers issue long-lived refresh tokens) or revoked (the user disconnected the app from the provider's settings).

Fix. The merchant needs to re-run Rutter Link for that connection. If this happens frequently for one platform, check whether the OAuth scopes you're requesting include the offline-access scope the provider needs to issue refresh tokens.


Tool calling

Tool returns operation_not_supported

Symptom. A write tool returns { "success": false, "error": "operation_not_supported", "suggestion": "..." }.

Cause. The platform doesn't support that mutation. Common cases:

  • delete_account on QBO/Xero — accounts can't be hard-deleted; use update_account(status=inactive).
  • delete_journal_entry on NetSuite — posted JEs can't be deleted; reverse the entry instead.
  • update_customer / delete_customer — Rutter doesn't have an endpoint for these on any platform yet.

Fix. The error response includes a suggestion field that tells the agent what to do instead. The agent can recover from these without retry loops.

Tool returns platform_unsupported

Symptom. A list/get call returns { "success": false, "error": "platform_unsupported" }.

Cause. The active connection is on a platform that doesn't expose that endpoint (e.g. estimates on Sage Business Cloud).

Fix. Surface the limitation to the user. The Coverage Explorer shows per-platform support for every endpoint.

Write succeeded but the result is wrong

Symptom. A create_* call returns success, but the record looks wrong in the platform UI.

Cause. The model passed bad arguments. Common cases: missing currency_code on QuickBooks Desktop (auto-defaulted, but you may want to override), unbalanced lines on a journal entry (rejected client-side before the call leaves Rutter Connect), missing platform_data.subsidiary_id on NetSuite multi-entity setups.

Fix. Open the call in Tool Call Logs, inspect the arguments JSON. Tighten the system prompt or guard the agent with get_active_connection before the write so the model knows the active platform.

Tool call timed out

Symptom. A tool call hangs past threshold and the UI shows an amber warning with a "Verify status" button.

Cause. Backend hiccups — ngrok dropouts during dev, slow QuickBooks writes, NetSuite under load.

Fix. Use the Verify status affordance in the UI to check whether the bill actually posted before retrying. Don't just retry blindly on timeouts — many platform APIs aren't idempotent on writes.


MCP client integration

Claude Desktop shows "0 tools"

Symptom. You added Rutter Connect to claude_desktop_config.json and restarted, but no tools appear in the picker.

Cause. The bearer token is wrong, the endpoint is unreachable, or mcp-remote failed to install.

Fix. Open Claude Desktop's MCP logs (Settings → Developer → Open MCP Log Folder). The log shows the connection attempt and any error. The most common fix is ensuring npx and mcp-remote are reachable — Node 20+ is required.

Cursor or Windsurf shows the server but tool calls 401

Symptom. The server appears in the MCP picker but every tool call fails 401.

Cause. The bearer token format in the headers config is wrong. Different clients want headers in different shapes, and some won't pass headers at all unless you use a wrapper.

Fix. Use the mcp-remote wrapper (the same one Claude Desktop uses) for clients that don't support custom headers natively. The wrapper takes the Authorization header as a CLI flag and proxies the connection.

Claude Code config not picking up Rutter Connect

Symptom. You added an entry under mcpServers in ~/.claude.json but the server doesn't show up.

Cause. Claude Code reads .mcp.json in the project directory first, then ~/.claude.json. A project-level config can shadow your global one.

Fix. Check for a .mcp.json in the current project. Either delete it or add the Rutter Connect entry there too.


Still stuck

If your problem isn't here:

  • The Tool Call Logs show the exact request and response for every tool call. Most "the agent didn't do what I expected" issues resolve when you read the actual request the model produced.
  • API Request Logs cover your backend's HTTP calls against the Rutter API — different surface, different error shapes.
  • Open a support ticket from the dashboard. Include the connection ID, the tool name, and a timestamp range — that's enough for us to find your call in our logs.