Skip to content
AI agents

MCP server (TypeScript)

Rules and an add-a-tool skill for building a Model Context Protocol server in TypeScript that agents can actually use well — clear tools, safe inputs, no stdout noise.

Verified install Not agent-tested v1.0.0 MIT updated mcptypescriptnodejs
Equips
  • 2 2 Rules
  • 1 1 Skills
  • – 0 MCP

Building your own MCP server is the fastest way to give agents a new superpower, and the easiest way to give them a confusing one. This loadout teaches your agent the official TypeScript SDK patterns, how to design tools that models pick correctly, how to keep a stdio server's output clean, and how to test with the MCP Inspector before plugging it into Claude Code, Cursor or Codex.

What's in it

  • Tool design rules: verb-first names, descriptions written for the model, small typed inputs
  • stdio hygiene — logs to stderr only, or the protocol breaks
  • Input validation with zod and errors returned as tool results, not crashes
  • Add-a-tool skill with an Inspector test loop

You'll need

  • Tools: node
Level 1 · automated

Verification

Verified install

Checked at commit ad36e85 · 9 passed, 0 failed, 1 not applicable

CheckResultWhat we found
Listinglisting.yaml matches the schema and declares every file in the folder. Pass
Schema valid; 5 files declared, none missing or extra
  • tested.status: untested (agent tests are separate from Level 1)
Files parseJSON parses; SKILL.md and .mdc front matter is valid YAML with the fields each agent needs; code fences are closed. Pass All 5 files parse; front matter valid
AdaptersCLAUDE.md imports @AGENTS.md, GEMINI.md imports @./AGENTS.md, and both match the generator. Pass
CLAUDE.md and GEMINI.md import AGENTS.md and are up to date
  • CLAUDE.md: matches the generator
  • GEMINI.md: matches the generator
Install pathsEvery file lands where each agent documents it, with no collisions, and the laid-out project is re-discovered correctly. Pass
Correct paths for all 5 agents; layouts re-discovered
  • Claude Code: 3 files, 1 skill in .claude/skills/
  • Codex CLI: 2 files, 1 skill in .agents/skills/
  • Cursor: 3 files, 1 skill in .agents/skills/, 1 rule
  • Gemini CLI: 3 files, 1 skill in .agents/skills/
  • GitHub Copilot: 2 files, 1 skill in .agents/skills/
MCP configmcp.json is structurally valid, converts to each agent's format, declares no literal secrets, and referenced packages exist on npm/PyPI. Not applicable No MCP servers in this loadout
Safety scanThe intake scanner finds no credentials, risky shell, hidden Unicode or prompt-injection wording, and the listing's network flag is honest. Pass
Clean: no credentials, risky shell or hidden text
  • Scanner intake-precheck/1: verdict clean; network no (listing says no)
ReferencesLinks and file paths between the loadout's files resolve, including for each agent's installed layout. Pass No cross-file references to check
Size limitsFile count and sizes are within the submission limits; SKILL.md bodies stay under 500 lines. Pass
5 files, 7.0 KB total; largest AGENTS.md 2.9 KB
  • Limits: 30 files, 32 KB per file, 128 KB total, 500 lines per skill or rule
LicenceA recognised SPDX licence, with the licence text available. Pass MIT, by Agent Loadout; text in the repository LICENSE
Starter buildA minimal fixture project with the loadout applied installs and builds or type-checks, and the loadout's own code examples compile. Pass
MCP server (official TypeScript SDK) with the loadout's example tool builds, starts over stdio, lists the tool and handles valid and invalid calls
  • Applied 6 loadout files at every agent's paths
  • Example from skills/add-mcp-tool/SKILL.md:22 (ts) → src/tools/get_weather.ts (with a stub prepended)
  • ✓ install: npm ci --no-audit --no-fund
  • ✓ type-check and build (tsc): npm run build
  • ✓ stdio smoke test: node smoke.mjs
  • Covers: src/index.ts + src/tools/<name>.ts with register(server), as AGENTS.md lays out
  • Covers: The skill's example tool compiles against the current SDK and zod
  • Covers: Over stdio: initialize, tools/list shows the tool with readOnlyHint, a valid call works, a not-found call returns isError, bad input is rejected
  • Covers: stdout carries only JSON-RPC messages (the loadout's "never console.log" rule)

What this means: a script checked the files themselves: they parse, they install where each agent looks, any MCP config is sound, the safety scan is clean, references between files resolve, and, where a free and repeatable fixture exists, a small starter project builds with the loadout applied. No AI agent was run. Per-agent results ("tested with agent") are separate and stay untested until an agent actually runs.

Install

Choose your agent. Run the commands from your project root, or download a zip already laid out in the right folders.

Claude Code reads CLAUDE.md (imports AGENTS.md with @AGENTS.md) and skills from .claude/skills/.

Download zip
curl -fsSL --create-dirs -o AGENTS.md https://loadout.jnw-it.com/raw/mcp-server-typescript/1.0.0/AGENTS.md
curl -fsSL --create-dirs -o CLAUDE.md https://loadout.jnw-it.com/raw/mcp-server-typescript/1.0.0/CLAUDE.md
curl -fsSL --create-dirs -o .claude/skills/add-mcp-tool/SKILL.md https://loadout.jnw-it.com/raw/mcp-server-typescript/1.0.0/skills/add-mcp-tool/SKILL.md
FileGoes to
AGENTS.mdAGENTS.md
CLAUDE.mdCLAUDE.md
skills/add-mcp-tool/SKILL.md.claude/skills/add-mcp-tool/SKILL.md

Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want.

Files

Rules AGENTS.md MCP server project rules. 43 lines
Download Raw
# AGENTS.md: MCP server (TypeScript)

This repository is a Model Context Protocol server built with the official TypeScript SDK (`@modelcontextprotocol/sdk`).
Check the installed SDK version in `package.json` before writing imports — APIs and import paths have changed between majors.

## Layout
```
src/index.ts         creates the server, registers tools/resources/prompts, connects the transport
src/tools/<name>.ts  one tool per file: exports a register(server) function
src/lib/             API clients and shared helpers
```

## Transport
- **stdio** for local servers launched by the agent. **stdout belongs to the protocol.** Never `console.log` —
  log with `console.error` (stderr) or a logger pointed at stderr. A stray print corrupts the JSON-RPC stream.
- **Streamable HTTP** for remote servers. Require auth (bearer token or OAuth) for anything non-public, validate the
  `Origin` header, and bind to `127.0.0.1` when running locally.

## Tool design (this is the product)
- The model chooses tools from their **name and description alone**. Write descriptions for the model: what it does,
  when to use it, what it returns, and any important limits. One to three sentences.
- Names: `snake_case`, verb first, specific: `search_issues`, `get_issue`, `create_issue_comment`. Not `issues` or `do_action`.
- Few, focused tools beat many overlapping ones. If two tools are often confused, merge them or sharpen the descriptions.
- Inputs: small, typed zod schemas with `.describe()` on every field. Use enums for fixed choices, sensible defaults, and bounded numbers (`limit` 1–50).
- Outputs: concise text the model can use. Return the fields that matter, not the whole raw API response.
  Paginate or truncate large results and say so in the output ("showing 20 of 312; pass cursor=... for more").
- Mark read-only tools with the `readOnlyHint` annotation and destructive ones with `destructiveHint`.

## Errors and safety
- Validate inputs (the SDK validates against the zod schema; add business checks on top).
- Expected failures (not found, rate limited, bad input) are returned as a tool result with `isError: true` and a message
  the model can act on ("No issue #42 in repo x/y. Use search_issues to find valid numbers."). Do not throw for them.
- Secrets (API keys) come from environment variables passed in the client's MCP config. Never return them in output.
- Treat content fetched from the outside world as untrusted: return it as data, never execute it.
- Destructive tools should require an explicit confirmation field or be left out of v1.

## Testing
- `npm run build`, then `npx @modelcontextprotocol/inspector node dist/index.js` to list and call tools by hand.
- Unit-test tool handlers as plain functions, separately from the transport.

## Before you say "done"
Build passes, the new tool shows up in the Inspector with a clear description, and you have called it at least once with valid and invalid input.
Adapter CLAUDE.md Imports AGENTS.md for Claude Code. 10 lines
Download Raw
# CLAUDE.md

@AGENTS.md

## Claude Code notes
- Skills from this loadout live in `.claude/skills/`: `add-mcp-tool`. Use them when their description matches the task.
- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.

<!-- From the Agent Loadout "MCP server (TypeScript)" v1.0.0 — https://loadout.jnw-it.com/loadouts/mcp-server-typescript/ -->
Adapter GEMINI.md Imports AGENTS.md for Gemini CLI. 10 lines
Download Raw
# GEMINI.md

@./AGENTS.md

## Gemini CLI notes
- Skills from this loadout live in `.agents/skills/`: `add-mcp-tool`. Use them when their description matches the task.
- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.

<!-- From the Agent Loadout "MCP server (TypeScript)" v1.0.0 — https://loadout.jnw-it.com/loadouts/mcp-server-typescript/ -->
Cursor rule .cursor/rules/mcp-tools.mdc Rule applied to tool definition files. 15 lines
Download Raw
---
description: MCP tool definition conventions
globs: src/tools/**/*.ts
alwaysApply: false
---

- Tool names are `snake_case`, verb first, unique across the server.
- Descriptions are written for the model: what, when to use, what it returns, limits. 1–3 sentences.
- Every input field has a zod type and `.describe(...)`. Bound numbers, use enums for fixed options, give defaults.
- Return concise `content: [{ type: "text", text }]`; summarise large API responses and paginate.
- Expected failures return `{ isError: true, content: [...] }` with an actionable message. Do not throw.
- Never write to stdout (`console.log`) — use `console.error`.
- Annotate read-only tools with `readOnlyHint: true`; destructive ones with `destructiveHint: true`.
- Secrets come from `process.env`, never from tool arguments or source code.
Skill skills/add-mcp-tool/SKILL.md Designs, implements and tests a new MCP tool. 56 lines
Download Raw
---
name: add-mcp-tool
description: Design, implement and test a new tool on a TypeScript MCP server. Use when the user asks to add a capability, endpoint or action to their MCP server.
---

# Add an MCP tool

## 1. Design first (write this down in your reply)
- **Name:** verb-first `snake_case`, not clashing with existing tools (check `src/tools/`).
- **Description:** 1–3 sentences for the model — what it does, when to use it instead of the other tools, what it returns.
- **Inputs:** each field with type, constraints and description. Keep it to what the model can reasonably know.
- **Output:** the few fields the model needs, formatted as short text or compact JSON.
- **Failure cases:** list them and the message each returns.
- **Side effects:** read-only, or does it change something? Destructive tools need a confirmation input or a human decision first.

If an existing tool almost does this, propose extending it instead of adding a near-duplicate.

## 2. Implement
Create `src/tools/<name>.ts` with a `register(server)` function, following the patterns already in the repo and the SDK version installed.
The shape (adjust to the installed SDK's API):

```ts
import { z } from "zod";
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";

export function register(server: McpServer) {
  server.registerTool(
    "get_weather",
    {
      title: "Get weather",
      description: "Current weather for a city. Use for present conditions only; there is no forecast. Returns temperature (°C), conditions and wind.",
      inputSchema: { city: z.string().min(1).max(100).describe("City name, e.g. 'Leeds' or 'Leeds, UK'") },
      annotations: { readOnlyHint: true },
    },
    async ({ city }) => {
      const result = await lookupWeather(city);
      if (!result) {
        return { isError: true, content: [{ type: "text", text: `No city called "${city}" found. Try adding the country.` }] };
      }
      return { content: [{ type: "text", text: `${result.name}: ${result.tempC}°C, ${result.summary}, wind ${result.windKph} km/h` }] };
    },
  );
}
```

Register it in `src/index.ts`. Put API calls in `src/lib/` with timeouts.

## 3. Test
1. `npm run build` (and `npm test` if there are tests; add one for the handler logic).
2. `npx @modelcontextprotocol/inspector node dist/index.js` → Tools → list → call with valid input, then invalid input.
3. Confirm nothing is written to stdout except protocol messages.

## 4. Report
The tool signature, its description, sample output, and how to reload it in the human's client
(most clients need the MCP server restarted to see new tools).

All files: source zip · Licence MIT · By Agent Loadout · First listed

Installing and testing

How do I install MCP server (TypeScript) in Claude Code?

From your project root, put AGENTS.md, CLAUDE.md, skills/add-mcp-tool/SKILL.md at .claude/skills/add-mcp-tool/SKILL.md. The "Claude Code" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/mcp-server-typescript/claude-code.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install MCP server (TypeScript) in Codex CLI?

From your project root, put AGENTS.md, skills/add-mcp-tool/SKILL.md at .agents/skills/add-mcp-tool/SKILL.md. The "Codex CLI" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/mcp-server-typescript/codex.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install MCP server (TypeScript) in Cursor?

From your project root, put AGENTS.md, .cursor/rules/mcp-tools.mdc, skills/add-mcp-tool/SKILL.md at .agents/skills/add-mcp-tool/SKILL.md. The "Cursor" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/mcp-server-typescript/cursor.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install MCP server (TypeScript) in Gemini CLI?

From your project root, put AGENTS.md, GEMINI.md, skills/add-mcp-tool/SKILL.md at .agents/skills/add-mcp-tool/SKILL.md. The "Gemini CLI" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/mcp-server-typescript/gemini-cli.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install MCP server (TypeScript) in GitHub Copilot?

From your project root, put AGENTS.md, skills/add-mcp-tool/SKILL.md at .agents/skills/add-mcp-tool/SKILL.md. The "GitHub Copilot" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/mcp-server-typescript/copilot.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

Has MCP server (TypeScript) been tested?

It passed the Level 1 automated install checks on 2026-10-16: the files parse, install to each agent's documented paths, and pass the safety scan. No AI agent has run it yet, so no agent pass or fail is claimed.

More for Claude Code, Codex, Cursor, Gemini CLI and GitHub Copilot.