Skip to main content
Glama
buildfound

MCP Server Template

by buildfound

TypeScript MCP server template

A small, forkable Model Context Protocol server using the official @modelcontextprotocol/sdk 1.x, Zod, strict TypeScript, ESM and Node.js 20+. No API keys or external services required. MIT licensed.

It exposes two tools and one resource:

Capability

Input

Result

add tool

{ "a": 2, "b": 3 }

Text: 5

word_stats tool

{ "text": "Hello hello world!", "top": 1 }

Word count, character count and ranked words, as JSON text and schema-validated structuredContent

info://server resource

Resource URI

JSON with package name, version and tool names

word_stats defaults to five top words (range 1–20). Words are runs of Unicode letters/numbers, normalized to NFC and lowercased; punctuation separates words. Ties sort by word using JavaScript string order, without locale-dependent collation. Character count measures Unicode code points in the original text, including spaces and punctuation; it is not a grapheme count. Input is limited to 100,000 UTF-16 code units.

Quick start

git clone https://github.com/buildfound/mcp-server-template.git
cd mcp-server-template
npm install
npm run typecheck
npm run build
npm test
npm run inspect

The Inspector opens a UI for listing tools, calling them and reading resources. Try word_stats with {"text":"Hello hello world!","top":1}. It returns:

{
  "wordCount": 3,
  "characterCount": 18,
  "topWords": [{ "word": "hello", "count": 2 }]
}

After the first install, use npm ci for installs from package-lock.json.

Related MCP server: MCP Calculator Server

Project layout

src/
  server.ts             createServer(): tools, schemas and resource
  stdio.ts              Executable stdio entrypoint
  http.ts               HTTP factory and entrypoint
  tools/
    add.ts              Pure addition function
    word-stats.ts       Pure text analysis function
test/
  tools.test.ts         Unit tests
  server.test.ts        SDK Client + InMemoryTransport integration
  http.test.ts          Real HTTP endpoint + SDK clients

tsc compiles only src/ into dist/. Typechecking includes tests too. The package bin points at dist/stdio.js, which preserves the Node shebang. Server identity comes from package.json; keep that file next to dist/ when copying the build.

Add your own tool

Put business logic in a pure function under src/tools/, then import and register it inside createServer() in src/server.ts. For example:

// src/tools/greet.ts
export function greet(name: string): string {
  return `Hello, ${name}!`;
}

// src/server.ts (z and server already exist here)
// Add this import at the top:
import { greet } from "./tools/greet.js";

// Add this registration inside createServer():
server.registerTool(
  "greet",
  {
    description: "Greet someone by name.",
    inputSchema: { name: z.string().min(1).max(100) },
  },
  ({ name }) => ({ content: [{ type: "text", text: greet(name) }] }),
);

The SDK validates arguments against the Zod schema. Follow word_stats for an outputSchema and structuredContent; keep a text representation for clients that display text results. Update the tool list in info://server, add tests, and rebuild before restarting your client. See the SDK v1 server guide for other capabilities.

Transports and scripts

Stdio

npm start       # Runs node dist/stdio.js; build first
npm run dev    # Watches src/stdio.ts with tsx

Use stdio when a local MCP client launches the server as a child process. Running it in a terminal waits for MCP messages; it is not an interactive CLI. Stdout carries protocol messages only. Send diagnostics to stderr with console.error.

Streamable HTTP

npm run build
npm run start:http
curl http://127.0.0.1:3000/health
# {"status":"ok"}

The endpoint is http://127.0.0.1:3000/mcp. Configure HOST and PORT in the process environment; defaults are 127.0.0.1 and 3000. For example, in a POSIX shell:

HOST=127.0.0.1 PORT=3001 npm run start:http
npx tsx watch src/http.ts

HTTP uses stateless mode: every POST gets a fresh McpServer and StreamableHTTPServerTransport, with JSON responses and no session ID. There is no persistent server-to-client stream, session storage or resumability. GET /mcp and DELETE /mcp return 405 Method Not Allowed, as there is no stream or session to manage. GET /health returns JSON. Use HTTP for a separately running process or as a starting point for a secured network service.

Script

Purpose

npm run build

Compile TypeScript to dist/

npm run typecheck

Check source and test types without emitting

npm test

Run unit, in-memory integration and real HTTP tests

npm run inspect

Build and launch MCP Inspector against stdio

Connect a client

Build first. Replace /absolute/path/mcp-server-template below with your checkout's absolute path. If a GUI client cannot find node, use the absolute path to your Node executable too. On Windows, use escaped paths such as C:\\path\\mcp-server-template\\dist\\stdio.js in JSON.

Claude Desktop

Open Settings → Developer → Edit Config and merge this into claude_desktop_config.json, preserving any existing servers. Quit and reopen the app after saving. See the local server setup guide.

{
  "mcpServers": {
    "template": {
      "command": "node",
      "args": ["/absolute/path/mcp-server-template/dist/stdio.js"]
    }
  }
}

Claude Code

Choose one transport. The HTTP command requires the HTTP server to be running separately. These follow the Claude Code MCP commands.

claude mcp add --transport stdio template -- node /absolute/path/mcp-server-template/dist/stdio.js
claude mcp add --transport http template-http http://127.0.0.1:3000/mcp
claude mcp list

Use /mcp inside Claude Code to check the connection.

Cursor

Add this to .cursor/mcp.json in your project, or merge it into ~/.cursor/mcp.json for a global setup. See Cursor's MCP configuration.

{
  "mcpServers": {
    "template": {
      "command": "node",
      "args": ["/absolute/path/mcp-server-template/dist/stdio.js"]
    }
  }
}

VS Code

For the VS Code configuration format, create .vscode/mcp.json with the following. Use MCP: List Servers to start it. See the VS Code MCP configuration reference.

{
  "servers": {
    "template": {
      "type": "stdio",
      "command": "node",
      "args": ["/absolute/path/mcp-server-template/dist/stdio.js"]
    }
  }
}

For a separately running HTTP server, replace the entry with {"type":"http","url":"http://127.0.0.1:3000/mcp"}.

MCP Inspector

npm run inspect builds and starts the official Inspector with the stdio entrypoint. To inspect HTTP, run npm run start:http in one terminal and npx @modelcontextprotocol/inspector in another, choose Streamable HTTP, and enter http://127.0.0.1:3000/mcp.

Testing

Unit tests exercise pure logic, including Unicode, empty input and ranking ties. The in-memory test uses an SDK Client to initialize, list tools/resources, call both tools, read info://server and check schema rejection. The HTTP test binds an ephemeral port and connects two independent SDK clients; it also checks health, unsupported methods, malformed JSON and Host/Origin rejection. No external services are needed.

Security and forking

  • HTTP binds to loopback by default and has no authentication. Add authentication, authorization, TLS, request limits and deployment-specific validation before exposing it beyond your machine.

  • Host validation helps prevent DNS rebinding: accepted authorities are 127.0.0.1, localhost, [::1] and the configured HOST, each with the bound port. Wildcard bind addresses (0.0.0.0, ::) are excluded from this allowlist. If you bind a wildcard address, only loopback authorities work until you explicitly extend validation for your deployment.

  • Requests with an Origin must match http:// plus the validated Host exactly. Cross-origin requests are rejected; CORS is not enabled. Configure an explicit trusted host/origin policy when adding a reverse proxy, TLS or browser access. Host/Origin checks are not authentication.

  • Example tools are offline and read-only. Treat new tools as code running with the server process's permissions. Validate inputs, bound work, protect secrets and avoid logging sensitive tool data. .env is ignored but is not automatically loaded.

Fork the repository, rename the package and bin in package.json, update descriptions and resource metadata, and replace the example tools. Run npm install to refresh lockfile metadata after renaming, then typecheck, build and test. Keep the MIT copyright and license notice.

Built by BuildFound, a founder-led AI product studio.

License

MIT © 2026 Fekri Darkaoui.

Available Tools

2 tools
addB
Read-only

Add two numbers.

NameRequiredDescriptionDefault
aYes
bYes

TDQS

B3.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description is consistent with the annotations: readOnlyHint=true and openWorldHint=false match a pure, side-effect-free computation. However, it adds nothing beyond what the annotations already imply — no statement about the return type (number vs. string) or handling of edge inputs like very large or non-finite values.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single sentence with zero waste, front-loading the only information needed. Proportional to the complexity of the tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With annotations covering the safety profile and no output schema, the definition is workable, but the caller is never told what comes back (a number, a formatted string?) for a tool whose entire value is its return value. That single omission is the main completeness gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must carry the load; 'two numbers' confirms both parameters are numeric operands, which is the only semantics these trivially named params ('a', 'b') require. It adds no ordering or range meaning, but little is genuinely missing.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and the exact operation ('Add two numbers'), which is unambiguous even though the tool name 'add' alone is generic. It does not need to differentiate from the only sibling (word_stats), which operates on an entirely different domain.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use this versus alternatives, nor any stated preconditions. For a trivial arithmetic tool the omission is low-cost, but the description still leaves usage entirely to inference from the name.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

word_statsA
Read-only

Count words and Unicode characters, and rank words by frequency (case-insensitive).

NameRequiredDescriptionDefault
topNoNumber of top words to return.
textYesText to analyze (up to 100,000 UTF-16 code units).

Output Schema

NameRequiredDescription
topWordsYes
wordCountYes
characterCountYes

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare this as a safe read-only, closed-world operation. The description adds useful behavioral detail beyond that: frequency ranking is case-insensitive and character counting is Unicode-aware.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The definition is a single well-structured sentence with no wasted words and the core capabilities are front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only utility with complete schema descriptions, annotations, and an output schema, the description provides enough context for correct invocation. No critical behavioral or parameter information is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Both parameters are fully documented in the schema, including the 'text' size limit and 'top' default/range. The description does not add parameter-level meaning beyond the schema, which is acceptable at 100% schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states specific operations: counting words, counting Unicode characters, and ranking words by frequency. This is a clear verb+resource statement, and the utility is readily distinguishable from the unrelated sibling 'add'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains what the tool does but gives no guidance on when to use it versus alternatives, prerequisites, or exclusions. The only sibling is unrelated, but no usage context is still provided.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 2 tool updatesv1.0.0
    • First observedadd
    • First observedword_stats

TDQS

B3.4/5.0

Scored across 2 tools

Disambiguation5/5

The two tools target completely disjoint domains: `add` performs numeric addition and `word_stats` performs text analysis. There is no plausible way for an agent to confuse one with the other.

Naming Consistency2/5

`add` is a bare verb while `word_stats` is a noun phrase, so the two names follow different conventions. With only two tools there is no discernible pattern to learn from.

Tool Count3/5

Two tools is thin even for a template server, and they are unrelated utilities rather than a coherent capability set. The count is not harmful, but it sits at the borderline of feeling under-scoped.

Completeness3/5

Each tool is self-contained and appears to fully cover its tiny operation, so there are no obvious internal gaps. However, there is no unifying domain, so coverage cannot be meaningfully assessed and the surface is minimal for any real workflow.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • -
    license
    Not graded
    quality
    Not graded
    maintenance
    A production-ready TypeScript MCP server providing basic tools (add, echo, timestamp), resources (server info, greetings, data access), and prompt templates (analyze, code-review, summarize). Serves as a foundation for building custom MCP servers with extensible architecture.
    289 npm
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    A lightweight TypeScript-based MCP server that demonstrates how to build custom MCP tools by implementing a simple addition calculator. Serves as a starting point for building MCP-compatible tools.
    2,031 npm
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    A boilerplate project for quickly developing MCP servers using TypeScript, featuring example implementations of tools (calculator, greetings) and resources (server info) with Zod schema validation.
    ISC