mcpresso

TypeScript library to simplify Model Context Protocol server implementation

šŸ“¦ Open Source •License: MIT •Version: 1.0.0 •Requirements: Node.js 18+, TypeScript 4.5+

šŸ”§ TypeScript • šŸ” OAuth 2.1 • 🚦 Rate Limiting • šŸ”„ Auto Retry • šŸ“ Generated Types

Installation

Package InstallationBash
# npm
npm install mcpresso zod

# yarn  
yarn add mcpresso zod

# pnpm
pnpm add mcpresso zod

šŸ’” Requirements: Node.js 18+ and TypeScript 4.5+. Zod is required for schema validation.

Quick Start

Create a functional MCP server in just a few lines:

server.tsTYPESCRIPT
import { z } from "zod";
import { createResource, createMCPServer } from "mcpresso";

// 1. Define a schema
const UserSchema = z.object({
  id: z.string(),
  name: z.string(),
  email: z.string().email(),
});

// Mock data
const users = [
  { id: "1", name: "Alice Smith", email: "alice@company.com" },
  { id: "2", name: "Bob Johnson", email: "bob@company.com" }
];

// 2. Create a resource
const userResource = createResource({
  name: "user",
  schema: UserSchema,
  uri_template: "users/{id}",
  handlers: {
    list: async () => users,
    get: async ({ id }) => users.find(u => u.id === id),
  },
});

// 3. Start the server
const server = createMCPServer({
  name: "my_simple_server",
  resources: [userResource],
});

server.listen(3000, () => {
  console.log("mcpresso server running on http://localhost:3000");
});

āœ… What does mcpresso generate automatically?

  • MCP Tools: list_user, get_user
  • Validation: Zod schemas automatically applied
  • TypeScript Types: Inferred from schemas
  • Error Handling: Standard JSON-RPC responses
  • Documentation: Metadata exposed to AI agents

Define Resources

Resources are the heart of mcpresso. They expose your data to AI agents:

note-resource.tsTYPESCRIPT
const noteResource = createResource({
  name: "note",
  schema: NoteSchema,
  uri_template: "notes/{id}",
  description: "User notes with tags and search",
  
  // Relations to other resources
  relations: {
    authorId: { type: 'user' },
    tagIds: { type: 'tag' }
  },
  
  // CRUD handlers
  handlers: {
    list: async () => await db.notes.findMany(),
    get: async ({ id }) => await db.notes.findUnique({ where: { id } }),
    create: async (data) => await db.notes.create({ data }),
    update: async ({ id, ...data }) => {
      return await db.notes.update({ where: { id }, data });
    },
    delete: async ({ id }) => await db.notes.delete({ where: { id } }),
    
    // Custom handler for search
    search: async ({ query, authorId, tags }) => {
      return await db.notes.findMany({
        where: {
          OR: [
            { title: { contains: query } },
            { content: { contains: query } }
          ],
          authorId: authorId || undefined,
          tags: tags ? { hasSome: tags } : undefined
        }
      });
    }
  },
  
  // Method configuration
  methodConfig: {
    create: { 
      omit: ['id', 'createdAt', 'updatedAt'] // Auto-generated fields
    },
    update: { 
      pick: ['title', 'content', 'tags'] // Modifiable fields only
    },
    search: {
      schema: z.object({
        query: z.string().describe("Search in title and content"),
        authorId: z.string().optional().describe("Filter by author"),
        tags: z.array(z.string()).optional().describe("Filter by tags")
      })
    }
  }
});

šŸ”— Relations

Define links between resources. mcpresso automatically generates $ref references in JSON schemas.

āš™ļø methodConfig

Fine-grained control over which fields are exposed for each operation (create, update, search).

Advanced Features

šŸ†• MCPresso OpenAPI Generator

New dedicated package: Generate complete MCPresso servers from OpenAPI 3.x specifications with full type safety.

Installation & UsageBash
# Install the generator globally
npm install -g mcpresso-openapi-generator

# Generate a server from OpenAPI spec
mcpresso-generate generate \
  --source ./api-spec.json \
  --output ./my-server \
  --name my-api-server \
  --verbose

# Initialize a new MCPresso project
mcpresso-generate init \
  --name my-project \
  --output ./projects \
  --verbose

# Features:
# šŸš€ Automatic generation from any OpenAPI 3.0 spec
# šŸ”’ Full TypeScript support with Zod validation
# šŸŽÆ MCP compliance out of the box
# šŸ“¦ Complete project structure with dependencies

šŸ†• Granular Field Control

Control which fields are editable vs read-only using Zod's .readonly() method:

Readonly FieldsTYPESCRIPT
const UserSchema = z.object({
  id: z.string().readonly(),           // Auto-generated by server
  name: z.string(),                    // Editable
  email: z.string().email(),           // Editable
  createdAt: z.date().readonly(),      // Set by server
  updatedAt: z.date().readonly(),      // Set by server
});

// Behavior:
// • GET/LIST: All properties (including readonly) returned
// • CREATE: Only editable properties accepted
// • UPDATE: Only editable properties accepted
// • Readonly fields automatically excluded from operations

šŸ†• Resource Relations

Define relationships between resources with automatic schema linking:

One-to-One & One-to-Many RelationsTYPESCRIPT
const noteResource = createResource({
  name: "note",
  schema: NoteSchema,
  uri_template: "notes/{id}",
  
  // Define relations
  relations: {
    authorId: { type: 'user' },     // one-to-one
    tagIds: { type: 'tag' },        // one-to-many
  },
  
  handlers: { /* CRUD handlers */ }
});

// Generated schema includes $ref links:
// "authorId": { "$ref": "type://my_server/user" }
// This helps AI agents understand data structure

šŸ†• Custom Search Methods

Add sophisticated search capabilities with dedicated input schemas:

Advanced SearchTYPESCRIPT
const noteResource = createResource({
  name: "note",
  schema: NoteSchema,
  uri_template: "notes/{id}",
  
  methods: {
    // Dedicated search method
    search: {
      description: "Search notes by content, author, and tags",
      inputSchema: z.object({
        query: z.string().describe("Search text in content"),
        authorId: z.string().optional().describe("Filter by author"),
        tags: z.array(z.string()).optional().describe("Filter by tags"),
        dateRange: z.object({
          from: z.date().optional(),
          to: z.date().optional()
        }).optional()
      }),
      handler: async ({ query, authorId, tags, dateRange }) => {
        return db.notes.findMany({
          where: {
            content: { contains: query },
            authorId,
            tags: tags ? { hasSome: tags } : undefined,
            createdAt: dateRange ? {
              gte: dateRange.from,
              lte: dateRange.to
            } : undefined
          }
        });
      }
    }
  }
});

šŸ†• Server Metadata Exposure

Automatically expose comprehensive server information to help clients understand capabilities:

Complete Server InformationTYPESCRIPT
const server = createMCPServer({
  name: "my_api_server",
  resources: [userResource, noteResource],
  
  // Enable automatic metadata exposure
  serverMetadata: {
    name: "My API Server",
    version: "1.0.0",
    description: "Comprehensive API with user and note management",
    url: "https://api.example.com",
    contact: {
      name: "API Support Team",
      email: "support@example.com",
      url: "https://example.com/support",
    },
    license: {
      name: "MIT",
      url: "https://opensource.org/licenses/MIT",
    },
    capabilities: {
      authentication: true,
      rateLimiting: true,
      retries: true,
      streaming: true,
    },
  },
});

// Automatically exposed at: metadata://my_api_server/server

Custom Business Methods

Add methods specific to your business domain:

Domain-Specific OperationsTYPESCRIPT
const noteResource = createResource({
  name: "note",
  schema: NoteSchema,
  
  methods: {
    // Business method: generate AI summary
    generate_summary: {
      description: "Generate AI summary of user's notes for a period",
      inputSchema: z.object({
        userId: z.string(),
        period: z.enum(['week', 'month', 'quarter']),
        topics: z.array(z.string()).optional()
      }),
      handler: async ({ userId, period, topics }) => {
        const notes = await getNotesForPeriod(userId, period, topics);
        const summary = await generateAISummary(notes);
        return { summary, noteCount: notes.length };
      }
    },
    
    // Business method: archive by date
    archive_by_date: {
      description: "Archive notes older than specified days",
      inputSchema: z.object({
        days: z.number().min(1).describe("Number of days"),
        dryRun: z.boolean().default(false)
      }),
      handler: async ({ days, dryRun }) => {
        const cutoffDate = new Date(Date.now() - days * 24 * 60 * 60 * 1000);
        
        if (dryRun) {
          const count = await db.notes.count({
            where: { createdAt: { lt: cutoffDate } }
          });
          return { message: `Would archive ${count} notes`, count };
        }
        
        const result = await db.notes.updateMany({
          where: { createdAt: { lt: cutoffDate } },
          data: { archived: true }
        });
        
        return { message: `Archived ${result.count} notes`, count: result.count };
      }
    }
  },
  
  handlers: { /* standard CRUD handlers */ }
});

Type Exposure

mcpresso can automatically expose your types to AI models:

Types Exposed to AI AgentsTYPESCRIPT
const server = createMCPServer({
  name: "my_server",
  resources: [userResource, noteResource],
  
  // Enable type exposure
  exposeTypes: true
});

// AI agents can now access:
// - type://my_server/user
// - type://my_server/note
// 
// With complete JSON schemas including relations

Production Configuration

Secure ServerTYPESCRIPT
const server = createMCPServer({
  name: "production_server",
  resources: [userResource, noteResource],
  
  // OAuth 2.1 authentication
  auth: {
    issuer: process.env.OAUTH_ISSUER!,
    audience: process.env.OAUTH_AUDIENCE!,
    algorithms: ['RS256']
  },
  
  // Rate limiting to prevent abuse
  rateLimit: {
    windowMs: 15 * 60 * 1000, // 15 minutes
    limit: process.env.NODE_ENV === 'production' ? 50 : 100,
    message: 'Too many requests, please try again later',
    standardHeaders: true,
    legacyHeaders: false
  },
  
  // Automatic retry with exponential backoff
  retry: {
    retries: 3,
    factor: 2,
    minTimeout: 1000,
    maxTimeout: 10000,
    randomize: true
  },
  
  // Logs for monitoring
  onRequest: (req, info) => {
    logger.info('MCP Request', {
      method: req.method,
      resource: info.resource,
      userId: req.auth?.sub,
      timestamp: new Date().toISOString(),
      userAgent: req.headers['user-agent']
    });
  },
  
  onError: (error, req) => {
    logger.error('MCP Error', {
      error: error.message,
      stack: error.stack,
      method: req.method,
      userId: req.auth?.sub
    });
  },
  
  // Strict validation
  validateRequests: true,
  sanitizeOutputs: true,
  
  // CORS for web apps
  cors: {
    origin: process.env.ALLOWED_ORIGINS?.split(',') || [],
    credentials: true
  }
});

šŸ” Production Security Checklist

  • āœ… HTTPS mandatory (valid SSL certificate)
  • āœ… Environment variables for secrets
  • āœ… Rate limiting configured for your load
  • āœ… Monitoring and alerts in place
  • āœ… Structured logs for audit
  • āœ… Critical data backup
  • āœ… Load testing before production

Deployment

mcpresso is compatible with all modern deployment platforms:

šŸš€ Vercel

Serverless with Edge Functions

vercel deploy

ā˜ļø AWS Lambda

Serverless with API Gateway

serverless deploy

šŸ”„ Cloudflare Workers

Global edge computing

wrangler deploy

šŸ“š Detailed guides: Check our deployment documentation for step-by-step instructions for each platform.

Examples & Use Cases

mcpresso includes comprehensive examples for every feature. Find them in the GitHub repository examples folder.

Complete Full-Featured Server

enterprise-server.tsTYPESCRIPT
// Full example available at: examples/mcpresso.ts
import { z } from "zod";
import { createResource, createMCPServer } from "mcpresso";

// User schema with readonly fields
const UserSchema = z.object({
  id: z.string().readonly(),
  name: z.string(),
  email: z.string().email(),
  role: z.enum(['admin', 'user', 'guest']),
  createdAt: z.date().readonly(),
  updatedAt: z.date().readonly(),
});

// Note schema with relations
const NoteSchema = z.object({
  id: z.string().readonly(),
  title: z.string(),
  content: z.string(),
  authorId: z.string(),
  tagIds: z.array(z.string()),
  featured: z.boolean().default(false),
  createdAt: z.date().readonly(),
});

// User resource with search
const userResource = createResource({
  name: "user",
  schema: UserSchema,
  uri_template: "users/{id}",
  
  methods: {
    search: {
      description: "Search users by name, email, or role",
      inputSchema: z.object({
        query: z.string().optional(),
        role: z.enum(['admin', 'user', 'guest']).optional(),
        limit: z.number().max(100).default(10)
      }),
      handler: async ({ query, role, limit }) => {
        return await db.users.findMany({
          where: {
            OR: query ? [
              { name: { contains: query } },
              { email: { contains: query } }
            ] : undefined,
            role
          },
          take: limit
        });
      }
    }
  },
  
  handlers: {
    list: async () => await db.users.findMany(),
    get: async ({ id }) => await db.users.findUnique({ where: { id } }),
    create: async (data) => await db.users.create({ data }),
    update: async ({ id, ...data }) => await db.users.update({ where: { id }, data }),
    delete: async ({ id }) => await db.users.delete({ where: { id } })
  }
});

// Note resource with relations and custom methods
const noteResource = createResource({
  name: "note", 
  schema: NoteSchema,
  uri_template: "notes/{id}",
  
  // Define relationships
  relations: {
    authorId: { type: 'user' },
    tagIds: { type: 'tag' }
  },
  
  methods: {
    // Advanced search
    search: {
      description: "Search notes with full-text and filters",
      inputSchema: z.object({
        query: z.string().optional(),
        authorId: z.string().optional(), 
        featured: z.boolean().optional(),
        tags: z.array(z.string()).optional()
      }),
      handler: async (params) => { /* implementation */ }
    },
    
    // Business logic
    generate_summary: {
      description: "AI-powered note summarization",
      inputSchema: z.object({
        userId: z.string(),
        period: z.enum(['week', 'month', 'quarter'])
      }),
      handler: async ({ userId, period }) => {
        const notes = await getNotesForPeriod(userId, period);
        return await generateAISummary(notes);
      }
    }
  },
  
  handlers: { /* CRUD implementations */ }
});

// Production server with all features
const server = createMCPServer({
  name: "enterprise_mcp_server",
  resources: [userResource, noteResource],
  
  // Security
  auth: {
    issuer: process.env.OAUTH_ISSUER!,
    audience: process.env.OAUTH_AUDIENCE!
  },
  
  // Protection
  rateLimit: {
    windowMs: 15 * 60 * 1000,
    limit: 100
  },
  
  // Resilience  
  retry: {
    retries: 5,
    factor: 2,
    minTimeout: 1000,
    maxTimeout: 60000
  },
  
  // Metadata
  serverMetadata: {
    name: "Enterprise MCP Server",
    version: "1.0.0",
    description: "Full-featured MCP server with users and notes",
    capabilities: {
      authentication: true,
      rateLimiting: true,
      retries: true,
      streaming: true
    }
  },
  
  // Type exposure
  exposeTypes: true
});

server.listen(3000);

šŸ“ Available Examples in GitHub

  • mcpresso.ts - Complete server with all features
  • retry.ts - Automatic retry with failing handlers
  • rate-limit.ts - Rate limiting configuration
  • server-metadata.ts - Metadata exposure example
  • openapi-integration.ts - OpenAPI generator usage
  • custom-search.ts - Advanced search methods
  • relations.ts - Resource relationships

OpenAPI Generator Workflow

From OpenAPI to MCPresso ServerBash
# 1. Install the generator
npm install -g mcpresso-openapi-generator

# 2. Generate from existing API spec
mcpresso-generate generate \
  --source https://petstore.swagger.io/v2/swagger.json \
  --output ./petstore-mcp \
  --name petstore-server \
  --verbose

# 3. Generated structure:
petstore-mcp/
ā”œā”€ā”€ src/
│   ā”œā”€ā”€ resources/      # Generated resources with schemas
│   ā”œā”€ā”€ handlers/       # CRUD implementations  
│   ā”œā”€ā”€ server.ts       # Complete MCP server
│   └── types.ts        # TypeScript types
ā”œā”€ā”€ package.json        # Dependencies included
ā”œā”€ā”€ tsconfig.json       # TypeScript config
└── README.md          # Usage instructions

# 4. Run immediately
cd petstore-mcp
npm install
npm start

# 5. Your OpenAPI spec is now a compliant MCP server!

Real-World Use Cases

šŸ¢ Enterprise CRM

  • User management with roles
  • Customer data with relations
  • Advanced search capabilities
  • OAuth 2.1 security
  • Rate limiting protection

šŸ“š Knowledge Base

  • Article management
  • Full-text search
  • Category relationships
  • AI-powered summaries
  • Metadata exposure

šŸ›’ E-commerce API

  • Product catalogs
  • Inventory management
  • Order processing
  • Customer analytics
  • OpenAPI integration

Ready to revolutionize your AI operations?

Get early access to build and deploy production-ready AI agents with enterprise-grade security and governance