Skip to main content

MCP Server Scaffolder

Generate MCP server boilerplate in TypeScript or Python from your tool definitions.

100% client-side⛁ data verified 2026-06-11⌁ zero network calls
Language

Tools

server.ts
#!/usr/bin/env node
// issue-tracker — MCP server (stdio). Generated by forg.pro/tools/mcp-server-scaffolder.
//
// Install:  npm init -y && npm install @modelcontextprotocol/sdk zod
//           npm install -D typescript tsx @types/node
// Run:      npx tsx server.ts

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const server = new McpServer({ name: "issue-tracker", version: "0.1.0" });

server.tool(
  "search_issues",
  "Search the issue tracker. Use when the user asks about existing bugs or tickets.",
  {
    query: z.string().describe("TODO: describe query"),
    limit: z.number().describe("TODO: describe limit"),
  },
  async ({ query, limit }) => {
    // TODO: implement — this stub echoes its inputs.
    return {
      content: [{ type: "text" as const, text: `search_issues called with ${JSON.stringify({ query, limit })}` }],
    };
  }
);

server.tool(
  "create_issue",
  "Create a new issue. Use only after confirming the title with the user.",
  {
    title: z.string().describe("TODO: describe title"),
    body: z.string().describe("TODO: describe body"),
  },
  async ({ title, body }) => {
    // TODO: implement — this stub echoes its inputs.
    return {
      content: [{ type: "text" as const, text: `create_issue called with ${JSON.stringify({ title, body })}` }],
    };
  }
);

const transport = new StdioServerTransport();
await server.connect(transport);
console.error("issue-tracker running on stdio");

Client config (Claude Code / Cursor / OpenCode mcpServers block)

{
  "mcpServers": {
    "issue-tracker": {
      "command": "npx",
      "args": [
        "tsx",
        "/absolute/path/to/server.ts"
      ]
    }
  }
}
18
models in the dataset
2026-06-11
reference data verified
100%
logic runs in your browser
0
network requests per keystroke

How it works

Name your server, define your tools — name, description, parameters — and get a complete MCP server you can run immediately, in TypeScript on the official @modelcontextprotocol/sdk or in Python on FastMCP. The output includes install commands, the run command, and the client config snippet that wires it into Claude Code, Cursor or OpenCode. Copy it or download it as a file.

The Model Context Protocol standardizes the boring-but-fiddly part of giving models tools: a JSON-RPC protocol over a transport, capability negotiation, schema declaration and invocation framing. The scaffolder handles all of it so your remaining work is exactly one function body per tool. The generated handlers are honest stubs — they echo their arguments back as text — because pretending to generate your business logic would produce code you would have to untangle. What you get instead is every line of protocol plumbing already correct.

The design choices baked in are the ones that survive production contact. Stdio transport, because local single-user servers should not open network ports. One file, because MCP servers grow by adding decorated functions, not by adding architecture. Explicit parameter descriptions in the schema, because the model chooses tools and fills arguments by reading them — a tool with a vague description gets misused or ignored, and no amount of correct plumbing fixes that. The generated comments mark exactly where descriptions matter.

A scoping tip from teams running many servers: resist the mega-server. Every tool you register is serialized into the model's context on every call, whether invoked or not, so a 20-tool kitchen-sink server taxes every conversation it is attached to. Group tools by domain — one server for your issue tracker, one for your database — and attach only what the session needs. The scaffolder makes spinning up another server cheap precisely so you never feel pressure to overload one.

Frequently asked questions

What exactly does the scaffolder generate?

A complete, runnable single-file MCP server: in TypeScript, an @modelcontextprotocol/sdk server with stdio transport, one registered handler per tool you define, and typed input schemas; in Python, a FastMCP server from the official mcp package with one decorated function per tool. Alongside the code you get the exact install and run commands and a client config snippet, so the path from 'generated' to 'connected in Claude Code' is copy-paste.

TypeScript or Python — which should I pick?

Match your team and your integration surface. The TypeScript SDK is the reference implementation and fits naturally if your tools wrap Node libraries or you ship JavaScript already. FastMCP in Python is remarkably terse — a tool is a decorated function with type hints, and the schema is derived automatically — and wins when your tools wrap Python ecosystems like data science or internal ML services. Functionally both speak identical protocol; clients cannot tell them apart.

What is stdio transport and why is it the default?

The client launches your server as a child process and exchanges JSON-RPC messages over stdin and stdout. No port, no TLS, no auth layer — the process boundary is the security boundary, which is exactly right for local development tools used by Claude Code, Cursor or OpenCode. The alternative, HTTP-based transport, exists for remote servers shared across users, but it brings authentication and deployment concerns you should not take on until you actually need multi-client access.

How do I connect the generated server to Claude Code?

Add an entry to your MCP configuration pointing at the run command — the scaffolder prints the exact JSON snippet for your server name and language. For Claude Code that is a mcpServers block with command and args; Cursor and OpenCode use the same shape in their own config files. After restarting the client, your tools appear in the model's tool list under the names you defined here, with the descriptions you wrote guiding when the model invokes them.

What should I edit after generating?

Each tool handler contains a clearly marked implementation stub that echoes its inputs — replace that with real logic and return your result as text content. Beyond that: tighten the parameter descriptions, since the model selects tools by reading them; add input validation for anything destructive; and keep one server per domain rather than one mega-server, because every tool's schema is loaded into the model's context whether used or not.

Built by FORG — AI cost observability for agentic coding. Free tools, no signup, nothing leaves your browser.

Learn about FORG