How to add customer support to an MCP server

To add customer support to an MCP server, mount three tools inside the server: support_ask answers from your own rules in code, support_open_ticket sends a ticket to a help desk with a context block your server attaches, and support_ticket_status reads the team's reply back. The customer stays in Claude, ChatGPT or Cursor, and nobody describes the problem twice.

The three tools

Step by step

  1. 1. Record each tool call

    In your tool wrapper, keep the last 12 calls per account: tool name, time, duration, ok or not, and the error text. Keep it in process; it is only used to build the context block.

  2. 2. Mount support_ask

    Match the question against rules you already know (credits, connection, permissions, rate limits) and answer with the tool the agent should call next. Make no model call. If no rule matches, say so and point at support_open_ticket. Never invent an answer.

  3. 3. Mount support_open_ticket

    Take a subject, a message, a priority and a category. Add the context block under the customer's words and POST the ticket to your canhelpto workspace with your key and X-Service-Mode: true.

  4. 4. Mount support_ticket_status

    GET the ticket without service mode, so internal notes stay out. Show it only if metadata.mcp.account.userId or the customer email matches the caller.

  5. 5. Tell the agent when to call them

    Add one sentence to your server's instructions, and a support hint to every error body: if this keeps failing, call support_ask; support_open_ticket puts it to the team with this error attached.

The context block

Your server knows what the customer's agent just tried. The customer does not. Attach it, and the person answering sees the failed call next to the question. This is an example block:

- Connector context -
Account: [email protected] · user 7f3e…
Client: claude-user/1.0 · catalogue 1.8.0
Last calls:
- 16:05:00 approve_drafts · 120 ms · FORBIDDEN: managed account

Open the ticket

// support_open_ticket, the part that matters (TypeScript)
const ctx = { account: user, client: { userAgent }, recentCalls: recent.get(user.id) ?? [] };

const res = await fetch("https://canhelpto.com/api/v1/tickets", {
  method: "POST",
  headers: { "X-API-Key": process.env.CANHELPTO_API_KEY!, "X-Service-Mode": "true", "Content-Type": "application/json" },
  body: JSON.stringify({
    summary: input.subject,
    message: input.message + "\n\n" + renderContext(ctx),   // words first, context under them
    customerName: user.name,
    customerEmail: user.email,
    priority: input.priority,
    category: input.category,
    tags: ["mcp", input.category],
    page: "mcp://your-server",
    metadata: { mcp: ctx },                                    // comes back on read
  }),
});

Questions

Does support_ask need a model?
No. It answers from rules in your code. That keeps it fast, free per call and predictable. A question with no matching rule points at the ticket.
What is in the context block?
The account, the client user-agent, your catalogue version and the last tool calls with their errors. It sits under the customer's words in the ticket and also in metadata.mcp.
How does the customer get the answer?
Your team replies in the canhelpto inbox. The reply goes out by email and the customer's agent can read it with support_ticket_status.
Is it free to start?
Yes. The free plan covers one workspace and unlimited tickets. See the pricing page for what Pro adds.

Full contract, REST calls and the TypeScript wrapper: docs for agents. Plans: pricing.