npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mcp-setup

v0.0.13

Published

The Module for Setup MCP servers with Typescript language

Downloads

34

Readme

MCP Setup

MCP-Setup is a module for building Model Context Protocol (MCP) servers elegantly in TypeScript.

MCP-Setup gives you architecture out of the box, with automatic directory-based discovery for tools, resources, and prompts. Use our powerful MCP abstractions to define tools, resources, or prompts in an elegant way. Our cli makes getting started with your own MCP server a breeze

Features

  • 🛠️ Automatic discovery and loading of tools, resources, and prompts
  • Multiple transport support (stdio, SSE, HTTP Stream)
  • TypeScript-first development with full type safety
  • Built on the official MCP SDK
  • Easy-to-use base classes for tools, prompts, and resources
  • Out of the box authentication for SSE endpoints

Creating a repository with mcp-setup

Using the CLI (Recommended)

# Install the module globally
npm install -g mcp-setup

# Create a new MCP server project
mcp-server create my-mcp-server

# Navigate to your project
cd my-mcp-server

# Your server is ready to use!

CLI Usage

The setup provides a powerful CLI for managing your MCP server projects:

Project Creation

# Create a new project
mcp-server create <your project name here>

# Create a new project with the new EXPERIMENTAL HTTP transport
Heads up: This will set cors allowed origin to "*", modify it in the index if you wish
mcp-server create <your project name here> --http --port 1337 --cors

Options:

--http: Use HTTP transport instead of default stdio

--port : Specify HTTP port (default: 8080)

--cors: Enable CORS with wildcard (*) access

Adding a Tool

# Add a new tool
mcp-server add tool price-fetcher

Building and Validation

The setup provides comprehensive validation to ensure your tools are properly documented and functional:

# Build with automatic validation (recommended)
npm run build

# Build with custom validation settings
MCP_SKIP_TOOL_VALIDATION=false npm run build  # Force validation (default)
MCP_SKIP_TOOL_VALIDATION=true npm run build   # Skip validation (not recommended)

Validating Tools

# Validate all tools have proper descriptions (for Zod schemas)
mcp-server validate

This command checks that all tools using Zod schemas have descriptions for every field. The validation runs automatically during build, but you can also run it standalone:

  • During build: npm run build automatically validates tools
  • Standalone: mcp-server validate for manual validation
  • Development: Use defineSchema() helper for immediate feedback
  • Runtime: Server validates tools on startup

Example validation error:

❌ Tool validation failed:
  ❌ PriceFetcher.js: Missing descriptions for fields in price_fetcher: symbol, currency. 
All fields must have descriptions when using Zod object schemas. 
Use .describe() on each field, e.g., z.string().describe("Field description")

Integrating validation into CI/CD:

{
  "scripts": {
    "build": "tsc && mcp-build",
    "test": "jest && mcp-server validate",
    "prepack": "npm run build && mcp-server validate"
  }
}

Adding a Prompt

# Add a new prompt
mcp-server add prompt price-analysis

Adding a Resource

# Add a new prompt
mcp-server add resource market-data

Development Workflow

  1. Create your project:

    mcp-server create my-mcp-server
    cd my-mcp-server
  2. Add tools:

    mcp-server add tool data-fetcher
    mcp-server add tool data-processor
    mcp-server add tool report-generator
  3. Define your tool schemas with automatic validation:

    // tools/DataFetcher.ts
    import { MCPTool, MCPInput as AddToolInput } from "mcp-setup";

import { z } from "zod";

const AddToolSchema = z.object({ a: z.number().describe("First number to add"), b: z.number().describe("Second number to add"), });

class AddTool extends MCPTool { name = "add"; description = "Add tool description"; schema = AddToolSchema;

async execute(input: AddToolInput) { const result = input.a + input.b; return Result: ${result}; } } export default AddTool;


4. **Build with automatic validation:**
```bash
npm run build  # Automatically validates schemas and compiles
  1. Optional: Run standalone validation:

    mcp-server validate  # Check all tools independently
  2. Test your server:

    node dist/index.js  # Server validates tools on startup
  3. Add to MCP Client (see Claude Desktop example below)

Pro Tips:

  • Use defineSchema() during development for immediate feedback
  • Build process automatically catches missing descriptions
  • Server startup validates all tools before accepting connections
  • Use TypeScript's autocomplete with McpInput<this> for better DX

Using with Claude Desktop

Local Development

Add this configuration to your Claude Desktop config file:

MacOS: ~/Library/Application Support/Claude/claude_desktop_config.json Windows: %APPDATA%/Claude/claude_desktop_config.json

{
"mcpServers": {
"${projectName}": {
      "command": "node",
      "args":["/absolute/path/to/${projectName}/dist/index.js"]
    }
  }
}

After Publishing

Add this configuration to your Claude Desktop config file:

MacOS: ~/Library/Application Support/Claude/claude_desktop_config.json Windows: %APPDATA%/Claude/claude_desktop_config.json

{
"mcpServers": {
"${projectName}": {
      "command": "npx",
      "args": ["${projectName}"]
    }
  }
}

Building and Testing

  1. Make changes to your tools
  2. Run npm run build to compile
  3. The server will automatically load your tools on startup

Environment Variables

The setup supports the following environment variables for configuration:

| Variable | Description | Default | |-----------------------|-------------------------------------------------------|-------------| | MCP_ENABLE_FILE_LOGGING | Enable logging to files (true/false) | false | | MCP_LOG_DIRECTORY | Directory where log files will be stored | logs | | MCP_DEBUG_CONSOLE | Display debug level messages in console (true/false) | false |

Example usage:

# Enable file logging
MCP_ENABLE_FILE_LOGGING=true node dist/index.js

# Specify a custom log directory
MCP_ENABLE_FILE_LOGGING=true MCP_LOG_DIRECTORY=my-logs node dist/index.js

# Enable debug messages in console
MCP_DEBUG_CONSOLE=true node dist/index.js

Quick Start

Defining Tools

MCP Setup uses Zod schemas for defining tool inputs, providing type safety, validation, and automatic documentation:

import { MCPTool, McpInput } from "mcp-setup";
import { z } from "zod";

const AddToolSchema = z.object({
  a: z.number().describe("First number to add"),
  b: z.number().describe("Second number to add"),
});

class AddTool extends MCPTool {
  name = "add";
  description = "Add tool description";
  schema = AddToolSchema;

  async execute(input: McpInput<this>) {
    const result = input.a + input.b;
    return `Result: ${result}`;
  }
}

export default AddTool;

Key Benefits:

  • Single source of truth - Define types and validation in one place
  • Automatic type inference - TypeScript types are inferred from your schema
  • Rich validation - Leverage Zod's powerful validation features
  • Required descriptions - Setup enforces documentation
  • Better IDE support - Full autocomplete and type checking
  • Cleaner code - No duplicate type definitions

Advanced Zod Schema Features

The setup supports all Zod features:

import { MCPTool, McpInput } from "mcp-setup";
import { z } from "zod";

const AdvancedSchema = z.object({
  // String constraints and formats
  email: z.string().email().describe("User email address"),
  name: z.string().min(2).max(50).describe("User name"),
  website: z.string().url().optional().describe("Optional website URL"),
  
  // Number constraints
  age: z.number().int().positive().max(120).describe("User age"),
  rating: z.number().min(1).max(5).describe("Rating from 1 to 5"),
  
  // Arrays and objects
  tags: z.array(z.string()).describe("List of tags"),
  metadata: z.object({
    priority: z.enum(['low', 'medium', 'high']).describe("Task priority"),
    dueDate: z.string().optional().describe("Due date in ISO format")
  }).describe("Additional metadata"),
  
  // Default values
  status: z.string().default('pending').describe("Current status"),
  
  // Unions and enums
  category: z.union([
    z.literal('personal'),
    z.literal('work'),
    z.literal('other')
  ]).describe("Category type")
});

class AdvancedTool extends MCPTool {
  name = "advanced_tool";
  description = "Tool demonstrating advanced Zod features";
  schema = AdvancedSchema;

  async execute(input: McpInput<this>) {
    // TypeScript automatically knows all the types!
    const { email, name, website, age, rating, tags, metadata, status, category } = input;
    
    console.log(input.name.toUpperCase()); // ✅ TypeScript knows this is valid
    console.log(input.age.toFixed(2));     // ✅ Number methods available
    console.log(input.tags.length);       // ✅ Array methods available
    console.log(input.website?.includes("https")); // ✅ Optional handling
    
    return `Processed user: ${name}`;
  }
}

Automatic Type Inference

The McpInput<this> type automatically infers the correct input type from your schema, eliminating the need for manual type definitions:

class MyTool extends MCPTool {
  schema = z.object({
    name: z.string().describe("User name"),
    age: z.number().optional().describe("User age"),
    tags: z.array(z.string()).describe("User tags")
  });

  async execute(input: McpInput<this>) {
    // TypeScript automatically knows:
    // input.name is string
    // input.age is number | undefined  
    // input.tags is string[]
    
    console.log(input.name.toUpperCase()); // ✅ TypeScript knows this is valid
    console.log(input.age?.toFixed(2));    // ✅ Handles optional correctly
    console.log(input.tags.length);       // ✅ Array methods available
  }
}

No more duplicate interfaces or generic type parameters needed!

Schema Validation & Descriptions

All schema fields must have descriptions. This ensures your tools are well-documented and provides better user experience in MCP clients.

The setup validates descriptions at multiple levels:

1. Build-time Validation (Recommended)

npm run build  # Automatically validates during compilation

2. Development-time Validation

Use the defineSchema helper for immediate feedback:

import { defineSchema } from "mcp-setup";

// This will throw an error immediately if descriptions are missing
const MySchema = defineSchema({
  name: z.string(),  // ❌ Error: Missing description
  age: z.number().describe("User age")  // ✅ Good
});

3. Standalone Validation

mcp-server validate  # Check all tools for proper descriptions

4. Runtime Validation

The server automatically validates tools on startup.

To skip validation (not recommended):

# Skip during build
MCP_SKIP_TOOL_VALIDATION=true npm run build

# Skip during development
NODE_ENV=production npm run dev

Setting up the Server

import { MCPServer } from "mcp-setup";

const server = new MCPServer();

// OR (mutually exclusive!) with SSE transport
const server = new MCPServer({
  transport: {
    
    http: {
      options: {
        port: 8000            // Optional (default: 8000)
      }
    }
    sse: {
      options: {
        port: 8433            // Optional (default: 8433)
      }
    }
  }
});

// Start the server
await server.start();

Transport Configuration

stdio Transport (Default)

The stdio transport is used by default if no transport configuration is provided:

const server = new MCPServer();
// or explicitly:
const server = new MCPServer({
  transport: {
    stdio: {
      options: {
        // setup for stdio
      }
    } 
  }
});

SSE Transport

To use Server-Sent Events (SSE) transport:

const server = new MCPServer({
  transport: {
    sse: {
      options: {
        port: 8080,            // Optional (default: 8080)
        endpoint: "/sse",      // Optional (default: "/sse")
        messageEndpoint: "/messages", // Optional (default: "/messages")
        cors: {
          allowOrigin: "*",    // Optional (default: "*")
          allowMethods: "GET, POST, OPTIONS", // Optional (default: "GET, POST, OPTIONS")
          allowHeaders: "Content-Type, Authorization, x-api-key", // Optional (default: "Content-Type, Authorization, x-api-key")
          exposeHeaders: "Content-Type, Authorization, x-api-key", // Optional (default: "Content-Type, Authorization, x-api-key")
          maxAge: "86400"      // Optional (default: "86400")
        }
      },
    }
  }
});

HTTP Stream Transport

To use HTTP Stream transport:

const server = new MCPServer({
  transport: {
    http: {
      options: {
        port: 8080,                // Optional (default: 8080)
        endpoint: "/mcp",          // Optional (default: "/mcp") 
        responseMode: "batch",     // Optional (default: "batch"), can be "batch" or "stream"
        batchTimeout: 30000,       // Optional (default: 30000ms) - timeout for batch responses
        maxMessageSize: "4mb",     // Optional (default: "4mb") - maximum message size
        
        // Session configuration
        session: {
          enabled: true,           // Optional (default: true)
          headerName: "Mcp-Session-Id", // Optional (default: "Mcp-Session-Id")
          allowClientTermination: true, // Optional (default: true)
        },
        
        // Stream resumability (for missed messages)
        resumability: {
          enabled: false,          // Optional (default: false)
          historyDuration: 300000, // Optional (default: 300000ms = 5min) - how long to keep message history
        },
        
        // CORS configuration
        cors: {
          allowOrigin: "*"         // Other CORS options use defaults
        }
      },
    }
  }
});

Response Modes

The HTTP Stream transport supports two response modes:

  1. Batch Mode (Default): Responses are collected and sent as a single JSON-RPC response. This is suitable for typical request-response patterns and is more efficient for most use cases.

  2. Stream Mode: All responses are sent over a persistent SSE connection opened for each request. This is ideal for long-running operations or when the server needs to send multiple messages in response to a single request.

You can configure the response mode based on your specific needs:

// For batch mode (default):
const server = new MCPServer({
  transport: {
    http: {
      options: {
        responseMode: "batch"
      }
    }
  }
});

// For stream mode:
const server = new MCPServer({
  transport: {
    http: {
      options: {
        responseMode: "stream"
      }
    }
  }
});

HTTP Stream Transport Features

  • Session Management: Automatic session tracking and management
  • Stream Resumability: Optional support for resuming streams after connection loss
  • Batch Processing: Support for JSON-RPC batch requests/responses
  • Comprehensive Error Handling: Detailed error responses with JSON-RPC error codes

Authentication

MCP Setup provides optional authentication for SSE endpoints. You can choose between JWT and API Key authentication, or implement your own custom authentication provider.

JWT Authentication

import { MCPServer, JWTAuthProvider } from "mcp-setup";
import { Algorithm } from "jsonwebtoken";

const server = new MCPServer({
  transport: {
    sse: {
      options: {
        auth: {
          provider: new JWTAuthProvider({
            secret: process.env.JWT_SECRET,
            algorithms: ["HS256" as Algorithm], // Optional (default: ["HS256"])
            headerName: "Authorization"         // Optional (default: "Authorization")
          }),
          endpoints: {
            sse: true,      // Protect SSE endpoint (default: false)
            messages: true  // Protect message endpoint (default: true)
          }
        }
      }
    },
  }
});

Clients must include a valid JWT token in the Authorization header:

Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

API Key Authentication

import { MCPServer, APIKeyAuthProvider } from "mcp-setup";

const server = new MCPServer({
  transport: {
    sse: {
      options: {
        auth: {
          provider: new APIKeyAuthProvider({
            keys: [process.env.API_KEY],
            headerName: "X-API-Key" // Optional (default: "X-API-Key")
          })
        }
      }
    },
  }
});

Clients must include a valid API key in the X-API-Key header:

X-API-Key: your-api-key

Custom Authentication

You can implement your own authentication provider by implementing the AuthProvider interface:

import { AuthProvider, AuthResult } from "mcp-setup";
import { IncomingMessage } from "node:http";

class CustomAuthProvider implements AuthProvider {
  async authenticate(req: IncomingMessage): Promise<boolean | AuthResult> {
    // Implement your custom authentication logic
    return true;
  }

  getAuthError() {
    return {
      status: 401,
      message: "Authentication failed"
    };
  }
}

License

MIT