Advanced

Running an MCP server

Run your capabilities as MCP tools for Claude, Cursor, and other AI clients.

How it works

Routecraft uses the Model Context Protocol (MCP) to expose capabilities as typed tools. You define the tool as a capability using the mcp() source adapter, run it with craft run, and point your AI client at the process. The AI can then call your tool with validated inputs -- nothing else is accessible.

A capability becomes an MCP tool when you use mcp() as its source: the tool name is the route's .id(), and the .description() and .input() schema live on the route builder so Routecraft can validate every call before any business logic runs. See the MCP example for a complete, copyable capability, and the mcp() adapter reference for the full option surface.

Install

bun add @routecraft/ai zod

Stdio transport (default)

Stdio is the simplest transport. The AI client spawns Routecraft as a subprocess and communicates over stdin/stdout. No networking, no auth required.

Claude Desktop

Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS):

{
  "mcpServers": {
    "my-tools": {
      "command": "bunx",
      "args": [
        "@routecraft/cli",
        "run",
        "./capabilities/search-orders.ts"
      ]
    }
  }
}

Restart Claude Desktop completely after saving. Look for the hammer icon in the input area.

Cursor

Open Cursor Settings > Features > Model Context Protocol, then add:

{
  "my-tools": {
    "command": "bunx",
    "args": [
      "@routecraft/cli",
      "run",
      "./capabilities/search-orders.ts"
    ]
  }
}

Claude Code

Add the following to your .mcp.json (project-level) or ~/.claude/mcp.json (global):

{
  "mcpServers": {
    "my-tools": {
      "command": "bunx",
      "args": [
        "@routecraft/cli",
        "run",
        "./capabilities/search-orders.ts"
      ]
    }
  }
}

HTTP transport

Use the HTTP transport when you want a long-running server that multiple clients can connect to, or when you need authentication. Add mcpPlugin to your config with transport: 'http':

// craft.config.ts
import { mcpPlugin, jwt } from '@routecraft/ai'

export default {
  plugins: [
    mcpPlugin({
      transport: 'http',
      port: 3001,
      auth: jwt({
        secret: process.env.JWT_SECRET!,
        issuer: 'https://idp.example.com',
        audience: 'https://mcp.example.com',
      }),
    }),
  ],
}

Start the server with craft run, then point your AI client at it. Anything reachable over the network must be authenticated: see Securing capabilities for every auth mode (jwt(), jwks(), custom validators, the OAuth 2.1 proxy), identity enrichment, RFC 9728 discovery metadata, and CORS.

Claude Desktop (HTTP)

{
  "mcpServers": {
    "my-tools": {
      "url": "http://localhost:3001/mcp",
      "headers": {
        "Authorization": "Bearer <your-jwt-token>"
      }
    }
  }
}

Cursor (HTTP)

{
  "my-tools": {
    "url": "http://localhost:3001/mcp",
    "headers": {
      "Authorization": "Bearer <your-jwt-token>"
    }
  }
}

Claude Code (HTTP)

{
  "mcpServers": {
    "my-tools": {
      "url": "http://localhost:3001/mcp",
      "headers": {
        "Authorization": "Bearer <your-jwt-token>"
      }
    }
  }
}

Server identity and branding

When a client like Claude adds your server, it renders the server's identity from the MCP initialize handshake. Configure it on mcpPlugin (or the mcp key of defineConfig):

// craft.config.ts
import { mcpPlugin } from '@routecraft/ai'

export default {
  plugins: [
    mcpPlugin({
      name: 'acme-bot',                          // serverInfo.name (machine id)
      title: 'Acme Bot',                         // serverInfo.title (display name)
      version: '2.1.0',                          // serverInfo.version
      description: 'Acme operations over MCP.',  // serverInfo.description
      websiteUrl: 'https://acme.example.com',    // serverInfo.websiteUrl
      instructions: 'Call orders_search before orders_refund.', // initialize.instructions
      icons: [
        { src: 'https://acme.example.com/icon.svg', mimeType: 'image/svg+xml' },
        { src: 'data:image/png;base64,...', mimeType: 'image/png', sizes: ['48x48'], theme: 'light' },
      ],
    }),
  ],
}

instructions is server-wide guidance the client may add to the model's context (advisory per the spec). It complements each tool's own .description(), which is the per-tool equivalent.

Defaults and how to opt out

When you do not set them, Routecraft fills in a "powered by Routecraft" identity. Each default is overridable with your own value or suppressible with an empty value:

FieldDefault when unsetSuppress with
iconsRoutecraft logo (light and dark variants)icons: []
description"Powered by Routecraft.dev"description: ""
websiteUrl"https://routecraft.dev"websiteUrl: ""
instructionsnone (omitted)instructions: ""

Per-tool icons and inheritance

A capability can carry its own icon via the mcp() source. The icon shape follows the MCP Icon spec (src, optional mimeType, sizes as a string array, and an optional theme):

craft()
  .id('orders_search')
  .description('Search orders')
  .from(mcp({
    annotations: { readOnlyHint: true },
    icons: [{ src: 'https://acme.example.com/search.svg', mimeType: 'image/svg+xml', sizes: ['48x48'] }],
  }))

Icons resolve with the same rule at both levels: omit icons to inherit (a tool with no icon of its own shows the server's icon, including the Routecraft default), set icons: [...] for a custom icon, or set icons: [] to show none.

Production

Pin the CLI version so your capabilities do not break on package updates:

{
  "mcpServers": {
    "my-tools": {
      "command": "bunx",
      "args": [
        "@routecraft/cli@2.0.0",
        "run",
        "/absolute/path/to/capabilities/search-orders.ts"
      ]
    }
  }
}

Use absolute paths in production to avoid working-directory ambiguity.


Securing capabilities

Authenticate HTTP endpoints, enrich identity, RFC 9728, CORS.

MCP tool

A copyable capability exposed as an MCP tool.

Calling an MCP

Call external MCP servers from within a capability.

mcp() adapter reference

Full MCP adapter API and options.

Previous
Programmatic Invocation