Skip to content

Callspec

Stop duct-taping your API stack.

One TypeScript route → typed SDK, docs, OpenAPI, and MCP.

  • Open source

    MIT licensed — free to use and fork.

  • RPC routes

    Methods like getProductById — not bikeshedding REST.

  • Structured errors

    Errors as values with typed codes — no try/catch needed.

  • Test without HTTP

    Unit-test handler(input, ctx) — no server setup.

  • MCP included

    Same routes become Cursor/Claude tools — no second spec.

Most teams duct-tape the same API across REST routes, OpenAPI specs, DIY clients, docs, types, validators and MCP. That's a ton of repetitive work and brittle code that drifts.

GET/api/v2/orgs/acme-corp/teams/platform/products/catalog/items/12345/variants/67890/inventory/snapshots/latest?include=openapi,docs,sdk,mcp,validators,types&expand=errors,metadata&fields=id,name,sku,price,currency,stock,warehouse,supplier,audit&filter[status]=active&sort=-updated_at&page[size]=50&page[cursor]=eyJpZCI6ImN1cnNvciJ9
Duct-taped tech stack — types, errors, OpenAPI, docs, SDKs, and more glued together

How it works

  1. Define

    export const searchPosts = route({
      input,
      output,
      handler: async (inp, ctx) => {
        // your logic
      },
    })
    
    export const api = spec({
      routes: {searchPosts},
    })
  2. Serve

    • MCP/mcp
    • HTTP RPC/v1/*
    • Docs UI/docs
    • OpenAPI/openapi.json
  3. Generate

    npx callspec
    api.searchPosts({…})generated/api.ts
  4. Integrate

    Generate multi-language SDKs and docs from your openapi.json with tools like Fern or Microsoft Kiota.

    • Python
    • Go
    • Java
    • C#

Built-in docs UI

Try-it panels, search, OpenAPI, and MCP connect — shipped with your API, no extra wiring. Whitelabel with your logo, accent, and nav links when you want; the defaults are simple and ready to go.

Chirp docs UI — routes sidebar, Connect MCP panel, Cursor MCP config

Typed SDK from the same spec

Docs, OpenAPI, and MCP share one contract — your frontend gets the same types and error codes, so nothing drifts when routes change.

const result = await api.getProductById({id});

if (!result.ok) {
  if (result.code === 'NOT_FOUND') return null;
  throw result;
}

return result.value; // typed Product

Built for coding agents

Agents call the same routes as your app — mountSpec exposes them as MCP tools with shared validation, auth, and error codes. The explorer ships connect snippets; the package ships a coding-agent skill.

  • MCP from your routes

    Set mcp: true on a route — mountSpec exposes it as a tool with the same validation, auth, and error codes as RPC.

  • Connect from docs

    The explorer home panel ships copy-paste snippets — server URL, bearer hints, and tool names ready for Cursor or Claude.

  • Agent skill included

    The npm package ships SKILL.md so agents follow Callspec conventions — Result errors, callspec.json codegen, route layout.

We do file uploads too

Small files on the same RPC — avatars, CSVs, a PDF. Same handler, same generated client, same auth and errors. The client posts multipart for you.

const result = await api.upload({
  file: input.files[0],
  caption: 'hi',
});

Bring your own auth

Callspec reads the Bearer token from each request. Wire authenticate on your spec to verify it and return context — your existing provider or session logic.

Works with
  • Clerk
  • Auth0
  • GitHub
  • Google
or yours

Need a hand?

Questions, a stuck integration, or just saying hi — join us on Discord.