Skip to content

Workflow · Agents

Build an MCP Server from Your API

Wrap your REST or GraphQL API as an MCP server so Claude Desktop, Cursor, and any MCP client can call it — write once, use everywhere.

Intermediate2–4 hoursStack: TypeScript or Python, MCP SDK, Your existing REST / GraphQL API
MCPAPIToolsAgents
Edited by The AIKnowHub team · Editorial team

Problem

Your team has useful APIs — CRM, billing, inventory, support tickets — but every AI client needs a custom integration. You end up writing the same GitHub-Slack-DB glue for ChatGPT, Claude, Cursor, and your internal agent.

Final output

A local MCP server (stdio transport) that exposes 5–10 curated tools from your API — with typed inputs, clear descriptions, and read-only resources for common lookups. Works in Claude Desktop and Cursor via a one-line config entry.

Architecture

MCP client (Claude Desktop / Cursor / custom app)
  → stdio transport
  → Your MCP server process
    → Tool handlers (POST /orders, GET /customer/:id, …)
    → Resource providers (recent tickets, account summary)
    → Auth layer (API key / OAuth token from env)
  → Your existing REST / GraphQL API

Step-by-step

  1. 01

    Pick the API surface

    List the 5–10 operations an AI assistant actually needs — not every endpoint. Favor read + safe writes. Skip destructive ops until you have guardrails.

  2. 02

    Scaffold with the official SDK

    Use @modelcontextprotocol/sdk (TypeScript) or mcp (Python). Start from the quickstart template. Register tools with Zod / Pydantic schemas for inputs.

  3. 03

    Implement tool handlers

    Each tool maps to one API call (or a small orchestration). Return structured text or JSON. Handle 4xx/5xx with clear error messages the model can relay to the user.

  4. 04

    Add resources for read-heavy data

    Expose stable lookups as MCP resources — e.g. uri://customers/{id}, uri://docs/onboarding. Resources are cheaper than tool round-trips for context the model should skim.

  5. 05

    Wire auth and config

    Read API base URL and credentials from env vars. Never hardcode secrets. Document required env in a README the client operator can follow.

  6. 06

    Register in Claude Desktop / Cursor

    Add the server to claude_desktop_config.json or Cursor MCP settings. Restart the client. Smoke-test each tool from the chat surface.

What you'll build

An MCP server that wraps your existing API so any MCP-compatible client — Claude Desktop, Cursor, your internal agent — can call it without custom glue per client.

If you haven't read MCP Explained yet, start there. This workflow is the hands-on follow-up.

Why MCP for your API

Before MCP, integrating your billing API into three AI surfaces meant three separate plugins. MCP standardizes the wire format:

  • Tools — actions (create ticket, refund order, search customers).
  • Resources — read-only context (account summary, open incidents).
  • Prompts — reusable templates your server ships to the client.

The client still uses the model's native tool-calling API. MCP just defines where those tools come from.

Step 1 — Curate the surface

Don't mirror your OpenAPI spec 1:1. Ask: what would a helpful coworker need in chat?

Good first tools:

ToolWhy
get_customerEvery support / sales question starts here
search_customersWhen the user has email, not ID
list_open_ticketsContext before drafting a reply
get_orderBilling and fulfillment questions

Defer until v2: bulk exports, admin deletes, anything irreversible.

Step 2 — Scaffold the server

TypeScript (most common for MCP servers):

npm init -y
npm install @modelcontextprotocol/sdk zod

Python:

pip install mcp httpx

Register each tool with a schema the SDK validates before your handler runs. Tight schemas = fewer bad API calls.

Step 3 — Tool handlers

Each handler should:

  1. Validate input (SDK does this if schemas are correct).
  2. Call your API with the user's credentials from env.
  3. Return concise, structured text — not a 50 KB JSON dump unless asked.
  4. On failure, return an actionable error string.

Example response shape:

Customer: Acme Corp (id: cust_8f2a)
Plan: Pro ($299/mo) · 12 seats · renews 2026-07-01
Open tickets: 2 (billing, SSO setup)
Last login: 2026-06-04

The model can quote this directly in chat.

Step 4 — Resources for read-heavy lookups

Tools are for actions and lookups the model chooses. Resources are for data the client can prefetch.

Expose stable URIs:

  • customer://{id} — full account snapshot
  • docs://runbooks/billing — internal markdown your team maintains

Resources shine when the same context gets attached to many conversations.

Step 5 — Auth

Pattern that works:

API_BASE_URL=https://api.yourco.com
API_KEY=sk_live_...

For OAuth SaaS (Linear, Slack, GitHub): complete OAuth once, store refresh token locally, refresh in the server on startup. Never pass tokens through the model's context.

Step 6 — Connect the client

Claude Desktop — add to claude_desktop_config.json:

{
  "mcpServers": {
    "your-api": {
      "command": "node",
      "args": ["/path/to/server/dist/index.js"],
      "env": {
        "API_KEY": "..."
      }
    }
  }
}

Cursor — same shape in MCP settings. Restart after changes.

Smoke-test: ask the client to "look up customer X" and verify the tool call in logs.

Production guardrails

  • Read-only v1 — ship reads first, add writes with dry_run or confirmation.
  • Rate limits — wrap your API client with backoff; the model will retry aggressively.
  • Audit log — append-only local log of tool name + args hash + timestamp.
  • Allowlist — if the API is powerful, restrict which tools appear per environment.

What to build next

Once the base server works:

  • Composite toolsprepare_support_context(customer_id) that fetches customer + tickets + recent orders in one call.
  • MCP prompts — ship "Investigate billing dispute" as a server prompt with embedded tool hints.
  • HTTP transport — host for the team when local stdio doesn't scale.

The platform compounds. Your API becomes a first-class citizen in every AI surface your team uses.

Prompt examples

Copy any of these, replace the placeholders, run.

Tool description template

Tool name: get_customer

Description (for the model):
Fetch a customer record by ID. Returns name, plan tier, MRR, open ticket count, and last login. Use when the user asks about a specific account or before creating a support reply.

Input schema:
{
  "customer_id": { "type": "string", "description": "UUID or external ID" }
}

Rules:
- Read-only. Never mutate data through this tool.
- If customer_id is missing, ask the user — do not guess.

Error message shape

When an API call fails, return text the model can quote:

"API error 404: Customer 'abc-123' not found. Verify the ID or search by email with search_customers."

Avoid raw stack traces. Include the HTTP status, a human sentence, and a suggested next step.

Cost estimate

Line itemApprox. cost
MCP server hosting (local)$0.00
Your API calls (depends on usage)marginal
Dev time (first server)2–4 hours
Maintenance per quarter1–2 hours
Total per run (approx.)~$3.00

Costs depend on model choice, content length, and how aggressively you cache.

Optimizations

  • Start with read-only tools — ship faster, fewer incident classes.
  • Cache GET responses in-memory with a 60s TTL for hot lookups.
  • Use MCP prompts to ship vetted templates ("draft refund reply for customer X").
  • Batch related reads into one composite tool when the model always chains them.
  • Log tool invocations locally — essential for debugging and auditing.

Common mistakes

  • Exposing every endpoint — the model gets confused and users get hurt.
  • Vague tool descriptions — the model calls the wrong tool or hallucinates parameters.
  • No input validation — bad args become 500s your API team has to triage.
  • Putting write tools live without confirmation — add a dry_run flag or human-in-the-loop.
  • Forgetting stdio buffering on Windows — flush stdout after each response.

Frequently asked questions

If you only have one client, plain function calling is fine. MCP pays off when the same tools must work in Claude Desktop, Cursor, Continue, and your custom agent — write once, plug everywhere. See MCP Explained for the full picture.