MCP Server Template
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@MCP Server Templatecount the words in 'Hello hello world!' and show the top 1"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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 |
|
| Text: |
|
| Word count, character count and ranked words, as JSON text and schema-validated |
| 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 inspectThe 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 clientstsc 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 tsxUse 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.tsHTTP 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 |
| Compile TypeScript to |
| Check source and test types without emitting |
| Run unit, in-memory integration and real HTTP tests |
| 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 listUse /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 configuredHOST, 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
Originmust matchhttp://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.
.envis 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 toolsaddBRead-only
Add two numbers.
| Name | Required | Description | Default |
|---|---|---|---|
| a | Yes | ||
| b | Yes |
TDQS
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.
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.
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.
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.
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.
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_statsARead-only
Count words and Unicode characters, and rank words by frequency (case-insensitive).
| Name | Required | Description | Default |
|---|---|---|---|
| top | No | Number of top words to return. | |
| text | Yes | Text to analyze (up to 100,000 UTF-16 code units). |
Output Schema
| Name | Required | Description |
|---|---|---|
| topWords | Yes | |
| wordCount | Yes | |
| characterCount | Yes |
TDQS
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.
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.
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.
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.
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.
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.
2 tool updates
v1.0.0- First observed
add - First observed
word_stats
TDQS
Scored across 2 tools
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.
`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.
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.
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
Related MCP Connectors
MCP server for progressive tool usage at any scale (see https://klavis.ai)
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
Build your own tools from chat: design, test and host them on a shareable MCP server URL.
A simple Typescript MCP server built using the official MCP Typescript SDK and smithery/cli. This…
Related MCP Servers
- -licenseNot gradedqualityNot gradedmaintenanceA 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-
- AlicenseNot gradedqualityDmaintenanceA 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 npmMIT
- AlicenseNot gradedqualityDmaintenanceA 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
- FlicenseAqualityDmaintenanceA TypeScript MCP server template with Zod validation, dual transport (stdio/HTTP), and modular architecture for building MCP-compatible tools, resources, and prompts.11-