Comparison
How mcpcraft compares to the raw MCP SDK and other frameworks.
Comparison
See how mcpcraft stacks up against the raw @modelcontextprotocol/sdk and other MCP frameworks.
vs. Raw SDK
The official @modelcontextprotocol/sdk is powerful but requires significant boilerplate. mcpcraft builds on top of it to eliminate repetitive code.
| Task | Raw SDK | mcpcraft |
|---|---|---|
| Server setup | 30+ lines (imports, transport config, capability declaration) | 3 lines |
| Tool registration | Manual schema definition + request handler | server.add(tool({...})) |
| Input validation | Manual type checks in handler | Automatic Zod validation |
| Type inference | Manual type annotations | Automatic from schema |
| Resource templates | Manual URI parsing | Built-in {variable} support |
| File size | Minimal (you write everything) | ~5KB gzipped |
Raw SDK Example (100+ lines)
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
const server = new Server(
{ name: "my-server", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [{
name: "send_email",
description: "Sends an email",
inputSchema: {
type: "object",
properties: {
to: { type: "string" },
body: { type: "string" },
},
required: ["to", "body"],
},
}],
};
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name !== "send_email") {
throw new Error("Tool not found");
}
const { to, body } = request.params.arguments as any;
if (typeof to !== "string" || typeof body !== "string") {
throw new Error("Invalid arguments");
}
return { content: [{ type: "text", text: "Sent!" }] };
});
const transport = new StdioServerTransport();
await server.connect(transport);mcpcraft Equivalent (12 lines)
import { createServer, tool } from "mcpcraft-sdk";
const server = createServer({ name: "my-server" });
server.add(tool({
name: "send_email",
description: "Sends an email",
input: {
to: { type: "string", description: "Recipient" },
body: { type: "string", description: "Content" },
},
run: async ({ to, body }) => {
return { success: true };
},
}));
server.start();vs. Other Frameworks
| Feature | mcpcraft | FastMCP (Python) | MCP SDK (official) |
|---|---|---|---|
| Language | TypeScript | Python | TypeScript |
| Type Safety | Automatic from schema | Via Pydantic | Manual |
| Validation | Zod (built-in) | Pydantic | Manual |
| Transport | stdio (built-in) | stdio + SSE | Manual setup |
| Resource Templates | {variable} URIs | Template URIs | Manual parsing |
| Bundle Size | ~5KB gzipped | N/A | Minimal |
| Learning Curve | Low | Medium | High |
When to Use mcpcraft
mcpcraft is ideal for:
- Quick prototyping — get an MCP server running in minutes
- TypeScript projects — full type safety with minimal annotations
- Production services — built on the official SDK with automatic validation
- Learning MCP — simple API abstracts protocol complexity
- CLI tools — lightweight bundle suitable for CLI distribution
Consider the raw SDK if you need:
- Custom transports beyond stdio
- Fine-grained control over JSON-RPC messages
- Advanced protocol features not yet exposed by mcpcraft
- Non-TypeScript environments