All posts

Debugging Claude Connectors: Fix Common Errors in Development and Production

Abe Wheeler
Claude Connectors Claude Connector Testing Claude Connector Framework Claude Apps MCP Apps MCP App Framework MCP App Testing
Debug Claude Connectors locally with the sunpeak inspector before connecting to Claude.

Debug Claude Connectors locally with the sunpeak inspector before connecting to Claude.

TL;DR: Debug Claude Connectors locally with sunpeak’s inspector (sunpeak dev) before connecting to Claude. Most issues fall into six categories: connection failures, tools not being called, UI not rendering, OAuth errors, token limits, and timeouts. This post covers each one with the fix.

You built a Claude Connector. It works locally. You connect it to Claude and something breaks. Maybe Claude ignores your tools. Maybe the UI shows a blank card. Maybe the connection fails silently.

This post covers the errors you’ll actually hit when building Claude Connectors and how to fix each one. If you haven’t built a connector yet, start with the Claude Connectors tutorial.

Debug Locally First

The fastest way to debug a Claude Connector is to not use Claude at all. The sunpeak inspector replicates the Claude runtime on localhost, so you can test tools, resources, display modes, and themes without a paid account or deployment.

pnpm add -g sunpeak
sunpeak new my-connector
cd my-connector
sunpeak dev

Open http://localhost:3000 and select Claude from the Host dropdown. Your connector runs in a local Claude replica with hot reloading and DevTools access.

When you hit a bug in Claude, reproduce it in the inspector first. If you can reproduce it locally, you can fix it without the slow tunnel-and-refresh cycle.

Connection Failures

Symptom: Claude says it cannot reach your connector, or the connector appears disconnected in Settings.

Check the URL format. Claude expects your MCP server URL with the /mcp path suffix. If your server runs on port 8000 and you’re using ngrok:

# Correct
https://abc123.ngrok.io/mcp

# Wrong — missing /mcp
https://abc123.ngrok.io

# Wrong — wrong path
https://abc123.ngrok.io/api/mcp

Check your tunnel. If you’re using ngrok, verify the tunnel is active:

ngrok http 8000

Copy the HTTPS URL from the ngrok output and add /mcp at the end. If ngrok shows 502 Bad Gateway in its web inspector at http://localhost:4040, your MCP server is not running on the expected port.

Check your server is running. Look at your terminal. If you see no output when Claude tries to connect, the server is not receiving requests. Verify the port matches what your tunnel points to.

Check transport type. Claude uses Streamable HTTP transport. If your MCP server only supports stdio transport, Claude cannot connect to it over a URL. sunpeak servers use Streamable HTTP by default.

Team and Enterprise plans. On Team and Enterprise Claude plans, org admins must approve custom connectors before team members can use them. If your connector appears in Settings but you can’t enable it, check with your admin.

Claude Does Not Call Your Tools

Symptom: You ask Claude to use your connector, but it responds with text instead of calling a tool.

This is almost always a tool description problem. Claude decides which tool to call based on the tool’s name, description, and input schema. If the description doesn’t clearly match the user’s request, Claude won’t pick it.

Fix your descriptions. Compare these:

// Bad — too vague, Claude can't match this to a specific request
export const tool: AppToolConfig = {
  title: 'Query Service',
  description: 'Interact with the service',
};

// Good — Claude knows exactly when to call this
export const tool: AppToolConfig = {
  title: 'Search Tickets',
  description: 'Search open support tickets by keyword, status, or assignee. Returns ticket ID, title, status, priority, and assignee for each match.',
};

See Designing Claude Connector Tools for the full guide on descriptions, schemas, and granularity.

Check the connector is enabled. Adding a connector in Settings makes it available, but you need to enable it per conversation. Click the + button in the chat input and select your connector. If you skip this step, Claude doesn’t see your tools.

Check tool count. If you have many connectors enabled with dozens of tools each, Claude has a harder time picking the right one. Disable connectors you don’t need for the current conversation.

UI Not Rendering

Symptom: Claude calls your tool, but the response shows as text instead of rendering your MCP App resource.

Return structuredContent. For a resource to render, your tool handler must return structuredContent, not just text:

// This renders the resource UI
export default async function (args: Args) {
  return {
    structuredContent: {
      title: args.title,
      items: await fetchItems(args.query),
    },
  };
}

// This shows as text — no UI
export default async function (args: Args) {
  const items = await fetchItems(args.query);
  return {
    content: [{ type: 'text', text: JSON.stringify(items) }],
  };
}

Check the resource name matches. Your tool config’s resource field must match the filename (without extension) of a file in src/resources/:

// src/tools/search-tickets.ts
export const tool: AppToolConfig = {
  resource: 'ticket-list',  // Must match src/resources/ticket-list.tsx
  // ...
};

Check the build. Claude’s iframe sandbox blocks HTTP script sources, so it loads your resources from a pre-built production bundle. If the bundle is broken or missing, the resource won’t render. Run pnpm build locally and check for errors:

pnpm build

sunpeak auto-rebuilds when you save a file during development. If you’re connected to Claude via ngrok, sunpeak detects Claude’s user-agent and serves the production bundle automatically. But if the build itself has errors (TypeScript issues, missing imports), the resource will fail silently in Claude.

Check browser DevTools. In Claude, open DevTools (F12) and look for errors in the Console tab. You may need to select the correct iframe context from the console dropdown to see errors from your resource component.

OAuth Errors

Symptom: Users get an error when trying to authenticate with your connector, or the OAuth callback fails.

Allowlist both callback URLs. Claude uses two domains, and your OAuth provider must accept both:

https://claude.ai/api/mcp/oauth_callback
https://claude.com/api/mcp/oauth_callback

Missing one of these is one of the most common issues. Some users access Claude on claude.ai, others on claude.com.

Use authorization code grant with PKCE. Claude does not support pure client credentials flow (machine-to-machine OAuth without user interaction). Your OAuth server must support the authorization code grant type. If you’re using an OAuth provider like Auth0 or Okta, make sure the application type is set to “Regular Web Application” or “SPA,” not “Machine to Machine.”

Provide a test account. If you’re submitting to the Connectors Directory, Anthropic reviewers need a way to test your connector. Provide test credentials or a sandbox environment in your submission.

For the full OAuth flow, see Claude Connector OAuth Authentication.

Token Limit Errors

Symptom: Your tool returns data, but Claude shows an incomplete or empty response.

Claude Connectors have a 25,000 token limit per tool result. If your tool returns more than that, the result gets truncated or dropped entirely.

Paginate large data sets. Instead of returning all records, return a page with a nextCursor field and let the user (or Claude) request the next page:

export default async function (args: { query: string; cursor?: string }) {
  const { items, nextCursor } = await searchItems(args.query, {
    cursor: args.cursor,
    limit: 20,
  });

  return {
    structuredContent: {
      items,
      nextCursor,
      hasMore: !!nextCursor,
    },
  };
}

Return summaries. If the user asked for a list of tickets, return the title, status, and ID. Don’t include the full description, comment history, and audit log for every ticket in the list view. Let a separate get-ticket tool fetch details for a specific ticket.

Use structuredContent for UI. When you return structuredContent, the data goes to your resource component for rendering. The component handles display, so you can keep the payload focused on what the UI needs rather than giving Claude a wall of text.

Timeout Errors

Symptom: The tool call starts but Claude shows an error or the spinner runs indefinitely.

Claude Connector tool handlers must complete within 5 minutes. Most handlers should finish in seconds.

Add timeouts to external requests. If your handler calls a slow API, don’t let it hang:

export default async function (args: Args) {
  const controller = new AbortController();
  const timeout = setTimeout(() => controller.abort(), 30_000); // 30s

  try {
    const data = await fetch('https://api.example.com/data', {
      signal: controller.signal,
    });
    return { structuredContent: await data.json() };
  } finally {
    clearTimeout(timeout);
  }
}

Break large operations into smaller tools. Instead of one tool that does a heavy computation, give Claude a “start” tool that kicks off the work and a “check status” tool that polls for the result. Claude can call the status tool in a follow-up message.

Cache repeated calls. If the same data gets requested multiple times in a conversation, cache it in memory or in a store so subsequent calls return immediately.

Blank Screen in Claude

Symptom: The tool call succeeds and you see the iframe placeholder, but the resource shows a white or empty card.

This usually means a JavaScript error is preventing your component from rendering. The error happens inside Claude’s iframe sandbox, which makes it harder to see.

Check for undefined data. The most common cause is accessing properties on output before data arrives. Always handle the loading state:

import { useToolData, SafeArea } from 'sunpeak';

export function TicketResource() {
  const { output, isLoading, isError } = useToolData<unknown, TicketData>(
    undefined,
    undefined
  );

  if (isLoading) return <SafeArea className="p-4">Loading...</SafeArea>;
  if (isError) return <SafeArea className="p-4">Something went wrong.</SafeArea>;
  if (!output) return null;

  return (
    <SafeArea className="p-4">
      <h1>{output.title}</h1>
    </SafeArea>
  );
}

See MCP App Error Handling for the full pattern with isError, isCancelled, and cancelReason.

Check the production build. Run pnpm build and look for TypeScript errors, missing imports, or bundle size warnings. A component that works in the sunpeak inspector with Vite HMR might fail in the production bundle if it relies on a dev-only import or a node module that doesn’t bundle for the browser.

Test in the inspector with the Claude host. In the sunpeak inspector, select Claude from the Host dropdown. sunpeak replicates Claude’s iframe sandbox behavior, including the production bundle serving. If it works in the inspector’s Claude host but not in real Claude, the issue is likely a network or tunnel problem rather than a code problem.

Useful Debug Commands

Here’s a quick reference for debugging a connector during development:

# Start the inspector with your MCP server
sunpeak dev

# Build the production bundle and check for errors
pnpm build

# Run unit tests
pnpm test

# Run e2e tests against the inspector
pnpm test:e2e

# Start an ngrok tunnel to connect to real Claude
ngrok http 8000

# Check ngrok request logs
# Open http://localhost:4040 in your browser

For automated testing patterns, see the complete testing guide and the CI/CD setup for GitHub Actions.

When to Debug in Real Claude

The sunpeak inspector covers most issues. But some things only show up in real Claude:

  • MCP connection edge cases. Real Claude’s connection layer has retry logic, timeout behavior, and session handling that the inspector simplifies.
  • OAuth in production. The full OAuth redirect flow with Claude’s callback URLs only runs in real Claude.
  • Claude’s iframe sandbox. The inspector replicates the sandbox, but there are occasional differences in CSP headers and script loading.

For these cases, connect to Claude via ngrok and use live tests to automate the validation. Keep your development loop in the inspector and use real Claude for final verification.

Get Started

Documentation →
pnpm add -g sunpeak && sunpeak new

Further Reading

Frequently Asked Questions

Why is my Claude Connector not working?

The most common causes are: MCP server not running, tunnel URL missing the /mcp path, Claude cannot reach your server due to network issues, tool descriptions are too vague for Claude to match, or your tool handler is throwing an error. Start by checking your server terminal for errors, then verify the URL in Claude Settings > Connectors includes the /mcp suffix.

How do I debug a Claude Connector locally?

Use sunpeak to run a local Claude inspector with "sunpeak dev" at localhost:3000. Select Claude from the Host dropdown to test your connector in a replica of the Claude runtime. You get hot reloading, DevTools access, and simulation files for deterministic testing, all without a paid Claude account.

Why does Claude not call my connector tools?

Claude picks tools based on their name, description, and schema. If your description is vague (like "interact with the service"), Claude may not match it to the user request. Write descriptions that say exactly what the tool does and returns. Also check that you enabled the connector for your conversation using the + button in the chat input.

Why is my Claude Connector UI not rendering?

Claude serves MCP App resources from a pre-built production bundle, not a Vite dev server. If your resource does not render, check that your tool returns structuredContent (not just text content), your resource component name matches the tool config resource field, and your build succeeds without errors. Run "pnpm build" locally to verify the production bundle builds cleanly.

How do I fix Claude Connector OAuth errors?

Common OAuth errors include mismatched callback URLs and unsupported grant types. Allowlist both https://claude.ai/api/mcp/oauth_callback and https://claude.com/api/mcp/oauth_callback as redirect URIs. Claude does not support pure client credentials flow (machine-to-machine without user interaction). Use authorization code grant with PKCE.

What is the tool result token limit for Claude Connectors?

Claude Connectors have a 25,000 token limit per tool result. If your tool returns more than 25,000 tokens, Claude truncates or drops the result. Paginate large data sets, return summaries instead of full records, or let the user filter before fetching. Use structuredContent for UI rendering to keep the token payload small.

How do I fix Claude Connector timeout errors?

Claude Connector tool handlers must complete within 5 minutes. If your handler calls a slow API or processes large data, add timeouts to external requests, cache repeated calls, and break large operations into smaller tools. For long-running operations, return a status message immediately and let the user check progress with a separate tool.

Can I use console.log to debug a Claude Connector?

Yes, but where logs appear depends on your environment. In the sunpeak inspector, server-side console.log output appears in your terminal. Client-side logs from resource components appear in browser DevTools. In a real Claude session, server logs appear in your terminal and client-side logs appear in browser DevTools (select the right iframe context in the console dropdown).