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

@outfitter/mcp

v0.1.0

Published

MCP server framework with typed tools for Outfitter

Readme

@outfitter/mcp

MCP (Model Context Protocol) server framework with typed tools and Result-based error handling.

Installation

bun add @outfitter/mcp

Quick Start

import { createMcpServer, defineTool } from "@outfitter/mcp";
import { Result } from "@outfitter/contracts";
import { z } from "zod";

const server = createMcpServer({
  name: "calculator",
  version: "1.0.0",
});

server.registerTool(
  defineTool({
    name: "add",
    description: "Add two numbers together",
    inputSchema: z.object({
      a: z.number(),
      b: z.number(),
    }),
    handler: async (input, ctx) => {
      ctx.logger.debug("Adding numbers", { a: input.a, b: input.b });
      return Result.ok({ sum: input.a + input.b });
    },
  })
);

await server.start();

Features

  • Typed Tools — Define tools with Zod schemas for automatic input validation
  • Result-Based Errors — All operations return Result<T, E> for explicit error handling
  • Handler Contract — Tools use the same Handler pattern as other Outfitter packages
  • Core Tools — Built-in docs, config, and query tools for common patterns
  • Deferred Loading — Support for MCP tool search with deferLoading flag

API Reference

createMcpServer(options)

Creates an MCP server instance.

interface McpServerOptions {
  name: string;      // Server name for MCP handshake
  version: string;   // Server version (semver)
  logger?: Logger;   // Optional structured logger
}

const server = createMcpServer({
  name: "my-server",
  version: "1.0.0",
  logger: createLogger({ name: "mcp" }),
});

defineTool(definition)

Helper for defining typed tools with better type inference.

interface ToolDefinition<TInput, TOutput, TError> {
  name: string;                    // Unique tool name (kebab-case)
  description: string;             // Human-readable description
  inputSchema: z.ZodType<TInput>;  // Zod schema for validation
  handler: Handler<TInput, TOutput, TError>;
  deferLoading?: boolean;          // Default: true
}

const getUserTool = defineTool({
  name: "get-user",
  description: "Retrieve a user by their unique ID",
  inputSchema: z.object({ userId: z.string().uuid() }),
  handler: async (input, ctx) => {
    const user = await db.users.find(input.userId);
    if (!user) {
      return Result.err(new NotFoundError("user", input.userId));
    }
    return Result.ok(user);
  },
});

defineResource(definition)

Helper for defining MCP resources.

interface ResourceDefinition {
  uri: string;           // Unique resource URI
  name: string;          // Human-readable name
  description?: string;  // Optional description
  mimeType?: string;     // Content MIME type
}

const configResource = defineResource({
  uri: "file:///etc/app/config.json",
  name: "Application Config",
  description: "Main configuration file",
  mimeType: "application/json",
});

Server Methods

interface McpServer {
  readonly name: string;
  readonly version: string;

  // Registration
  registerTool<TInput, TOutput, TError>(tool: ToolDefinition): void;
  registerResource(resource: ResourceDefinition): void;

  // Introspection
  getTools(): SerializedTool[];
  getResources(): ResourceDefinition[];

  // Invocation
  invokeTool<T>(name: string, input: unknown, options?: InvokeToolOptions): Promise<Result<T, McpError>>;

  // Lifecycle
  start(): Promise<void>;
  stop(): Promise<void>;
}

McpHandlerContext

Extended handler context for MCP tools with additional metadata:

interface McpHandlerContext extends HandlerContext {
  toolName?: string;  // Name of the tool being invoked
}

Core Tools

Pre-built tools for common MCP patterns. These are marked with deferLoading: false for immediate availability.

Docs Tool

Provides documentation, usage patterns, and examples.

import { defineDocsTool, createCoreTools } from "@outfitter/mcp";

const docsTool = defineDocsTool({
  docs: {
    overview: "Calculator server for arithmetic operations",
    tools: [{ name: "add", summary: "Add two numbers" }],
    examples: [{ input: { a: 2, b: 3 }, description: "Basic addition" }],
  },
});

// Or use getDocs for dynamic content
const dynamicDocsTool = defineDocsTool({
  getDocs: async (section) => {
    return loadDocsFromFile(section);
  },
});

Config Tool

Read and modify server configuration.

import { defineConfigTool } from "@outfitter/mcp";

const configTool = defineConfigTool({
  initial: { debug: false, maxRetries: 3 },
});

// With custom store
const persistedConfigTool = defineConfigTool({
  store: {
    get: async (key) => db.config.get(key),
    set: async (key, value) => db.config.set(key, value),
    list: async () => db.config.all(),
  },
});

Query Tool

Search and discovery with pagination.

import { defineQueryTool } from "@outfitter/mcp";

const queryTool = defineQueryTool({
  handler: async (input, ctx) => {
    const results = await searchIndex(input.q, {
      limit: input.limit,
      cursor: input.cursor,
      filters: input.filters,
    });
    return Result.ok({
      results: results.items,
      nextCursor: results.nextCursor,
    });
  },
});

Bundle All Core Tools

import { createCoreTools } from "@outfitter/mcp";

const coreTools = createCoreTools({
  docs: { docs: myDocs },
  config: { initial: myConfig },
  query: { handler: myQueryHandler },
});

for (const tool of coreTools) {
  server.registerTool(tool);
}

Transport Helpers

connectStdio

Connect server to stdio transport for Claude Desktop integration.

import { createMcpServer, connectStdio } from "@outfitter/mcp";

const server = createMcpServer({ name: "my-server", version: "1.0.0" });
// ... register tools ...

await connectStdio(server);

createSdkServer

Create the underlying @modelcontextprotocol/sdk server.

import { createSdkServer } from "@outfitter/mcp";

const { server: sdkServer, toolsList, callTool } = createSdkServer(mcpServer);

Error Handling

Tools return Results with typed errors. The framework automatically translates OutfitterError categories to JSON-RPC error codes:

| Category | JSON-RPC Code | Description | |----------|--------------|-------------| | validation | -32602 | Invalid params | | not_found | -32601 | Method not found | | permission | -32600 | Invalid request | | internal | -32603 | Internal error |

const result = await server.invokeTool("get-user", { userId: "123" });

if (result.isErr()) {
  // result.error is McpError with code and context
  console.error(result.error.message, result.error.code);
}

Schema Utilities

zodToJsonSchema

Convert Zod schemas to JSON Schema for MCP protocol.

import { zodToJsonSchema } from "@outfitter/mcp";

const schema = z.object({
  name: z.string(),
  age: z.number().optional(),
});

const jsonSchema = zodToJsonSchema(schema);
// { type: "object", properties: { name: { type: "string" }, ... } }

Action Adapter

buildMcpTools

Build MCP tools from an action registry (for structured action-based servers).

import { buildMcpTools } from "@outfitter/mcp";

const tools = buildMcpTools({
  actions: myActionRegistry,
  prefix: "myapp",
});

for (const tool of tools) {
  server.registerTool(tool);
}

Claude Desktop Configuration

Add your MCP server to Claude Desktop:

{
  "mcpServers": {
    "my-server": {
      "command": "bun",
      "args": ["run", "/path/to/server.ts"]
    }
  }
}

Config location:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • Linux: ~/.config/claude/claude_desktop_config.json

Related Packages