@traversymediaNoteUpdated October 10, 2026

Simple MCP Server Example

Complete TypeScript MCP server walkthrough with MCP Inspector browser testing and Claude Code setup.

Simple MCP Server Example

Build a small TypeScript MCP server with one temperature-conversion tool.

The temperature converter is intentionally simple. An AI model can usually do this calculation without a tool. The point is to make the complete MCP flow easy to see: define a tool, validate its arguments, connect through a transport, inspect the contract, and let an AI client call it.

Real MCP servers are more useful when they expose something the model cannot access by itself, such as private databases, current service data, local development tools, or actions in another system.

Set up the project

Bash / Shell
mkdir mcp-crash-course-dev
cd mcp-crash-course-dev
npm init -y
npm pkg set type=module
npm install --save-dev typescript tsx @types/node
npm install @modelcontextprotocol/server@2 zod@4
mkdir src
npm pkg set scripts.dev="tsx src/index.ts"
npm pkg set scripts.typecheck="tsc --noEmit"

TypeScript configuration

Create tsconfig.json:

JSON
{
  "compilerOptions": {
    "target": "ES2024",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "strict": true,
    "noEmit": true,
    "types": ["node"]
  },
  "include": ["src/**/*.ts"]
}

Temperature conversion

Create src/temperature.ts and define the allowed units:

TypeScript
export const temperatureUnits = ['celsius', 'fahrenheit', 'kelvin'] as const;

export type TemperatureUnit = (typeof temperatureUnits)[number];

as const preserves the three literal values, so TemperatureUnit becomes their exact union instead of string.

Add the public conversion function:

TypeScript
export function convertTemperature(
  value: number,
  from: TemperatureUnit,
  to: TemperatureUnit,
): number {
  if (from === to) {
    return value;
  }

  const celsius = toCelsius(value, from);
  const converted = fromCelsius(celsius, to);

  return Number(converted.toFixed(2));
}

Every value is converted to Celsius first, then from Celsius to the requested unit.

Finish the file with the two internal helpers:

TypeScript
function toCelsius(value: number, unit: TemperatureUnit): number {
  if (unit === 'fahrenheit') {
    return (value - 32) * (5 / 9);
  }

  if (unit === 'kelvin') {
    return value - 273.15;
  }

  return value;
}

function fromCelsius(value: number, unit: TemperatureUnit): number {
  if (unit === 'fahrenheit') {
    return value * (9 / 5) + 32;
  }

  if (unit === 'kelvin') {
    return value + 273.15;
  }

  return value;
}

MCP server

Create src/index.ts with the imports and server metadata:

TypeScript
import { McpServer } from '@modelcontextprotocol/server';
import { StdioServerTransport } from '@modelcontextprotocol/server/stdio';
import * as z from 'zod/v4';

import { convertTemperature, temperatureUnits } from './temperature.js';

const server = new McpServer({
  name: 'temperature-server',
  version: '1.0.0',
});

The .js extension matches the JavaScript module path Node will run after TypeScript processing.

Create the reusable unit schema:

TypeScript
const temperatureUnitSchema = z.enum(temperatureUnits);

Register the tool with its description, input contract, and handler:

TypeScript
server.registerTool(
  'convert-temperature',
  {
    title: 'Convert temperature',
    description:
      'Convert a temperature between Celsius, Fahrenheit, and Kelvin.',
    inputSchema: z.object({
      value: z.number().describe('The temperature value to convert.'),
      from: temperatureUnitSchema.describe('The current temperature unit.'),
      to: temperatureUnitSchema.describe('The target temperature unit.'),
    }),
  },
  async ({ value, from, to }) => {
    const result = convertTemperature(value, from, to);

    return {
      content: [
        {
          type: 'text',
          text: `${value} ${from} is ${result} ${to}.`,
        },
      ],
    };
  },
);

Finally, connect the server through stdio:

TypeScript
const transport = new StdioServerTransport();

await server.connect(transport);
console.error('Temperature MCP server is running over stdio.');

stdout carries MCP messages, so send diagnostic logs to stderr with console.error().

Check the server

Bash / Shell
npm run typecheck

Use the browser-based MCP Inspector

Launch MCP Inspector with the local server command:

Bash / Shell
npx @modelcontextprotocol/inspector npm run dev

Inspector opens in the browser with an npm server card. If the card says Disconnected, use its toggle to connect. The card should turn green and show Connected.

Select Tools at the top of the page, then select convert-temperature. Enter these arguments:

JSON
{
  "value": 20,
  "from": "celsius",
  "to": "fahrenheit"
}

Run the tool. The result should report that 20 Celsius is 68 Fahrenheit.

To see schema validation, try an unsupported unit. Inspector should reject the request before the conversion function runs.

The Read-only session banner is expected when Inspector is launched with an ad-hoc server command. It means the server entry cannot be edited or saved in Inspector. It does not prevent connecting to the server or calling its tools.

Connect the server to Claude Code

From the mcp-crash-course-dev project folder, add the server to Claude Code:

Bash / Shell
claude mcp add --transport stdio --scope local temperature-server -- npm run dev

The double dash separates Claude's CLI options from the command that starts the MCP server. Local scope makes the server available only when Claude Code is running in this project.

Claude saves the launch command, not a permanently running process. When a session needs the server, Claude starts npm run dev and communicates with it over stdio.

Verify the connection:

Bash / Shell
claude mcp list

Start Claude Code from the same project folder:

Bash / Shell
claude

Inside Claude Code, run /mcp and confirm that temperature-server is connected with one available tool.

Then ask:

Plain Text
What is 20 degrees Celsius in Fahrenheit? Use the convert-temperature tool.

Review and approve the tool call if Claude requests permission. Claude should send 20, celsius, and fahrenheit to the server. The server validates the arguments, runs the conversion function, and returns the text result.

To remove the project-local connection later, run:

Bash / Shell
claude mcp remove temperature-server --scope local

RawImageDownload