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

@lushly-dev/afd-server

v0.1.0

Published

Server-side utilities for building AFD-compliant MCP servers with Zod validation

Readme

@afd/server

Server-side utilities for building AFD-compliant MCP servers with Zod validation.

Installation

npm install @afd/server
# or
pnpm add @afd/server

Features

  • Zod-based Command Definition - Define commands with Zod schemas for type-safe validation
  • Auto JSON Schema Generation - Automatic conversion to JSON Schema for MCP tool definitions
  • Multiple Transport Support - stdio for IDE/agent integration, HTTP/SSE for browser clients
  • Auto Transport Detection - Automatically selects the right transport based on environment
  • Built-in Validation - Automatic input validation before handler execution
  • Middleware System - Logging, tracing, rate limiting, and custom middleware
  • Full TypeScript Support - Complete type inference from Zod schemas

Quick Start

import { z } from 'zod';
import { defineCommand, createMcpServer, success, failure } from '@afd/server';

// Define a command with Zod schema
const greet = defineCommand({
  name: 'greet',
  description: 'Greet a user by name',
  category: 'demo',
  input: z.object({
    name: z.string().min(1, 'Name is required'),
    formal: z.boolean().default(false),
  }),
  
  async handler(input) {
    const greeting = input.formal 
      ? `Good day, ${input.name}.` 
      : `Hello, ${input.name}!`;
    
    return success({ greeting }, {
      reasoning: `Generated ${input.formal ? 'formal' : 'casual'} greeting`,
      confidence: 1.0,
    });
  },
});

// Create and start the server (auto-detects transport)
const server = createMcpServer({
  name: 'my-server',
  version: '1.0.0',
  commands: [greet],
  port: 3100,
});

await server.start();
console.log(`Server running at ${server.getUrl()}`);

Transport Protocols

The server supports multiple transport protocols for different use cases:

Auto-Detection (Default)

By default, the server auto-detects the best transport based on the environment:

const server = createMcpServer({
  name: 'my-server',
  version: '1.0.0',
  commands: [greet],
  // transport: 'auto' is the default
});

// When stdin is piped (IDE/agent context): uses stdio
// When stdin is a TTY (interactive context): uses HTTP

stdio Transport (IDE/Agent Integration)

Use stdio for integration with IDE MCP clients like Cursor, Claude Code, or Antigravity:

const server = createMcpServer({
  name: 'my-server',
  version: '1.0.0',
  commands: [greet],
  transport: 'stdio',  // Explicit stdio mode
});

await server.start();
// Server reads JSON-RPC from stdin, writes to stdout

In your IDE's MCP configuration (adjust the path to match your project):

{
  "mcpServers": {
    "my-server": {
      "command": "node",
      "args": ["path/to/your/server.js"]
    }
  }
}

HTTP Transport (Browser/Web UI)

Use HTTP for browser-based clients and web UIs:

const server = createMcpServer({
  name: 'my-server',
  version: '1.0.0',
  commands: [greet],
  transport: 'http',  // Explicit HTTP mode
  port: 3100,
});

await server.start();
console.log(`Server running at ${server.getUrl()}`);
// Exposes /sse, /message, /health endpoints

Defining Commands

Basic Command

import { z } from 'zod';
import { defineCommand, success, failure } from '@afd/server';

const createUser = defineCommand({
  name: 'user.create',
  description: 'Create a new user',
  category: 'users',
  mutation: true,
  
  input: z.object({
    email: z.string().email(),
    name: z.string().min(1).max(100),
    role: z.enum(['admin', 'user', 'guest']).default('user'),
  }),
  
  async handler(input) {
    // Your implementation
    const user = await db.users.create(input);
    
    return success(user, {
      reasoning: `Created user ${user.email} with role ${user.role}`,
    });
  },
});

Command with Error Handling

const getUser = defineCommand({
  name: 'user.get',
  description: 'Get a user by ID',
  category: 'users',
  errors: ['NOT_FOUND'],
  
  input: z.object({
    id: z.string().uuid(),
  }),
  
  async handler(input) {
    const user = await db.users.find(input.id);
    
    if (!user) {
      return failure({
        code: 'NOT_FOUND',
        message: `User with ID "${input.id}" not found`,
        suggestion: 'Check the ID or use user.list to find available users',
      });
    }
    
    return success(user);
  },
});

Server Configuration

const server = createMcpServer({
  // Required
  name: 'my-server',
  version: '1.0.0',
  commands: [cmd1, cmd2, cmd3],
  
  // Optional
  port: 3100,              // Default: 3100
  host: 'localhost',       // Default: localhost
  cors: true,              // Enable CORS (default: true)
  
  // Middleware
  middleware: [
    createLoggingMiddleware(),
    createTimingMiddleware({ slowThreshold: 1000 }),
  ],
  
  // Callbacks
  onCommand(command, input, result) {
    console.log(`Executed ${command}:`, result.success);
  },
  onError(error) {
    console.error('Server error:', error);
  },
});

Middleware

Logging

import { createLoggingMiddleware } from '@afd/server';

const middleware = createLoggingMiddleware({
  log: console.log,        // Custom log function
  logInput: false,         // Don't log input (may contain sensitive data)
  logResult: false,        // Don't log full results
});

Timing

import { createTimingMiddleware } from '@afd/server';

const middleware = createTimingMiddleware({
  slowThreshold: 1000,     // Warn if command takes > 1s
  onSlow(command, durationMs) {
    console.warn(`Slow command: ${command} took ${durationMs}ms`);
  },
});

OpenTelemetry Tracing

import { trace } from '@opentelemetry/api';
import { createTracingMiddleware } from '@afd/server';

const tracer = trace.getTracer('my-app');

const middleware = createTracingMiddleware({
  tracer,
  spanPrefix: 'command',   // Span names: command.user.create, etc.
});

Rate Limiting

import { createRateLimitMiddleware } from '@afd/server';

const middleware = createRateLimitMiddleware({
  maxRequests: 100,
  windowMs: 60000,         // 100 requests per minute
  keyFn: (context) => context.userId ?? 'anonymous',
});

Custom Middleware

import type { CommandMiddleware } from '@afd/server';

const myMiddleware: CommandMiddleware = async (commandName, input, context, next) => {
  console.log(`Before: ${commandName}`);
  const result = await next();
  console.log(`After: ${commandName}, success: ${result.success}`);
  return result;
};

Validation Utilities

import { validateInput, validateOrThrow, isValid, patterns } from '@afd/server';

// Validate and get result
const result = validateInput(schema, data);
if (!result.success) {
  console.log(result.errors);
}

// Validate or throw
try {
  const data = validateOrThrow(schema, input);
} catch (e) {
  if (e instanceof ValidationException) {
    console.log(e.errors);
  }
}

// Check validity
if (isValid(schema, data)) {
  // data is typed
}

// Common patterns
const schema = z.object({
  id: patterns.uuid,
  email: patterns.email,
  count: patterns.positiveInt,
  ...patterns.pagination,
});

API Reference

defineCommand(options)

Create a command definition with Zod schema.

| Option | Type | Required | Description | |--------|------|----------|-------------| | name | string | Yes | Unique command name (e.g., user.create) | | description | string | Yes | Human-readable description | | input | ZodType | Yes | Zod schema for input validation | | handler | function | Yes | Command implementation | | category | string | No | Category for grouping | | mutation | boolean | No | Whether command has side effects | | version | string | No | Command version | | tags | string[] | No | Additional tags | | errors | string[] | No | Possible error codes |

createMcpServer(options)

Create an MCP server from commands.

| Option | Type | Required | Description | |--------|------|----------|-------------| | name | string | Yes | Server name | | version | string | Yes | Server version | | commands | array | Yes | Command definitions | | transport | 'stdio' \| 'http' \| 'auto' | No | Transport protocol (default: 'auto') | | port | number | No | Port for HTTP transport (default: 3100) | | host | string | No | Host for HTTP transport (default: localhost) | | devMode | boolean | No | Enable development mode (default: false) | | cors | boolean | No | Enable CORS for HTTP transport (default: follows devMode) | | middleware | array | No | Middleware functions | | onCommand | function | No | Command execution callback | | onError | function | No | Error callback |

Server Methods

| Method | Description | |--------|-------------| | start() | Start the server | | stop() | Stop the server | | getUrl() | Get server URL ("stdio://" for stdio transport) | | getTransport() | Get the resolved transport mode ("stdio" or "http") | | getCommands() | Get registered commands | | execute(name, input, context) | Execute command directly |

Endpoints

The server exposes these endpoints:

| Endpoint | Method | Description | |----------|--------|-------------| | /sse | GET | SSE connection for MCP clients | | /message | POST | JSON-RPC message endpoint | | /health | GET | Health check |

Related