Loomal

Convert an existing API into an MCP server.

Your REST API already does the work — agents just can't find or call it. A thin MCP wrapper fixes that, and the design decision that matters isn't code, it's which endpoints become tools.

If you operate an API, you already have the hard parts: working logic, infrastructure, documentation. What you don't have is reachability from the agent side — Claude, Cursor, and every other MCP client can only call tools exposed over the Model Context Protocol, not arbitrary REST endpoints.

Converting is genuinely thin: an MCP server that translates tool calls into requests against your existing API. The code takes an afternoon. The judgment call — and the thing that decides whether agents use it well — is how you carve your API surface into tools.

Don't map endpoints 1:1

The reflex is to generate one tool per REST endpoint, perhaps straight from an OpenAPI spec. Resist it. A 40-endpoint API becomes a 40-tool server that overwhelms the model's tool selection and exposes plumbing (auth refresh, pagination cursors, batch variants) no agent should reason about.

Design tools around tasks instead. An agent doesn't want list_orders, get_order, and get_order_items — it wants look_up_order that takes an order number and returns everything relevant in one shot. Five to ten task-shaped tools with crisp descriptions beat an exhaustive mirror of your routes every time, because the tool list is effectively a prompt.

The wrapper

With the TypeScript SDK, each tool is a name, a description the model reads, a zod schema for inputs, and a handler that calls your API. The MCP server holds your API credentials server-side; the agent never sees them.

server.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";

const server = new McpServer({ name: "acme", version: "1.0.0" });

server.tool(
  "search_products",
  "Search the Acme catalog. Returns name, price, and stock per match.",
  { query: z.string(), limit: z.number().int().max(50).default(10) },
  async ({ query, limit }) => {
    const res = await fetch(
      `https://api.acme.dev/v1/products?q=${encodeURIComponent(query)}&limit=${limit}`,
      { headers: { Authorization: `Bearer ${process.env.ACME_API_KEY}` } },
    );
    return { content: [{ type: "text", text: JSON.stringify(await res.json()) }] };
  },
);

Handle auth and errors for a machine audience

Keep upstream credentials in the wrapper's environment, never in tool parameters — an agent will happily echo a parameter called api_key into a chat log. If your API enforces per-user permissions, the wrapper is where you scope what the agent can reach.

Errors deserve more care than usual: the consumer is a model that will read your error text and decide what to do next. Translate a bare 429 into 'rate limit hit, retry after 30 seconds' and a 422 into which field was wrong. Good error strings measurably improve agent recovery; status codes alone don't.

Ship it both ways — and decide what a call is worth

Run the wrapper over stdio for local development and as a remote Streamable HTTP endpoint for everyone else. The remote deployment is the strategic one: it's a URL any agent can connect to without installing anything, and it's the only form that can charge.

Gated with x402, each tool call quotes a price (minimum $0.01 on Loomal), the agent pays in USDC, settlement clears on Base in about two seconds, and your handler runs — payment is secured before your upstream API spends a cycle. If your API already bills humans by subscription, this is the per-call rate card for the machine audience, listed on Loomal where agents can discover it. The platform fee is 5% on settled transactions, currently waived.

FAQ

Can I generate the MCP server automatically from my OpenAPI spec?

Tools exist for it and they're fine for a prototype, but the output mirrors your REST surface — every endpoint, every parameter — which is exactly the 1:1 mapping that confuses agents. Generate to scaffold if you like, then consolidate into a handful of task-shaped tools with descriptions written for a model.

Where do my API keys go?

In the wrapper's environment, server-side. The agent calls the tool; the wrapper attaches credentials when it calls your API. Never accept secrets as tool parameters — anything in a parameter can end up reproduced in model output or logs.

Does wrapping my API change how it's secured or rate-limited?

No — your API keeps its existing controls, and the wrapper is just another client of it. You'll likely want a rate limit on the MCP endpoint itself too, since agents can emit bursts of calls; an x402 payment gate doubles as natural throttling because every call costs the caller money.

How do agents find the wrapped server?

List it. Publishing to the official MCP registry gets it into the ecosystem's indexes, and a Loomal listing adds a live tool list plus, if you attach a priced endpoint, a per-call price agents can pay programmatically. Discovery is the entire reason to wrap an API you already run.

See wrapped APIs in the wild.

Browse the Loomal Index for servers built exactly this way.

Browse the marketplace