Skip to main content
Glama
mcp-server-template

mcp-server-template

mcp-server-template

A model context protocol server that already does the boring parts: typed tools, resources, prompts, stderr logging, graceful shutdown, integration tests, and a Docker image. Replace three files, ship your server.

$ npx mcp-server-template
[info] mcp-server-template 1.0.0 ready on stdio

Works with Claude Desktop, Claude Code, Cursor, VS Code, and any MCP client that speaks stdio.


Why not start from the SDK example

Concern

SDK example

This template

Tool input validation

optional

zod, enforced at the boundary

stdout safety

not enforced

logger writes to stderr only, a test guards it

Graceful shutdown

none

SIGINT and SIGTERM close the transport

Error shape

thrown strings

isError: true with a readable message

Tests

none

unit plus a real stdio round trip

Docker

none

multi-stage, non-root, 60 MB

CI

none

Node 20, 22, 24


Related MCP server: ToolForge MCP Server

Quickstart

git clone https://github.com/ayushrajdev-dev/mcp-server-template
cd mcp-server-template
npm ci
npm run build
node dist/index.js        # speaks JSON-RPC on stdio

Or run the published package:

npx mcp-server-template

Claude Desktop

~/Library/Application Support/Claude/claude_desktop_config.json on macOS, %APPDATA%\Claude\claude_desktop_config.json on Windows:

{
  "mcpServers": {
    "template": {
      "command": "node",
      "args": ["/absolute/path/to/mcp-server-template/dist/index.js"],
      "env": { "MCP_LOG_LEVEL": "info" }
    }
  }
}

Restart the app. Three tools appear: echo, now, uuid.

Claude Code

claude mcp add template -- node /absolute/path/to/dist/index.js

Cursor

.cursor/mcp.json in the project root:

{
  "mcpServers": {
    "template": {
      "command": "node",
      "args": ["dist/index.js"]
    }
  }
}

Docker

docker build -t mcp-template .
docker run -i --rm mcp-template

The -i flag matters: stdio transport needs an open stdin.


Add your own tool

Edit src/tools/index.ts. Ten lines, no boilerplate:

server.registerTool(
  "reverse",
  {
    title: "Reverse text",
    description: "Reverse a string. Use when the user asks to flip text.",
    inputSchema: {
      text: z.string().min(1).describe("Text to reverse"),
    },
  },
  async ({ text }) => ({
    content: [{ type: "text", text: [...text].reverse().join("") }],
  }),
);

Rules that keep the server usable:

  1. description is the model's only instruction. Say what it does and when to call it.

  2. .describe() on every field. The schema is shown to the model verbatim.

  3. Return isError: true for expected failures. Throw only for bugs.

  4. Never console.log. stdout is the protocol.


Layout

src/
  index.ts              server wiring, transport, shutdown
  tools/index.ts        echo, now, uuid
  resources/index.ts    config://manifest
  prompts/index.ts      review-diff
  lib/logger.ts         stderr-only logger
test/
  server.test.js        unit tests plus a live stdio round trip

Tools

Functions the model can call. Input is a zod schema; output is { content: [...] }.

Resources

Read-only data addressed by URI. This template exposes config://manifest with the package name, version, license, Node version, and MCP SDK version.

Prompts

Reusable templates the client surfaces as slash commands. review-diff takes a diff and a language, and asks for correctness findings only.


Environment

Variable

Default

Purpose

MCP_LOG_LEVEL

info

debug, info, warn, error

Logs go to stderr at every level. There is no configuration file and no network access.


Tests

npm test        # builds, then runs unit and stdio integration tests
npm run typecheck

The integration test spawns dist/index.js, connects a real MCP client, lists tools, calls echo, and asserts that an invalid time zone returns isError: true. If the transport breaks, CI fails.


Deploy

The image is a standard stdio MCP server, so it runs anywhere a container runs. For a hosted deployment, wrap the transport: the SDK ships StreamableHTTPServerTransport and SSEServerTransport, and the tool, resource, and prompt registrations stay unchanged.


License

MIT. See LICENSE.

Available Tools

3 tools
echoEchoA

Return the input text unchanged. Use this to confirm the server is connected.

NameRequiredDescriptionDefault
textYesText to return unchanged

TDQS

A4/5.0
Behavior4/5

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

With no annotations provided, the description must carry the behavioral burden, and it does so adequately by stating the input is returned unchanged, implying a pure, side-effect-free round-trip. It does not explicitly state the absence of side effects or latency characteristics, which keeps it short of a 5.

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?

Two short sentences with zero filler, and the behavioral statement is front-loaded ahead of the usage hint. Every sentence earns its place.

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

Completeness4/5

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

For a one-parameter, no-output-schema round-trip tool, the description covers purpose and the primary use case sufficiently. Minor gaps such as confirming no side effects or that the response mirrors the request are low-risk given the tool's simplicity.

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 coverage is 100% and there is a single required string parameter already documented as "Text to return unchanged". The description restates the same meaning rather than adding format, length, or encoding details, so the baseline 3 applies.

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?

The description uses a specific verb+resource pairing ("Return the input text unchanged") that unambiguously describes the operation. It does not differentiate from siblings (now, uuid), but those siblings are distinct enough that no differentiation is needed.

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

Usage Guidelines4/5

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

"Use this to confirm the server is connected" gives explicit when-to-use guidance for the primary scenario. It lacks exclusions or named alternatives, but for a connectivity check there is no competing sibling that would warrant them.

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

nowCurrent timeA

Current date and time in an IANA time zone, such as Asia/Kolkata or UTC.

NameRequiredDescriptionDefault
timeZoneNoIANA time zone name, for example Europe/BerlinUTC

TDQS

A3.6/5.0
Behavior3/5

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

No annotations are supplied, so the description carries the behavioral burden; it implicitly conveys a harmless read of the clock, which is the main thing an agent needs. However, it says nothing about the returned format (ISO 8601? offset included? precision?) and there is no output schema to fill that gap.

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?

One sentence, front-loaded with the resource and immediately followed by the qualifier (time zone) with concrete examples. No filler or redundancy.

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

Completeness4/5

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

For a one-optional-parameter clock tool this is close to sufficient: the resource and the parameter meaning are both covered. The only meaningful gap is the shape of the returned timestamp, which matters because no output schema exists.

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 100% and the single parameter already documents the IANA zone with an example, so the description adds nothing new. It also omits the schema's UTC default, which is the one piece of semantics a caller might otherwise miss.

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?

The description names the exact resource (current date and time) and its scope (an IANA time zone), so an agent knows precisely what it returns. It does not explicitly distinguish itself from the siblings echo/uuid, but those are unrelated utilities so confusion is unlikely.

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

Usage Guidelines3/5

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

Usage is only implied: an agent infers it should call this whenever it needs the current time, and the mention of a time zone hints that the zone should be supplied. There is no explicit statement of when to prefer this over computing time elsewhere, nor any exclusion or precondition.

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

uuidUUID v4A

Generate a random UUID v4.

NameRequiredDescriptionDefault

No parameters

TDQS

A4/5.0
Behavior3/5

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

With no annotations supplied, the description carries the full burden: it does disclose the key behavioral trait that output is random (non-deterministic) and version 4, which is what matters here. It does not state side-effect freedom or repeated-call behavior (a new value each time), which are the traits an agent might still need clarified.

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 short sentence with the actionable verb and the version qualifier front-loaded; every word earns its place and nothing is padded.

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

Completeness4/5

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

For a zero-parameter utility with no annotations and no output schema, the description covers what the tool does and that the result is random v4. It stops just short of stating the return type (a string) and that each invocation yields a distinct value.

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

Parameters4/5

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

The tool takes zero parameters, so there is nothing for the description to disambiguate and the baseline of 4 applies. No parameter constraints are missing.

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?

States a specific verb and resource ('Generate a ... UUID v4') with the exact variant specified, so an agent knows precisely what comes back. It is trivially distinguishable from the sibling utilities 'echo' and 'now'.

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

Usage Guidelines3/5

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

Usage is implied — an agent needing a fresh unique identifier should call this rather than 'now' or 'echo'. No explicit when-to-use or when-not framing, and no alternatives are named, but for a single-purpose utility the implication is unambiguous.

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. 3 tool updatesv1.0.0
    • First observedecho
    • First observednow
    • First observeduuid

TDQS

A3.8/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: connectivity check, current time retrieval, and UUID generation. There is no plausible scenario where an agent would confuse one for another.

Naming Consistency4/5

All three names are single lowercase words following the same terse style, so the set is internally predictable. It deviates from a verb_noun convention, but consistency is high with no mixed casing or styles.

Tool Count3/5

Three tools is thin for a functional server, though defensible for a template/starter server whose purpose is minimal demonstration. It borders on under-scoped relative to a general utility server.

Completeness3/5

Each tool is self-contained with no lifecycle gaps (nothing to create/update/delete), but the surface is notably minimal—no timezone conversion, formatting, or typical utility operations beyond these three primitives.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    A Node.js/TypeScript MCP server template with sample tools (ping and system_info) that demonstrates how to build custom tools for Claude Desktop using stdio transport.
    2 npm
    ISC
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables AI agents to securely discover, execute, and observe tools with role-based access control and audit logging. Serves tools over MCP stdio and HTTP for integration with Claude Desktop, Cursor, and other clients.
    1
    -
  • A
    license
    C
    quality
    B
    maintenance
    Provides a ready-to-use starter kit for building custom MCP servers, enabling developers to scaffold and register tools with type-safe Zod schemas, run over stdio with auto-bootstrapping, and connect to AI clients like Claude Desktop, Google Antigravity, Cursor, and VS Code.
    3
    1
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Provides a runnable local stdio Python server scaffold that coding agents extend into custom tool integrations by describing an idea and letting the agent investigate, build, test, and install it. Ships with no prebuilt tools, so it enables guided, agent-assisted creation of MCP tools connected to external APIs, databases, or websites while writes stay disabled until explicitly agreed.
    1
    MIT