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

@breadstone/archipel-platform-mcp

v0.0.41

Published

Reusable MCP (Model Context Protocol) server module for NestJS applications

Downloads

3,108

Readme

@breadstone/archipel-platform-mcp

Reusable NestJS module for building Model Context Protocol (MCP) servers. Provides decorators, automatic handler discovery, and transport management — all wired through NestJS dependency injection.

Features

  • Decorator-driven — Annotate methods with @McpTool, @McpResource, or @McpPrompt to register MCP handlers
  • Auto-discovery — Handlers discovered at module init via NestJS DiscoveryService, no manual registration required
  • Dynamic module — Configure via McpModule.register() (sync) or McpModule.registerAsync() (factory / class / existing provider)
  • Transport-agnostic — Built-in support for Stdio, Streamable HTTP, and SSE transports; plug in any custom Transport implementation
  • Zod schemas — Define input/output schemas for tools and argument schemas for prompts using Zod
  • NPM-publishable — Designed as a standalone library for reuse across multiple NestJS projects
  • Health checksMcpHealthIndicator for readiness probes (separate /health subpath)

Quick Start

import { Module, Injectable } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { McpModule, McpServerService, McpTool } from '@breadstone/archipel-platform-mcp';
import { z } from 'zod';

// 1. Define a provider with tools
@Injectable()
class CalculatorProvider {
  @McpTool({
    name: 'add',
    description: 'Adds two numbers',
    inputSchema: { a: z.number(), b: z.number() },
  })
  public add(input: { a: number; b: number }) {
    return {
      content: [{ type: 'text' as const, text: String(input.a + input.b) }],
    };
  }
}

// 2. Import McpModule and register the provider
@Module({
  imports: [
    McpModule.register({
      name: 'calculator-server',
      version: '1.0.0',
    }),
  ],
  providers: [CalculatorProvider],
})
class AppModule {}

// 3. Bootstrap and connect a transport
async function main() {
  const app = await NestFactory.createApplicationContext(AppModule);
  const mcpServer = app.get(McpServerService);
  await mcpServer.connectStdio();
}

main();

Health indicator (optional):

import { McpHealthIndicator } from '@breadstone/archipel-platform-mcp/health';

Module Configuration

Synchronous

McpModule.register({
  name: 'my-mcp-server',
  version: '1.0.0',
  capabilities: {
    tools: { listChanged: true },
    resources: { subscribe: false, listChanged: true },
    prompts: { listChanged: true },
  },
  instructions: 'Optional instructions for MCP clients.',
});

Asynchronous

Using a factory function

McpModule.registerAsync({
  imports: [ConfigModule],
  inject: [ConfigService],
  useFactory: (config: ConfigService) => ({
    name: config.get('MCP_SERVER_NAME'),
    version: config.get('MCP_SERVER_VERSION'),
  }),
});

Using an existing provider

McpModule.registerAsync({
  useExisting: McpConfigService,
});

Where McpConfigService implements IMcpModuleOptionsFactory:

@Injectable()
class McpConfigService implements IMcpModuleOptionsFactory {
  public createMcpOptions(): IMcpModuleOptions {
    return { name: 'dynamic-server', version: '2.0.0' };
  }
}

Using a class

McpModule.registerAsync({
  useClass: McpConfigService,
});

This instantiates McpConfigService and calls createMcpOptions() to produce the options.


Decorators

All decorators are placed on methods of NestJS @Injectable() providers. The class must be registered as a provider in a NestJS module.

@McpTool

Registers a method as an MCP tool handler.

import { McpTool } from '@breadstone/archipel-platform-mcp';
import { z } from 'zod';

@Injectable()
class FileTools {
  @McpTool({
    name: 'read-file',
    title: 'Read File',
    description: 'Reads the contents of a file at the given path.',
    inputSchema: {
      path: z.string().describe('Absolute file path'),
    },
    annotations: {
      readOnlyHint: true,
    },
  })
  public readFile(input: { path: string }) {
    const content = fs.readFileSync(input.path, 'utf-8');

    return {
      content: [{ type: 'text' as const, text: content }],
    };
  }
}

Options (IMcpToolMetadata):

| Property | Type | Required | Description | | -------------- | ------------------------- | -------- | ------------------------------------- | | name | string | Yes | Unique tool name | | title | string | No | Human-readable title | | description | string | No | What the tool does | | inputSchema | ZodRawShape | No | Zod schema for input parameters | | outputSchema | ZodRawShape | No | Zod schema for structured output | | annotations | Record<string, unknown> | No | Hints (readOnlyHint, destructiveHint) |

@McpResource

Registers a method as an MCP resource handler. Supports both static URIs and URI templates.

import { McpResource } from '@breadstone/archipel-platform-mcp';

@Injectable()
class ConfigResources {
  // Static resource
  @McpResource({
    name: 'app-config',
    uri: 'config://application',
    mimeType: 'application/json',
    description: 'Application configuration',
  })
  public getAppConfig() {
    return {
      contents: [
        {
          uri: 'config://application',
          text: JSON.stringify({ debug: false }),
        },
      ],
    };
  }

  // Template resource (dynamic)
  @McpResource({
    name: 'user-profile',
    uri: 'users://{userId}/profile',
    mimeType: 'application/json',
  })
  public getUserProfile(uri: URL, params: { userId: string }) {
    return {
      contents: [
        {
          uri: uri.href,
          text: JSON.stringify({ userId: params.userId, name: 'Jane' }),
        },
      ],
    };
  }
}

URIs containing {…} placeholders are automatically registered as ResourceTemplate instances.

Options (IMcpResourceMetadata):

| Property | Type | Required | Description | | ------------- | -------- | -------- | -------------------------- | | name | string | Yes | Unique resource name | | uri | string | Yes | Static URI or URI template | | title | string | No | Human-readable title | | description | string | No | Resource description | | mimeType | string | No | MIME type of the content |

@McpPrompt

Registers a method as an MCP prompt handler.

import { McpPrompt } from '@breadstone/archipel-platform-mcp';
import { z } from 'zod';

@Injectable()
class PromptProviders {
  @McpPrompt({
    name: 'code-review',
    title: 'Code Review',
    description: 'Generates a code review prompt for the given code.',
    argsSchema: {
      code: z.string().describe('The code to review'),
      language: z.string().optional().describe('Programming language'),
    },
  })
  public codeReview(args: { code: string; language?: string }) {
    return {
      messages: [
        {
          role: 'user' as const,
          content: {
            type: 'text' as const,
            text: `Review this ${args.language ?? ''} code:\n\n${args.code}`,
          },
        },
      ],
    };
  }
}

Options (IMcpPromptMetadata):

| Property | Type | Required | Description | | ------------- | ------------- | -------- | -------------------------- | | name | string | Yes | Unique prompt name | | title | string | No | Human-readable title | | description | string | No | Prompt description | | argsSchema | ZodRawShape | No | Zod schema for prompt args |


Transports

Stdio

Best for CLI tools and process-spawned integrations (e.g., VS Code extensions).

const app = await NestFactory.createApplicationContext(AppModule);
const mcpServer = app.get(McpServerService);
await mcpServer.connectStdio();

Streamable HTTP

The recommended transport for HTTP-based deployments. Use with Express or any HTTP server.

import express from 'express';
import { NestFactory } from '@nestjs/core';
import { McpServerService } from '@breadstone/archipel-platform-mcp';

const app = await NestFactory.createApplicationContext(AppModule);
const mcpServer = app.get(McpServerService);
const transport = await mcpServer.createStreamableHttpTransport({
  sessionIdGenerator: () => crypto.randomUUID(),
  enableJsonResponse: false,
});

const httpApp = express();

httpApp.post('/mcp', async (req, res) => {
  await transport.handleRequest(req, res);
});

httpApp.get('/mcp', async (req, res) => {
  await transport.handleRequest(req, res);
});

httpApp.delete('/mcp', async (req, res) => {
  await transport.handleRequest(req, res);
});

httpApp.listen(3000);

Server-Sent Events (SSE)

Legacy transport for clients that do not support Streamable HTTP.

import express from 'express';
import { McpServerService } from '@breadstone/archipel-platform-mcp';

const app = await NestFactory.createApplicationContext(AppModule);
const mcpServer = app.get(McpServerService);

const httpApp = express();

httpApp.get('/sse', async (req, res) => {
  const transport = await mcpServer.createSseTransport({ endpoint: '/messages' }, res);
});

httpApp.post('/messages', async (req, res) => {
  // Handle incoming messages from the SSE transport
});

httpApp.listen(3000);

Custom Transport

Connect any transport implementing the MCP Transport interface:

const customTransport: Transport = /* your implementation */;
await mcpServer.connectTransport(customTransport);

Services

McpServerService

The main entry point for controlling the MCP server at runtime.

| Method | Description | | ----------------------------------------- | ------------------------------------------------ | | server: McpServer | The underlying McpServer instance (read-only) | | connectStdio() | Connects a stdio transport | | createStreamableHttpTransport(options?) | Creates and connects a Streamable HTTP transport | | createSseTransport(options, response) | Creates and connects an SSE transport | | connectTransport(transport) | Connects any custom Transport |

McpRegistryService

Holds all registered tools, resources, and prompts. Populated automatically by McpDiscoveryService but can also be used for manual registration.

| Property / Method | Description | | --------------------------------------------- | ---------------------------- | | tools: Map<string, IRegisteredTool> | All registered tools | | resources: Map<string, IRegisteredResource> | All registered resources | | prompts: Map<string, IRegisteredPrompt> | All registered prompts | | registerTool(metadata, handler) | Manually register a tool | | registerResource(metadata, handler) | Manually register a resource | | registerPrompt(metadata, handler) | Manually register a prompt |


API Reference

Interfaces

| Interface | Description | | --------------------------------- | --------------------------------------------------- | | IMcpModuleOptions | Server name, version, capabilities, instructions | | IMcpModuleAsyncOptions | Async module configuration (factory/class/existing) | | IMcpModuleOptionsFactory | Factory interface for async configuration | | IMcpToolMetadata | Tool decorator options | | IMcpResourceMetadata | Resource decorator options | | IMcpPromptMetadata | Prompt decorator options | | IMcpHandlerMetadata | Internal handler discovery metadata | | IRegisteredTool | Registered tool entry (metadata + handler) | | IRegisteredResource | Registered resource entry (metadata + handler) | | IRegisteredPrompt | Registered prompt entry (metadata + handler) | | IStreamableHttpTransportOptions | Streamable HTTP transport config | | ISseTransportOptions | SSE transport config |

Constants

| Constant | Description | | -------------------- | ---------------------------------- | | MCP_MODULE_OPTIONS | Injection token for module options |

SDK Re-exports

For convenience, the following are re-exported from @modelcontextprotocol/sdk:

  • McpServer
  • ResourceTemplate
  • StdioServerTransport
  • SSEServerTransport
  • StreamableHTTPServerTransport

Resource Limits

| Limit | Value | Description | | ---------------- | --------- | ---------------------------------------------------------------------- | | Max transports | 1,000 | McpServerService tracks up to 1,000 active transports | | Shutdown timeout | 5 seconds | Each transport and the server are closed with a 5-second timeout guard |

Lifecycle

| Service | Hook | Behaviour | | --------------------- | ----------------- | -------------------------------------------------------------------------------------------------- | | McpDiscoveryService | OnModuleInit | Scans all providers for @McpTool, @McpResource, @McpPrompt decorators and registers handlers | | McpServerService | OnModuleInit | Creates the underlying McpServer instance and registers discovered handlers | | McpServerService | OnModuleDestroy | Closes all active transports and the server with a 5-second timeout guard |

Peer Dependencies

| Package | Required | Notes | | -------------------------------------- | -------- | ----------------------------- | | @nestjs/common | Yes | NestJS core | | @nestjs/core | Yes | NestJS core | | @modelcontextprotocol/sdk | Yes | MCP SDK | | zod | Yes | Schema validation | | rxjs | Yes | NestJS peer requirement | | reflect-metadata | Yes | Decorator metadata | | @breadstone/archipel-platform-health | No | Required for health indicator | | @nestjs/terminus | No | Required for health indicator |

Documentation

📖 Package Docs: .docs/packages/platform-mcp/index.md

Development

# Build
yarn nx build platform-mcp

# Test
yarn nx test platform-mcp

# Lint
yarn nx lint platform-mcp