https://github.com/btwld/nest-mcp
Build Model Context Protocol (MCP) servers, clients, and gateways using the NestJS ecosystem you already know.
https://github.com/btwld/nest-mcp
mcp mcp-client mcp-gateway mcp-server model-context-protocol modelcontextprotocol nestjs
Last synced: about 2 months ago
JSON representation
Build Model Context Protocol (MCP) servers, clients, and gateways using the NestJS ecosystem you already know.
- Host: GitHub
- URL: https://github.com/btwld/nest-mcp
- Owner: btwld
- License: bsd-3-clause
- Created: 2026-02-26T15:58:07.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-03-01T20:10:55.000Z (4 months ago)
- Last Synced: 2026-03-01T20:34:02.805Z (4 months ago)
- Topics: mcp, mcp-client, mcp-gateway, mcp-server, model-context-protocol, modelcontextprotocol, nestjs
- Language: TypeScript
- Homepage:
- Size: 688 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# nest-mcp
[](https://github.com/btwld/nest-mcp/actions/workflows/ci.yml)
[](https://www.npmjs.com/package/@nest-mcp/server)
[](https://www.npmjs.com/package/@nest-mcp/server)
[](https://github.com/btwld/nest-mcp/blob/main/LICENSE)
[](https://deepwiki.com/btwld/nest-mcp)
Build [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) servers, clients, and gateways using the NestJS ecosystem you already know: decorators, dependency injection, modules, and guards, without learning a new framework.
## Packages
| Package | Description |
|---------|-------------|
| [`@nest-mcp/server`](./packages/server) | Build MCP servers with decorators, auth, resilience, and multi-transport support |
| [`@nest-mcp/client`](./packages/client) | Connect to and consume MCP servers with typed injection and health checks |
| [`@nest-mcp/gateway`](./packages/gateway) | Aggregate multiple upstream servers behind one unified MCP endpoint |
| [`@nest-mcp/common`](./packages/common) | Shared types and utilities (peer dependency) |
## Architecture
```
┌─────────────────────────────────────────────┐
│ AI Client (LLM host) │
└──────────────────────┬──────────────────────┘
│ MCP (Streamable HTTP / SSE / STDIO)
┌────────────▼────────────┐
│ @nest-mcp/gateway │ ← optional aggregation layer
│ (NestJS application) │
└──┬──────────────┬───────┘
│ │ upstream MCP connections (@nest-mcp/client)
┌──────────▼──┐ ┌──────▼──────┐
│ @nest-mcp/ │ │ @nest-mcp/ │ ← MCP servers built with @nest-mcp/server,
│ server A │ │ server B │ or any other MCP-compatible server
└─────────────┘ └─────────────┘
```
### @nest-mcp/server — internal architecture
```
HTTP / SSE / STDIO
│
▼
┌─────────────────────────────────────────────────────────┐
│ Transport Layer │
│ (StreamableHttpService / SseService / │
│ StdioService) │
└──────────────────────┬──────────────────────────────────┘
│ MCP request (tool/resource/prompt)
▼
┌─────────────────────────────────────────────────────────┐
│ Execution Pipeline │
│ │
│ ContextFactory → McpExecutionContext │
│ │ │
│ ▼ │
│ Auth Guards (@Public / @Scopes / @Roles / @Guards) │
│ │ │
│ ▼ │
│ Middleware (@UseMiddleware → McpMiddleware chain) │
│ │ │
│ ▼ │
│ Resilience (@RateLimit → @CircuitBreaker → @Retry │
│ → @Timeout) │
│ │ │
│ ▼ │
│ ExecutorService → @Tool / @Resource / @Prompt / │
│ @ResourceTemplate / @Completion │
└─────────────────────────────────────────────────────────┘
│ │
▼ ▼
┌─────────────┐ ┌────────────────────┐
│ Session / │ │ Dynamic Builders │
│ Subscription│ │ McpToolBuilder / │
│ / Task │ │ McpResourceBuilder │
│ Managers │ │ McpPromptBuilder │
└─────────────┘ └────────────────────┘
```
### @nest-mcp/client — internal architecture
```
McpClientModule.forRoot({ connections: [...] })
│
▼
┌─────────────────────────────────────────────────────────┐
│ McpClientsService │
│ (registry of named McpClient instances) │
└──────┬─────────────────────┬────────────────────────────┘
│ │
▼ ▼
┌─────────────┐ ┌───────────────┐
│ McpClient │ │ McpClient │ (one per connection)
│ "server-a" │ │ "server-b" │
│ │ │ │
│ Transport │ │ Transport │
│ (SSE / │ │ (Streamable │
│ Streamable │ │ HTTP / │
│ HTTP / │ │ STDIO) │
│ STDIO) │ │ │
│ + auth │ │ + reconnect │
│ headers │ │ backoff │
└──────┬──────┘ └───────────────┘
│
├── @InjectMcpClient('server-a') → injected into any service
│
├── @OnMcpNotification(method) → notification handler registry
│
└── McpClientHealthIndicator → health check (ping-based)
```
### @nest-mcp/gateway — internal architecture
```
AI Client
│ MCP request
▼
┌──────────────────────────────────────────────────────────┐
│ McpGatewayModule │
│ │
│ RouterService (aggregated tool/resource/prompt list) │
│ ├── ToolAggregatorService prefix: weather_* │
│ ├── ResourceAggregatorService prefix: weather://... │
│ ├── PromptAggregatorService prefix: weather_* │
│ └── ResourceTemplateAggregator │
│ │
│ On tool call: │
│ PolicyEngineService (allow / deny / require_approval) │
│ │ │
│ RequestTransformService (custom hooks) │
│ │ │
│ ResponseCacheService (TTL cache check) │
│ │ cache miss │
│ ▼ │
│ UpstreamManagerService ──────────────────────────┐ │
│ (resolves prefix → upstream connection) │ │
│ │ │ │
│ ResponseTransformService (custom hooks) │ │
│ │ │ │
│ ResponseCacheService (store result) │ │
└─────────────────────────────────────────────────────┼────┘
│
┌──────────────────────┬─────────────────────┐ │
▼ ▼ ▼ │
┌─────────────┐ ┌──────────────┐ ┌──────────────┐
│ Upstream A │ │ Upstream B │ │ Upstream C │
│ (weather) │ │ (search) │ │ (...) │
│ McpClient │ │ McpClient │ │ McpClient │
└─────────────┘ └──────────────┘ └──────────────┘
↕ health ping ↕ health ping
HealthCheckerService (periodic ping per upstream)
TaskAggregatorService (tasks proxied with upstream prefix)
```
## Installation
```bash
# Server — expose tools/resources to AI clients
npm install @nest-mcp/server @modelcontextprotocol/sdk zod@^4
# Client — call tools on a remote MCP server
npm install @nest-mcp/client @modelcontextprotocol/sdk zod@^4
# Gateway — aggregate multiple servers into one
npm install @nest-mcp/gateway @modelcontextprotocol/sdk zod@^4
```
NestJS peer dependencies (if not already installed):
```bash
npm install @nestjs/common @nestjs/core reflect-metadata rxjs
```
## Quick start
### Server
Define tools with decorators and register the module:
```typescript
// tools.service.ts
import { Injectable } from '@nestjs/common';
import { Tool } from '@nest-mcp/server';
import { z } from 'zod';
@Injectable()
export class ToolsService {
@Tool({
name: 'greet',
description: 'Greet a user by name',
schema: z.object({ name: z.string() }),
})
async greet({ name }: { name: string }) {
return `Hello, ${name}!`;
}
}
```
```typescript
// app.module.ts
import { Module } from '@nestjs/common';
import { McpModule, McpTransportType } from '@nest-mcp/server';
import { ToolsService } from './tools.service';
@Module({
imports: [
McpModule.forRoot({
name: 'my-server',
version: '1.0.0',
transports: [{ type: McpTransportType.STREAMABLE_HTTP }],
}),
],
providers: [ToolsService],
})
export class AppModule {}
```
### Client
Connect to a server and inject the client:
```typescript
// app.module.ts
import { Module } from '@nestjs/common';
import { McpClientModule, McpTransportType } from '@nest-mcp/client';
@Module({
imports: [
McpClientModule.forRoot({
connections: [
{
name: 'my-server',
transport: {
type: McpTransportType.STREAMABLE_HTTP,
url: 'http://localhost:3000/mcp',
},
},
],
}),
],
})
export class AppModule {}
```
```typescript
// my.service.ts
import { Injectable } from '@nestjs/common';
import { InjectMcpClient, McpClient } from '@nest-mcp/client';
@Injectable()
export class MyService {
constructor(@InjectMcpClient('my-server') private client: McpClient) {}
async greet(name: string) {
return this.client.callTool({ name: 'greet', arguments: { name } });
}
}
```
### Gateway
Aggregate two upstream servers behind one endpoint:
```typescript
// app.module.ts
import { Module } from '@nestjs/common';
import { McpGatewayModule, McpTransportType } from '@nest-mcp/gateway';
@Module({
imports: [
McpGatewayModule.forRoot({
name: 'my-gateway',
version: '1.0.0',
upstreams: [
{
name: 'weather',
transport: { type: McpTransportType.STREAMABLE_HTTP, url: 'http://weather-service/mcp' },
},
{
name: 'search',
transport: { type: McpTransportType.STREAMABLE_HTTP, url: 'http://search-service/mcp' },
},
],
}),
],
})
export class AppModule {}
```
Tools from upstream servers are exposed with a prefix (`weather_forecast`, `search_query`). Downstream clients see one unified server.
## Documentation
Full documentation lives in the [`docs/`](./docs/index.md) folder.
| Section | Description |
|---------|-------------|
| [Server docs](./docs/server/README.md) | Decorators, auth, resilience, transports, sessions, testing |
| [Client docs](./docs/client/README.md) | Connections, injection, notifications, health, OAuth |
| [Gateway docs](./docs/gateway/README.md) | Upstreams, routing, policies, caching, transforms, tasks |
## Examples
Working examples live in the [`apps/`](./apps/) directory:
| App | Description |
|-----|-------------|
| `example-sse-server` | MCP server using SSE transport |
| `example-client` | NestJS client consuming a remote MCP server |
| `example-gateway` | Gateway aggregating multiple upstream servers |
| `example-stdio` | MCP server using STDIO transport |
| `example-browser-mcp` | Browser-based MCP integration |
| `example-postgres-mcp` | MCP server exposing PostgreSQL tools |
## Development
This is a pnpm monorepo managed with Turborepo.
```bash
# Install dependencies
pnpm install
# Build all packages
pnpm build
# Run all tests
pnpm test
# Lint
pnpm lint
# Type check
pnpm typecheck
```
**Requirements:** Node.js >= 20, pnpm >= 9.
## Contributing
1. Fork the repository and create a branch from `main`
2. Make your changes with tests
3. Run `pnpm test` and `pnpm lint` to verify
4. Open a pull request
Changes to published packages require a [changeset](https://github.com/changesets/changesets):
```bash
pnpm changeset
```
## License
BSD-3-Clause