Skip to main content
RapidDev - Software Development Agency
mcp-tutorial

How to publish your MCP server to npm

Publish your MCP server to npm so anyone can run it with npx -y your-mcp-server. Configure package.json with a bin entry pointing to your compiled entry file, add a shebang line, compile TypeScript to JavaScript, and run npm publish. Users will then add your server to Claude Desktop or Cursor config with a single npx command — no manual installation needed.

What you'll learn

  • How to configure package.json for npm distribution of an MCP server
  • How to set up the bin entry and shebang for npx execution
  • How to compile, test, and publish your MCP server to npm
  • How users will configure your published server in their AI hosts
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate7 min read20 minnpm registry, Node.js 18+, TypeScriptMarch 2026RapidDev Engineering Team
TL;DR

Publish your MCP server to npm so anyone can run it with npx -y your-mcp-server. Configure package.json with a bin entry pointing to your compiled entry file, add a shebang line, compile TypeScript to JavaScript, and run npm publish. Users will then add your server to Claude Desktop or Cursor config with a single npx command — no manual installation needed.

Package and Distribute Your MCP Server via npm

Publishing your MCP server to npm is the standard way to distribute it. Once published, anyone can run your server with npx -y your-package-name without cloning a repo or installing dependencies manually. This is how the official MCP servers are distributed (e.g., @modelcontextprotocol/server-filesystem). This tutorial covers the complete publishing workflow from package configuration through npm publish.

Prerequisites

  • A working MCP server in TypeScript (tested with MCP Inspector)
  • An npm account (create one at npmjs.com if needed)
  • Node.js 18+ and npm CLI installed
  • Basic understanding of npm package publishing

Step-by-step guide

1

Add the shebang line to your entry file

Add #!/usr/bin/env node as the first line of your server's entry file (src/index.ts). This tells the operating system to execute the file with Node.js when it is run as a CLI command. Without this line, npx cannot execute your package directly.

typescript
1#!/usr/bin/env node
2
3import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5import { z } from "zod";
6
7// ... rest of your server code

Expected result: Your entry file has #!/usr/bin/env node as its first line.

2

Configure package.json for distribution

Update package.json with the fields npm needs for proper distribution. The bin field maps a command name to your compiled entry file. The files field controls which files are included in the published package. Set main to point to the compiled output. Choose a descriptive, unique package name.

typescript
1{
2 "name": "my-weather-mcp-server",
3 "version": "1.0.0",
4 "description": "MCP server for weather data lookups",
5 "type": "module",
6 "main": "dist/index.js",
7 "bin": {
8 "my-weather-mcp-server": "dist/index.js"
9 },
10 "files": [
11 "dist/**/*.js",
12 "dist/**/*.d.ts"
13 ],
14 "scripts": {
15 "dev": "tsx src/index.ts",
16 "build": "tsc",
17 "start": "node dist/index.js",
18 "inspect": "npx -y @modelcontextprotocol/inspector tsx src/index.ts",
19 "prepublishOnly": "npm run build"
20 },
21 "keywords": ["mcp", "model-context-protocol", "weather", "ai-tools"],
22 "license": "MIT",
23 "engines": {
24 "node": ">=18.0.0"
25 },
26 "dependencies": {
27 "@modelcontextprotocol/sdk": "^1.0.0",
28 "zod": "^3.22.0"
29 },
30 "devDependencies": {
31 "typescript": "^5.0.0",
32 "tsx": "^4.0.0",
33 "@types/node": "^20.0.0"
34 }
35}

Expected result: package.json has bin, files, engines, and prepublishOnly configured for npm distribution.

3

Configure TypeScript to emit declarations

Update tsconfig.json to generate declaration files (.d.ts) alongside the compiled JavaScript. This is good practice for npm packages and helps users who might import your server programmatically. Also ensure the output directory matches what package.json references.

typescript
1// tsconfig.json
2{
3 "compilerOptions": {
4 "target": "ES2022",
5 "module": "NodeNext",
6 "moduleResolution": "NodeNext",
7 "outDir": "./dist",
8 "rootDir": "./src",
9 "declaration": true,
10 "declarationMap": true,
11 "sourceMap": true,
12 "strict": true,
13 "esModuleInterop": true,
14 "skipLibCheck": true,
15 "forceConsistentCasingInFileNames": true
16 },
17 "include": ["src/**/*"],
18 "exclude": ["node_modules", "dist"]
19}

Expected result: TypeScript is configured to output compiled JS, declaration files, and source maps to the dist directory.

4

Build and verify the compiled output

Run the build to compile TypeScript to JavaScript. Verify the dist directory contains your compiled files with the shebang preserved. Then test the compiled version with MCP Inspector to ensure it works the same as the development version.

typescript
1# Build
2npm run build
3
4# Verify the shebang is in the compiled file
5head -1 dist/index.js
6# Should output: #!/usr/bin/env node
7
8# Test the compiled version with Inspector
9npx -y @modelcontextprotocol/inspector node dist/index.js

Expected result: dist/index.js exists, starts with the shebang line, and works correctly in the MCP Inspector.

5

Test locally with npm link

Before publishing, test that your package works as if it were installed from npm. Use npm link to create a global symlink, then test running it with npx. This catches issues with missing files, incorrect paths, or misconfigured bin entries.

typescript
1# Create a global link to your package
2npm link
3
4# Test running it as if installed globally
5my-weather-mcp-server
6# (This starts the server on stdio press Ctrl+C to stop)
7
8# Test with Inspector
9npx -y @modelcontextprotocol/inspector my-weather-mcp-server
10
11# Clean up when done
12npm unlink -g my-weather-mcp-server

Expected result: Your server runs correctly via its bin command name, just as it will when installed from npm.

6

Publish to npm

Log in to npm and publish your package. If this is your first time publishing, you will need to verify your email. Use npm publish --access public for scoped packages (e.g., @yourname/mcp-server). The prepublishOnly script runs the build automatically before publishing.

typescript
1# Log in to npm (one-time setup)
2npm login
3
4# Publish the package
5npm publish
6
7# For scoped packages:
8npm publish --access public

Expected result: Your package is live on npm. Users can run it with npx -y my-weather-mcp-server.

7

Document the installation for users

Create clear instructions showing users how to add your server to their AI host configuration. The beauty of npm-published MCP servers is that users just add a single npx command to their config — no cloning or manual setup required.

typescript
1// Claude Desktop: ~/Library/Application Support/Claude/claude_desktop_config.json
2{
3 "mcpServers": {
4 "weather": {
5 "command": "npx",
6 "args": ["-y", "my-weather-mcp-server"]
7 }
8 }
9}
10
11// Cursor: .cursor/mcp.json
12{
13 "mcpServers": {
14 "weather": {
15 "command": "npx",
16 "args": ["-y", "my-weather-mcp-server"]
17 }
18 }
19}
20
21// VS Code: .vscode/mcp.json
22{
23 "servers": {
24 "weather": {
25 "command": "npx",
26 "args": ["-y", "my-weather-mcp-server"]
27 }
28 }
29}

Expected result: Users can add your server to any MCP host with a simple config entry.

Complete working example

package.json
1{
2 "name": "my-weather-mcp-server",
3 "version": "1.0.0",
4 "description": "MCP server for weather data lookups — works with Claude Desktop, Cursor, and VS Code",
5 "type": "module",
6 "main": "dist/index.js",
7 "bin": {
8 "my-weather-mcp-server": "dist/index.js"
9 },
10 "files": [
11 "dist/**/*.js",
12 "dist/**/*.d.ts",
13 "README.md",
14 "LICENSE"
15 ],
16 "scripts": {
17 "dev": "tsx src/index.ts",
18 "build": "tsc",
19 "start": "node dist/index.js",
20 "inspect": "npx -y @modelcontextprotocol/inspector tsx src/index.ts",
21 "prepublishOnly": "npm run build",
22 "test": "npx -y @modelcontextprotocol/inspector node dist/index.js"
23 },
24 "keywords": [
25 "mcp",
26 "model-context-protocol",
27 "weather",
28 "ai-tools",
29 "claude",
30 "cursor"
31 ],
32 "author": "Your Name",
33 "license": "MIT",
34 "engines": {
35 "node": ">=18.0.0"
36 },
37 "repository": {
38 "type": "git",
39 "url": "https://github.com/yourname/my-weather-mcp-server"
40 },
41 "dependencies": {
42 "@modelcontextprotocol/sdk": "^1.0.0",
43 "zod": "^3.22.0"
44 },
45 "devDependencies": {
46 "typescript": "^5.0.0",
47 "tsx": "^4.0.0",
48 "@types/node": "^20.0.0"
49 }
50}

Common mistakes when publishing your MCP server to npm

Why it's a problem: Forgetting the shebang line in the entry file

How to avoid: Without #!/usr/bin/env node as the first line, the OS does not know to run the file with Node.js. npx will fail with a permission or execution error. Add it as the very first line of src/index.ts.

Why it's a problem: Publishing src/ instead of dist/

How to avoid: The files field in package.json must point to the compiled JavaScript in dist/, not the TypeScript source in src/. Users do not have tsx installed and cannot run .ts files directly.

Why it's a problem: Missing the -y flag in user documentation

How to avoid: Always document npx -y your-package (with -y) in configuration examples. Without -y, npx prompts for confirmation which causes the AI host to hang waiting for input that never comes.

Why it's a problem: Not running prepublishOnly build before publishing

How to avoid: If you publish without building, the dist/ directory may be stale or missing. Add "prepublishOnly": "npm run build" to scripts so npm automatically builds before every publish.

Best practices

  • Always include the shebang #!/usr/bin/env node as the first line of your entry file
  • Use the files field to include only dist/ output — do not publish src/, node_modules, or test files
  • Add a prepublishOnly script that runs the build to ensure published code is always fresh
  • Test with npm link before publishing to catch path and configuration issues early
  • Include 'mcp' and 'model-context-protocol' in keywords so users can find your server on npm
  • Document config examples for Claude Desktop, Cursor, and VS Code in your README
  • Always use -y in npx commands shown in documentation to prevent hanging
  • Set engines.node to >=18.0.0 to communicate the minimum Node.js version requirement

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I built an MCP server in TypeScript and want to publish it to npm. Show me the complete package.json configuration including bin, files, scripts, and keywords. Explain the shebang line, the build process, and how users will add my published server to Claude Desktop and Cursor configurations.

MCP Prompt

Help me publish my MCP server to npm. I need the correct package.json configuration, TypeScript build setup, and testing steps. Also generate the README section that shows users how to install and configure my server in their AI tools.

Frequently asked questions

Can I publish a Python MCP server to npm?

No, npm is for JavaScript/TypeScript packages. Python MCP servers should be published to PyPI with pip or as a uvx-runnable package. Users would configure them with command: 'uvx' or command: 'python' instead of npx.

Should I use a scoped package name like @myorg/mcp-server?

Scoped names are great for organizations and avoiding name conflicts. Use npm publish --access public to make scoped packages publicly available. Unscoped names are simpler for users to type in npx commands.

How do I update a published package?

Increment the version in package.json (follow semver: patch for fixes, minor for features, major for breaking changes), then run npm publish again. The prepublishOnly script rebuilds automatically.

Can RapidDev help distribute MCP servers for my organization?

Yes. RapidDev helps teams package, publish, and maintain MCP servers including setting up private npm registries for internal distribution, CI/CD pipelines for automated publishing, and documentation for end users.

How do users pass API keys to my published server?

Document the environment variables your server needs. Users add them to the env field in their host config: { "command": "npx", "args": ["-y", "your-server"], "env": { "API_KEY": "value" } }. Never require hardcoded keys.

What if my package name is taken on npm?

Use a scoped name (@yourname/mcp-weather-server) or choose a more specific name (mcp-openweather-server). Check availability with npm search before publishing.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.