"We want to make our REST APIs accessible to AI agents." Since April, requests like this have skyrocketed. The catalyst was Block (formerly Square) enabling MCP support across its entire payment and inventory API suite. Merchants can now ask Claude, "What were our fish taco sales last month?" and receive a sales breakdown via the Square API. That user experience sent shockwaves through the industry.
As reported in ProofX's research article, a major movement to rewrap existing business APIs with MCP servers is gaining momentum, led by global fintech innovators. In this article, we organize design patterns for turning existing REST/GraphQL APIs into MCP servers as practical guidelines for custom development projects.
Why simple API wrappers are not enough
"Just auto-generate an MCP server from our OpenAPI spec." This is the initial solution almost everyone considers, yet it almost always fails. There are three key reasons:
- Tool explosion: A single SaaS application often exposes hundreds of endpoints, causing AI agents to get lost when selecting tools
- Verbose schemas: Passing raw OpenAPI responses directly to the model causes token consumption to balloon dramatically
- Missing explanations of side effects: Understanding exactly what "DELETE /users/{id}" removes requires reading external documentation
As we discussed in our migration guide to Drizzle ORM, "machine-readable" does not equal "AI-friendly". When building MCP servers, tool definitions must be redesigned by humans based on actual use cases.
Four design patterns
When implementing MCP servers for clients, our team selects from the following four patterns based on the characteristics of the project:
Pattern A: Use-case aggregated pattern (recommended)
Consolidate multiple underlying APIs into a single tool exposed around a specific business use case.
// NG: 自動生成された薄いラッパー
tools: [
"get_customer", "get_order", "get_invoice",
"list_payments", "list_refunds", "list_disputes" // … 100 個続く
]
// OK: ユースケース集約
tools: [
{
name: "summarize_customer_billing",
description: "顧客の請求状況サマリ(請求・入金・未収・係争中)を取得",
arguments: { customer_id: "string", period: "string?" }
}
]
Inside a tool like "summarize_customer_billing", the server calls multiple internal APIs sequentially and shapes the response. To the AI, it appears as a single tool, minimizing both token consumption and round trips.
Pattern B: SDK wrapper pattern
For APIs backed by mature official SDKs (such as Stripe, Salesforce, or GitHub), re-export SDK methods directly as MCP tools.
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_KEY);
server.tool("create_customer", async (args) => {
return await stripe.customers.create(args);
});
The advantage is delegating authentication, retries, and rate limiting to the SDK. The drawback is the potential explosion of tools, which is mitigated by establishing a strict whitelist beforehand.
Pattern C: GraphQL query builder pattern
For internal services that already expose GraphQL APIs, having the MCP server pass query fragments is highly efficient. The AI selects only the necessary fields, retrieving just the required data.
server.tool("graphql_query", {
description: "社内 GraphQL に対し、許可されたフィールドのみクエリ実行",
schema: ALLOWLISTED_SCHEMA,
});
However, make sure to enforce strict query depth and complexity limits. Real-world incidents have shown AI inadvertently generating massive N+1 queries that crash production databases.
Pattern D: Event stream pattern
A pattern where state changes are delivered to the AI via webhooks or Server-Sent Events (SSE). Implemented as an MCP Resource, it feeds contextual updates to the AI on a scheduled basis. Ideal for inventory alerts, incident notifications, and system status changes.
Schema shaping for token optimization
Passing raw JSON returned by APIs directly to AI causes token usage to escalate to unsustainable levels. Introducing a three-stage shaping process on the MCP server is standard practice.
| Shaping step | Target reduction | Examples |
|---|---|---|
| Removing unnecessary fields | 30〜50% | Discarding duplicate metadata such as created_at_unix |
| Shortening enumerated values | 10〜20% | "PAYMENT_STATUS_SUCCEEDED" → "ok" |
| Summarizing into tabular format | 50〜80% | Summarizing 100 raw records into a 5-line Markdown table |
The cost optimization principles we detailed in our production guide for pgvector apply directly to shaping MCP server responses.
Designing operations that require HITL (human approval)
For destructive, financial, or external-facing operations, it is safest to design MCP tools that can enter a "pending confirmation" state.
server.tool("send_invoice", async (args, ctx) => {
if (!ctx.userApproved) {
return {
kind: "approval_required",
summary: `${args.customer} に ¥${args.amount} の請求書を送ります`,
approval_token: issueApprovalToken(args),
};
}
return await invoiceClient.send(args);
});
The client UI displays an approval button, and upon confirmation, the tool is re-invoked accompanied by approval_token. This design reflects the standard HITL approach for autonomous agents, which we also highlighted in our guide on integrating Anthropic Computer Use into business workflows.
Summary — APIs are shifting from being called by code to being invoked by AI
Historically, APIs were designed with the expectation of being called by humans via frontend interfaces or batch jobs. With the advent of MCP, however, systems must be redesigned with the assumption that they will be invoked in natural language by AI agents.
Deciding which pattern (A through D) to adopt depends not on how many APIs you have, but on where you draw the line regarding what AI is authorized to execute—such as what to exclude from your whitelist and which operations require HITL checkpoints. Because these decisions depend on existing API architectures and internal approval flows, there is no universal template. If you describe the scale of your current endpoints and the initial use cases you want accessible via natural language in our inquiry form, we can help you determine the best place to start.








