Skip to main content
Glama
Co-Ventech

mcp-server-boilerplate

by Co-Ventech

mcp-server-boilerplate

CI License: MIT

A tested TypeScript starter for building local Model Context Protocol (MCP) servers with the official MCP TypeScript SDK v2.

This template uses the v2 package split, Standard Schema-compatible Zod 4 schemas, the canonical stdio server runner, a real v2 client/server integration suite, MCP Inspector, and automated CI/release workflows.

What is included

Component

Purpose

echo

Minimal read-only tool with v2 structured output

add

Typed numeric input/output and schema validation

server://info

Static JSON resource with server metadata

summarize

Prompt template accepting a text argument

createServer()

Factory for isolated tests and future transports

InMemoryTransport

No-socket v2 client/server integration tests

scripts/rename.mjs

Updates package, lockfile, server name, and GitHub links

GitHub Actions

CI on pushes/PRs and npm provenance release on v* tags

Requirements

  • Node.js 20 or newer

  • npm 10 or newer

The server runtime uses @modelcontextprotocol/server. The test harness uses @modelcontextprotocol/client. The v2 SDK is split into focused packages instead of the v1 monolithic @modelcontextprotocol/sdk package.

Quick start

npm ci
npm test
npm run inspect

npm test compiles the TypeScript source and runs the end-to-end tests. npm run inspect opens the MCP Inspector against the compiled stdio server.

The server speaks stdio, which is the normal transport when a local MCP host launches the server as a child process. Keep protocol traffic on stdout; diagnostic logging belongs on stderr.

Connect to an MCP host

Build the server first:

npm run build

Example Claude Code command:

claude mcp add my-server -- node /absolute/path/to/your-repo/dist/index.js

Equivalent JSON configuration for Claude Desktop, Cursor, Windsurf, or VS Code:

{
  "mcpServers": {
    "my-server": {
      "command": "node",
      "args": ["/absolute/path/to/your-repo/dist/index.js"]
    }
  }
}

After publishing a uniquely named npm package:

claude mcp add my-server -- npx -y your-package-name

Add a tool

Create a registration function in src/tools/, then call it from src/tools/index.ts:

import { McpServer } from "@modelcontextprotocol/server";
import * as z from "zod/v4";

const greetInput = z.object({
  name: z.string().min(1).max(100).describe("Name to greet"),
});

export function registerGreetTool(server: McpServer): void {
  server.registerTool(
    "greet",
    {
      title: "Greet",
      description: "Return a greeting for a person's name.",
      inputSchema: greetInput,
      annotations: { readOnlyHint: true, idempotentHint: true },
    },
    async ({ name }) => ({
      content: [{ type: "text", text: `Hello, ${name}!` }],
    }),
  );
}

Register it explicitly:

import { registerGreetTool } from "./greet.js";

export function registerTools(server: McpServer): void {
  registerEchoTool(server);
  registerAddTool(server);
  registerGreetTool(server);
}

For machine-consumed data, add a v2 outputSchema and return matching structuredContent together with a readable text block. Mark tools with annotations that accurately describe their behavior. Write an end-to-end test for every new tool.

Rename the template

Run this from the repository root. The optional second argument is the GitHub owner:

node scripts/rename.mjs your-package-name your-github-owner

The script updates:

  • package.json name, binary, repository, issue tracker, and homepage;

  • the package-lock root name;

  • src/meta.ts server name;

  • the README title, package references, and repository links.

Use a unique, unscoped npm package name or adapt the repository-name mapping for your organization.

Development commands

npm ci              # install the locked dependency tree
npm run typecheck   # type-check without emitting files
npm run build       # compile TypeScript to dist/
npm test            # build and run node:test integration tests
npm run dev         # watch TypeScript files
npm run inspect     # launch MCP Inspector against dist/index.js

The tests use a real v2 Client, McpServer, and InMemoryTransport pair. They cover tool discovery, v2 annotations and schemas, structured tool results, invalid input, resource reads, and prompt retrieval.

Publish

The package name must be available on npm. Configure an NPM_TOKEN repository secret before publishing. The release workflow runs tests, publishes with npm provenance, and creates a GitHub release when a v* tag is pushed.

npm version patch
git push --follow-tags

Design and safety

This starter is intentionally local and stdio-only. It has no network calls, filesystem access, shell execution, or required API keys. If you add capabilities that access files, commands, or external services:

  • validate every input with a bounded schema;

  • restrict filesystem access to approved workspace roots;

  • use command allowlists and timeouts instead of arbitrary shell input;

  • redact secrets from results and logs;

  • require confirmation for writes or destructive operations;

  • return clear isError: true results for recoverable tool failures.

For a remote multi-client deployment, keep the createServer() factory and add a separately tested Streamable HTTP entry point with authentication and origin protection.

Contributing

See CONTRIBUTING.md. Keep examples small, schemas explicit, tests protocol-level, and stdout reserved for MCP messages.

License

MIT, see LICENSE.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Co-Ventech/MCP-server-boilerplate'

If you have feedback or need assistance with the MCP directory API, please join our Discord server