FrontMCP vs the official MCP TypeScript SDK

The official MCP TypeScript SDK is the Model Context Protocol project's own implementation of the protocol: a server library, a client library and adapters for a few web frameworks. FrontMCP is a framework for building servers, and it uses the SDK's protocol layer underneath. With the SDK you write the server around the protocol; with FrontMCP you declare tools, apps, providers and auth, and FrontMCP runs the protocol for you. This page explains what each one is, what FrontMCP uses from the SDK, when the SDK alone is the better choice, and what FrontMCP adds, with the same server written in both.

This site documents FrontMCP, so read it knowing who wrote it. Every SDK fact below comes from the SDK's own documentation, repository and npm entries for v2.3.1, checked on 2026-10-10, and links to them. Every FrontMCP fact links to the page on this site that shows FrontMCP 1.9.4 doing it.


What the official SDK is

The SDK lives in the modelcontextprotocol/typescript-sdk repository, under the MCP project's GitHub organization; its npm packages name Anthropic, PBC as the author. Version 2 is the current line. Its README calls it "the stable release line, implementing the 2026-07-28 MCP spec", and its roadmap says v2.0.0 was released on 2026-07-27, alongside that revision of the spec. The MCP conformance suite runs against the 2025-11-25 and 2026-07-28 revisions on every push.

v2 is split into packages (Packages), as published on 2026-10-10:

PackageVersionWhat it's for
@modelcontextprotocol/server2.3.1McpServer, tools, resources, prompts, createMcpHandler() for HTTP, serveStdio()
@modelcontextprotocol/client2.3.1Client, transports, OAuth for clients
@modelcontextprotocol/core2.3.1The protocol's wire schemas, shared by both
@modelcontextprotocol/node, express, hono, fastify2.0.1 to 2.1.1Thin adapters that mount a server in Node's http module or in one of those frameworks
@modelcontextprotocol/server-legacy2.3.1A frozen copy of v1's HTTP+SSE server transport and authorization-server helpers, deprecated
@modelcontextprotocol/codemod2.3.1v1-to-v2, which rewrites a v1 project for v2

v1, the single package @modelcontextprotocol/sdk, is the maintenance line (1.32.1 on 2026-10-10). Its README says it implements the spec up to 2025-11-25, that "support for the 2026-07-28 spec is not planned for v1.x", and that it gets bug fixes and security updates for at least six months after v2's release (v1.x README).

The v2 packages have been Apache-2.0 since 2.3.0 and were MIT before; the repository's LICENSE explains the transition. v1 is MIT. The SDK needs Node 20 or later (Build your first server), and its README says it runs on Node, Bun and Deno.

It's used far more than anything else on this list. On 2026-10-10 the repository had 13,543 GitHub stars (GitHub API), and in the week of 2026-10-02 to 2026-10-08 npm counted 65,440,256 downloads of v1's @modelcontextprotocol/sdk and 10,051,078 of @modelcontextprotocol/server (npm API). FrontMCP had 146 stars and 8,479 downloads of @frontmcp/sdk in the same week.

What FrontMCP uses from it

FrontMCP 1.9.4 is built on v1 of the SDK, not v2. Every import of the SDK goes through one internal package, @frontmcp/protocol, which pins @modelcontextprotocol/sdk to exactly 1.29.0 (its package.json at v1.9.4). From the SDK, FrontMCP takes (index.ts):

  • The protocol's types and Zod schemas for every request, result and notification, from @modelcontextprotocol/sdk/types.js.
  • The low-level Server class, for clients that open a session with initialize (2025-11-25 and earlier). FrontMCP registers its own handler for each MCP method on it; it doesn't use McpServer or registerTool().
  • The server transports: Streamable HTTP, for Node and for web-standard runtimes, and stdio.
  • InMemoryTransport, which links a client to a server in the same process, behind connect().
  • The Client and its Streamable HTTP, SSE and stdio transports. FrontMCP uses it to reach remote servers and in connect(), and @frontmcp/testing re-exports it as McpClient.

FrontMCP writes the rest itself: everything from your decorators to those handlers, the older HTTP+SSE server transport, auth, and the whole of MCP 2026-07-28, because the v1 SDK doesn't have it. Its 2026-07-28 types say so in their header (types-20260728.ts), and the stateless request handling, server/discover and a client for that revision are in transport/mcp-20260728. So both projects serve 2026-07-28, with separate implementations.

The same server in both

One tool, add, that takes two numbers and returns their sum.

With the official SDK

This is the shape of the SDK's Build your first server guide with the add tool in place of its weather tool, as we ran it with @modelcontextprotocol/server 2.3.1, zod 4.6.5 and tsx, after npm pkg set type=module:

src/index.ts
import { McpServer } from '@modelcontextprotocol/server';
import { serveStdio } from '@modelcontextprotocol/server/stdio';
import * as z from 'zod/v4';

function createServer(): McpServer {
    const server = new McpServer({ name: 'hello', version: '1.0.0' });

    server.registerTool(
        'add',
        {
            description: 'Add two numbers',
            inputSchema: z.object({ a: z.number(), b: z.number() })
        },
        async ({ a, b }) => ({
            content: [{ type: 'text', text: String(a + b) }]
        })
    );

    return server;
}

void serveStdio(createServer);
console.error('hello MCP server running on stdio');

npx tsx src/index.ts runs it over stdio. Over HTTP, the HTTP guide builds a handler from the same kind of factory, here mounted on Node's http module with @modelcontextprotocol/node 2.1.1:

src/http.ts
import { createServer } from 'node:http';

import { localhostHostValidation, localhostOriginValidation, toNodeHandler } from '@modelcontextprotocol/node';
import { createMcpHandler, McpServer } from '@modelcontextprotocol/server';
import * as z from 'zod/v4';

const handler = createMcpHandler(() => {
    const server = new McpServer({ name: 'hello', version: '1.0.0' });
    server.registerTool(
        'add',
        {
            description: 'Add two numbers',
            inputSchema: z.object({ a: z.number(), b: z.number() })
        },
        async ({ a, b }) => ({ content: [{ type: 'text', text: String(a + b) }] })
    );
    return server;
});

const nodeHandler = toNodeHandler(handler);
const validateHost = localhostHostValidation();
const validateOrigin = localhostOriginValidation();
createServer((req, res) => {
    if (!validateHost(req, res) || !validateOrigin(req, res)) return;
    void nodeHandler(req, res);
}).listen(3201, '127.0.0.1');

console.error('hello MCP server on http://127.0.0.1:3201/mcp');

A client from @modelcontextprotocol/client 2.3.1 called add with { "a": 2, "b": 3 } twice: once with the default initialize handshake, and once with versionNegotiation: { mode: "auto" }, which asks for 2026-07-28 first:

legacy 2025-11-25 {"content":[{"type":"text","text":"5"}]}
modern 2026-07-28 {"_meta":{"io.modelcontextprotocol/serverInfo":{"name":"hello","version":"1.0.0"}},"content":[{"type":"text","text":"5"}]}

2026-07-28 is opt-in on both sides. The SDK's guide to it says that "a hand-constructed Client / Server / McpServer keeps speaking the 2025-era protocol", and that serving 2026-07-28 "is always an explicit opt-in" (2026-07-28 protocol support). createMcpHandler() and serveStdio() are those entry points, and they serve 2025-era clients too: both servers above answered every revision we tried, 2024-11-05 to 2026-07-28. The README's shorter example, server.connect(new StdioServerTransport()), answered the four 2025-era revisions and not 2026-07-28.

With FrontMCP

The same tool in a FrontMCP server, with an app that lists it. The Playground runs it and calls add, and the Tests tab runs the checks:

Open
import { App, FrontMcp, Tool, ToolContext, z } from "@frontmcp/sdk";

@Tool({
  name: "add",
  description: "Add two numbers",
  inputSchema: { a: z.number(), b: z.number() },
})
export class Add extends ToolContext {
  async execute({ a, b }: { a: number; b: number }) {
    return { sum: a + b };
  }
}

@App({ id: "calc", name: "Calculator", tools: [Add] })
export class CalcApp {}

@FrontMcp({ info: { name: "calc", version: "1.0.0" }, apps: [CalcApp] })
export default class Server {}

Starting FrontMCP in your browser…

FrontMCP starts when this example comes into view.

The differences in this small case:

  • The SDK builds the server in a function you write; FrontMCP builds it from the classes you list. Neither needs you to touch JSON-RPC.
  • Results. The SDK's tool returns MCP content blocks. FrontMCP's returns a plain object, which arrives as structuredContent with a text copy (Your First Tool).
  • Running it. The SDK's server is a script tsx runs, with no build step. FrontMCP needs Node 24 or later and TypeScript's decorator settings (Installation); tool() and app() are forms without decorators. In Node, importing the @FrontMcp class starts an HTTP server (FrontMcpInstance), runStdio() serves it over stdio, and frontmcp dev runs it while you work.
  • Revisions. Like the SDK's createMcpHandler(), FrontMCP serves 2024-11-05 to 2026-07-28 on one endpoint (Error codes).
  • Size. On 2026-10-10, npm install @modelcontextprotocol/server installed 3 packages (the server, core and zod) in 16 MB; npm install @frontmcp/sdk installed 126 packages in 61 MB.

When the SDK alone is the better choice

  • You're building a client, a host or a gateway. @modelcontextprotocol/client connects to any server, negotiates the protocol revision, and handles OAuth for users and machines (OAuth). FrontMCP's clients on this site are for calling your own server's tools in-process (connect()) and for serving a remote server's tools from a FrontMCP server (Remote servers).
  • The server is small and you want few dependencies. A handful of tools in one file, three packages, plain functions, no decorators or reflect-metadata, and Node 20 rather than 24.
  • You want to follow the specification closely. v2.0.0 shipped with the 2026-07-28 revision, the conformance suite runs on every push, and the other libraries compared here build on the SDK. FrontMCP builds on v1 and implements 2026-07-28 itself.
  • MCP is one route in an app you already have. The adapters mount a server in Express, Hono, Fastify or Node's http module, and createMcpHandler() returns a web-standard fetch handler for Workers, Deno and Bun (Web-standard runtimes).
  • You want a schema library other than Zod. Schemas are Standard Schema: Zod 4, ArkType, Valibot, or plain JSON Schema through fromJsonSchema().
  • Your identity provider issues the tokens. The SDK makes your server an OAuth resource server: requireBearerAuth() with a verifier you write, protected resource metadata and scope step-up per tool (Authorization).

What FrontMCP adds

Each row links to the lesson that teaches it and the reference page that covers it.

You needThe SDK v2FrontMCP 1.9.4
Tools organised as the server growsregisterTool() calls in a factory (Tools)@Tool classes grouped in @Apps, several apps on one server: Grouping Capabilities into Apps, @App, Apps, discovery and splitting
Shared services, like a database clientModule-scope objects the factory closes over (HTTP)Providers with scopes, read with this.get(): Sharing State with Providers, @Provider
Code that runs around every callNot documented on the serverHooks and plugins: Hooking into Calls, Extending with Plugins, Hooks
Rate limits, concurrency caps, timeoutsNot documentedPer tool or server: Limiting and Timing Out Calls, Guard options
Sign-inA resource-server gate; the authorization-server helpers are frozen in server-legacy, and the docs say to "use a dedicated identity provider" (Authorization)Five modes, from static keys and JWT checks to FrontMCP as the OAuth server, with its own sign-in page or an upstream provider: Authenticating Clients, Auth modes
Who may call whatScope checks per tool with scopeChallengeRules on tools, resources and prompts: Deciding Who Can Call What, Authorities
TestsAn in-process client against the handler's fetch (Testing)@frontmcp/testing with MCP matchers and fixtures, run by frontmcp test: Testing Your Server, Testing
Agents, jobs, workflows, skillsNot documentedYour First Agent, Your First Job, Chaining Jobs into Workflows, Teaching the Model Skills; @Agent, @Job, @Workflow, @Skill
Widgets for MCP Apps hostsA separate official package, @modelcontextprotocol/ext-appsA tool's ui option, which also serves the OpenAI Apps SDK: Your First Widget, Tool UI, Hosts and platforms
Caching tool results on the server, memory, approvals, feature flagsNot documented. The SDK's caching is the freshness hint a server puts on a result, which the client's response cache honours (Caching)Official plugins: Built-in Plugins and Adapters, Plugins
Tools from an OpenAPI specNot documentedWrapping an OpenAPI Service, OpenAPI adapter
A project to start from, and a build per platformA manual setup; the CLI is the codemodfrontmcp create, dev, build for Node, Vercel, AWS Lambda, Cloudflare Workers and more, test: Installation, Deploying Your Server, CLI
Errors the model can read, without leaking internalsTyped protocol errors (Errors)PublicMcpError; other errors hidden in production: Your First Tool, Error classes

The SDK documents things this site doesn't show for FrontMCP, too: completion of prompt arguments with completable() (Completion; FrontMCP's pages show it for resource template parameters), a choice of schema library, mounting in Express, Fastify or Hono with an adapter, and Bun and Deno, which run in its CI.

Side by side

Official SDK 2.3.1FrontMCP 1.9.4
MCP revisions served2024-11-05 to 2026-07-28 through createMcpHandler() and serveStdio(); 2025-era only through a hand-wired transport (Protocol versions)2024-11-05 to 2026-07-28 (Error codes)
Declaring a toolserver.registerTool(name, config, handler)A @Tool class, or the tool() function
SchemasStandard Schema: Zod 4, ArkType, Valibot, JSON Schema; outputSchemaZod 4; outputSchema (Schemas Are Contracts)
Resources, prompts, completions, elicitationAll four (Resources, Prompts, Completion, Elicitation)All four (@Resource, @Prompt, completers, this.elicit)
Transportsstdio, Streamable HTTP (stateless, or with sessions for 2025-era clients); the old HTTP+SSE server only in the deprecated server-legacy (Legacy clients)Streamable HTTP with or without sessions, the older HTTP+SSE, stdio, a Unix socket, in-memory (FrontMcpInstance)
RuntimesNode 20+, Bun, Deno, Cloudflare Workers; adapters for Express, Hono, FastifyNode 24+; builds for Vercel, AWS Lambda, Cloudflare Workers, a browser module (Production build); createFetchHandler() for other runtimes
LicenseApache-2.0 (v2 since 2.3.0); v1 MITApache-2.0

The overview compares every library on the full list of criteria.

How this was checked

On 2026-10-10 we installed @modelcontextprotocol/server 2.3.1 with @modelcontextprotocol/node 2.1.1, ran both servers above, and called add with @modelcontextprotocol/client 2.3.1. We then sent each server an initialize request for every revision from 2024-11-05 to 2025-11-25, and the 2026-07-28 server/discover and tools/call requests. The createMcpHandler() and serveStdio() servers answered all five; a server wired by hand to NodeStreamableHTTPServerTransport, and the README's StdioServerTransport example, answered the four 2025-era revisions only. FrontMCP's side is checked by this page's Playground and its tests. The overview describes the method for every library.