Command Palette

Search for a command to run...

UnylyUnyly
Весь каталог

Node

БесплатноНе проверен

An MCP server that offers arithmetic operations (addition and division) and current weather data from OpenWeatherMap. It serves as a learning project for buildi

GitHubEmbed

Описание

An MCP server that offers arithmetic operations (addition and division) and current weather data from OpenWeatherMap. It serves as a learning project for building MCP servers with Node.js and TypeScript, supporting both stdio and Streamable HTTP transports.

README

A training project for building MCP (Model Context Protocol) servers with Node.js and TypeScript.

Stack

  • Node.js with ES modules ("type": "module")
  • TypeScript (NodeNext module mode)
  • @modelcontextprotocol/sdk — official MCP TypeScript SDK
  • Zod — input/output schema validation
  • Express — HTTP server for Streamable HTTP transport
  • openweather-api-node — OpenWeatherMap API client
  • dotenv — environment variable loading

Project Structure

node-mcp/
├── index.ts                        # Server entry point — registers all tools, selects transport
├── toolHandler.ts                  # Generic error-handling wrapper for tool handlers
├── tools/
│   ├── opperations/
│   │   ├── add.ts                  # Add tool
│   │   └── divide.ts               # Divide tool
│   └── weather/
│       └── weather.ts              # Weather tool
├── types.d.ts                      # Module declarations for untyped packages
├── .env                            # API keys and config (not committed)
├── dist/                           # Compiled output (generated by tsc)
├── tsconfig.json
└── package.json

Getting Started

pnpm install

Create a .env file in the project root:

OPEN_WEATHER_API_KEY=your_key_here
NODE_ENV=development
TRANSPORT=stdio        # or "http"
MCP_PORT=3000          # optional, HTTP mode only

Build:

pnpm build

Running the Server

stdio mode (for Claude Desktop / Claude Code)

$env:TRANSPORT="stdio"; node dist/index.js

The server communicates over stdin/stdout and waits for JSON-RPC messages from an MCP client. No visible output when idle.

HTTP mode (persistent process)

$env:TRANSPORT="http"; node dist/index.js

Starts an Express server on port 3000 (or MCP_PORT):

Starting Express MCP server on port 3000
MCP endpoint: http://localhost:3000/mcp
Server is running on http://localhost:3000

Testing with MCP Inspector

stdio mode

pnpm exec mcp-inspector node dist/index.js

HTTP mode

Start the server first, then open the inspector without arguments:

pnpm exec mcp-inspector

In the inspector UI, set transport type to Streamable HTTP and URL to http://localhost:3000/mcp.

Connecting to Claude Code

stdio (project-level)

claude mcp add --scope project node-mcp-server node C:/Training/node-mcp/dist/index.js

HTTP

Add the server URL directly in Claude Code's MCP settings pointing at http://localhost:3000/mcp.

Tools

add

Adds two numbers together and returns the result.

Inputs

Name Type Description
numOne number First operand
numTwo number Second operand

Output

{ "result": "32 + 32 = 64" }

divide

Divides two numbers and returns the result. Both inputs must be positive — validated by Zod before the handler runs.

Inputs

Name Type Description
numOne number (positive) Dividend
numTwo number (positive) Divisor (cannot be zero)

Output

{ "result": "10 / 2 = 5" }

weather

Returns current weather data for a location using the OpenWeatherMap API. Results are in metric units.

Supply one of the following location strategies:

Name Type Description
lat number (-90 to 90) Latitude (use with lng)
lng number (-180 to 180) Longitude (use with lat)
locationName string City or place name (e.g. "London")
zipCode string Zip/postal code (e.g. "90210")

Priority order when multiple are provided: coordinates → zip code → location name. At least one strategy must be supplied or the tool returns an error.

Output

Returns a JSON object with temperature, humidity, wind speed, weather description, and more.

Requires OPEN_WEATHER_API_KEY in .env.

Key Concepts

Transport selection

The server supports two transports, selected via the TRANSPORT environment variable:

Value Use case
stdio Local servers spawned as child processes (Claude Code, Claude Desktop)
http Persistent process accessible over a network

Tools are registered once and shared between both transports — the capability is decoupled from the delivery mechanism.

Tool registration pattern

Each tool lives in its own file and exports a registration function that accepts the server instance:

export const myTool = (server: McpServer) => {
  server.registerTool('tool-name', { ... }, toolHandler(async (inputs) => {
    // handler logic
  }))
}

In index.ts:

myTool(server)

Error handling — toolHandler

All tool handlers are wrapped with toolHandler, a generic wrapper that catches any thrown error and returns it in the correct MCP format:

export const toolHandler = <T>(fn: (inputs: T) => Promise<CallToolResult>) => {
  return async (inputs: T) => {
    try {
      return await fn(inputs)
    } catch (err) {
      return {
        isError: true,
        content: [{
          type: 'text' as const,
          text: err instanceof Error
            ? process.env.NODE_ENV === 'development' ? err.stack ?? err.message : err.message
            : 'Something went wrong...'
        }]
      }
    }
  }
}
  • In development (NODE_ENV=development): returns the full stack trace
  • In production: returns the error message only
  • For non-Error throws: returns a generic fallback message

Input validation with Zod

Zod schemas on inputSchema are validated by the SDK before your handler runs. Invalid inputs return a -32602 protocol error — they never reach your handler:

inputSchema: {
  numTwo: z.number().positive()            // rejects zero and negatives
  numTwo: z.number().refine(n => n !== 0)  // rejects only zero
}

Streamable HTTP transport

The HTTP transport uses Express with the SDK's StreamableHTTPServerTransport. Key points:

  • sessionIdGenerator: randomUUID — required, assigns a unique ID to each client session
  • express.json() middleware parses the request body before it reaches the transport
  • The parsed body is passed as the third argument to handleRequest — the SDK uses it directly rather than re-parsing the raw request
app.use(express.json())
app.all('/mcp', (req, res) => {
  transport.handleRequest(req, res, req.body)
})

ES module import paths

With "module": "NodeNext" in tsconfig, imports require explicit .js extensions even in .ts source files:

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'

Environment variables

Loaded via import 'dotenv/config' at the top of index.ts. Add .env to .gitignore to avoid committing API keys.

from github.com/styles102/node-mcp

Установка Node

У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.

▸ github.com/styles102/node-mcp

FAQ

Node MCP бесплатный?

Да, Node MCP бесплатный — установка в пару кликов через Unyly без оплаты.

Нужен ли API-ключ для Node?

Нет, Node работает без API-ключей и переменных окружения.

Node — hosted или self-hosted?

Доступен hosted-вариант: Unyly запускает сервер в облаке, локальная установка не обязательна.

Как установить Node в Claude Desktop, Claude Code или Cursor?

Открой Node на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.

Похожие MCP

Compare Node with

Не уверен что выбрать?

Найди свой стек за 60 секунд

Автор?

Embed-бейдж для README

Похожее

Все в категории development