# https://github.com/fstubner/npm-run-mcp-server Project Manual

Generated at: 2026-05-30 11:29:43 UTC

## Table of Contents

- [Quick Start Guide](#quick-start)
- [Installation Methods](#installation)
- [Configuration Guide](#configuration-guide)
- [CLI Reference](#cli-reference)
- [System Architecture](#system-architecture)
- [Package Manager Detection](#package-manager-detection)
- [Tool Schema and MCP Integration](#tool-schema)
- [Troubleshooting](#troubleshooting)
- [Integration Testing](#integration-testing)

<a id='quick-start'></a>

## Quick Start Guide

### Related Pages

Related topics: [Installation Methods](#installation), [Configuration Guide](#configuration-guide)



# Quick Start Guide

This guide provides everything you need to get `npm-run-mcp-server` running with your AI assistant in minutes. The server bridges your project's `package.json` scripts to your AI agent using the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/), enabling your AI to execute build, test, and deployment commands directly.

## Prerequisites

Before using `npm-run-mcp-server`, ensure your environment meets the following requirements:

| Requirement | Version | Notes |
|-------------|---------|-------|
| Node.js | ≥ 18.18.0 | Required for running the server binary Source: [package.json:28](https://github.com/fstubner/npm-run-mcp-server/blob/main/package.json) |
| npm, pnpm, yarn, or bun | Any recent version | Package manager is auto-detected Source: [src/index.ts:147-153](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts) |
| MCP-compatible AI client | — | Claude Desktop, Cursor, or VS Code with Copilot |

The server uses the **Stdio transport** for MCP protocol communication, which is the standard transport for local AI integrations. Source: [server.json:15-16](https://github.com/fstubner/npm-run-mcp-server/blob/main/server.json)

## Installation

`npm-run-mcp-server` requires no global installation. The server is executed on-demand via `npx`, which downloads and runs the package automatically.

### No Install Required

Simply reference the package name in your client configuration:

```bash
npx -y npm-run-mcp-server
```

The `-y` flag automatically confirms the download. Source: [README.md:45-51](https://github.com/fstubner/npm-run-mcp-server/blob/main/README.md)

## Client Setup

This section covers configuration for popular MCP-compatible AI clients. Choose your client below:

---

### Claude Desktop

1. Locate your Claude Desktop configuration file:
   - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
   - **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`

2. Add the `npm-scripts` server entry to the `mcpServers` object:

```json
{
  "mcpServers": {
    "npm-scripts": {
      "command": "npx",
      "args": ["-y", "npm-run-mcp-server"]
    }
  }
}
```

3. **Restart Claude Desktop** to load the new configuration.

Source: [README.md:38-48](https://github.com/fstubner/npm-run-mcp-server/blob/main/README.md)

---

### Cursor

1. Open Cursor and navigate to **Settings** → **Features** → **MCP Servers**.

2. Click **+ Add New MCP Server**.

3. Enter the following details:
   | Field | Value |
   |-------|-------|
   | **Type** | `command` |
   | **Name** | `npm-scripts` |
   | **Command** | `npx` |
   | **Args** | `-y npm-run-mcp-server` |

Alternatively, add directly to your workspace `.vscode/settings.json`:

```json
{
  "mcpServers": {
    "npm-scripts": {
      "command": "npx",
      "args": ["-y", "npm-run-mcp-server"]
    }
  }
}
```

Source: [README.md:20-35](https://github.com/fstubner/npm-run-mcp-server/blob/main/README.md)

---

### VS Code (GitHub Copilot)

Add the server configuration to your workspace `.vscode/settings.json`:

```json
{
  "github.copilot.chat.mcpServers": {
    "npm-scripts": {
      "command": "npx",
      "args": ["-y", "npm-run-mcp-server"]
    }
  }
}
```

Source: [README.md:54-60](https://github.com/fstubner/npm-run-mcp-server/blob/main/README.md)

## How It Works

When the server starts, it performs the following initialization sequence:

```mermaid
sequenceDiagram
    participant Client as MCP Client (Claude/Cursor)
    participant Server as npm-run-mcp-server
    participant FS as File System

    Client->>Server: Start process via npx
    Server->>FS: Find nearest package.json
    FS-->>Server: Return package.json path
    Server->>FS: Read package.json contents
    Server->>FS: Detect package manager (npm/pnpm/yarn/bun)
    Server->>FS: Look for npm-run-mcp.config.json
    Server->>FS: Load and parse config (supports JSONC)
    Server->>Server: Filter scripts based on config
    Server->>Server: Register tools per script
    Server->>Server: Watch package.json and config for changes
    Server->>Client: Ready (stdio transport)
    Client->>Server: listTools request
    Server-->>Client: Return available script tools
```

### Package Manager Detection

The server automatically detects which package manager to use:

1. **Explicit override**: If `--pm` flag is provided, use that value
2. **packageManager field**: Check `package.json` for the `packageManager` field
3. **Lockfile heuristic**: Detect based on lockfile presence:
   - `pnpm-lock.yaml` → pnpm
   - `yarn.lock` → yarn
   - `bun.lockb` or `bun.lock` → bun
   - Default → npm

Source: [src/index.ts:147-153](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

## Basic Configuration

While the server works out-of-the-box with no configuration, you may want to restrict which scripts are exposed to your AI agent.

### Creating a Config File

Create `npm-run-mcp.config.json` in your project root (next to `package.json`):

```json
{
  "include": ["test", "lint", "build", "start"]
}
```

This configuration exposes only the specified scripts. Without an `include` array, **all scripts** are exposed by default. Source: [npm-run-mcp.config.schema.json:13-15](https://github.com/fstubner/npm-run-mcp-server/blob/main/npm-run-mcp.config.schema.json)

### Configuration Options

| Option | Type | Description |
|--------|------|-------------|
| `include` | `string[]` | Whitelist of script names to expose. If omitted, all scripts are eligible. |
| `exclude` | `string[]` | Blacklist of script names to hide. |
| `scripts` | `object` | Per-script metadata overrides (description, inputSchema, etc.) |

Source: [npm-run-mcp.config.schema.json:17-31](https://github.com/fstubner/npm-run-mcp-server/blob/main/npm-run-mcp.config.schema.json)

### Supported Config Filenames

The server searches for configuration in this order:

1. Path specified via `--config` CLI flag (highest priority)
2. `npm-run-mcp.config.json` in project root
3. `.npm-run-mcp.json` in project root

The config file supports **JSONC** (JSON with Comments), allowing trailing commas and inline comments. Source: [src/index.ts:189-223](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

## Per-Script Configuration

You can provide detailed metadata for individual scripts to help your AI understand how to use them:

```json
{
  "scripts": {
    "test": {
      "description": "Run the test suite. Use --watch for interactive mode.",
      "inputSchema": {
        "properties": {
          "watch": { "type": "boolean", "description": "Watch files for changes" }
        }
      }
    },
    "build": {
      "description": "Compile TypeScript to JavaScript"
    }
  }
}
```

Source: [npm-run-mcp.config.schema.json:28-45](https://github.com/fstubner/npm-run-mcp-server/blob/main/npm-run-mcp.config.schema.json)

## CLI Flags

The server accepts the following command-line arguments:

| Flag | Description | Example |
|------|-------------|---------|
| `--cwd <path>` | Set the working directory manually | `--cwd /path/to/project` |
| `--pm <manager>` | Force a specific package manager | `--pm pnpm` |
| `--config <path>` | Path to a specific config file | `--config ./config.json` |
| `--verbose` | Enable debug logging to stderr | `--verbose` |
| `--list-scripts` | Print available scripts and exit | `--list-scripts` |

Source: [README.md:67-73](https://github.com/fstubner/npm-run-mcp-server/blob/main/README.md)

### Verbose Mode

Enable verbose logging to troubleshoot server behavior:

```bash
npx npm-run-mcp-server --verbose
```

This outputs diagnostic information including:
- Working directory and detected package.json path
- Detected package manager
- Config file location
- Number of registered tools

Source: [src/index.ts:64-78](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

## Testing Your Setup

### List Available Scripts

Verify the server can see your scripts by running:

```bash
npx npm-run-mcp-server --list-scripts
```

This outputs each script name followed by its command:

```
test: jest
lint: eslint src
build: tsc
start: node dist/index.js
```

Source: [src/index.ts:237-239](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

### Test in Claude Desktop

1. Restart Claude Desktop after adding the configuration.
2. Ask Claude: "What npm scripts are available in this project?"
3. Claude should respond with the list of exposed scripts.

## Dynamic Configuration Reloading

The server watches `package.json` and your config file for changes. When a change is detected, the server exits gracefully (exit code 0), allowing your MCP client to restart it with the updated configuration.

```mermaid
graph LR
    A[Edit package.json] --> B[FS watcher detects change]
    B --> C[Server exits with code 0]
    C --> D[MCP client restarts server]
    D --> E[Server reloads with new scripts]
```

Source: [src/index.ts:266-290](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

## Common Issues

### No Scripts Available

If you see "No scripts found" or "No scripts selected for exposure":

1. Verify `package.json` exists and has a `scripts` section.
2. Check your config file's `include` list—ensure the script names match exactly.
3. Run with `--verbose` to see diagnostic output.

Source: [src/index.ts:79-87](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

### Tool Name Collisions

If two scripts normalize to the same tool name (e.g., `build` and `build:prod`), use `toolName` to disambiguate:

```json
{
  "scripts": {
    "build:prod": {
      "toolName": "build_production"
    }
  }
}
```

Source: [src/index.ts:224-232](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

### Config File Parsing Errors

The config supports JSONC (comments + trailing commas). If you encounter parsing errors:

1. Ensure valid JSON syntax (balanced braces, quotes).
2. Verify no syntax errors in JSON Schema properties.

Source: [src/index.ts:195-209](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

## Environment Variables

| Variable | Effect |
|----------|--------|
| `MCP_VERBOSE` | Enable verbose logging (equivalent to `--verbose`) |
| `DEBUG=mcp*` | Enable debug output if DEBUG includes "mcp" |

Source: [src/index.ts:64-65](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

## Next Steps

- **[Configuration Reference](configuration)** — Full configuration schema and options
- **[Architecture Overview](../architecture)** — Internal server design and MCP integration
- **[Troubleshooting](../troubleshooting)** — Common issues and solutions

## See Also

- [npm-run-mcp-server on NPM](https://www.npmjs.com/package/npm-run-mcp-server)
- [Model Context Protocol Documentation](https://modelcontextprotocol.io)
- [MCP Registry Listing](https://registry.modelcontextprotocol.io)

---

<a id='installation'></a>

## Installation Methods

### Related Pages

Related topics: [Quick Start Guide](#quick-start), [CLI Reference](#cli-reference)



# Installation Methods

This page documents all supported methods for installing and configuring the `npm-run-mcp-server` MCP server. The server bridges your project's `package.json` scripts to AI assistants via the Model Context Protocol (MCP), enabling agents like Claude, Cursor, and GitHub Copilot to execute your existing npm scripts directly.

## Overview

`npm-run-mcp-server` is a Node.js-based MCP server published to npm. It requires **Node.js >= 18.18.0** and communicates with AI clients via the stdio transport protocol. Source: [package.json:29](https://github.com/fstubner/npm-run-mcp-server/blob/main/package.json#L29)

```mermaid
graph TD
    A[AI Client<br/>Claude, Cursor, Copilot] -->|stdio MCP| B[npm-run-mcp-server]
    B -->|Reads| C[package.json]
    B -->|Reads| D[npm-run-mcp.config.json<br/>Optional]
    C -->|Discovers| E[Scripts: build, test, lint...]
    B -->|Executes via| F[Package Manager<br/>npm, pnpm, yarn, bun]
    
    style A fill:#e1f5fe
    style B fill:#fff3e0
    style F fill:#e8f5e9
```

## Method 1: npx (Zero-Install)

The fastest way to use `npm-run-mcp-server` without any installation. The AI client invokes the server via `npx`, which downloads and caches the package automatically.

### Command Structure

```bash
npx -y npm-run-mcp-server [options]
```

| Argument | Purpose |
|----------|---------|
| `-y` | Skip confirmation prompt for npx |
| `npm-run-mcp-server` | Package name on npm |

This is the recommended approach for most users as it requires no upfront setup and always uses the latest version. Source: [README.md](https://github.com/fstubner/npm-run-mcp-server/blob/main/README.md)

### Configuration Example

Add the following to your AI client's MCP server configuration:

```json
{
  "mcpServers": {
    "npm-scripts": {
      "command": "npx",
      "args": ["-y", "npm-run-mcp-server"]
    }
  }
}
```

## Method 2: Global NPM Installation

For developers who prefer a persistent installation or need to run the server from the command line directly, install globally via npm:

```bash
npm install -g npm-run-mcp-server
```

### Running After Global Install

Once installed globally, the server can be invoked directly:

```bash
# List all available scripts
npm-run-mcp-server --list-scripts

# Run the server
npm-run-mcp-server
```

Source: [package.json:7](https://github.com/fstubner/npm-run-mcp-server/blob/main/package.json#L7)

```mermaid
graph LR
    A[Global Install] --> B[npm install -g]
    B --> C[/usr/local/bin/npm-run-mcp-server]
    C --> D[Direct CLI Usage]
    C --> E[MCP Client Connection]
    
    style B fill:#fff3e0
```

## Method 3: Per-Project Installation

For reproducible setups, install `npm-run-mcp-server` as a project dependency:

```bash
npm install --save-dev npm-run-mcp-server
```

### Advantages of Per-Project Installation

- **Version Locking**: Ensures the same server version across all team members
- **CI/CD Compatible**: Predictable behavior in automated environments
- **No External Dependencies**: Everything is managed within the project

Source: [package.json](https://github.com/fstubner/npm-run-mcp-server/blob/main/package.json)

### Package Manager Detection

The server automatically detects which package manager your project uses:

```mermaid
graph TD
    A[Check package.json<br/>packageManager field] --> B{Found?}
    B -->|Yes| C[Use specified PM]
    B -->|No| D[Check lockfiles]
    D --> E{pnpm-lock.yaml?}
    E -->|Yes| F[pnpm]
    E -->|No| G{yarn.lock?}
    G -->|Yes| H[yarn]
    G -->|No| I{bun.lock[b]?}
    I -->|Yes| J[bun]
    I -->|No| K[npm default]
    
    style F fill:#e8f5e9
    style H fill:#e8f5e9
    style J fill:#e8f5e9
    style K fill:#e8f5e9
```

Priority order for package manager detection:
1. Explicit `--pm` CLI argument (highest priority)
2. `packageManager` field in `package.json`
3. Lockfile detection: `pnpm-lock.yaml`, `yarn.lock`, `bun.lock`/`bun.lockb`
4. Default to `npm` (lowest priority)

Source: [src/index.ts](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts) - `detectPackageManager` function

## AI Client Integration

### Claude Desktop

Add the server configuration to your Claude Desktop config file:

**Config File Location:**
- macOS/Linux: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`

```json
{
  "mcpServers": {
    "npm-scripts": {
      "command": "npx",
      "args": ["-y", "npm-run-mcp-server"]
    }
  }
}
```

After editing, restart Claude Desktop to load the new configuration.

Source: [README.md](https://github.com/fstubner/npm-run-mcp-server/blob/main/README.md)

### Cursor

1. Open **Settings** → **Features** → **MCP Servers**
2. Click **+ Add New MCP Server**
3. Enter the following details:

| Field | Value |
|-------|-------|
| Type | `command` |
| Name | `npm-scripts` |
| Command | `npx` |
| Args | `-y npm-run-mcp-server` |

Alternatively, add directly to your workspace `.vscode/settings.json`:

```json
{
  "mcpServers": {
    "npm-scripts": {
      "command": "npx",
      "args": ["-y", "npm-run-mcp-server"]
    }
  }
}
```

Source: [README.md](https://github.com/fstubner/npm-run-mcp-server/blob/main/README.md)

### VS Code (GitHub Copilot Chat)

Add the configuration to your workspace `.vscode/settings.json`:

```json
{
  "github.copilot.chat.mcpServers": {
    "npm-scripts": {
      "command": "npx",
      "args": ["-y", "npm-run-mcp-server"]
    }
  }
}
```

Source: [README.md](https://github.com/fstubner/npm-run-mcp-server/blob/main/README.md)

## Command-Line Options

The server accepts several CLI flags for customization:

| Flag | Description | Example |
|------|-------------|---------|
| `--cwd <path>` | Set the working directory for the server | `--cwd /path/to/project` |
| `--pm <manager>` | Force a specific package manager | `--pm pnpm` |
| `--config <path>` | Path to a custom config file | `--config ./my-config.json` |
| `--verbose` | Enable debug logging to stderr | `--verbose` |
| `--list-scripts` | Print available scripts and exit | `--list-scripts` |

### Working Directory Detection

The server automatically searches for `package.json` starting from the current working directory. It also intelligently handles VS Code and Cursor workspace folders:

```bash
# Run in a specific directory
npx npm-run-mcp-server --cwd /path/to/project

# Run with verbose logging
npx npm-run-mcp-server --verbose

# Force pnpm package manager
npx npm-run-mcp-server --pm pnpm
```

Source: [src/index.ts](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts) - CLI argument parsing section

### Verbose Mode

Enable verbose logging to debug server behavior:

```bash
npx npm-run-mcp-server --verbose
```

Verbose output includes:
- Detected working directory
- Package manager selection
- Config file location
- Script filtering details

You can also enable verbose mode via environment variables:

```bash
MCP_VERBOSE=1 npx npm-run-mcp-server
# or
DEBUG=mcp npx npm-run-mcp-server
```

Source: [src/index.ts](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts) - verbose flag handling

## Configuration Files

After installation, you can create a per-project configuration file to control which scripts are exposed:

| Config File Name | Priority |
|------------------|----------|
| `npm-run-mcp.config.json` | Primary |
| `.npm-run-mcp.json` | Fallback |

Both JSON and JSONC (JSON with Comments) formats are supported. Source: [npm-run-mcp.config.schema.json](https://github.com/fstubner/npm-run-mcp-server/blob/main/npm-run-mcp.config.schema.json)

### Example Configuration

```json
{
  "include": ["test", "lint", "build", "start"],
  "exclude": ["eject", "publish"],
  "scripts": {
    "test": {
      "description": "Run the test suite",
      "inputSchema": {
        "properties": {
          "watch": {
            "type": "boolean",
            "description": "Watch files for changes"
          }
        }
      }
    }
  }
}
```

### Config Schema Properties

| Property | Type | Description |
|----------|------|-------------|
| `include` | `string[]` | Whitelist of script names to expose |
| `exclude` | `string[]` | Blacklist of script names to hide |
| `scripts` | `object` | Per-script metadata overrides |

For detailed schema information, see the [Configuration Schema Reference](./Configuration-Schema). Source: [npm-run-mcp.config.schema.json](https://github.com/fstubner/npm-run-mcp-server/blob/main/npm-run-mcp.config.schema.json)

## MCP Server Manifest

The package includes a `server.json` manifest for MCP registry integration:

```json
{
  "name": "io.github.fstubner/npm-run-mcp-server",
  "description": "An MCP server that exposes package.json scripts as tools for agents.",
  "version": "0.2.13",
  "packages": [{
    "registryType": "npm",
    "identifier": "npm-run-mcp-server",
    "transport": {
      "type": "stdio"
    }
  }]
}
```

Source: [server.json](https://github.com/fstubner/npm-run-mcp-server/blob/main/server.json)

## Installation Troubleshooting

### Common Issues

| Issue | Cause | Solution |
|-------|-------|----------|
| Server not responding | Wrong working directory | Use `--cwd` to specify project path |
| Wrong package manager | Auto-detection failed | Use `--pm <manager>` to override |
| Config file not found | Wrong filename or path | Use `--config <path>` to specify |
| No scripts visible | Empty include/exclude filter | Check configuration file settings |

### Verification Steps

1. **List scripts manually:**
   ```bash
   npx npm-run-mcp-server --list-scripts
   ```

2. **Run with verbose logging:**
   ```bash
   npx npm-run-mcp-server --verbose
   ```

3. **Verify package.json exists:**
   ```bash
   ls -la package.json
   ```

Source: [src/index.ts](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts) - list-scripts and verbose handling

## Dependencies

The server has the following runtime dependencies:

| Package | Version | Purpose |
|---------|---------|---------|
| `@modelcontextprotocol/sdk` | ^1.25.1 | MCP protocol implementation |
| `cross-spawn` | ^7.0.5 | Cross-platform script execution |
| `jsonc-parser` | ^3.3.1 | JSONC parsing (config files) |
| `zod` | ^3.23.8 | Schema validation |

Source: [package.json:20-24](https://github.com/fstubner/npm-run-mcp-server/blob/main/package.json#L20-L24)

## Summary

| Method | Best For | Setup Required |
|--------|----------|----------------|
| npx | Quick testing, demos | None |
| Global npm | CLI usage, multiple projects | Yes (one-time) |
| Per-project dev dep | Team consistency, CI/CD | Yes (per-project) |
| Claude Desktop | Claude AI integration | Yes (config file) |
| Cursor | Cursor IDE integration | Yes (settings UI) |
| VS Code Copilot | GitHub Copilot integration | Yes (settings.json) |

## See Also

- [Configuration Guide](./Configuration-Guide) - Detailed configuration options
- [Configuration Schema](./Configuration-Schema) - JSON Schema reference
- [Architecture Overview](./Architecture) - Internal server architecture
- [Usage Examples](./Usage-Examples) - Common usage patterns
- [MCP Protocol Documentation](https://modelcontextprotocol.io/) - MCP specification

---

<a id='configuration-guide'></a>

## Configuration Guide

### Related Pages

Related topics: [CLI Reference](#cli-reference), [Tool Schema and MCP Integration](#tool-schema)



# Configuration Guide

This guide covers all configuration options for `npm-run-mcp-server`, enabling you to control which package.json scripts are exposed to AI agents and customize their behavior.

## Overview

`npm-run-mcp-server` works without any configuration out of the box, automatically detecting your project's `package.json` and exposing all scripts. However, in most production scenarios, you'll want to restrict which scripts are available to your AI assistant for security and usability reasons.

The configuration system provides:

- **Script filtering**: Whitelist (`include`) or blacklist (`exclude`) specific scripts
- **Per-script metadata**: Customize tool names, descriptions, and input schemas
- **JSONC support**: Use comments and trailing commas in config files
- **CLI overrides**: Override config file settings via command-line flags

---

## Configuration Files

### File Discovery

The server searches for configuration files in the following order, stopping at the first match:

1. Path specified via `--config` CLI flag
2. `npm-run-mcp.config.json` in the project root
3. `.npm-run-mcp.json` in the project root

Source: [src/index.ts:48-68](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts#L48-L68)

```mermaid
graph TD
    A[Start] --> B{--config flag set?}
    B -->|Yes| C[Load from specified path]
    B -->|No| D{npm-run-mcp.config.json exists?}
    D -->|Yes| E[Load npm-run-mcp.config.json]
    D -->|No| F{.npm-run-mcp.json exists?}
    F -->|Yes| G[Load .npm-run-mcp.json]
    F -->|No| H[Use empty config]
    C --> I[Parse and apply config]
    E --> I
    G --> I
```

### File Format

Configuration files support **JSONC** (JSON with Comments), allowing:

- Line comments (`// comment`)
- Block comments (`/* comment */`)
- Trailing commas

Source: [src/index.ts:96-110](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts#L96-L110)

### Basic Example

Create `npm-run-mcp.config.json` in your project root:

```jsonc
{
  // Only expose safe scripts to the AI agent
  "include": ["dev", "build", "test", "lint", "typecheck"],
  
  // Scripts to never expose
  "exclude": ["publish", "release", "eject", "deploy"],
  
  // Per-script customization
  "scripts": {
    "test": {
      "description": "Run the test suite. Use --watch for interactive mode.",
      "inputSchema": {
        "properties": {
          "watch": { "type": "boolean", "description": "Watch files for changes" }
        }
      }
    }
  }
}
```

---

## Configuration Schema

The complete configuration schema is published at `npm-run-mcp.config.schema.json` and validates your config files.

Source: [npm-run-mcp.config.schema.json](https://github.com/fstubner/npm-run-mcp-server/blob/main/npm-run-mcp.config.schema.json)

### Configuration Options

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `include` | `string[]` | No | Whitelist of exact script names to expose. If omitted, all scripts (except those in `exclude`) are exposed. |
| `exclude` | `string[]` | No | Blacklist of exact script names to hide. Takes precedence over `include`. |
| `scripts` | `object` | No | Per-script configuration overrides. Keys must match script names in `package.json`. |

Source: [npm-run-mcp.config.schema.json:12-30](https://github.com/fstubner/npm-run-mcp-server/blob/main/npm-run-mcp.config.schema.json#L12-L30)

---

## Per-Script Configuration

Each script in the `scripts` object can have the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `toolName` | `string` | Override the tool name seen by the AI. By default, the script name is normalized (lowercased, special characters replaced with underscores). |
| `description` | `string` | Custom description to help the AI understand when and how to use the script. |
| `argsDescription` | `string` | Description shown for the `args` input field in the MCP tool. |
| `inputSchema` | `object` | JSON Schema defining additional tool inputs. These keys are converted to CLI arguments. |

Source: [npm-run-mcp.config.schema.json:31-50](https://github.com/fstubner/npm-run-mcp-server/blob/main/npm-run-mcp.config.schema.json#L31-L50)

### Tool Name Normalization

MCP tools can only contain lowercase letters, numbers, underscores, and hyphens (`[a-z0-9_-]`). The server automatically sanitizes script names:

- `"test:unit"` → `"test_unit"`
- `"build:prod"` → `"build_prod"`
- `"serve-hot"` → `"serve_hot"`

To override this behavior, use the `toolName` property:

```json
{
  "scripts": {
    "test:unit": {
      "toolName": "run_unit_tests",
      "description": "Run unit tests with Jest"
    }
  }
}
```

Source: [src/index.ts:112-114](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts#L112-L114)

### Tool Name Collisions

If two scripts normalize to the same tool name, the server will exit with an error and list the collisions. To resolve:

```json
{
  "scripts": {
    "test": {
      "toolName": "run_tests"
    },
    "test:e2e": {
      "toolName": "run_e2e_tests"
    }
  }
}
```

Source: [src/index.ts:116-130](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts#L116-L130)

---

## Input Schema to CLI Arguments

The `inputSchema` property lets you define structured inputs that are converted to CLI arguments when the script runs.

### Supported JSON Schema Types

| JSON Schema Type | CLI Output | Example |
|-----------------|------------|---------|
| `boolean` | `--key` (present) or `--no-key` (absent) | `{ "watch": true }` → `--watch` |
| `string` | `--key value` | `{ "env": "production" }` → `--env production` |
| `enum` | `--key value` | `{ "tier": "free" }` → `--tier free` |
| `array` | Multiple `--key value` | `{ "tags": ["a", "b"] }` → `--tags a --tags b` |

Source: [src/index.ts:132-180](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts#L132-L180)

### Example: Complex Input Schema

```json
{
  "scripts": {
    "build": {
      "description": "Build the project for production or development",
      "inputSchema": {
        "type": "object",
        "properties": {
          "mode": {
            "type": "string",
            "enum": ["development", "production", "staging"],
            "description": "Build mode"
          },
          "watch": {
            "type": "boolean",
            "description": "Watch for file changes"
          },
          "analyze": {
            "type": "boolean",
            "description": "Generate bundle analysis"
          }
        }
      }
    }
  }
}
```

When the AI calls the `build` tool with `{ "mode": "production", "analyze": true }`, the server executes:

```bash
npm run build -- --mode production --analyze
```

---

## CLI Options

The server accepts the following command-line flags:

| Flag | Description | Overrides Config |
|------|-------------|------------------|
| `--cwd <path>` | Set the working directory for script execution | No |
| `--pm <npm\|pnpm\|yarn\|bun>` | Force a specific package manager | No |
| `--config <path>` | Path to a specific configuration file | Yes |
| `--verbose` | Enable debug logging to stderr | No |
| `--list-scripts` | Print available scripts and exit (for testing) | N/A |

### Usage Examples

```bash
# Run in a specific directory
npx npm-run-mcp-server --cwd /path/to/project

# Force pnpm package manager
npx npm-run-mcp-server --pm pnpm

# Use a custom config file
npx npm-run-mcp-server --config ./mcp-config.json

# Enable verbose output
npx npm-run-mcp-server --verbose

# List available scripts (for debugging)
npx npm-run-mcp-server --list-scripts
```

Source: [src/index.ts:16-38](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts#L16-L38)

---

## Environment Variables

The following environment variables affect server behavior:

| Variable | Description |
|----------|-------------|
| `MCP_VERBOSE` | Enable verbose logging (any truthy value) |
| `DEBUG` | If set and contains "mcp" (case-insensitive), enables verbose logging |
| `VSCODE_WORKSPACE_FOLDER` | Used for workspace detection in VS Code |
| `CURSOR_WORKSPACE_FOLDER` | Used for workspace detection in Cursor |

Source: [src/index.ts:74-82](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts#L74-L82)

---

## Package Manager Detection

The server automatically detects which package manager to use based on:

1. **Explicit override**: `--pm` CLI flag
2. **packageManager field**: The `packageManager` field in `package.json` (e.g., `"pnpm@8.0.0"`)
3. **Lockfile heuristics**: Check for `pnpm-lock.yaml`, `yarn.lock`, `bun.lockb`, or `bun.lock`
4. **Fallback**: Default to `npm`

Source: [src/index.ts:182-194](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts#L182-L194)

---

## Script Filtering Logic

The following diagram shows how scripts are filtered:

```mermaid
graph TD
    A[All scripts from package.json] --> B{include array set?}
    B -->|Yes| C[Filter to only included scripts]
    B -->|No| D[Keep all scripts]
    C --> E{exclude array set?}
    D --> E
    E -->|Yes| F[Remove excluded scripts]
    E -->|No| G[Final script list]
    F --> G
    G --> H[Register as MCP tools]
```

### Filtering Example

Given these scripts in `package.json`:
```json
{
  "scripts": {
    "dev": "...",
    "build": "...",
    "test": "...",
    "publish": "...",
    "deploy": "..."
  }
}
```

And this config:
```json
{
  "include": ["dev", "build", "test"],
  "exclude": ["publish"]
}
```

Result: Only `dev`, `build`, and `test` are exposed to the AI agent.

---

## File Watching and Hot Reload

When the server detects changes to `package.json` or the config file, it automatically exits (exit code 0) to allow the MCP client to restart it with the updated configuration.

Source: [src/index.ts:222-250](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts#L222-L250)

The server sets up file watchers for:
- The detected `package.json` path
- The active config file path (if any)

Cleanup handlers are registered for `SIGINT` and `SIGTERM` signals to properly close watchers.

---

## Common Configuration Patterns

### Pattern 1: Safe Defaults with Exclusions

```json
{
  "exclude": ["publish", "release", "eject", "prune", "cache:clean"]
}
```

### Pattern 2: Explicit Whitelist

```json
{
  "include": ["dev", "build", "test", "lint", "typecheck", "preview"]
}
```

### Pattern 3: Development-Only Scripts

```json
{
  "include": ["dev", "build", "test"],
  "exclude": ["start:prod", "debug"],
  "scripts": {
    "dev": {
      "description": "Start development server with hot reload"
    }
  }
}
```

### Pattern 4: Production Build with Analysis

```json
{
  "include": ["build", "test:ci"],
  "scripts": {
    "build": {
      "toolName": "build_production",
      "description": "Build for production with bundle analysis",
      "inputSchema": {
        "properties": {
          "analyze": {
            "type": "boolean",
            "description": "Generate interactive bundle analysis"
          }
        }
      }
    }
  }
}
```

---

## Troubleshooting

### No Scripts Found

```
npm-run-mcp-server: No package.json found starting from /path/to/directory
```

**Solution**: Ensure you're running the server from a directory containing `package.json`, or use `--cwd` to specify the correct path.

### No Scripts Selected

```
npm-run-mcp-server: No scripts selected for exposure. Check your config "include"/"exclude" settings.
```

**Solution**: Verify your `include` array contains script names that exist in `package.json`. Use `--verbose` for debug output.

### Config File Parse Error

```
npm-run-mcp-server: Failed to read config file /path/to/config.json: Unexpected token }
```

**Solution**: Ensure your config file is valid JSON. Remember that JSONC allows comments and trailing commas, but standard JSON does not.

### Missing Scripts in Include List

If `--verbose` is enabled, the server warns about include list entries that don't match any scripts:

```
[mcp] include list references missing scripts: build:missing, deploy:staging
```

**Solution**: Either remove these entries from `include` or add corresponding scripts to `package.json`.

---

## See Also

- [Installation Guide](Installation) - Setting up npm-run-mcp-server with various AI clients
- [README.md](https://github.com/fstubner/npm-run-mcp-server/blob/main/README.md) - Project overview and quick start
- [MCP Protocol Documentation](https://modelcontextprotocol.io/) - Understanding the MCP protocol

---

<a id='cli-reference'></a>

## CLI Reference

### Related Pages

Related topics: [Configuration Guide](#configuration-guide), [Troubleshooting](#troubleshooting)



# CLI Reference

This page documents the command-line interface for `npm-run-mcp-server`, a Model Context Protocol server that exposes `package.json` scripts as tools for AI agents.

## Overview

The `npm-run-mcp-server` CLI provides a bridge between your project's npm scripts and AI assistants via the MCP protocol. It auto-detects your project context, package manager, and available scripts without requiring any configuration. Source: [src/index.ts:1-50]()

### Entry Point

The CLI binary is defined in `package.json` and can be invoked via npx or direct execution:

```bash
# Via npx (recommended)
npx npm-run-mcp-server [options]

# Direct execution after global/local install
npm-run-mcp-server [options]

# Via Node.js
node ./dist/index.js [options]
```

Source: [package.json:10-12]()

### Requirements

- **Node.js**: `>=18.18.0`
- **Package Manager**: npm, pnpm, yarn, or bun

Source: [package.json:29]()

## Command Line Options

### Synopsis

```
npm-run-mcp-server [options]
npm-run-mcp-server --cwd <path> --pm <manager> --config <file> --verbose
npm-run-mcp-server --list-scripts
```

### Options

| Option | Description | Default |
|--------|-------------|---------|
| `--cwd <path>` | Set the working directory for script execution | Current working directory |
| `--pm <manager>` | Force a specific package manager (`npm`, `pnpm`, `yarn`, `bun`) | Auto-detected |
| `--config <path>` | Path to a specific JSON configuration file | Auto-discovered |
| `--verbose` | Enable verbose debug logging to stderr | Disabled |
| `--list-scripts` | Print available scripts and exit | Disabled |

Source: [README.md:58-68]()

### `--cwd` Option

Sets the working directory where the server looks for `package.json` and executes scripts. If not specified, the server uses the current working directory and attempts to find a suitable parent directory if running within the MCP server's own directory.

```bash
# Run in a specific project directory
npx npm-run-mcp-server --cwd /path/to/project

# Run in the current directory
npx npm-run-mcp-server --cwd .
```

The server implements intelligent workspace detection:

```mermaid
graph TD
    A[Start] --> B{Running in MCP server dir?}
    B -->|Yes| C[Search parent dirs for package.json]
    C --> D{Found within 5 levels?}
    D -->|Yes| E[Use found directory]
    D -->|No| F[Use current directory]
    B -->|No| G[Use current directory]
    E --> H[Load package.json]
    F --> H
    G --> H
```

Source: [src/index.ts:48-69]()

### `--pm` Option

Forces a specific package manager for script execution, bypassing auto-detection.

```bash
# Force pnpm
npx npm-run-mcp-server --pm pnpm

# Force yarn
npx npm-run-mcp-server --pm yarn
```

**Supported values**: `npm`, `pnpm`, `yarn`, `bun`

Source: [src/index.ts:146-158]()

### `--config` Option

Specifies a path to a custom configuration file, overriding the default config file discovery.

```bash
# Use a specific config file
npx npm-run-mcp-server --config /path/to/custom-config.json
```

The config file supports both JSON and JSONC (JSON with Comments) formats, allowing trailing commas and comments.

Source: [src/index.ts:190-210]()

### `--verbose` Option

Enables detailed debug logging to stderr, useful for troubleshooting configuration issues.

```bash
# Enable verbose logging
npx npm-run-mcp-server --verbose
```

Verbose output includes:
- Detected working directory and workspace folder
- Located `package.json` path
- Loaded server name and version
- Detected package manager
- Configuration file path (if used)
- Number of registered tools

Source: [src/index.ts:27-44]()

### `--list-scripts` Option

Lists all available scripts based on current configuration (respects `include`/`exclude` filters) and exits immediately. Useful for debugging configuration.

```bash
npx npm-run-mcp-server --list-scripts
```

**Output format**:
```
<script-name>: <script-command>
```

Example output:
```
dev: vite
build: vite build
test: vitest run
lint: eslint src
```

Source: [src/index.ts:238-243]()

## Package Manager Detection

The server automatically detects which package manager your project uses based on a priority order.

### Detection Priority

```mermaid
graph LR
    A[Detect Package Manager] --> B{Override --pm flag?}
    B -->|Yes| Z[Use specified manager]
    B -->|No| C{packageManager field?}
    C -->|Yes| Y[Use packageManager value]
    C -->|No| D{pnpm-lock.yaml?}
    D -->|Yes| X[Use pnpm]
    D -->|No| E{yarn.lock?}
    E -->|Yes| W[Use yarn]
    E -->|No| F{bun.lock/bun.lockb?}
    F -->|Yes| V[Use bun]
    F -->|No| U[Default to npm]
```

Source: [src/index.ts:146-158]()

### Lockfile Heuristics

The server checks for lockfiles in the project directory:

| Lockfile | Package Manager |
|----------|-----------------|
| `pnpm-lock.yaml` | pnpm |
| `yarn.lock` | yarn |
| `bun.lock` or `bun.lockb` | bun |
| None found | npm (default) |

Source: [src/index.ts:150-157]()

### `packageManager` Field Support

If your `package.json` contains a `packageManager` field (used by corepack), it takes precedence over lockfile detection:

```json
{
  "packageManager": "pnpm@8.0.0"
}
```

The server extracts the package manager name from this field, supporting `npm`, `pnpm`, `yarn`, and `bun`.

Source: [src/index.ts:148-149]()

## Configuration File Options

The server supports per-project configuration to control which scripts are exposed and their metadata.

### Configuration File Discovery

The server searches for configuration files in this order:

1. Path specified via `--config <path>` CLI flag
2. `npm-run-mcp.config.json` in project root
3. `.npm-run-mcp.json` in project root

Source: [src/index.ts:190-210]()

### Configuration Schema

| Field | Type | Description |
|-------|------|-------------|
| `include` | `string[]` | Exact script names to include. If omitted, all scripts are eligible (subject to `exclude`). |
| `exclude` | `string[]` | Exact script names to exclude. |
| `scripts` | `object` | Per-script tool metadata overrides. |

Source: [npm-run-mcp.config.schema.json:8-28]()

### Per-Script Configuration

Inside the `scripts` object, map script names to their configuration:

| Field | Type | Description |
|-------|------|-------------|
| `toolName` | `string` | Override the tool name (after sanitization). |
| `description` | `string` | Custom description for the tool. |
| `inputSchema` | `object` | JSON Schema for additional tool inputs (converted to CLI args). |
| `argsDescription` | `string` | Description for the `args` input field. |

Source: [npm-run-mcp.config.schema.json:30-45]()

### Example Configuration

```json
{
  "include": ["test", "lint", "build", "start"],
  "exclude": ["publish", "eject"],
  "scripts": {
    "test": {
      "description": "Run the test suite. Use --watch for interactive mode.",
      "inputSchema": {
        "properties": {
          "watch": { "type": "boolean", "description": "Watch files for changes" }
        }
      }
    },
    "build:prod": {
      "toolName": "build_production"
    }
  }
}
```

Source: [README.md:80-95]()

## Tool Name Normalization

MCP tools have naming constraints—they can only contain lowercase letters, numbers, underscores, and hyphens: `[a-z0-9_-]`.

### Normalization Rules

The server sanitizes script names automatically:

1. Convert to lowercase
2. Replace any non-alphanumeric character (except `_` and `-`) with underscore `_`
3. If the result is empty, use `script` as fallback

```javascript
// Examples:
"test:unit"     → "test_unit"
"build:prod"    → "build_prod"
"lint-fix"      → "lint_fix"
"@scope/script" → "_scope_script"
```

Source: [src/index.ts:220-222]()

### Tool Name Collisions

If two scripts normalize to the same tool name, the server exits with an error:

```
npm-run-mcp-server: Tool name collisions detected. Set "scripts.<name>.toolName" in npm-run-mcp.config.json to disambiguate.
  normalized_name: script1, script2
```

To resolve collisions, use the `toolName` override in your config:

```json
{
  "scripts": {
    "script-one": { "toolName": "run_script_one" },
    "script_1": { "toolName": "run_script_1" }
  }
}
```

Source: [src/index.ts:224-234]()

## Environment Variables

### Verbose Logging

| Variable | Description |
|----------|-------------|
| `MCP_VERBOSE` | Set to any value to enable verbose logging |
| `DEBUG` | If contains `mcp` (case-insensitive), enables verbose logging |

Source: [src/index.ts:27-28]()

### Workspace Detection

| Variable | Description |
|----------|-------------|
| `VSCODE_WORKSPACE_FOLDER` | VS Code workspace folder (for verbose logging) |
| `CURSOR_WORKSPACE_FOLDER` | Cursor IDE workspace folder (for verbose logging) |

Source: [src/index.ts:31]()

## Command Execution

### Running Scripts

When an AI agent invokes a tool, the server executes the corresponding npm script:

```bash
<package-manager> run <script-name> [-- <extra-args>]
```

Examples:
- `npm run build`
- `pnpm run test -- --watch`
- `yarn dev`

Source: [src/index.ts:160-166]()

### Command Builder

The `buildRunCommand` function constructs the spawn command:

```javascript
// Without extra args
{ command: "npm", args: ["run", "build"] }

// With extra args
{ command: "npm", args: ["run", "test", "--", "--watch"] }
```

Source: [src/index.ts:160-166]()

### Tool Input to CLI Args

When a tool receives input matching the configured `inputSchema`, those inputs are converted to CLI arguments:

```javascript
// inputSchema:
{
  "properties": {
    "watch": { "type": "boolean" }
  }
}

// Tool call with { watch: true }
→ CLI args: ["--watch"]
```

Source: [src/index.ts:180-188]()

### Timeout Handling

The server has a default timeout for script execution. If a script times out, the response includes:

```
Command timed out after <timeout> seconds: <command> <args>
```

Source: [src/index.ts:280-282]()

## Exit Codes

| Code | Description |
|------|-------------|
| `0` | Success (or `--list-scripts` completed) |
| `1` | Error (invalid config, collision, missing package.json) |

### Error Scenarios

**No package.json found**:
```
npm-run-mcp-server: No package.json found starting from <path>
```

**No scripts selected**:
```
npm-run-mcp-server: No scripts selected for exposure. Check your config "include"/"exclude" settings.
```

**Tool name collision**:
```
npm-run-mcp-server: Tool name collisions detected. Set "scripts.<name>.toolName"...
```

**Invalid config file**:
```
npm-run-mcp-server: Failed to read config file <path>: <error-message>
```

Source: [src/index.ts:70-75, 83-90, 198-209, 224-234]()

## File Watching

The server watches `package.json` and the config file for changes. When a change is detected, the server exits gracefully (exit code 0) to allow the MCP client to restart it with the updated configuration.

```mermaid
graph LR
    A[Start Server] --> B[Register Tools]
    B --> C[Watch package.json]
    C --> D[Watch config file?]
    D -->|Yes| E[Watch config]
    D -->|No| F[Await requests]
    E --> F
    F --> G{File changed?}
    G -->|Yes| H[Exit 0]
    G -->|No| F
    H --> I[Client restarts server]
```

Source: [src/index.ts:330-360]()

### Signal Handling

The server handles termination signals gracefully:

- `SIGINT`: Clean up watchers, exit 0
- `SIGTERM`: Clean up watchers, exit 0

Source: [src/index.ts:348-357]()

## See Also

- [Home](../Home) - Overview of npm-run-mcp-server
- [Configuration Guide](../Configuration) - Detailed configuration examples
- [MCP Integration](../MCP-Integration) - Setting up with AI clients
- [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk) - MCP SDK documentation

---

<a id='system-architecture'></a>

## System Architecture

### Related Pages

Related topics: [Package Manager Detection](#package-manager-detection), [Tool Schema and MCP Integration](#tool-schema)



# System Architecture

npm-run-mcp-server is a Model Context Protocol (MCP) server that bridges `package.json` scripts to AI agents. This page describes the internal architecture, component relationships, and data flows that enable this functionality.

---

## Overview

The server operates as a middle layer between an AI agent and the local project's npm ecosystem. It reads the project's `package.json`, exposes scripts as MCP tools, and executes them on behalf of the agent.

```mermaid
graph TD
    subgraph "AI Agent"
        A[MCP Client]
    end
    
    subgraph "npm-run-mcp-server"
        B[StdioServerTransport]
        C[McpServer]
        D[Tool Registry]
        E[Package Manager Detection]
        F[Config Parser]
    end
    
    subgraph "Local Project"
        G[package.json]
        H[Config File]
        I[node_modules]
    end
    
    A <-->|"MCP Protocol"| B
    B <--> C
    C --> D
    C --> E
    C --> F
    D -->|"listToolNames"| G
    D -->|"executeScript"| I
    F --> H
```

Source: [src/index.ts:1-50](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

---

## Core Components

### 1. StdioServerTransport

The server uses the **StdioServerTransport** from the `@modelcontextprotocol/sdk` package for communication with MCP clients. This transport uses standard input/output streams, making it compatible with various AI agent platforms like Claude Desktop, Cursor, and VS Code Copilot.

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

Source: [src/index.ts:120-123](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

### 2. McpServer

The `McpServer` instance from `@modelcontextprotocol/sdk` manages the MCP protocol lifecycle, including:
- Handling `initialize` requests from clients
- Managing tool registration and discovery
- Processing tool execution requests

```typescript
const server = new McpServer({ name: serverName, version: serverVersion });
```

Source: [src/index.ts:66-68](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

### 3. Tool Registration System

Each `package.json` script is registered as an MCP tool using the `registerTool` method. The registration process includes:

| Parameter | Description |
|-----------|-------------|
| `toolName` | Sanitized name (lowercase, alphanumeric + underscore/hyphen) |
| `description` | Human-readable description of the script |
| `inputSchema` | JSON Schema for tool arguments (converted to Zod) |

```typescript
server.registerTool(
  toolName,
  {
    description,
    inputSchema: buildToolInputSchema(configForScript),
  },
  async (input: Record<string, unknown>) => { /* execution logic */ }
);
```

Source: [src/index.ts:155-167](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

---

## Package Manager Detection

The server automatically detects which package manager the project uses based on the following priority:

```mermaid
graph TD
    A[Detect Package Manager] --> B{packageManager field?}
    B -->|Yes| C[Parse packageManager field]
    B -->|No| D{pnpm-lock.yaml exists?}
    D -->|Yes| E[Use pnpm]
    D -->|No| F{yarn.lock exists?}
    F -->|Yes| G[Use yarn]
    F -->|No| H{bun.lock exists?}
    H -->|Yes| I[Use bun]
    H -->|No| J[Use npm]
    C --> K[Return PM]
    E --> K
    G --> K
    I --> K
    J --> K
```

The detection logic checks for:
1. `packageManager` field in `package.json` (e.g., `pnpm@8.0.0`)
2. Lockfiles: `pnpm-lock.yaml`, `yarn.lock`, `bun.lock`/`bun.lockb`
3. Falls back to `npm` if no lockfile is found

Source: [src/index.ts:178-194](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

---

## Configuration System

### Config File Discovery

The server searches for configuration files in this order:

| Priority | Filename | Location |
|----------|----------|----------|
| 1 | Path provided via `--config` CLI flag | User-specified |
| 2 | `npm-run-mcp.config.json` | Project root |
| 3 | `.npm-run-mcp.json` | Project root |

Source: [src/index.ts:248-270](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

### JSONC Support

Configuration files support JSON with Comments (JSONC), allowing developers to include trailing commas and inline comments:

```typescript
const parsed = parseJsonOrJsonc(raw, candidate);
```

Source: [src/index.ts:258](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

### Configuration Schema

The `npm-run-mcp.config.schema.json` defines the structure:

| Field | Type | Description |
|-------|------|-------------|
| `include` | `string[]` | Whitelist of script names to expose |
| `exclude` | `string[]` | Blacklist of script names to hide |
| `scripts` | `object` | Per-script metadata overrides |

Source: [npm-run-mcp.config.schema.json:1-50](https://github.com/fstubner/npm-run-mcp-server/blob/main/npm-run-mcp.config.schema.json)

### Per-Script Configuration

Each script can have the following overrides:

| Property | Type | Purpose |
|----------|------|---------|
| `toolName` | `string` | Override the generated tool name |
| `description` | `string` | Custom description for the tool |
| `inputSchema` | `object` | JSON Schema for additional tool inputs |
| `argsDescription` | `string` | Description for the args input field |

Source: [npm-run-mcp.config.schema.json:40-55](https://github.com/fstubner/npm-run-mcp-server/blob/main/npm-run-mcp.config.schema.json)

---

## Tool Execution Flow

```mermaid
sequenceDiagram
    participant Agent as AI Agent
    participant Server as MCP Server
    participant Spawn as cross-spawn
    participant PM as Package Manager

    Agent->>Server: Call tool "test" with args {watch: true}
    Server->>Server: Validate input against inputSchema
    Server->>Spawn: spawn(pm, ["run", "test", "--", "--watch"])
    Spawn->>PM: Execute: pnpm run test -- --watch
    PM-->>Spawn: stdout/stderr streams
    Spawn-->>Server: ProcessResult {stdout, stderr, exitCode}
    Server->>Server: Format response
    Server-->>Agent: ToolResult with output
```

### Execution Parameters

The `buildRunCommand` function constructs the execution command:

```typescript
function buildRunCommand(
  pm: PackageManager,
  scriptName: string,
  extraArgs: string[]
): { command: string; args: string[] } {
  const baseArgs = ['run', scriptName];
  const args = extraArgs.length > 0 ? [...baseArgs, '--', ...extraArgs] : baseArgs;
  return { command: pm, args };
}
```

Source: [src/index.ts:196-204](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

---

## Project Discovery

The server locates the project to manage using a hierarchical search strategy:

```mermaid
graph TD
    A[Start: process.cwd] --> B{Running in mcp-server dir?}
    B -->|Yes| C[Search parent dirs for package.json]
    B -->|No| E[Use current directory]
    C --> D{Found within 5 levels?}
    D -->|Yes| E
    D -->|No| F[Use current directory]
    E --> G[Find nearest package.json]
    F --> G
    G --> H[Read and parse package.json]
```

This approach handles both local development (when the MCP server runs from within the project) and production scenarios (when AI editors like Cursor or VS Code invoke the server from different working directories).

Source: [src/index.ts:14-43](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

---

## Hot Reload Support

The server monitors `package.json` and the config file for changes using Node.js `fs.watch`:

```typescript
watchers.push(
  watch(pathToWatch, (eventType) => {
    if (eventType !== 'change') return;
    process.exit(0);  // Exit to allow MCP client to restart
  })
);
```

Source: [src/index.ts:217-226](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

### Signal Handling

The server gracefully handles termination signals:

```typescript
process.on('SIGINT', () => {
  cleanup();
  process.exit(0);
});
process.on('SIGTERM', () => {
  cleanup();
  process.exit(0);
});
```

Source: [src/index.ts:228-234](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

---

## Tool Name Normalization

MCP tools must have names containing only `[a-z0-9_-]`. The `normalizeToolName` function sanitizes script names:

```typescript
function normalizeToolName(name: string): string {
  const normalized = name.toLowerCase().replace(/[^a-z0-9_-]/g, '_');
  return normalized.length > 0 ? normalized : 'script';
}
```

Source: [src/index.ts:275-278](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

### Name Collision Detection

When multiple scripts normalize to the same tool name, the server exits with an error, prompting users to set explicit `toolName` overrides:

```typescript
const collisions = Array.from(toolNameToScripts.entries()).filter(([, names]) => names.length > 1);
if (collisions.length > 0) {
  console.error('npm-run-mcp-server: Tool name collisions detected...');
  process.exit(1);
}
```

Source: [src/index.ts:145-154](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

---

## CLI Arguments

The server accepts the following CLI flags:

| Flag | Type | Description |
|------|------|-------------|
| `--cwd <path>` | string | Manually set the working directory |
| `--pm <pm>` | enum | Force a specific package manager (npm, pnpm, yarn, bun) |
| `--config <path>` | string | Path to a specific JSON config file |
| `--verbose` | flag | Print debug logs to stderr |
| `--list-scripts` | flag | List filtered scripts and exit |

Source: [src/index.ts:44-61](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

---

## Dependencies

The server relies on these key dependencies:

| Package | Version | Purpose |
|---------|---------|---------|
| `@modelcontextprotocol/sdk` | ^1.25.1 | MCP protocol implementation |
| `cross-spawn` | ^7.0.5 | Cross-platform process spawning |
| `jsonc-parser` | ^3.3.1 | JSONC parsing with comment support |
| `zod` | ^3.23.8 | Schema validation |

Source: [package.json:27-33](https://github.com/fstubner/npm-run-mcp-server/blob/main/package.json)

---

## Error Handling

### Missing Scripts

When no scripts are found or all are filtered out:

```typescript
if (filteredScriptNames.length === 0) {
  const hint = mcpConfig.include?.length
    ? 'Check your config "include"/"exclude" settings.'
    : 'Check your package.json "scripts" section.';
  console.error(`npm-run-mcp-server: No scripts selected for exposure. ${hint}`);
}
```

Source: [src/index.ts:89-95](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

### Tool Execution Results

Each tool execution returns a structured result:

| Field | Type | Description |
|-------|------|-------------|
| `stdout` | string | Standard output from the script |
| `stderr` | string | Standard error from the script |
| `exitCode` | number | Process exit code |
| `timedOut` | boolean | Whether the command timed out |

Source: [src/index.ts:168-183](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

---

## MCP Server Manifest

The `server.json` manifest declares the server to the MCP registry:

```json
{
  "name": "io.github.fstubner/npm-run-mcp-server",
  "description": "An MCP server that exposes package.json scripts as tools for agents.",
  "transport": { "type": "stdio" }
}
```

Source: [server.json:1-12](https://github.com/fstubner/npm-run-mcp-server/blob/main/server.json)

---

## See Also

- [README.md](https://github.com/fstubner/npm-run-mcp-server#readme) — Usage and installation guide
- [npm-run-mcp.config.schema.json](https://github.com/fstubner/npm-run-mcp-server/blob/main/npm-run-mcp.config.schema.json) — Configuration schema reference
- [MCP SDK Documentation](https://github.com/modelcontextprotocol/typescript-sdk) — Protocol implementation details

---

<a id='package-manager-detection'></a>

## Package Manager Detection

### Related Pages

Related topics: [System Architecture](#system-architecture), [CLI Reference](#cli-reference)



# Package Manager Detection

## Overview

The npm-run-mcp-server provides automatic package manager detection to execute `package.json` scripts using the appropriate package manager for your project. This feature ensures seamless integration with any Node.js project regardless of whether it uses npm, pnpm, yarn, or bun as its package manager.

The detection mechanism is designed to be intelligent yet predictable, following a clear hierarchy of preference that prioritizes explicit configuration over file-based heuristics.

**Key capabilities:**

- Automatic detection from lockfiles and package configuration
- CLI override option for explicit control
- Support for all major Node.js package managers
- Verbose logging for debugging detection issues

Source: [src/index.ts:1-50]()

---

## Detection Hierarchy

The package manager detection follows a strict priority order. When determining which package manager to use, the system checks each level in sequence until a match is found.

```mermaid
graph TD
    A[Start Detection] --> B{--pm flag provided?}
    B -->|Yes| C[Use specified PM]
    B -->|No| D{packageManager field in package.json?}
    D -->|Yes| E{Valid PM value?}
    D -->|No| F{Check lockfiles}
    E -->|npm/pnpm/yarn/bun| G[Use detected PM]
    E -->|Unknown| F
    F --> H{pnpm-lock.yaml exists?}
    H -->|Yes| I[Use pnpm]
    H -->|No| J{yarn.lock exists?}
    J -->|Yes| K[Use yarn]
    J -->|No| L{bun.lockb or bun.lock exists?}
    L -->|Yes| M[Use bun]
    L -->|No| N[Default to npm]
    
    C --> O[Return PackageManager]
    G --> O
    I --> O
    K --> O
    M --> O
    N --> O
```

### Detection Priority Order

| Priority | Source | Description |
|----------|--------|-------------|
| 1 | CLI flag `--pm` | Explicit override via command line |
| 2 | `packageManager` field | Explicit declaration in `package.json` |
| 3 | Lockfile presence | File-based heuristics from project root |
| 4 | Default fallback | Falls back to `npm` |

Source: [src/index.ts:88-100]()

---

## Supported Package Managers

The server supports four major Node.js package managers:

| Package Manager | Identifier | Lockfile Pattern |
|-----------------|------------|------------------|
| npm | `npm` | `package-lock.json` (not checked) |
| pnpm | `pnpm` | `pnpm-lock.yaml` |
| Yarn | `yarn` | `yarn.lock` |
| Bun | `bun` | `bun.lockb` or `bun.lock` |

### Type Definition

```typescript
type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun';
```

Source: [src/index.ts:27]()

---

## Detection Implementation

### The `detectPackageManager` Function

The core detection logic is implemented in the `detectPackageManager` function located in `src/index.ts`. This function accepts three parameters and returns the appropriate package manager identifier.

```typescript
function detectPackageManager(
  projectDir: string, 
  pkg: PackageJson, 
  override?: PackageManager
): PackageManager
```

**Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `projectDir` | `string` | Absolute path to the project directory containing `package.json` |
| `pkg` | `PackageJson` | Parsed contents of the project's `package.json` |
| `override` | `PackageManager \| undefined` | Optional CLI override value |

**Return value:** One of `npm`, `pnpm`, `yarn`, or `bun`

### Algorithm Details

#### Step 1: CLI Override Check

```typescript
if (override) return override;
```

If the `--pm` flag is provided via command line, that value is returned immediately, bypassing all other detection logic.

Source: [src/index.ts:89]()

#### Step 2: Package Manager Field Parsing

```typescript
if (pkg.packageManager) {
  const pm = pkg.packageManager.split('@')[0] as PackageManager;
  if (pm === 'npm' || pm === 'pnpm' || pm === 'yarn' || pm === 'bun') return pm;
}
```

The `packageManager` field from `package.json` is parsed by splitting on `@` and taking the first segment. Only recognized values are accepted; unknown values trigger fallback to lockfile detection.

**Example:** `"packageManager": "pnpm@8.15.0"` → extracts `pnpm`

Source: [src/index.ts:90-94]()

#### Step 3: Lockfile Heuristics

```typescript
if (existsSync(resolve(projectDir, 'pnpm-lock.yaml'))) return 'pnpm';
if (existsSync(resolve(projectDir, 'yarn.lock'))) return 'yarn';
if (existsSync(resolve(projectDir, 'bun.lockb')) || existsSync(resolve(projectDir, 'bun.lock'))) return 'bun';
```

Lockfile detection checks for the presence of specific files in the project root directory:

- `pnpm-lock.yaml` → pnpm
- `yarn.lock` → yarn
- `bun.lockb` or `bun.lock` → bun

The checks occur in this specific order (pnpm → yarn → bun).

**Note:** npm's `package-lock.json` is not checked because npm is the default fallback when no other package manager is detected.

Source: [src/index.ts:95-97]()

#### Step 4: Default Fallback

If no detection method identifies a package manager, the function defaults to `npm`:

```typescript
return 'npm';
```

---

## Command Execution

Once detected, the package manager is used to build the execution command for running scripts.

### Building the Run Command

```typescript
function buildRunCommand(
  pm: PackageManager,
  scriptName: string,
  extraArgs: string[]
): { command: string; args: string[] } {
  const command = pm;
  const baseArgs = ['run', scriptName];
  const args = extraArgs.length > 0 ? [...baseArgs, '--', ...extraArgs] : baseArgs;
  return { command, args };
}
```

This function generates a command array that will be passed to `cross-spawn` for execution. The structure is identical across all package managers since they all use the `run <script>` convention.

**Example outputs:**

| Package Manager | Command | Args |
|-----------------|---------|------|
| npm | `npm` | `['run', 'test']` |
| pnpm | `pnpm` | `['run', 'build']` |
| yarn | `yarn` | `['run', 'lint']` |
| bun | `bun` | `['run', 'dev']` |

Source: [src/index.ts:102-110]()

---

## CLI Integration

### The `--pm` Flag

The `--pm` flag provides explicit control over package manager selection, useful in CI/CD environments or when testing specific package managers.

```bash
# Force pnpm regardless of detection
npx npm-run-mcp-server --pm pnpm

# Force npm explicitly
npx npm-run-mcp-server --pm npm
```

**Accepted values:**

| Value | Description |
|-------|-------------|
| `npm` | Force npm package manager |
| `pnpm` | Force pnpm package manager |
| `yarn` | Force yarn package manager |
| `bun` | Force bun package manager |

**Error handling:** Invalid values passed to `--pm` are silently ignored, and detection falls back to the automatic detection logic.

Source: [src/index.ts:47-48]()

### Verbose Logging

When debugging detection issues, enable verbose logging:

```bash
npx npm-run-mcp-server --verbose
```

The verbose output includes:

```
[mcp] detected package manager: pnpm
```

Source: [src/index.ts:53-54]()

---

## Configuration Integration

### Environment Variables

The detection process respects the following environment variables for debugging:

| Variable | Effect |
|----------|--------|
| `MCP_VERBOSE=true` | Enables verbose logging |
| `DEBUG=mcp` | Enables debug output (if DEBUG contains 'mcp') |

These can be set in the MCP client configuration:

```json
{
  "mcpServers": {
    "npm-scripts": {
      "command": "npx",
      "args": ["-y", "npm-run-mcp-server"],
      "env": {
        "MCP_VERBOSE": "true"
      }
    }
  }
}
```

Source: [src/index.ts:55-60]()

---

## Common Failure Modes

### Missing Lockfiles with Non-Standard Setup

**Problem:** Projects using pnpm, yarn, or bun without the expected lockfile in the project root will default to npm.

**Symptoms:** Scripts execute with npm instead of the expected package manager, potentially causing errors if the project relies on pnpm-specific features like `pnpm-workspace.yaml`.

**Solution:** Either:
1. Ensure the lockfile exists in the project root
2. Add the `packageManager` field to `package.json`
3. Use the `--pm` CLI flag to override detection

### Mismatched packageManager Field

**Problem:** The `packageManager` field uses an unrecognized value.

```json
{
  "packageManager": "pnpm@8.15.0"
}
```

**Symptoms:** The system falls back to lockfile detection or npm.

**Solution:** Ensure the value before `@` matches exactly: `npm`, `pnpm`, `yarn`, or `bun`.

### Script Not Found in Non-npm Projects

**Problem:** Some scripts in `package.json` use npm-specific syntax that other package managers don't support.

**Symptoms:** The detected package manager runs the script, but execution fails because the script command is npm-specific.

**Solution:** Update `package.json` scripts to use portable syntax, or configure per-script descriptions in `npm-run-mcp.config.json` to help the AI understand script requirements.

---

## Workspace Detection

The server includes special handling for workspace environments. When running inside the MCP server directory itself, it attempts to find a parent directory with a `package.json`.

```typescript
// If we're in the MCP server directory, try to find a parent directory with package.json
if (currentDir.includes('npm-run-mcp-server')) {
  let testDir = dirname(currentDir);
  for (let i = 0; i < 5; i++) {
    const testPkgJson = resolve(testDir, 'package.json');
    if (existsSync(testPkgJson)) {
      startCwd = testDir;
      break;
    }
    testDir = dirname(testDir);
  }
}
```

This logic searches up to 5 parent directories for a valid `package.json`, ensuring the server can operate correctly when invoked from within its own development environment.

Source: [src/index.ts:115-135]()

---

## See Also

- [MCP Server Overview](README.md) - General usage and configuration
- [Configuration File](npm-run-mcp.config.schema.json) - Per-project configuration schema
- [CLI Reference](README.md#-advanced--cli-usage) - Complete CLI flag documentation
- [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/sdk) - The underlying MCP SDK used for transport and tool registration

---

<a id='tool-schema'></a>

## Tool Schema and MCP Integration

### Related Pages

Related topics: [System Architecture](#system-architecture), [Configuration Guide](#configuration-guide)



# Tool Schema and MCP Integration

This page documents how npm-run-mcp-server bridges `package.json` scripts to the Model Context Protocol (MCP), including tool schema generation, input validation, and the MCP server lifecycle.

## Overview

npm-run-mcp-server exposes `package.json` scripts as MCP tools that AI agents can invoke. The tool schema system transforms script definitions into structured MCP tool interfaces with input validation, custom descriptions, and runtime argument handling.

**Key capabilities:**

- Automatic tool registration from `package.json` scripts
- JSON Schema-based input definitions per script
- Zod schema generation for runtime validation
- Configurable tool names, descriptions, and argument schemas
- File watcher for hot-reload on config changes

Source: [src/index.ts:1-50](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

## Architecture

```mermaid
graph TD
    A[package.json] --> B[Script Discovery]
    C[npm-run-mcp.config.json] --> D[Config Parsing]
    B --> E[Script Filtering]
    D --> E
    E --> F[Tool Registration]
    F --> G[McpServer]
    G --> H[StdioServerTransport]
    H --> I[MCP Client<br/>Claude/Cursor/Copilot]
    
    J[AI Agent] --> K[Tool Call]
    K --> G
    G --> L[Script Execution]
    L --> M[npm/pnpm/yarn/bun]
    
    N[File Watcher] -.->|package.json change| O[Server Restart]
    N -->|config change| O
```

### Core Components

| Component | Responsibility | Location |
|-----------|---------------|----------|
| `McpServer` | MCP protocol server from SDK | `@modelcontextprotocol/sdk` |
| `StdioServerTransport` | Communication via stdio | `@modelcontextprotocol/sdk` |
| Tool Registry | Maps scripts to MCP tools | `src/index.ts` |
| Schema Builder | Converts JSON Schema to Zod | `src/index.ts:normalizeToolName` |
| File Watcher | Hot reload on config changes | `src/index.ts` |

Source: [src/index.ts:1-30](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

## Tool Registration Flow

The server follows a defined sequence to register scripts as MCP tools:

```mermaid
sequenceDiagram
    participant Client as MCP Client
    participant Server as McpServer
    participant Registry as Tool Registry
    participant Watcher as File Watcher
    
    Note over Server: Server starts
    Server->>Server: Load package.json
    Server->>Server: Detect package manager
    Server->>Server: Load MCP config
    Server->>Registry: Filter scripts
    Registry->>Registry: Register tools
    Server->>Watcher: Watch config files
    Server->>Client: Ready (stdio connected)
    
    Note over Client,Server: Tool invocation cycle
    Client->>Server: call_tool (tool_name, args)
    Server->>Server: Validate input (Zod)
    Server->>Registry: Execute script
    Server->>Client: Tool result
```

### Step-by-Step Process

1. **Startup**: Server initializes and connects stdio transport
2. **Package Detection**: Locates `package.json` and detects package manager
3. **Config Loading**: Reads `npm-run-mcp.config.json` or `.npm-run-mcp.json`
4. **Script Filtering**: Applies `include`/`exclude` rules
5. **Tool Registration**: Registers each script as an MCP tool with schema
6. **File Watching**: Sets up watchers for hot-reload capability

Source: [src/index.ts:50-100](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

## Tool Schema Definition

### Default Schema Generation

When no custom schema is provided, the server generates a standard input schema for each tool:

```typescript
{
  description: string,        // "Run npm script "test": npm test"
  inputSchema: {
    type: "object",
    properties: {
      args: {
        type: "string",
        description: "Additional arguments to pass to the script"
      }
    }
  }
}
```

Source: [src/index.ts:buildToolInputSchema](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

### Input Schema Schema

The `inputSchema` field in `npm-run-mcp.config.json` supports a subset of JSON Schema for defining tool inputs. The server converts these to Zod schemas for validation.

**Supported Schema Types:**

| JSON Schema Keyword | Zod Equivalent | Notes |
|--------------------|----------------|-------|
| `type: "string"` | `z.string()` | Basic string input |
| `type: "number"` | `z.number()` | Numeric input |
| `type: "boolean"` | `z.boolean()` | Toggle/flag input |
| `type: "array"` | `z.array()` | Array input |
| `type: "object"` | `z.object()` | Nested object input |
| `enum: [...]` | `z.enum([...])` | Constrained choices |
| `properties` | Chained `.shape()` | Object structure |
| `required` | Chained `.required()` | Mandatory fields |

Source: [src/index.ts:jsonSchemaToZod](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

### Schema Conversion Examples

**String with description:**
```json
{
  "type": "string",
  "description": "File path to process"
}
```
```typescript
z.string().describe("File path to process")
```

**Enum (choice):**
```json
{
  "enum": ["development", "staging", "production"]
}
```
```typescript
z.enum(["development", "staging", "production"])
```

**Object with properties:**
```json
{
  "type": "object",
  "properties": {
    "watch": { "type": "boolean" },
    "verbose": { "type": "boolean" }
  },
  "required": ["watch"]
}
```
```typescript
z.object({
  watch: z.boolean(),
  verbose: z.boolean()
}).required().shape({ watch: z.boolean() })
```

Source: [src/index.ts:jsonSchemaToZod:140-170](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

## Configuration Schema

### Configuration File Location

The server searches for config files in order:

1. Path specified via `--config` CLI flag
2. `npm-run-mcp.config.json` in project root
3. `.npm-run-mcp.json` in project root

### Config Schema Properties

| Property | Type | Description |
|----------|------|-------------|
| `include` | `string[]` | Whitelist of script names to expose |
| `exclude` | `string[]` | Blacklist of script names to hide |
| `scripts` | `Record<string, ScriptConfig>` | Per-script metadata overrides |

Source: [npm-run-mcp.config.schema.json](https://github.com/fstubner/npm-run-mcp-server/blob/main/npm-run-mcp.config.schema.json)

### Per-Script Configuration

```typescript
type McpScriptConfig = {
  toolName?: string;           // Override generated tool name
  description?: string;         // Override tool description
  argsDescription?: string;    // Description for the args field
  inputSchema?: unknown;       // JSON Schema for tool inputs
};
```

| Field | Purpose | Example |
|-------|---------|---------|
| `toolName` | Custom MCP tool name | `"run_tests"` instead of `"test"` |
| `description` | Human-readable tool description | `"Run the test suite with coverage"` |
| `argsDescription` | Description for CLI args field | `"Pass --watch for interactive mode"` |
| `inputSchema` | Define structured inputs | `{"type": "object", "properties": {...}}` |

Source: [npm-run-mcp.config.schema.json](https://github.com/fstubner/npm-run-mcp-server/blob/main/npm-run-mcp.config.schema.json)

### Example Configuration

```json
{
  "include": ["test", "lint", "build"],
  "exclude": ["postinstall", "prepublishOnly"],
  "scripts": {
    "test": {
      "description": "Run the test suite with Vitest",
      "inputSchema": {
        "type": "object",
        "properties": {
          "watch": {
            "type": "boolean",
            "description": "Watch files for changes"
          },
          "coverage": {
            "type": "boolean",
            "description": "Generate coverage report"
          },
          "grep": {
            "type": "string",
            "description": "Run only tests matching pattern"
          }
        }
      }
    },
    "lint": {
      "toolName": "run_linter",
      "description": "Run ESLint on source files",
      "argsDescription": "Additional ESLint flags"
    }
  }
}
```

Source: [npm-run-mcp.config.schema.json](https://github.com/fstubner/npm-run-mcp-server/blob/main/npm-run-mcp.config.schema.json)

## Tool Name Normalization

MCP tool names have strict constraints: only lowercase letters (`a-z`), digits (`0-9`), underscores (`_`), and hyphens (`-`) are allowed.

### Normalization Rules

The server sanitizes script names to valid tool names:

| Original Script | Normalized Tool Name | Notes |
|----------------|---------------------|-------|
| `test` | `test` | No change needed |
| `test:unit` | `test_unit` | Colon replaced |
| `build:prod` | `build_prod` | Colon replaced |
| `lint-fix` | `lint_fix` | Hyphen to underscore |
| `TEST` | `test` | Lowercased |
| `build(/*)` | `build____` | Invalid chars replaced |

Source: [src/index.ts:normalizeToolName](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

### Tool Name Collisions

If two scripts normalize to the same tool name, the server exits with an error:

```
npm-run-mcp-server: Tool name collisions detected. 
Set "scripts.<name>.toolName" in npm-run-mcp.config.json to disambiguate.
  build_prod: build:prod, build.prod
```

Source: [src/index.ts:collision-detection](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

## Tool Execution Pipeline

```mermaid
graph LR
    A[Tool Call] --> B[Input Validation<br/>Zod Schema]
    B -->|Valid| C[Parse Arguments]
    B -->|Invalid| D[Error Response]
    C --> E[buildRunCommand]
    E --> F[cross-spawn]
    F --> G[Script Execution]
    G --> H{Exit Code?}
    H -->|0| I[Success Result<br/>stdout + stderr]
    H -->|Non-zero| J[Error Result<br/>exit code + signal]
```

### Argument Processing

The `toolInputToExtraArgs` function transforms validated inputs into CLI arguments:

```typescript
// Input schema:
{
  "watch": { "type": "boolean" },
  "grep": { "type": "string" }
}

// Tool call input:
{ watch: true, grep: "auth" }

// Resulting CLI args:
["--watch", "--grep", "auth"]
```

Source: [src/index.ts:toolInputToExtraArgs](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

### Command Building

```typescript
function buildRunCommand(
  pm: PackageManager,
  scriptName: string,
  extraArgs: string[]
): { command: string; args: string[] }
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `pm` | `npm \| pnpm \| yarn \| bun` | Package manager to use |
| `scriptName` | `string` | Script name from package.json |
| `extraArgs` | `string[]` | Additional arguments from tool input |

**Example outputs:**

| Package Manager | Script | Args | Command |
|-----------------|--------|------|---------|
| npm | `test` | `["--watch"]` | `npm run test -- --watch` |
| pnpm | `build` | `[]` | `pnpm run build` |
| yarn | `lint` | `["--fix"]` | `yarn run lint --fix` |
| bun | `dev` | `["--port", "3000"]` | `bun run dev --port 3000` |

Source: [src/index.ts:buildRunCommand](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

## Hot Reload with File Watchers

The server monitors `package.json` and config files for changes and exits gracefully when detected, allowing the MCP client to restart the server with updated tool definitions.

```mermaid
graph TD
    A[File Change Detected] --> B{Which file?}
    B -->|package.json| C[Informs MCP Client]
    B -->|config.json| C
    C --> D[Cleanup Watchers]
    D --> E[Exit Process]
    F[MCP Client] -->|Restarts| G[Server with new config]
```

### Watched Files

| File | Watch Condition |
|------|----------------|
| `package.json` | Found during startup |
| `npm-run-mcp.config.json` | Found during startup |
| `.npm-run-mcp.json` | Found during startup |

### Signal Handling

The server properly cleans up file watchers on termination:

```typescript
process.on('SIGINT', () => {
  cleanup();
  process.exit(0);
});

process.on('SIGTERM', () => {
  cleanup();
  process.exit(0);
});
```

Source: [src/index.ts:watcher-cleanup](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

## MCP SDK Integration

### Server Initialization

```typescript
const server = new McpServer({ 
  name: serverName, 
  version: serverVersion 
});

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

### Tool Registration

```typescript
server.registerTool(
  toolName,
  {
    description: string,
    inputSchema: ZodSchema
  },
  async (input) => {
    // Execution handler
    return { content: [...] };
  }
);
```

### SDK Version

| Dependency | Version | Purpose |
|------------|---------|---------|
| `@modelcontextprotocol/sdk` | `^1.25.1` | MCP protocol implementation |

Source: [package.json](https://github.com/fstubner/npm-run-mcp-server/blob/main/package.json)

## Error Handling

### Common Error Scenarios

| Scenario | Error Message | Resolution |
|----------|--------------|------------|
| No scripts in package.json | `No scripts found in <path>` | Add scripts to package.json |
| No scripts after filtering | `No scripts selected for exposure` | Check `include`/`exclude` config |
| Config parse error | `Failed to read config file: <message>` | Validate JSON/JSONC syntax |
| Tool name collision | `Tool name collisions detected` | Set `scripts.<name>.toolName` |
| Script timeout | `Command timed out after 30s` | Reduce script complexity |

### Validation Errors

When tool input validation fails, the MCP client receives an error response:

```json
{
  "content": [
    {
      "type": "text",
      "text": "Invalid input: ..."
    }
  ],
  "isError": true
}
```

### Verbose Logging

Enable debug output via:

```bash
npx npm-run-mcp-server --verbose
```

Or via environment:

```bash
MCP_VERBOSE=1 npx npm-run-mcp-server
DEBUG=mcp npx npm-run-mcp-server
```

Verbose output includes:
- Detected workspace folder
- Package.json location
- Detected package manager
- Config file path
- Number of registered tools

Source: [src/index.ts:verbose-logging](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

## JSONC Support

The config file parser supports JSONC (JSON with Comments), allowing:

### Comments

```json
{
  // Include only safe scripts
  "include": ["test", "lint", "build"],
  "exclude": ["postinstall"]
}
```

### Trailing Commas

```json
{
  "scripts": {
    "test": {
      "description": "Run tests",
    },  // <-- trailing comma allowed
  }
}
```

Source: [src/index.ts:parseJsonOrJsonc](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

## CLI Options

| Flag | Description | Default |
|------|-------------|---------|
| `--cwd <path>` | Working directory for script execution | Current directory |
| `--pm <npm\|pnpm\|yarn\|bun>` | Force specific package manager | Auto-detected |
| `--config <path>` | Path to config file | Search default locations |
| `--verbose` | Enable debug logging | `false` |
| `--list-scripts` | Print discovered scripts and exit | `false` |

### Package Manager Detection

The package manager is detected in priority order:

1. `--pm` CLI flag (if provided)
2. `packageManager` field in `package.json`
3. Lockfile presence:
   - `pnpm-lock.yaml` → `pnpm`
   - `yarn.lock` → `yarn`
   - `bun.lockb` or `bun.lock` → `bun`
   - Default → `npm`

Source: [src/index.ts:detectPackageManager](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

## See Also

- [README.md](https://github.com/fstubner/npm-run-mcp-server/blob/main/README.md) - Main project documentation with quick start guides
- [npm-run-mcp.config.schema.json](https://github.com/fstubner/npm-run-mcp-server/blob/main/npm-run-mcp.config.schema.json) - JSON Schema for configuration files
- [server.json](https://github.com/fstubner/npm-run-mcp-server/blob/main/server.json) - MCP server manifest for registry listing
- [Model Context Protocol Specification](https://modelcontextprotocol.io/) - Official MCP documentation

---

<a id='troubleshooting'></a>

## Troubleshooting

### Related Pages

Related topics: [CLI Reference](#cli-reference), [Integration Testing](#integration-testing)



# Troubleshooting

This page covers common issues, error messages, and resolution strategies for `npm-run-mcp-server`. The server is designed to fail gracefully with informative error messages, but understanding the underlying causes helps resolve issues faster.

---

## Overview

When `npm-run-mcp-server` encounters a problem, it typically outputs descriptive error messages to stderr before exiting. The server uses the following exit codes:

| Exit Code | Meaning |
|-----------|---------|
| `0` | Success (normal termination after `--list-scripts` or signal received) |
| `1` | Fatal error (config parsing failure, tool name collision, etc.) |

Source: [src/index.ts:305-310](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts#L305-L310)

---

## Common Issues and Solutions

### No package.json Found

**Error Message:**
```
npm-run-mcp-server: No package.json found starting from /path/to/directory
```

**Cause:** The server cannot locate a `package.json` file when searching from the current working directory or the workspace folder detected from environment variables (`VSCODE_WORKSPACE_FOLDER`, `CURSOR_WORKSPACE_FOLDER`).

**Solutions:**

1. **Run the server from a project directory** containing a `package.json`:
   ```bash
   cd /path/to/your/project
   npx npm-run-mcp-server
   ```

2. **Use the `--cwd` flag** to specify the project directory:
   ```bash
   npx npm-run-mcp-server --cwd /path/to/your/project
   ```

3. **Ensure VS Code/Cursor workspace is set correctly** — the server attempts to find a parent directory with `package.json` if run from within the MCP server directory itself. Source: [src/index.ts:30-53](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts#L30-L53)

---

### No Scripts Found

**Error Message:**
```
npm-run-mcp-server: No scripts found in /path/to/package.json
```

**Cause:** The detected `package.json` exists but contains no `scripts` section.

**Solutions:**

1. Add scripts to your `package.json`:
   ```json
   {
     "scripts": {
       "test": "jest",
       "build": "tsc"
     }
   }
   ```

2. Verify the correct `package.json` is being used with `--verbose`:
   ```bash
   npx npm-run-mcp-server --verbose
   ```

---

### No Scripts Selected for Exposure

**Error Message:**
```
npm-run-mcp-server: No scripts selected for exposure. Check your config "include"/"exclude" settings.
```

**or:**

```
npm-run-mcp-server: No scripts selected for exposure. Check your package.json "scripts" section.
```

**Cause:** The configuration file's `include` or `exclude` filters have eliminated all scripts, or the configuration references scripts that don't exist.

**Solutions:**

1. **Check your `include` list** — all scripts listed must exist in `package.json`:
   ```json
   {
     "include": ["test", "lint", "build"]
   }
   ```

2. **Use `exclude` instead** to hide specific scripts rather than whitelisting:
   ```json
   {
     "exclude": ["publish", "eject"]
   }
   ```

3. **Omit `include` entirely** to expose all scripts (the default behavior).

When running with `--verbose`, the server also warns about missing scripts in the include list: Source: [src/index.ts:81-85](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts#L81-L85)

```
[mcp] include list references missing scripts: missing-script, another-missing
```

---

### Config File Parsing Errors

**Error Message:**
```
npm-run-mcp-server: Failed to read config file /path/to/config.json: <error details>
```

**Cause:** The config file contains invalid JSON or JSONC syntax.

**Solutions:**

1. **Validate JSON syntax** — trailing commas and comments are supported (JSONC), but structural errors are not:
   ```jsonc
   {
     "include": ["test", "lint"],  // Trailing comma OK
     "exclude": ["publish"]        // Comment OK
   }
   ```

2. **Check for mismatched brackets or quotes**.

3. **Use the JSON Schema** for validation: [`npm-run-mcp.config.schema.json`](https://github.com/fstubner/npm-run-mcp-server/blob/main/npm-run-mcp.config.schema.json)

The server uses `jsonc-parser` to parse config files, which allows comments and trailing commas. Source: [src/index.ts:195-220](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts#L195-L220)

---

### Tool Name Collisions

**Error Message:**
```
npm-run-mcp-server: Tool name collisions detected. Set "scripts.<name>.toolName" in npm-run-mcp.config.json to disambiguate.
  my_script: script-one, script-two
```

**Cause:** After normalization (converting to lowercase and replacing invalid characters), multiple scripts produce the same tool name. MCP tool names can only contain `[a-z0-9_-]`.

**Example of collision:**
```json
{
  "scripts": {
    "build:prod": "...",
    "build_prod": "...",
    "Build-Prod": "..."
  }
}
```
All three normalize to `build_prod`.

**Solution:** Use `toolName` overrides in your config to disambiguate:
```json
{
  "scripts": {
    "build:prod": {
      "toolName": "build_production"
    },
    "build_prod": {
      "toolName": "build_underscore"
    },
    "Build-Prod": {
      "toolName": "build_dashed"
    }
  }
}
```

Source: [src/index.ts:95-112](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts#L95-L112)

---

### Script Execution Timeout

**Error Message:**
```
Command timed out after 30s: npm run script-name
```

**Cause:** A script took longer than the 30-second timeout to complete.

The default timeout is set to 30 seconds. Source: [src/index.ts:168](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts#L168)

**Solutions:**

1. **Optimize the script** to run faster (e.g., use watch mode for development tasks).

2. **Split long-running tasks** into smaller steps for the AI agent.

3. **Use background processes** where appropriate (scripts that don't block).

---

### Exit Code Non-Zero

**Error Message:**
```
Command failed (exit=<code>, signal=<signal>): npm run script-name
```

**Cause:** The npm script exited with a non-zero status code, indicating failure.

**Solutions:**

1. **Run the script manually** to see the actual error output:
   ```bash
   npm run <script-name>
   ```

2. **Check the script's implementation** in `package.json`.

3. **Review the combined stdout/stderr** in the tool result to understand what failed.

Source: [src/index.ts:249-263](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts#L249-L263)

---

### Wrong Package Manager Detected

**Cause:** The server auto-detects the package manager using lockfile heuristics or the `packageManager` field.

**Detection Order:** Source: [src/index.ts:230-240](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts#L230-L240)

```mermaid
graph TD
    A[Start Detection] --> B{packageManager field?}
    B -->|Yes| C[Parse first part of value]
    B -->|No| D{Check pnpm-lock.yaml?}
    C --> F{Valid PM?}
    D -->|Yes| E[Return pnpm]
    D -->|No| G{Check yarn.lock?}
    G -->|Yes| H[Return yarn]
    G -->|No| I{Check bun.lockb or bun.lock?}
    I -->|Yes| J[Return bun]
    I -->|No| K[Return npm]
    F -->|Yes| L[Return detected PM]
    F -->|No| D
```

**Solution:** Force a specific package manager using the `--pm` flag:
```bash
npx npm-run-mcp-server --pm pnpm
```

Supported values: `npm`, `pnpm`, `yarn`, `bun`.

---

### File Watching Issues on Restart

**Behavior:** The server exits with code 0 when `package.json` or the config file changes.

**Cause:** This is intentional behavior. The server sets up file watchers and gracefully exits when watched files change, allowing the MCP client to restart it with the updated configuration.

**If restart is not happening:**

1. **Verify the MCP client supports server restart** (most do, including Claude Desktop, Cursor, and VS Code Copilot).

2. **Check file permissions** on the watched files.

3. **Run with `--verbose`** to confirm watchers are set up:
   ```
   [mcp] setting up file watcher for package.json: /path/to/package.json
   [mcp] setting up file watcher for config: /path/to/npm-run-mcp.config.json
   ```

Source: [src/index.ts:285-312](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts#L285-L312)

---

## Debugging Tips

### Enable Verbose Logging

Use the `--verbose` flag or set environment variables:

```bash
# CLI flag
npx npm-run-mcp-server --verbose

# Environment variable
MCP_VERBOSE=1 npx npm-run-mcp-server

# Debug environment variable (must contain 'mcp')
DEBUG=mcp npx npm-run-mcp-server
```

Verbose output includes:
- Working directory and detected workspace
- Package.json path being used
- Detected package manager
- Number of registered tools
- Config file location
- File watcher setup

Source: [src/index.ts:55-72](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts#L55-L72)

### List Available Scripts Without Starting Server

```bash
npx npm-run-mcp-server --list-scripts
```

This outputs script names and commands to stderr, then exits cleanly. Useful for debugging what scripts are detected and filtered.

---

## Configuration Validation

### Using the JSON Schema

The published JSON Schema at [`npm-run-mcp.config.schema.json`](https://github.com/fstubner/npm-run-mcp-server/blob/main/npm-run-mcp.config.schema.json) can validate your config file:

```bash
# Using a schema validator like ajv
ajv -s npm-run-mcp.config.schema.json -d npm-run-mcp.config.json --valid
```

### Schema Properties

| Property | Type | Description |
|----------|------|-------------|
| `include` | `string[]` | Exact script names to include |
| `exclude` | `string[]` | Exact script names to exclude |
| `scripts` | `object` | Per-script metadata overrides |

Each script in `scripts` supports:

| Property | Type | Description |
|----------|------|-------------|
| `toolName` | `string` | Override normalized tool name |
| `description` | `string` | Custom description for the AI |
| `inputSchema` | `object` | JSON Schema for additional inputs |
| `argsDescription` | `string` | Description for args field |

Source: [npm-run-mcp.config.schema.json](https://github.com/fstubner/npm-run-mcp-server/blob/main/npm-run-mcp.config.schema.json)

---

## Integration-Specific Issues

### Claude Desktop

**Issue:** Server starts but tools don't appear.

**Check:**
1. Config file location: `%APPDATA%\Claude\claude_desktop_config.json` (Windows) or `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)
2. Run `clang -v` and restart Claude Desktop after config changes
3. Check Claude logs for errors

### Cursor

**Issue:** MCP server not connecting.

**Check:**
1. Settings → Features → MCP Servers shows the server
2. Click "Restart" after config changes
3. Verify `npx -y npm-run-mcp-server --list-scripts` works from terminal

### VS Code (GitHub Copilot)

**Issue:** Server not available in Copilot Chat.

**Check:**
1. Add to `.vscode/settings.json`:
   ```json
   {
     "github.copilot.chat.mcpServers": {
       "npm-scripts": {
         "command": "npx",
         "args": ["-y", "npm-run-mcp-server"]
       }
     }
   }
   ```
2. Reload VS Code window after changes

---

## Exit Codes Reference

| Scenario | Exit Code | Message |
|----------|-----------|---------|
| Normal `--list-scripts` completion | `0` | Scripts listed to stderr |
| Normal operation (signal received) | `0` | Server shutdown |
| Config file parse error | `1` | `Failed to read config file...` |
| Tool name collision | `1` | `Tool name collisions detected...` |
| Unhandled exception | `1` | Error printed to stderr |

---

## See Also

- [README.md](https://github.com/fstubner/npm-run-mcp-server/blob/main/README.md) — Installation and usage documentation
- [npm-run-mcp.config.schema.json](https://github.com/fstubner/npm-run-mcp-server/blob/main/npm-run-mcp.config.schema.json) — Full configuration schema
- [server.json](https://github.com/fstubner/npm-run-mcp-server/blob/main/server.json) — MCP registry configuration
- [MCP SDK Documentation](https://github.com/modelcontextprotocol/sdk) — MCP protocol details

---

<a id='integration-testing'></a>

## Integration Testing

### Related Pages

Related topics: [Troubleshooting](#troubleshooting), [System Architecture](#system-architecture)



# Integration Testing

This page documents the integration testing approach for npm-run-mcp-server, covering how the MCP server is validated as a complete system through end-to-end test scenarios.

## Overview

Integration testing in npm-run-mcp-server validates that the MCP server functions correctly as a complete system. The tests verify that the server properly exposes package.json scripts as MCP tools, executes scripts through various package managers, and handles configuration correctly. Source: [package.json:11](https://github.com/fstubner/npm-run-mcp-server/blob/main/package.json)

The integration test suite is the primary mechanism for validating the server's behavior in realistic usage scenarios, complementing any unit-level validations that may exist in the codebase.

## Test Architecture

### Test Execution Flow

```mermaid
graph TD
    A[Start Integration Test] --> B[Build Server: node scripts/build.cjs]
    B --> C[Start MCP Server: node dist/index.js --list-scripts]
    C --> D[Validate Script Discovery]
    D --> E[Run Integration Tests: node scripts/integration-test.mjs]
    E --> F{All Tests Pass?}
    F -->|Yes| G[Echo: 'MCP server test completed successfully']
    F -->|No| H[Test Failure + Exit Code]
    G --> I[Exit 0]
    H --> I
```

### Test Script Configuration

The integration tests are defined in `package.json` under the `scripts` section:

| Script Command | Purpose | Source |
|----------------|---------|--------|
| `npm run test` | Full test suite (build, list-scripts, integration) | [package.json:11](https://github.com/fstubner/npm-run-mcp-server/blob/main/package.json) |
| `npm run test:integration` | Run integration tests only | [package.json:10](https://github.com/fstubner/npm-run-mcp-server/blob/main/package.json) |
| `npm run build` | Build TypeScript to JavaScript | [package.json:9](https://github.com/fstubner/npm-run-mcp-server/blob/main/package.json) |

## Running Integration Tests

### Full Test Suite

To run the complete test suite including build, script listing, and integration tests:

```bash
npm run test
```

This executes three sequential steps:
1. Build the TypeScript source to JavaScript
2. List available scripts from the MCP server
3. Run the integration test suite
4. Print success message upon completion

Source: [package.json:11](https://github.com/fstubner/npm-run-mcp-server/blob/main/package.json)

### Integration Tests Only

To run only the integration tests without rebuilding:

```bash
npm run test:integration
```

### Manual Server Testing

You can also manually verify server functionality using the `--list-scripts` flag:

```bash
node dist/index.js --list-scripts
```

This command starts the MCP server and lists all discovered package.json scripts, which is useful for debugging script detection.

Source: [src/index.ts:88](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

## Test Infrastructure Components

### Test Script Entry Point

The integration test file is located at `scripts/integration-test.mjs`. This file contains the end-to-end test scenarios that validate:

- MCP server startup and initialization
- Script discovery from package.json
- Tool registration with the MCP protocol
- Script execution through the stdio transport

Source: [scripts/integration-test.mjs](https://github.com/fstubner/npm-run-mcp-server/blob/main/scripts/integration-test.mjs)

### Build System

The build process uses a custom CommonJS script (`scripts/build.cjs`) to compile TypeScript:

```bash
node scripts/build.cjs
```

The compiled output is placed in the `dist/` directory, which contains:
- `index.js` - Main server entry point
- `index.d.ts` - TypeScript declarations
- `index.d.ts.map` - Source map for debugging

Source: [package.json:9](https://github.com/fstubner/npm-run-mcp-server/blob/main/package.json)

## CI/CD Integration

### GitHub Actions Workflow

Integration tests run automatically via GitHub Actions on every push and pull request. The test workflow validates that:

1. The server builds successfully on multiple Node.js versions
2. Integration tests pass on Linux, macOS, and Windows
3. Package manager detection works across different environments

Source: [README.md](https://github.com/fstubner/npm-run-mcp-server/blob/main/README.md)

### Workflow Badges

The repository displays workflow status badges showing the current test status:

| Badge | Meaning |
|-------|---------|
| Test | Integration and unit tests pass |
| Build & Publish | Build process completes successfully |

Source: [README.md](https://github.com/fstubner/npm-run-mcp-server/blob/main/README.md)

## Test Scenarios

### Configuration Validation

Integration tests validate the configuration system by testing:

- Per-project config file loading (`npm-run-mcp.config.json` / `.npm-run-mcp.json`)
- JSONC parsing support (comments and trailing commas)
- Include/exclude script filtering
- Per-script metadata overrides

Source: [npm-run-mcp.config.schema.json](https://github.com/fstubner/npm-run-mcp-server/blob/main/npm-run-mcp.config.schema.json)

### Package Manager Detection

Tests validate that the server correctly detects the package manager from:

1. The `packageManager` field in package.json
2. Lockfile presence (pnpm-lock.yaml, yarn.lock, bun.lockb)
3. Default fallback to npm

Source: [src/index.ts](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

## Verbose Testing

For debugging test failures, enable verbose logging:

```bash
MCP_VERBOSE=1 npm run test
# or
DEBUG=mcp npm run test
```

Verbose mode outputs detailed diagnostic information to stderr including:
- Server startup parameters
- Detected workspace folder
- Package.json location
- Package manager detection results
- Registered tool count

Source: [src/index.ts:24-35](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

## Common Test Failures

### Missing package.json

If no package.json is found in the project directory, the server starts with no tools registered. The test should handle this gracefully by either skipping relevant tests or validating the empty state.

Source: [src/index.ts:58-71](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

### No Scripts Found

When package.json exists but has no scripts defined, the server logs a warning but continues running:

```
npm-run-mcp-server: No scripts found in /path/to/package.json
```

Source: [src/index.ts:82-84](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

### Config File Parse Errors

If the config file contains invalid JSON or JSONC syntax, the server exits with an error message:

```
npm-run-mcp-server: Failed to read config file /path/to/config.json: <error message>
```

Source: [src/index.ts](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

### Tool Name Collisions

When multiple scripts resolve to the same normalized tool name, the server exits with a collision report listing the conflicting scripts.

Source: [src/index.ts](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts)

## Development Workflow

### Recommended Test-Driven Development

1. Make changes to source code in `src/index.ts`
2. Run `npm run build` to compile TypeScript
3. Run `npm run test` to validate changes
4. Iterate until all tests pass

### Testing Config Changes

When modifying the config schema or parsing logic:

1. Update `npm-run-mcp.config.schema.json` with new schema definitions
2. Create or modify test config files
3. Run `npm run test:integration` to validate parsing
4. Use `--verbose` flag for detailed error output

## See Also

- [README.md](https://github.com/fstubner/npm-run-mcp-server/blob/main/README.md) - Main project documentation
- [src/index.ts](https://github.com/fstubner/npm-run-mcp-server/blob/main/src/index.ts) - Server implementation source
- [npm-run-mcp.config.schema.json](https://github.com/fstubner/npm-run-mcp-server/blob/main/npm-run-mcp.config.schema.json) - Configuration schema
- [GitHub Actions Test Workflow](https://github.com/fstubner/npm-run-mcp-server/actions/workflows/test.yml) - CI/CD pipeline configuration

---

<!-- evidence_pipeline_checked: true -->
<!-- evidence_injected: true -->

---

## Pitfall Log

# Pitfall Log

Project: fstubner/npm-run-mcp-server

Summary: 发现 7 个潜在Pitfall项，其中 0 个为 high/blocking；最高优先级：能力坑 - 能力判断依赖假设。

## 1. 能力坑 · 能力判断依赖假设

- 严重度：medium
- 证据强度：source_linked
- 发现：README/documentation is current enough for a first validation pass.
- 对用户的影响：假设不成立时，用户拿不到承诺的能力。
- 建议检查：将假设转成下游验证清单。
- 防护动作：假设必须转成验证项；没有验证结果前不能写成事实。
- 证据：capability.assumptions | mcp_registry:io.github.fstubner/npm-run-mcp-server:0.2.13 | https://registry.modelcontextprotocol.io/v0.1/servers/io.github.fstubner%2Fnpm-run-mcp-server/versions/0.2.13 | README/documentation is current enough for a first validation pass.

## 2. 维护坑 · 维护活跃度未知

- 严重度：medium
- 证据强度：source_linked
- 发现：未记录 last_activity_observed。
- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。
- 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。
- 防护动作：维护活跃度未知时，推荐强度不能标为高信任。
- 证据：evidence.maintainer_signals | mcp_registry:io.github.fstubner/npm-run-mcp-server:0.2.13 | https://registry.modelcontextprotocol.io/v0.1/servers/io.github.fstubner%2Fnpm-run-mcp-server/versions/0.2.13 | last_activity_observed missing

## 3. 安全/权限坑 · 下游验证发现风险项

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：下游已经要求复核，不能在页面中弱化。
- 建议检查：进入安全/权限治理复核队列。
- 防护动作：下游风险存在时必须保持 review/recommendation 降级。
- 证据：downstream_validation.risk_items | mcp_registry:io.github.fstubner/npm-run-mcp-server:0.2.13 | https://registry.modelcontextprotocol.io/v0.1/servers/io.github.fstubner%2Fnpm-run-mcp-server/versions/0.2.13 | no_demo; severity=medium

## 4. 安全/权限坑 · 存在安全注意事项

- 严重度：medium
- 证据强度：source_linked
- 发现：No sandbox install has been executed yet; downstream must verify before user use.
- 对用户的影响：用户安装前需要知道权限边界和敏感操作。
- 建议检查：转成明确权限清单和安全审查提示。
- 防护动作：安全注意事项必须面向用户前置展示。
- 证据：risks.safety_notes | mcp_registry:io.github.fstubner/npm-run-mcp-server:0.2.13 | https://registry.modelcontextprotocol.io/v0.1/servers/io.github.fstubner%2Fnpm-run-mcp-server/versions/0.2.13 | No sandbox install has been executed yet; downstream must verify before user use.

## 5. 安全/权限坑 · 存在评分风险

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：风险会影响是否适合普通用户安装。
- 建议检查：把风险写入边界卡，并确认是否需要人工复核。
- 防护动作：评分风险必须进入边界卡，不能只作为内部分数。
- 证据：risks.scoring_risks | mcp_registry:io.github.fstubner/npm-run-mcp-server:0.2.13 | https://registry.modelcontextprotocol.io/v0.1/servers/io.github.fstubner%2Fnpm-run-mcp-server/versions/0.2.13 | no_demo; severity=medium

## 6. 维护坑 · issue/PR 响应质量未知

- 严重度：low
- 证据强度：source_linked
- 发现：issue_or_pr_quality=unknown。
- 对用户的影响：用户无法判断遇到问题后是否有人维护。
- 建议检查：抽样最近 issue/PR，判断是否长期无人处理。
- 防护动作：issue/PR 响应未知时，必须提示维护风险。
- 证据：evidence.maintainer_signals | mcp_registry:io.github.fstubner/npm-run-mcp-server:0.2.13 | https://registry.modelcontextprotocol.io/v0.1/servers/io.github.fstubner%2Fnpm-run-mcp-server/versions/0.2.13 | issue_or_pr_quality=unknown

## 7. 维护坑 · 发布节奏不明确

- 严重度：low
- 证据强度：source_linked
- 发现：release_recency=unknown。
- 对用户的影响：安装命令和文档可能落后于代码，用户Pitfall概率升高。
- 建议检查：确认最近 release/tag 和 README 安装命令是否一致。
- 防护动作：发布节奏未知或过期时，安装说明必须标注可能漂移。
- 证据：evidence.maintainer_signals | mcp_registry:io.github.fstubner/npm-run-mcp-server:0.2.13 | https://registry.modelcontextprotocol.io/v0.1/servers/io.github.fstubner%2Fnpm-run-mcp-server/versions/0.2.13 | release_recency=unknown

<!-- canonical_name: fstubner/npm-run-mcp-server; human_manual_source: deepwiki_human_wiki -->
