← MCP in Practice: Building Model Context Protocol Servers
06 / 07 · 45 min

Publishing and Connecting to Claude, Cursor, and VS Code

Package an npm binary with bin and shebang, connect to Claude Code and Claude Desktop, Cursor, and VS Code, deploy a remote HTTP variant.

Lesson content is currently available in Russian.

What you will learn

  • →Упаковывать сервер в исполняемый npm-пакет с bin, shebang и корректной сборкой.
  • →Подключать сервер к Claude Code, Claude Desktop, Cursor и VS Code с передачей секретов.
  • →Разворачивать удалённый вариант на Streamable HTTP и выбирать между stdio и HTTP-дистрибуцией.

Пакуем сервер в npm-пакет

Цель дистрибуции stdio-сервера — одна команда у пользователя: npx -y @acme/orders-mcp. Для этого пакет должен быть исполняемым:

{
  "name": "@acme/orders-mcp",
  "version": "1.0.0",
  "type": "module",
  "bin": { "orders-mcp": "dist/index.js" },
  "files": ["dist"],
  "scripts": {
    "build": "tsc && chmod +x dist/index.js",
    "prepublishOnly": "npm run build"
  }
}

Три обязательных элемента. Первое — shebang первой строкой src/index.ts, чтобы ОС знала, чем исполнять файл:

#!/usr/bin/env node
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';

Второе — поле bin: по нему npm создаст исполняемую ссылку, а npx сможет запустить пакет без установки. Третье — files: ["dist"], чтобы в пакет не уехали исходники, тесты и .env (проверьте содержимое через npm pack --dry-run — этот же артефакт можно установить локально и проверить до публикации: npm install -g ./acme-orders-mcp-1.0.0.tgz).

Версионируйте по SemVer с точки зрения контракта инструментов: изменение схемы аргументов или удаление инструмента — это major, новый инструмент — minor, правка описания — patch. Пользователи с npx -y получают последнюю версию при каждом запуске, поэтому сломанный minor разлетится мгновенно.

Claude Code и Claude Desktop

В Claude Code сервер добавляется одной командой; всё после -- — команда запуска:

claude mcp add orders -- npx -y @acme/orders-mcp

# С передачей секрета:
claude mcp add orders --env PRODUCT_API_KEY=sk-prod-... -- npx -y @acme/orders-mcp

# Удалённый HTTP-сервер:
claude mcp add --transport http orders-remote https://mcp.acme.dev/mcp

У Claude Code три области видимости конфигурации: local (по умолчанию, только вы и только этот проект), user (все ваши проекты) и project — файл .mcp.json в корне репозитория, который коммитится в git и раздаёт сервер всей команде:

claude mcp add orders --scope project -- npx -y @acme/orders-mcp

Проверка — команда /mcp внутри сессии: покажет статус подключения, список инструментов и ошибки.

Claude Desktop настраивается файлом claude_desktop_config.json (на macOS — в ~/Library/Application Support/Claude/):

{
  "mcpServers": {
    "orders": {
      "command": "npx",
      "args": ["-y", "@acme/orders-mcp"],
      "env": { "PRODUCT_API_KEY": "sk-prod-..." }
    }
  }
}

Два вечных источника тикетов поддержки: конфиг вступает в силу только после полного перезапуска приложения, а невалидный JSON (лишняя запятая) молча ломает загрузку всех серверов. Кладите готовый блок конфигурации в README пакета — пользователи копируют его чаще, чем читают инструкцию.

Cursor и VS Code

Cursor использует тот же формат mcpServers: глобально — ~/.cursor/mcp.json, на проект — .cursor/mcp.json в корне репозитория:

{
  "mcpServers": {
    "orders": {
      "command": "npx",
      "args": ["-y", "@acme/orders-mcp"],
      "env": { "PRODUCT_API_KEY": "sk-prod-..." }
    }
  }
}

Статус виден в Settings → MCP; там же сервер можно перезапустить после обновления пакета.

VS Code (GitHub Copilot agent mode) читает .vscode/mcp.json с другим форматом — ключ servers и явный type. Зато есть механизм inputs, решающий проблему секретов в коммитируемом файле:

{
  "inputs": [
    {
      "id": "product-api-key",
      "type": "promptString",
      "description": "Product API key",
      "password": true
    }
  ],
  "servers": {
    "orders": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@acme/orders-mcp"],
      "env": { "PRODUCT_API_KEY": "${input:product-api-key}" }
    }
  }
}

VS Code запросит значение при первом запуске и сохранит его в защищённом хранилище — файл в git остаётся чистым. Это правильный паттерн для командных репозиториев: конфигурация коммитится, секреты — никогда.

Итого у вашего README три блока подключения: Claude (команда + JSON), Cursor (JSON), VS Code (JSON с inputs). Проверяйте все три на живых клиентах перед релизом — форматы похожи ровно настолько, чтобы перепутать.

Удалённый сервер: Streamable HTTP

Когда сервер — часть продукта, дистрибуция через npm неудобна: обновления у пользователей, секреты на их машинах, нет централизованного контроля. Решение — удалённый сервер на Streamable HTTP: один URL, обновления мгновенны, авторизация по OAuth из урока 4.

С тем же McpServer меняется только транспортный слой — например, на Express:

import express from 'express';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';

const app = express();
app.use(express.json());

app.post('/mcp', async (req, res) => {
  const transport = new StreamableHTTPServerTransport({
    sessionIdGenerator: undefined, // stateless-режим
  });
  res.on('close', () => transport.close());
  await server.connect(transport);
  await transport.handleRequest(req, res, req.body);
});

app.listen(3000);

Stateless-режим (без session id) — самый простой для горизонтального масштабирования: каждый запрос самодостаточен, подойдёт любой балансировщик. Stateful-режим с sessionIdGenerator и заголовком Mcp-Session-Id нужен, когда сервер держит состояние между вызовами или шлёт notifications — тогда потребуется sticky-маршрутизация или общее хранилище сессий.

Подключение у пользователей — одной строкой: claude mcp add --transport http orders https://mcp.acme.dev/mcp; Cursor и VS Code принимают "url" вместо "command" в тех же конфигах. Для публичного каталога добавьте сервер в официальный MCP Registry — клиенты постепенно учатся ставить серверы прямо из него.

Правило выбора: инструмент для разработчиков, работающий с локальными файлами, — npm + stdio; сервис вашего продукта для всех пользователей — удалённый HTTP с OAuth.

Practice

Релиз и подключение к двум клиентам

Соберите пакет своего сервера: shebang, bin, files, prepublishOnly. Прогоните npm pack --dry-run и проверьте состав. Установите пакет локально из tgz и подключите сервер к двум разным клиентам (например, Claude Code через claude mcp add и Cursor через .cursor/mcp.json). Напишите README с блоками конфигурации для трёх клиентов.

Deliverable

Артефакт npm pack, скриншоты списка инструментов сервера в двух клиентах и README с готовыми конфигурациями Claude / Cursor / VS Code.

Checkpoint

Пользователь установил ваш пакет, добавил конфиг, но сервер не появился в Claude Desktop. Назовите наиболее вероятные причины в порядке проверки.

  • ✓ Названы синтаксис JSON-конфига и необходимость полного перезапуска приложения.
  • ✓ Назван PATH-контекст запуска: npx/node может не находиться, лечится абсолютным путём к node.
  • ✓ Названы отсутствующий env-секрет с fail-fast-падением сервера и проверка логов mcp*.log.

Check yourself

Зачем в dist/index.js нужен shebang #!/usr/bin/env node?

01Зачем в dist/index.js нужен shebang #!/usr/bin/env node?

Как раздать MCP-сервер всей команде через репозиторий в Claude Code?

02Как раздать MCP-сервер всей команде через репозиторий в Claude Code?

Чем механизм inputs в .vscode/mcp.json лучше секрета прямо в env-блоке?

03Чем механизм inputs в .vscode/mcp.json лучше секрета прямо в env-блоке?

Когда удалённый Streamable HTTP-сервер предпочтительнее npm-пакета со stdio?

04Когда удалённый Streamable HTTP-сервер предпочтительнее npm-пакета со stdio?

Что даёт stateless-режим StreamableHTTPServerTransport (sessionIdGenerator: undefined)?

05Что даёт stateless-режим StreamableHTTPServerTransport (sessionIdGenerator: undefined)?

Sources

Publishing and Connecting to Claude, Cursor, and VS Code · MCP in Practice: Building Model Context Protocol Servers · VORCL