# MCP-Nest: Exposing NestJS Methods as MCP Tools

> MCP-Nest turns a NestJS application into a Model Context Protocol server by treating MCP as a microservice transport strategy. The design reuses NestJS guards, pipes and dependency injection, but it also means your tool layer inherits NestJS conventions whether you want them or not.

**rekog-labs/MCP-Nest** — A NestJS module to effortlessly create Model Context Protocol (MCP) servers for exposing AI tools, resources, and prompts.

- Repository: https://github.com/rekog-labs/MCP-Nest
- Stars: 712 · Forks: 119
- Language: TypeScript
- License: MIT
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/rekog-labs-mcp-nest

## The problem MCP-Nest solves for existing NestJS codebases

Writing an MCP server from scratch means implementing the protocol handshake, tool discovery, parameter validation and transport handling before you expose a single useful function. If the functions you want to expose already live in a NestJS application, that work duplicates what the framework already does. MCP-Nest targets that situation specifically. The README describes it as a module to expose tools, resources and prompts "from your NestJS applications", and the stated goal is to let you "leverage the full power of dependency injection to utilize your existing codebase".

The audience is therefore narrow but concrete: teams with a NestJS service, usually an internal or enterprise one, that want an AI client to call into it. A service that already has authentication guards, validated DTOs and service providers can reuse them rather than rebuild a parallel tool layer. If you are starting from an empty directory with no NestJS code, the module's main selling point does not apply to you. The README's own framing is about reuse, not about being a general MCP framework.

## How the microservice strategy mechanism actually works

The architectural decision that shapes everything else is that MCP runs as a NestJS CustomTransportStrategy. The README states this directly: tools, resources and prompts are real @MessagePattern handlers, so "guards, pipes, interceptors, and exception filters apply to them natively". That is not a wrapper around NestJS. It is NestJS's own request pipeline, with MCP messages arriving as microservice messages.

There is no McpModule in the v2 design. The README comments that "the strategy is the whole configuration". You construct an McpStrategy instance with a name, a version and a transports array, then hand it to app.connectMicroservice(). Handlers live on classes decorated with @McpController(), and individual methods are decorated with @Tool(), which takes a name, a description and a Zod schema for parameters. Method arguments use standard NestJS microservice decorators, @Payload() for the validated parameters and @Ctx() for an McpContext object that exposes request context and progress reporting.

Transport selection happens through the transports array rather than a mode flag. The README lists Streamable HTTP and STDIO, and notes that a single endpoint can serve both the 2025-era protocol with initialize and sessions and the stateless 2026-07-28 revision concurrently, "with no change to your tool code". That dual-era claim is worth reading carefully, because the README also states that progress reporting behaves differently across them: on the legacy stateless default, ctx.reportProgress is a no-op, and a 2025-era client needs new StreamableHttpTransport({ statefulMode: true }) or StdioTransport to receive it. The same tool method is portable; the observable streaming behaviour is not.

## Installing MCP-Nest and exposing a first tool

Installation pulls in the MCP protocol packages and Zod alongside the module itself. The README gives this exact command, and it is worth noting that the protocol packages are separate dependencies rather than bundled:

```bash
npm install @rekog/mcp-nest \
  @modelcontextprotocol/server \
  @modelcontextprotocol/core \
  @modelcontextprotocol/node \
  zod@^4
```

A tool is a method on an @McpController() class. The README's greeting example takes a name parameter defaulting to "World", reports progress at the halfway point, and returns a content array:

```typescript
import { McpController, Tool, McpContext } from '@rekog/mcp-nest';
import { Ctx, Payload } from '@nestjs/microservices';
import { z } from 'zod';

@McpController()
export class GreetingController {
  @Tool({
    name: 'greeting-tool',
    description: 'Returns a greeting with progress updates',
    parameters: z.object({ name: z.string().default('World') }),
  })
  async sayHello(
    @Payload() { name }: { name: string },
    @Ctx() ctx: McpContext,
  ) {
    await ctx.reportProgress({ progress: 50, total: 100 });
    return { content: [{ type: 'text', text: `Hello, ${name}!` }] };
  }
}
```

The strategy is constructed at module scope and registered as a provider only if something injects it. The README's app.module.ts example uses a StreamableHttpTransport and comments that the provider entry is optional, needed only for runtime or dynamic tool registration:

```typescript
export const mcp = new McpStrategy({
  name: 'my-mcp-server',
  version: '1.0.0',
  transports: [new StreamableHttpTransport()],
});
```

Bootstrap order matters and the README calls it out explicitly. The HTTP adapter must be passed to the strategy before connecting the microservice, startAllMicroservices() mounts the MCP transports, and it has to run before listen() so the routes exist before the server accepts connections:

```typescript
const app = await NestFactory.create(AppModule);
mcp.setHttpAdapter(app.getHttpAdapter());
app.connectMicroservice({ strategy: mcp });
await app.startAllMicroservices();
await app.listen(3000);
```

After that, the /mcp endpoint answers MCP requests while the same process continues to serve normal HTTP routes. For a STDIO-only server the README says to skip the HTTP adapter and use NestFactory.createMicroservice(AppModule, { strategy: mcp }) with StdioTransport in the transports array instead.

## Where MCP-Nest is the wrong tool or breaks down

The first constraint is that MCP-Nest is not standalone. Tools only exist as methods on NestJS controllers inside a NestJS application, so adopting it means adopting NestJS's module, provider and decorator model for your MCP surface. A team that wants a small MCP server in plain TypeScript, or one that already runs on Fastify without NestJS, gains nothing from the strategy indirection.

The second constraint is transport-dependent behaviour that the tool code cannot paper over. The README is explicit that ctx.reportProgress is a no-op for 2025-era clients on the legacy stateless default, and that such clients need statefulMode or STDIO to see progress. If your tool depends on streaming intermediate state to keep a client responsive, the transport configuration is part of correctness, not a deployment detail. Getting this wrong produces a server that works and silently drops updates.

The third is dependency surface. The install command already pulls four protocol packages plus Zod, and the authorization server moved into a separate package, @rekog/mcp-nest-auth, with @nestjs/typeorm and typeorm as additional optional peer dependencies if you use its TypeORM store. The README marks the built-in authorization server as Beta. A project that needs only unauthenticated tool calls still carries the protocol package set, and a project that wants the built-in auth server carries a beta component plus an ORM.

## How MCP-Nest differs from the official MCP SDK

The natural alternative is the official Model Context Protocol SDK for TypeScript, which the README lists as a direct dependency rather than a competitor. The difference is where the abstraction sits. With the SDK you construct a server object and register tools against it imperatively; you own the transport setup, the request lifecycle and any validation wiring yourself. MCP-Nest instead makes the MCP server a NestJS transport strategy, so registration happens through decorators on controller classes and the request lifecycle is NestJS's.

The practical consequence is what you get for free versus what you must understand. With MCP-Nest you inherit guards, pipes, interceptors and exception filters without writing adapter code, and dependency injection reaches into tool handlers. With the SDK you get a smaller, framework-neutral surface that can live in any Node process, at the cost of rebuilding the parts NestJS already provides. Neither is strictly better; the deciding question is whether the application you are exposing is already NestJS. The repository also points to a separate samples repository, MCP-Nest-Samples, for building ChatGPT widgets with the OpenAI SDK, which suggests the maintainers expect that use case to be handled outside this package.

## Licence, maintenance and what upgrading costs

The repository is MIT licensed, and the workspace root package.json carries "license": "MIT" as well. MIT permits commercial and closed-source use with the usual attribution requirement, but this is a description of the licence text, not legal advice; check the LICENSE file and your own obligations before shipping.

On maintenance, the last push to the default branch was on 2026-09-09, and the most recent release listed is v2.0.5 on the same date, following v2.0.4 and v2.0.3 earlier that month. The repository is not archived. That is a recent release cadence, and the version history shows the 2.x line is where current work sits.

Upgrade cost is dominated by the v2 architectural change rather than by patch versions. The README links a migration-to-v2 document, and the v2 design removed McpModule in favour of the strategy object, which means pre-v2 code that registered an McpModule must be rewritten around McpStrategy, connectMicroservice and startAllMicroservices. The protocol packages are peer-style dependencies with their own version lines, so a major bump in @modelcontextprotocol/server can require coordinated changes even when @rekog/mcp-nest itself has not changed. The repository's own scripts use Bun for building and testing, but the published package installs through npm, so consumers are not required to adopt Bun.

## Guards, elicitation and the authorization surface

Beyond basic tool exposure, the README lists several capabilities that determine whether MCP-Nest fits a production service. Per-tool authorization is documented separately, and the examples directory contains dedicated folders for per-tool-authorization, per-tool-authorization-jwt and per-tool-authorization-oauth, which indicates the intended pattern is finer-grained than a single server-wide guard. Guard-based authentication with OAuth support is described in the server examples, and there are separate documents for a built-in authorization server and for external authorization servers such as Keycloak or Auth0, with example folders for Azure AD and Casdoor.

Two features are easy to overlook when evaluating the module. Elicitation, documented under tools, allows an interactive tool call to request input from the user mid-execution, which changes how you think about a handler's lifetime. Resource templates let you expose dynamic resources with parameterized URIs rather than a fixed list. Both are documented rather than demonstrated in the README itself, so the docs directory is the place to confirm the exact API before designing around them. The README also mentions server mutation and instrumentation, which allows mutating the underlying MCP server for custom logic, and that is the escape hatch to reach for when a decorator does not cover your case.

## Conclusion

Adopt MCP-Nest if your service is already NestJS and you want MCP tools to sit behind the same guards, pipes and dependency injection as the rest of the application. Do not adopt it if you want a framework-neutral MCP server or a single-file script; the strategy, transport and controller wiring is more ceremony than that job needs. Before committing, verify that your NestJS version matches the peer dependencies in the install command, and check the protocol revisions document to confirm which clients you need to serve.

## FAQ

### What is an MCP server such as the one MCP-Nest builds?

It is a service that exposes functions to AI clients through the Model Context Protocol instead of a bespoke integration. MCP-Nest builds one from a NestJS application, exposing tools, resources and prompts that reuse the existing codebase.

### Is MCP a router?

The README does not describe MCP that way. It describes MCP as a protocol whose messages MCP-Nest receives as a NestJS microservice transport strategy, with tools registered as @MessagePattern handlers.

### What is NestJS used for, and why does MCP-Nest depend on it?

NestJS supplies the module, provider and decorator model that MCP-Nest reuses: tools live on @McpController() classes and dependency injection reaches into handlers. That reuse is the module's stated reason for existing.

### What does MCP connection stand for?

The README expands the acronym as Model Context Protocol. MCP-Nest is a NestJS module for serving it over Streamable HTTP or STDIO.

## Sources

- [Issues](https://github.com/rekog-labs/MCP-Nest/issues)
- [License: MIT](https://github.com/rekog-labs/MCP-Nest/blob/main/LICENSE)
- [README](https://github.com/rekog-labs/MCP-Nest/blob/main/README.md)
- [rekog-labs/MCP-Nest on GitHub](https://github.com/rekog-labs/MCP-Nest)
- [Releases](https://github.com/rekog-labs/MCP-Nest/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/rekog-labs-mcp-nest
