{
  "schema": "leumas.docs.page/1",
  "id": "skill:expose-as-mcp",
  "slug": "skills/expose-as-mcp",
  "kind": "tools",
  "bucket": "skill",
  "title": "expose-as-mcp",
  "name": "Expose as MCP",
  "eyebrow": null,
  "chip": null,
  "summary": "Turn a Leumas tool, adapter, service or SDK into a distributable, priceable MCP server that any coding agent can call.",
  "keywords": [
    "expose-as-mcp",
    "coding",
    "service",
    "turn",
    "agent",
    "leumas expose as mcp",
    "server",
    "call"
  ],
  "audience": "both",
  "funnel": {
    "product": null,
    "cta": null
  },
  "body": "\n# Expose a capability as an MCP server\n\nLeumas turns its tools into MCP servers so any coding agent (Claude, Cursor, a customer's agent) can\ncall them, and so they can be listed, metered, and **priced** in Leumas Studio. The engine that runs\nthem is `engines/mcp` (from `mcp-server-library`); the SDK that scaffolds them is `packages/mcp-kit`.\n\n## The contract\n\nAn MCP server is a folder under `engines/mcp/mcp-servers/<server-name>/`:\n\n```\nengines/mcp/mcp-servers/<server-name>/\n├─ server.json          # metadata + tool list (+ pricing)\n└─ tools/\n   ├─ <toolA>.js        # export default async function({ ...args }) { return result }\n   └─ <toolB>.js\n```\n\n`server.json`:\n```json\n{\n  \"name\": \"<server-name>\",\n  \"description\": \"What this server does\",\n  \"enabled\": true,\n  \"tools\": [\n    { \"name\": \"<toolA>\", \"description\": \"...\", \"inputs\": [{ \"key\": \"x\", \"type\": \"string\", \"required\": true }], \"price\": 0 }\n  ]\n}\n```\n\nEach tool file default-exports an async function that takes an args object and returns a result. It\nshould be a thin wrapper that calls the underlying capability (an `engines/` adapter, a `services/`\nendpoint, or a `packages/` SDK) — never re-implement the logic.\n\n## Steps\n\n1. **Identify the capability** to expose (an adapter in `engines/domain`, a service endpoint, an SDK).\n2. **Scaffold** with `packages/mcp-kit` (`createServer` / `registerTool`) or by hand from the contract above.\n3. **Wire each tool** to call the real capability (import the `@leumas/*` package or fetch the service). Keep tools thin.\n4. **Auto-registration** — `engines/mcp` (`loadServers.js`) scans `mcp-servers/` on start and exposes\n   `GET /mcp` (list) + `POST /tool` (execute) via `leumas-api`. No manual mounting.\n5. **Validate** — smoke-test the handshake, tool list, and a sample `POST /tool` call (schema + result).\n6. **Distribute & price** in **Leumas Studio**: enable the server, set per-tool `price`, and choose the\n   gate (membership entitlement and/or PassNode usage metering via `packages/auth`).\n\n## Rules\n\n- Tools are **thin adapters** over existing capabilities — no business logic lives in a tool file.\n- Every priced tool is gated through `packages/auth` (membership and/or PassNode) — enforced by the API, not the tool.\n- Keep servers single-purpose; a \"server\" groups related tools for one capability.\n- Distribution: **hosted** (called on Leumas infra) or **copy-paste**. There is no per-server\n  downloadable package — a `@leumas-mcp/<name>` family was described here for a long time and never\n  existed, so anyone who followed that sentence went looking for something that was not there.\n\n## How a stranger's agent actually connects\n\nNot by installing a server per capability. One package — **`leumas-mcp`** on npm\n(`shared/packages/mcp-bridge`, published unscoped with its `@leumas/*` deps inlined) — is a stdio ⇄\nstreamable-HTTP bridge pointed at an install:\n\n```sh\nnpx -y leumas-mcp --url https://api.leumas.tech          # Leumas-hosted\nnpx -y leumas-mcp --url http://localhost:3000            # the customer's own Studio\nnpx -y leumas-mcp --url <origin> --site <id>             # one hosted MCP server\n```\n\nEverything an install exposes reaches the agent through that one connection, so a tool added here\nappears with no release of anything. `pnpm bridge:build` · `pnpm bridge:release` (the gate packs the\ntarball, installs it outside the repo and runs a real `initialize` through it).\n",
  "source": {
    "path": ".claude/skills/expose-as-mcp/SKILL.md",
    "blobSha": "",
    "commit": "",
    "committedAt": "",
    "provenance": "no-git",
    "bytes": 3683,
    "hash": "3662b393899cfedc13f96a4b84094e97a48d14fd"
  },
  "urls": {
    "html": "/p/skills/expose-as-mcp",
    "json": "/docs/skills/expose-as-mcp.json",
    "md": "/docs/skills/expose-as-mcp.md"
  },
  "links": {
    "composes": [],
    "usedBy": [],
    "product": [],
    "howTo": [],
    "skills": []
  }
}
