---
title: "Reusable Patterns for Claude Skills and MCP Tools"
description: "Code-level patterns for Claude Skills and MCP tools — thin tools, fat skills, disclosure ladders, idempotency, and composition that scales."
canonical: https://callsphere.ai/blog/reusable-patterns-for-claude-skills-and-mcp-tools
category: "Agentic AI"
tags: ["agentic ai", "claude", "mcp", "agent skills", "design patterns", "anthropic", "prompt engineering"]
author: "CallSphere Team"
published: 2026-02-18T08:46:22.000Z
updated: 2026-06-06T21:47:44.746Z
---

# Reusable Patterns for Claude Skills and MCP Tools

> Code-level patterns for Claude Skills and MCP tools — thin tools, fat skills, disclosure ladders, idempotency, and composition that scales.

The first MCP server an engineer ships is always too clever. It bundles fetching, filtering, formatting, and a little business logic into one giant tool, and the Skill that drives it reads like a novel. It works, barely. The second one is better, and by the fifth you start to see the patterns that separate agent setups that scale from ones that rot. This post collects those patterns — the reusable shapes for tools, Skills, and context that experienced Claude builders converge on, with enough code to copy.

None of these are exotic. They are the agentic equivalent of "keep functions small" — boring, repeatable, and the reason your tenth integration is faster to build than your first.

## Pattern 1: Thin tools, fat skills

The strongest organizing principle is to keep MCP tools thin and push intelligence into Skills. A tool should do one verifiable thing — `get_order(id)`, `refund_order(id, amount)` — and return structured data. The decision logic — when a refund is justified, what the maximum auto-refund is, whether to escalate — lives in the Skill. This matters because tools are shared infrastructure used by many tasks, while Skills are task-specific judgment. Mixing them means every policy change forces a server redeploy.

```
// Thin tool: no policy, just capability
server.tool("refund_order",
  "Issue a refund for an order. Amount in cents.",
  { orderId: z.string(), amountCents: z.number().int().positive() },
  async (a) => ({ content: [{ type: "text",
    text: JSON.stringify(await issueRefund(a)) }] }));
```

The Skill then says: "Refund automatically up to $50; above that, summarize the case and ask the user to approve." Change the threshold? Edit one line of the Skill, no deploy.

## Pattern 2: The disclosure ladder

Context is your budget, and the disclosure ladder is how you spend it wisely. Structure every Skill in three tiers: a one-line description that is always cheaply visible; a core procedure loaded when the Skill triggers; and bulky reference material kept in separate files the Skill pulls in only when a specific branch needs it. Anthropic's Skills format supports exactly this — a short `SKILL.md` body that can reference larger files on demand.

```mermaid
flowchart TD
  A["Always loaded: name + 1-line description"] --> B{"Task matches?"}
  B -->|No| C["Skill stays dormant, ~0 tokens"]
  B -->|Yes| D["Load core procedure (SKILL.md body)"]
  D --> E{"Branch needs reference?"}
  E -->|No| F["Run with core procedure only"]
  E -->|Yes| G["Pull in reference file on demand"]
  G --> F
```

The payoff is that an agent can carry dozens of Skills at near-zero idle cost. The dormant ones occupy only their one-line descriptions; the expensive content materializes exactly when relevant. Treat every word above the trigger line as permanently rented context and you will design tighter Skills.

## Pattern 3: Return structure, not prose

Tools should return JSON the model can reason over, never pre-formatted English. The temptation is to have the tool produce a nice sentence — "Order 123 was refunded for $40." Resist it. Return `{ orderId: "123", refundedCents: 4000, status: "ok" }` and let Claude compose the prose with full awareness of context. Structured returns chain cleanly: the output of one tool feeds the input of the next without the model parsing free text in between, which is where multi-step agents most often go wrong.

A corollary: design return shapes for the *next* step. If a list tool's results will feed a detail tool, return the IDs in a form the detail tool accepts directly. Small ergonomic choices in return shape compound across long tool chains.

## Pattern 4: Idempotency keys for write tools

Any tool with a side effect should accept an idempotency key, because agents retry. If Claude calls `refund_order`, the network blips, and it retries, you do not want two refunds. Have write tools accept a client-supplied key and dedupe server-side.

```
server.tool("refund_order",
  "Issue a refund. Pass a stable idempotencyKey to make retries safe.",
  { orderId: z.string(), amountCents: z.number().int().positive(),
    idempotencyKey: z.string() },
  async (a) => ({ content: [{ type: "text",
    text: JSON.stringify(await issueRefundOnce(a)) }] }));
```

Then the Skill instructs Claude to derive the key deterministically from the order and reason — so a retry produces the same key and the server returns the original result instead of acting twice. This single pattern eliminates a whole class of agentic disasters.

## Pattern 5: Compose Skills, don't monolith them

Resist the urge to write one mega-Skill that handles your entire domain. Compose several narrow Skills — "refund-policy," "order-lookup," "escalation" — each with a sharp description. Narrow descriptions match tasks more precisely, so the right judgment loads and irrelevant judgment stays dormant. A monolithic Skill either triggers too eagerly (polluting context) or too rarely (because its description tries to cover everything and matches nothing well). Small, single-purpose Skills are to agents what small functions are to code: easier to test, reuse, and reason about.

## Pattern 6: Make tool errors actionable

The last pattern is about the seam between tool and model. Return errors as stable codes with hints, not raw exceptions: `{ error: "INSUFFICIENT_BALANCE", available: 1200 }`. The Skill can then branch on the code deterministically — "if INSUFFICIENT_BALANCE, propose a partial refund of the available amount." A tool that throws a stack trace forces the model to improvise; a tool that fails in a typed, documented way lets your Skill's guidance handle it the same way every time.

## Frequently asked questions

### Should one Skill ever call multiple MCP servers?

Yes, and that is common. A reconciliation Skill might orchestrate a payments server, a ledger server, and a ticketing server. The Skill is the conductor; the servers are independent instruments. Keep each server focused on its own domain and let the Skill sequence them.

### How big should a single tool's input schema be?

As small as the capability requires and no smaller. Prefer a few well-described required parameters over a sprawling options object. If a tool needs ten optional flags, that is usually a sign it should be split into two or three sharper tools.

### Where do I put truly large reference material, like a 40-page policy?

In a file the Skill references, not in the Skill body. The disclosure ladder exists precisely for this: keep the trigger and core procedure lean, and let the Skill pull the heavy document into context only on the branch that needs it.

## Bringing agentic AI to your phone lines

CallSphere builds on these same patterns — thin tools, disclosure ladders, idempotent writes — for **voice and chat**, so AI agents handle every call and message, use tools mid-conversation, and book work around the clock. See it in action at [callsphere.ai](https://callsphere.ai).

---

*Source & attribution: This is an independent, original explainer inspired by Anthropic's coverage on the Claude blog. Claude, Claude Code, Claude Cowork, Claude Opus, and the Model Context Protocol are products and trademarks of Anthropic. CallSphere is not affiliated with or endorsed by Anthropic.*

---

Source: https://callsphere.ai/blog/reusable-patterns-for-claude-skills-and-mcp-tools
