Introduction

An MCP server that nobody can find is an MCP server that nobody uses. Publishing your server to registries, following discovery conventions, and maintaining version compatibility are essential for ecosystem participation. This lesson covers npm publishing with the MCP scope, server discovery mechanisms, configuration schemas, and the versioning strategies that keep the ecosystem healthy.

Key Concepts

  • npm Publishing: MCP servers are distributed as npm packages, typically under the @modelcontextprotocol scope for official servers. Community servers use their own scope or unscoped packages. The package must include a proper bin field pointing to the server entry point.
  • Server Discovery: Users find MCP servers through the official MCP servers repository on GitHub, npm search, community registries, and documentation. Your server's discoverability depends on clear naming, accurate descriptions, and proper npm metadata.
  • Configuration Schemas: Well-designed servers accept configuration through environment variables and a documented schema. Users need to know what configuration is required (API keys, database URLs) and what is optional (timeout values, cache sizes).
  • Version Compatibility: MCP servers should follow semantic versioning. The MCP protocol version your server supports must be documented. Breaking changes to tool signatures require a major version bump.
  • README Conventions: MCP server READMEs follow a consistent structure: description, installation, configuration, available tools (with input/output schemas), and usage examples with Claude Desktop configuration.

Real World Context

You have built an MCP server that wraps your company's internal APIs. Other teams want to use it with Claude Desktop and Cursor. You publish it to your organization's private npm registry with proper configuration documentation. Within a week, three teams have integrated it into their AI workflows. Without publishing and discovery, each team would have built their own integration — exactly the N-times-M problem MCP was designed to solve.

Deep Dive

Publishing to npm

Your package.json must include the right fields for MCP server distribution:

json
{
  "name": "@myorg/mcp-server-analytics",
  "version": "1.2.0",
  "description": "MCP server for analytics queries and dashboards",
  "bin": {
    "mcp-server-analytics": "./dist/index.js"
  },
  "files": ["dist"],
  "keywords": ["mcp", "mcp-server", "analytics", "model-context-protocol"],
  "engines": {
    "node": ">=18.0.0"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^2.0.0",
    "zod": "^3.23.0"
  }
}

The bin field is critical — it defines the executable name that users reference in their MCP host configuration. The files field ensures only compiled output is published, not source code. Keywords including "mcp" and "mcp-server" make your package discoverable via npm search.

Server Entry Point Conventions

The entry point file must include a shebang line for direct execution:

typescript
#!/usr/bin/env node

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

const server = new McpServer({
  name: "analytics-server",
  version: "1.2.0"
});

// ... register tools, resources, prompts ...

const transport = new StdioServerTransport();
await server.connect(transport);

The shebang (#!/usr/bin/env node) tells the operating system to run the file with Node.js. This is necessary for the npx invocation pattern used by Claude Desktop.

Configuration Documentation

Document required and optional configuration clearly:

text
Configuration
─────────────────────────────────────────────────────────
Environment Variable    Required    Description
─────────────────────────────────────────────────────────
ANALYTICS_API_KEY       Yes         API key for analytics service
ANALYTICS_BASE_URL      No          API base URL (default: https://api.analytics.io)
ANALYTICS_TIMEOUT_MS    No          Request timeout in ms (default: 30000)
ANALYTICS_CACHE_TTL     No          Cache TTL in seconds (default: 300)

Users configure these in their MCP host config:

json
{
  "mcpServers": {
    "analytics": {
      "command": "npx",
      "args": ["-y", "@myorg/mcp-server-analytics"],
      "env": {
        "ANALYTICS_API_KEY": "your-key-here"
      }
    }
  }
}

Version Compatibility Matrix

Document which MCP protocol versions your server supports:

text
Server Version    MCP Protocol    Node.js    SDK Version
────────────────  ──────────────  ─────────  ───────────
1.0.x             2024-11-05      >= 18      SDK 1.x
1.1.x             2024-11-05      >= 18      SDK 1.x
2.0.x             2025-11-25      >= 20      SDK 2.x

This helps users know whether your server is compatible with their host's MCP protocol version.

Common Pitfalls

  1. Missing bin field — Without a bin field in package.json, npx cannot find your server's entry point. Users get "command not found" errors that are difficult to debug.
  2. Publishing source instead of compiled output — Use the files field to include only the dist directory. Publishing TypeScript source requires users to have ts-node or a build step, which adds friction.
  3. Undocumented required configuration — If your server needs an API key but does not document it, users get cryptic runtime errors. Validate required configuration at startup and emit clear error messages.

Best Practices

  1. Validate configuration at startup — Check for required environment variables before connecting the transport. If a required variable is missing, print a clear error message to stderr and exit with a non-zero code.
  2. Follow the naming convention — Name your package mcp-server-{domain} (e.g., mcp-server-analytics, mcp-server-slack). This makes it immediately clear that your package is an MCP server for a specific domain.
  3. Include Claude Desktop configuration examples — Users want to copy-paste working configuration. Include exact claude_desktop_config.json snippets in your README.

Summary

  • Publish MCP servers as npm packages with a bin field pointing to the server entry point.
  • Include a shebang line (#!/usr/bin/env node) in the entry point for direct execution.
  • Document all configuration (environment variables) with clear required/optional indicators.
  • Follow the mcp-server-{domain} naming convention for discoverability.
  • Maintain a version compatibility matrix documenting supported MCP protocol versions and Node.js requirements.

Code Examples

json
{
  "name": "@myorg/mcp-server-analytics",
  "version": "1.2.0",
  "description": "MCP server for analytics queries",
  "bin": {
    "mcp-server-analytics": "./dist/index.js"
  },
  "files": ["dist"],
  "keywords": ["mcp", "mcp-server", "analytics"],
  "engines": { "node": ">=18.0.0" },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^2.0.0",
    "zod": "^3.23.0"
  }
}
✓ Completed