From 4cd056bf890b73446b33300e40c9595d18ff1484 Mon Sep 17 00:00:00 2001 From: triepod-ai <199543909+triepod-ai@users.noreply.github.com> Date: Mon, 19 Jan 2026 03:45:00 -0600 Subject: [PATCH] docs: Document npm+npx deployment pattern for Node.js MCP servers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add documentation for an alternative Node.js deployment pattern using npm and npx instead of bundling node_modules. This complements the existing uvx pattern for Python. Changes: - MANIFEST.md: Add npx configuration example - README.md: Add npm-based deployment section with trade-offs table - examples/npx-node/: Complete minimal working example Benefits of this pattern: - Smaller bundle sizes (< 50 KB vs 50-300 MB) - Automatic updates from npm - Zero bundle maintenance Trade-offs: - Requires internet on first launch - 30-60 second initial download 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- MANIFEST.md | 18 +++++++++++++ README.md | 32 +++++++++++++++++++++++ examples/npx-node/README.md | 34 ++++++++++++++++++++++++ examples/npx-node/manifest.json | 46 +++++++++++++++++++++++++++++++++ examples/npx-node/package.json | 20 ++++++++++++++ examples/npx-node/src/index.ts | 26 +++++++++++++++++++ examples/npx-node/tsconfig.json | 11 ++++++++ 7 files changed, 187 insertions(+) create mode 100644 examples/npx-node/README.md create mode 100644 examples/npx-node/manifest.json create mode 100644 examples/npx-node/package.json create mode 100644 examples/npx-node/src/index.ts create mode 100644 examples/npx-node/tsconfig.json diff --git a/MANIFEST.md b/MANIFEST.md index 1bb7f50..c68e50b 100644 --- a/MANIFEST.md +++ b/MANIFEST.md @@ -490,6 +490,24 @@ The `mcp_config` object in the server configuration defines how the implementing } ``` +**Node.js Example (npm + npx):** + +For packages published to npm, you can use `npx` to fetch and run the server dynamically instead of bundling `node_modules`: + +```json +"mcp_config": { + "command": "npx", + "args": ["-y", "--package=@your-org/your-mcp-server", "your-mcp-server"], + "env": { + "API_KEY": "${user_config.api_key}" + } +} +``` + +This pattern creates smaller bundles (< 50 KB vs 50-300 MB) and automatically stays up-to-date with npm releases. The `-y` flag auto-confirms installation, and `--package= ` explicitly specifies the package when it has multiple bin entries. See `examples/npx-node/` for a complete example. + +**Note:** Claude Desktop ships with Node.js/npm/npx built-in, so this works out-of-the-box. Users need internet access on first launch. + **Binary Example (Cross-Platform):** ```json diff --git a/README.md b/README.md index f47446c..852be8b 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,38 @@ bundle.mcpb (ZIP file) - Use `npm ci` or `yarn install --frozen-lockfile` for reproducible builds - Server entry point specified in manifest.json's `server.entry_point` +**Node.js Bundles (npm + npx):** + +For packages published to npm, you can use `npx` to dynamically fetch and run the package instead of bundling `node_modules`. This creates significantly smaller bundles that automatically stay up-to-date with npm releases. + +Requirements: +- Package must be published to npm with a `bin` entry in `package.json` +- Claude for macOS and Windows ships with Node.js/npm/npx built-in + +Manifest configuration: +```json +"mcp_config": { + "command": "npx", + "args": ["-y", "--package=@your-org/your-mcp-server", "your-mcp-server"], + "env": {} +} +``` + +Trade-offs: + +| Aspect | Traditional Bundling | npm + npx | +|--------|---------------------|-----------| +| Bundle size | 50-300 MB | < 50 KB | +| First launch | Instant | 30-60s (download) | +| Updates | Manual rebuild | Automatic from npm | +| Offline support | Always works | After first run | + +When to use: +- **Use npx** when your package is published to npm and you want automatic updates +- **Use bundling** when your package is private, unpublished, or requires offline-first support + +See `examples/npx-node/` for a complete working example. + **Binary Bundles:** - Static linking preferred for maximum compatibility diff --git a/examples/npx-node/README.md b/examples/npx-node/README.md new file mode 100644 index 0000000..a015713 --- /dev/null +++ b/examples/npx-node/README.md @@ -0,0 +1,34 @@ +# npm + npx Node.js Example + +This example demonstrates using `npx` to run an npm-published MCP server instead of bundling dependencies. + +## Benefits + +- **Tiny bundles**: ~10 KB instead of 50-300 MB +- **Automatic updates**: Users always get the latest npm version +- **Zero maintenance**: No need to rebuild bundles for updates + +## How It Works + +The manifest uses `npx` as the command: + +```json +"mcp_config": { + "command": "npx", + "args": ["-y", "--package=example-npx-mcp", "example-npx-mcp"] +} +``` + +On first launch, npx downloads the package from npm. Subsequent launches use the cached version. + +## Requirements + +- Package must be published to npm with a `bin` entry +- Claude for macOS and Windows (ships with npx built-in) + +## Testing + +```bash +mcpb validate manifest.json +mcpb pack . +``` diff --git a/examples/npx-node/manifest.json b/examples/npx-node/manifest.json new file mode 100644 index 0000000..2a75d60 --- /dev/null +++ b/examples/npx-node/manifest.json @@ -0,0 +1,46 @@ +{ + "manifest_version": "0.3", + "name": "example-npx-mcp", + "display_name": "Example npx MCP Server", + "version": "1.0.0", + "description": "Demonstrates npm+npx deployment pattern for Node.js MCP servers", + "author": { + "name": "MCP Team" + }, + "repository": { + "type": "git", + "url": "https://github.com/modelcontextprotocol/mcpb.git" + }, + "server": { + "type": "node", + "entry_point": "dist/index.js", + "mcp_config": { + "command": "npx", + "args": ["-y", "--package=example-npx-mcp", "example-npx-mcp"], + "env": { + "API_KEY": "${user_config.api_key}" + } + } + }, + "tools": [ + { + "name": "hello", + "description": "Returns a greeting message" + } + ], + "user_config": { + "api_key": { + "type": "string", + "title": "API Key", + "description": "Optional API key for demonstration", + "sensitive": true, + "required": false + } + }, + "compatibility": { + "platforms": ["darwin", "win32", "linux"], + "runtimes": { + "node": ">=18.0.0" + } + } +} diff --git a/examples/npx-node/package.json b/examples/npx-node/package.json new file mode 100644 index 0000000..a764732 --- /dev/null +++ b/examples/npx-node/package.json @@ -0,0 +1,20 @@ +{ + "name": "example-npx-mcp", + "version": "1.0.0", + "description": "Example MCP server demonstrating npx deployment pattern", + "type": "module", + "main": "dist/index.js", + "bin": { + "example-npx-mcp": "dist/index.js" + }, + "scripts": { + "build": "tsc", + "start": "node dist/index.js" + }, + "dependencies": { + "@modelcontextprotocol/sdk": "^1.0.0" + }, + "devDependencies": { + "typescript": "^5.0.0" + } +} diff --git a/examples/npx-node/src/index.ts b/examples/npx-node/src/index.ts new file mode 100644 index 0000000..8236ce0 --- /dev/null +++ b/examples/npx-node/src/index.ts @@ -0,0 +1,26 @@ +#!/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: "example-npx-mcp", + version: "1.0.0" +}); + +server.tool( + "hello", + "Returns a greeting message", + { + name: { + type: "string", + description: "Name to greet" + } + }, + async ({ name }) => ({ + content: [{ type: "text", text: `Hello, ${name || "World"}!` }] + }) +); + +const transport = new StdioServerTransport(); +await server.connect(transport); diff --git a/examples/npx-node/tsconfig.json b/examples/npx-node/tsconfig.json new file mode 100644 index 0000000..066c742 --- /dev/null +++ b/examples/npx-node/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "outDir": "dist", + "strict": true, + "esModuleInterop": true + }, + "include": ["src/**/*"] +}