tool-forge
Provides typed access to GitHub's REST API from within the sandbox, enabling scripts to call operations such as fetching repository info, listing releases, and listing contributors. Supports read-only access by default, optional write operations, host-managed credentials, and search_api for GitHub's large API surface.
Allows interaction with an Immich instance's API from its OpenAPI spec, exposing Immich operations as typed api methods. Supports host-managed API-key authentication via headers, configurable base URL, and audit logging.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@tool-forgeget swamp-club/swamp's 3 latest releases and its top 5 contributors"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
tool-forge
Turn any OpenAPI spec into a code-mode MCP server.
npx -y github:moeealii/tool-forge serve https://petstore3.swagger.io/api/v3/openapi.jsonMost OpenAPI-to-MCP converters give the model one tool per endpoint. Point one at a real API and the model has to pick from hundreds of tools. Every intermediate response lands in its context, and a five-step task takes five round trips.
tool-forge gives the model a typed api object instead, and lets it write the glue:
const owner = "swamp-club", repo = "swamp";
const [info, releases, contributors] = await Promise.all([
api.reposGet({ owner, repo }),
api.reposListReleases({ owner, repo, per_page: 3 }),
api.reposListContributors({ owner, repo, per_page: 5 }),
]);
return {
stars: info.stargazers_count,
latestReleases: releases.map((r) => r.tag_name),
topContributors: contributors.map((c) => `${c.login} (${c.contributions})`),
};Against GitHub's live API, that script made 3 calls in parallel in about half a second. The release data alone was over 52,000 characters of JSON. The model got back the ~400-character answer and nothing else.
Models write code more reliably than they juggle tool calls, and code can loop, branch, join and filter. tool-forge supplies the parts that make that safe against a real service.
How it works
The MCP server exposes one tool, execute. Its description holds TypeScript declarations generated from the spec: one method per operation, with argument and return types, doc comments, and whether it is read-only or destructive:
declare const api: {
/**
* Get a pet
* GET /pets/{petId} · read-only
*/
getPet(args: {
petId: string;
}): Promise<{
id: string;
name: string;
nickname?: string | null;
}>;
};APIs too large to describe in full (GitHub's is 1.3 MB of TypeScript) also get search_api. It ranks operations with BM25 over their summaries, names, tags and paths, folds plurals and maps verb synonyms (add → create), and returns only the matching declarations. Return types are kept compact: the nesting is deep enough to write code against without paying for every field of every nested object.
The model's script runs in a QuickJS WebAssembly sandbox:
The only way out is
api.*. There is nofetch,require, filesystem,processor timers, andapiis frozen.Every
apicall goes back to the host, where credentials, rate limiting, retries and the audit log apply. Secrets never enter the sandbox.Each run has a heap limit (64 MB), a CPU deadline and wall-clock limit (60 s), and a call budget (50). Runaway loops are interrupted, and calls that never return time out.
A failed call throws
ApiErrorwith.statusand.body, so the script can handle a 404 itself. Uncaught errors come back with line numbers that match the script.console.logoutput is returned with the result. Large results are truncated with a hint to return less.
Related MCP server: yamcp
Safety, unchanged from before
Read-only by default.
POST/PUT/PATCH/DELETEoperations don't exist onapiunless you pass--allow-writes. Scope further with--include/--excludeglobs on operationId, tag or"METHOD /path".Secrets stay in the environment.
--auth bearer:GITHUB_TOKENnames a variable, never a value.Polite under load. A shared token-bucket rate limiter, retries with jittered backoff on 429/502/503/504 that honour
Retry-After, and per-request timeouts. APOSTorPATCHis only retried on 429 or a refused connection, never on a 5xx where it may already have been applied.Audit log.
--audit calls.jsonlrecords every API call (secret query values redacted, argument names but not values) and every script run (duration, call count, outcome).
Quick start
tool-forge types ./openapi.yaml # the TypeScript the model will see
tool-forge exec ./openapi.yaml script.js # run a script yourself, exactly as the model would
tool-forge list ./openapi.yaml # operations, access level, and what was skipped and whyClaude Code
claude mcp add github -e GITHUB_TOKEN=ghp_... -- \
npx -y github:moeealii/tool-forge serve \
https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.json \
--auth bearer:GITHUB_TOKEN --header "User-Agent:tool-forge"Claude Desktop, Cursor and other clients
{
"mcpServers": {
"immich": {
"command": "npx",
"args": ["-y", "github:moeealii/tool-forge", "serve", "http://nas.example.com:2283/api/spec.json",
"--base-url", "http://nas.example.com:2283/api", "--auth", "header:x-api-key:IMMICH_API_KEY",
"--audit", "/var/log/immich-mcp.jsonl"],
"env": { "IMMICH_API_KEY": "..." }
}
}
}Options
Flag | Default | |
| first | Relative server URLs resolve against the spec's URL |
| none |
|
| Static header on every request. Repeatable | |
| off | Put state-changing operations on |
| Repeatable | |
| 50 | API calls per script run |
| 60000 | Wall-clock limit per script run |
| 64 | Sandbox heap limit |
| 50000 | Output returned to the model |
| 20000 | Above this many characters of TypeScript, add |
| 5 / 10 | Shared across all calls. |
| 3 | |
| 30000 | Per HTTP request |
| JSON Lines |
How a spec becomes an API
Path, query and header parameters become properties of
args. The request body becomesargs.body. Path-level parameters are inherited and operation-level ones override them.$refs are inlined. Recursive schemas are cut off at the point of recursion.OpenAPI-only keywords are translated or removed:
nullablebecomes| null,readOnlyproperties are dropped from request bodies, andAuthorization/Cookieparameters are never exposed, because auth is injected by the host.Query parameters follow the spec's
style/explode. JSON, form-encoded and text bodies are supported. Operations that needmultipart/form-dataor binary uploads are listed as skipped, with the reason.
As a library
import { apiNames, buildTools, createServer, Executor, loadSpec, runInSandbox } from "tool-forge";
const spec = await loadSpec("./openapi.yaml");
const { tools } = buildTools(spec, { allowWrites: false, include: [], exclude: [] });
const executor = new Executor({ baseUrl: "https://api.example.com", auth: [], rps: 5, burst: 10,
retries: 3, timeoutMs: 30_000, maxResponseChars: 50_000 });
const result = await runInSandbox("return (await api.listPets()).length;", apiNames(tools), executor);
const server = createServer(tools, executor, { name: "pets", version: "1.0.0" });Limits
OpenAPI 3.0 and 3.1. Convert Swagger 2 first, for example with
swagger2openapi.Local
$refs only. Bundle multi-file specs first, for example withredocly bundle.stdio transport only.
Development
npm install
npm test # 47 tests: spec handling, HTTP policy, type generation, sandbox isolation and limits,
# and end-to-end runs where a real MCP client drives the server over stdio
npm run buildMIT licensed.
This server cannot be deployed
Maintenance
Related MCP Connectors
- TypeshipOAuthdev.typeship
Generate a typed SDK, CLI, and MCP server from any OpenAPI or GraphQL spec, and keep them current.
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
Host any HTTP API as a standard MCP server; auto-distribute to 12+ mainstream agent platforms.
Model Context Protocol server for the Apideck Unified API. Connect any MCP-compatible agent framework to 100+ accounting systems, HRIS platforms, file storage providers, and more through one integration. More information https://www.apideck.com/mcp-server
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceTurns OpenAPI specs into MCP tools with secure defaults, risk inspection, confirmation gates, response limits, audit logging, and secret redaction.-
- AlicenseNot gradedqualityDmaintenanceConvert any OpenAPI spec into a secure MCP server with scoped auth, per-tool allow/deny policies, rate limiting, and a redacted audit trail.10 npmMIT
- AlicenseNot gradedqualityBmaintenanceConverts any OpenAPI 3.x spec into a live MCP server, making every endpoint a validated tool that AI agents can call without writing glue code.5 npmMIT
- AlicenseNot gradedqualityCmaintenanceAn MCP server that exposes any OpenAPI REST API via two tools: search for discovering endpoints and execute for making API calls. It uses Code Mode to keep token footprint low and runs user-written JavaScript in a sandbox.6 npm3MIT