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
Add the shebang line to your entry file
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.
1#!/usr/bin/env node23import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";4import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";5import { z } from "zod";67// ... rest of your server codeExpected result: Your entry file has #!/usr/bin/env node as its first line.
Configure package.json for distribution
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.
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.
Configure TypeScript to emit declarations
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.
1// tsconfig.json2{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": true16 },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.
Build and verify the compiled output
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.
1# Build2npm run build34# Verify the shebang is in the compiled file5head -1 dist/index.js6# Should output: #!/usr/bin/env node78# Test the compiled version with Inspector9npx -y @modelcontextprotocol/inspector node dist/index.jsExpected result: dist/index.js exists, starts with the shebang line, and works correctly in the MCP Inspector.
Test locally with npm link
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.
1# Create a global link to your package2npm link34# Test running it as if installed globally5my-weather-mcp-server6# (This starts the server on stdio — press Ctrl+C to stop)78# Test with Inspector9npx -y @modelcontextprotocol/inspector my-weather-mcp-server1011# Clean up when done12npm unlink -g my-weather-mcp-serverExpected result: Your server runs correctly via its bin command name, just as it will when installed from npm.
Publish to npm
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.
1# Log in to npm (one-time setup)2npm login34# Publish the package5npm publish67# For scoped packages:8npm publish --access publicExpected result: Your package is live on npm. Users can run it with npx -y my-weather-mcp-server.
Document the installation for users
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.
1// Claude Desktop: ~/Library/Application Support/Claude/claude_desktop_config.json2{3 "mcpServers": {4 "weather": {5 "command": "npx",6 "args": ["-y", "my-weather-mcp-server"]7 }8 }9}1011// Cursor: .cursor/mcp.json12{13 "mcpServers": {14 "weather": {15 "command": "npx",16 "args": ["-y", "my-weather-mcp-server"]17 }18 }19}2021// VS Code: .vscode/mcp.json22{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
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.
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.
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.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation