@olaservo/mcp-wrappers
v0.2.0
Published
Generate typed TypeScript wrappers for MCP tools so agents can call them as code (the "MCP as code" pattern), plus the runtime bridge and a staleness-aware lifecycle.
Downloads
234
Maintainers
Readme
@olaservo/mcp-wrappers
Generate typed TypeScript wrappers for MCP tools so an agent can call them as code instead of over the protocol — the "MCP as code" / code-execution pattern. Ships the generator, the runtime bridge generated code calls, and a staleness-aware lifecycle helper.
What it does
Given an .mcp.json listing one or more MCP servers, the generator:
- connects to each server and lists its tools,
- compiles every tool's input/output JSON Schema into TypeScript interfaces,
- emits one wrapper function per tool under
./servers/<server>/, plus anindex.ts, a pointerREADME.md, and a.metadata.json, and - emits a per-server skill under
./.claude/skills/<server>-server/— aSKILL.mdseed (curated by hand thereafter) and an always-regeneratedreferences/tools.mdcatalog with descriptions and behavior hints.
Each generated wrapper imports callMCPTool from this package's /runtime
export, which maintains a per-server client connection pool and unwraps results
(structuredContent preferred, text/JSON fallback, isError → thrown Error).
Both the generator and the runtime support stdio, static-credential HTTP (headers in config), and OAuth 2.1 HTTP servers (see below).
Install
npm install @olaservo/mcp-wrappers @modelcontextprotocol/sdk@modelcontextprotocol/sdk is a peer dependency.
CLI
# generate wrappers + skills for every server in ./.mcp.json
npx mcp-wrappers generate
# check freshness and regenerate missing/stale wrappers (in-process)
npx mcp-wrappers ensureCommon options: --config=<path>, --output=<dir>, --skills=<dir>,
--timeout=<ms>, --runtime-import=<id>, --no-skill, --no-regenerate,
--quiet. OAuth options: --no-interactive, --callback-port=<n>,
--oauth-store=<dir>. The CLI loads .env from the working directory so ${VAR}
substitution in .mcp.json (e.g. Authorization: Bearer ${GITHUB_PAT}) works.
Server configuration
Each entry under mcpServers in .mcp.json is one of three shapes:
{
"mcpServers": {
// stdio — local subprocess
"local": { "type": "stdio", "command": "my-server", "args": ["--flag"] },
// HTTP with a static credential (PAT/API key)
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp/",
"headers": { "Authorization": "Bearer ${GITHUB_PAT}" }
},
// HTTP behind OAuth 2.1
"guildbridge": {
"type": "http",
"url": "https://guildbridge.modelcontextprotocol.io/mcp",
"auth": "oauth"
}
}
}OAuth 2.1 servers
Set "auth": "oauth" on an HTTP server and the library runs the full
authorization-code + PKCE flow, with dynamic client registration — no
client ID/secret to configure. On first use it:
- registers a client and starts a localhost callback server,
- opens your browser to the authorization page (the URL is also printed, in case the browser doesn't open),
- exchanges the returned code for tokens, and
- caches the client registration + tokens under
~/.mcp-wrappers/oauth/<host>.json.
Subsequent runs are non-interactive — cached tokens are reused and refreshed
automatically via the refresh token, so no browser is needed. This applies to
both generate/ensure (at generation time) and the runtime bridge (at call
time).
For headless environments, pass --no-interactive (CLI) or interactive: false
(API) to fail fast instead of attempting a browser flow. Tune the flow with
--callback-port / --oauth-store (CLI) or the oauth option (API).
Security note: OAuth tokens are cached unencrypted on disk under
~/.mcp-wrappers/oauth/. Treat that directory like any other credential store. Delete a server's file there to force re-authorization.
Programmatic API
import { generateWrappers, ensureWrappers } from "@olaservo/mcp-wrappers";
await generateWrappers({ configPath: "./.mcp.json", outputDir: "./servers" });
const status = await ensureWrappers({ regenerate: true, timeoutMs: 10000 });
if (!status.success) throw new Error(status.errors.join("; "));Generated wrappers import the runtime by a stable specifier:
import { callMCPTool } from "@olaservo/mcp-wrappers/runtime";Override it with runtimeImport (e.g. "../client.js") if you vendor a client.
If your config lives somewhere other than ./.mcp.json, call
configureRuntime({ configPath }) once at startup.
License
Apache-2.0
