Skip to content

Integrating NestJS with xmcp

Add an MCP server to your NestJS application with tool discovery and a customizable module.

Learn how to turn your existing NestJS app into an MCP server with xmcp. Instead of standing up a separate service, xmcp drops into your project as a regular Nest module: your tools live in src/tools/, they're discovered automatically, and they're served through Nest's own controllers, dependency injection, and lifecycle hooks.

What You'll Build

By the end of this guide, you'll have:

  • An /mcp endpoint served by a NestJS module
  • Tools auto-discovered from your src/tools/ directory
  • Tools that read from your existing Nest providers and services
  • Optional JWT authentication using a reusable guard

Install xmcp

xmcp works on top of your existing NestJS project. From your project directory, run:

The framework (@nestjs/core) and package manager are detected automatically. The only thing you're prompted for is which of tools, prompts, and resources to scaffold.

? Which components do you want to initialize? (tools, prompts, resources)

That single command does the whole setup for you. After it finishes, init has:

  • Generated xmcp.config.ts with the NestJS adapter and your selected paths.
  • Generated a src/xmcp/ folder with the module, controller, exception filter, and an auth guard stub.
  • Scaffolded a sample tool in src/tools/ (plus prompts/resources if you picked them).
  • Wired package.json so build runs xmcp build before your Nest build.
  • Updated tsconfig.json with the @xmcp/* path alias and xmcp-env.d.ts.
  • Updated .gitignore to ignore the generated .xmcp folder.
  • Installed xmcp and zod with your package manager.

The generated src/xmcp/ folder holds the module files you'll customize:

Adjust the Dev Script

Init already wired your build script to run xmcp build && nest build, added the @xmcp/* path alias and xmcp-env.d.ts to your tsconfig.json, and ignored the generated .xmcp folder in .gitignore. There's one script worth adjusting by hand.

NestJS apps watch with start:dev, so init can't know to combine it with xmcp. It writes a standalone dev: "xmcp dev". Update it to run both watchers together:

package.json
Info

The scaffolded files import from @xmcp/adapter, which resolves to the local .xmcp folder via the @xmcp/* alias init added to your tsconfig.json. That folder is generated the first time you run xmcp dev or xmcp build (both are wired into your scripts), so the imports resolve once you start the dev server. .xmcp is already gitignored.

The Generated Config

Because init detected @nestjs/core, it already generated an xmcp.config.ts set up for the NestJS adapter. You don't write this by hand:

xmcp.config.ts

The paths reflect the components you selected during init (false for the ones you skipped). The NestJS adapter uses HTTP transport and integrates with Nest's module system, so you can inject XmcpService into your own controllers if you ever need to. Edit this file only if you want to change the adapter or move your tool directories.

Register the Module

This is the one integration step init leaves to you, it prints these exact instructions when it finishes. This is deliberate: init won't edit your app.module.ts to auto-register XmcpModule, because mounting the service into your application graph without your say-so could introduce a breaking change to a project that's already running. You decide when the MCP endpoint goes live. Import XmcpModule into your application module:

src/app.module.ts

That's it for wiring. This registers a /mcp endpoint that handles MCP requests via POST.

A Tour of the Generated Files

The files in src/xmcp/ are yours to customize. Here's what each one does.

Controller

The controller extends XmcpController and uses standard Nest decorators:

src/xmcp/xmcp.controller.ts

Want a different route? Just change the @Controller argument:

Module

The module registers the controller and providers, and wires up OAuth resource metadata and the auth guard out of the box:

src/xmcp/xmcp.module.ts

OAUTH_ISSUER is only read when a client requests the OAuth resource metadata endpoint, so the module boots and serves tools even if you haven't set it yet. Wire it up when you're ready to advertise an authorization server.

Exception Filter

The filter handles MCP errors in JSON-RPC format. Customize it to handle specific error types or change the response shape:

src/xmcp/xmcp.filter.ts

Auth Guard

Init also generates an xmcp.auth.ts stub built around the createMcpAuthGuard factory. It's already imported by the module, so all you do is fill in verifyToken when you want authentication:

src/xmcp/xmcp.auth.ts

With required: false, the guard lets unauthenticated requests through and never calls verifyToken, so the default scaffold runs without any auth wiring. The Authentication section below shows how to fill it in.

Add a Tool

Tools are discovered automatically from your src/tools/ directory. Create a file, export a schema, metadata, and a default handler:

src/tools/greet.ts

When you run xmcp dev or xmcp build, xmcp registers this as an MCP tool. No extra configuration, no manual registration.

The more interesting part is that tools can read from the rest of your application. A tool is just a function, so it can call into your existing stores and services:

src/tools/list-users.ts

This is the payoff of running inside your Nest app: the same data that backs your REST API now backs your MCP tools.

Authentication

The guard from createMcpAuthGuard is already generated in xmcp.auth.ts and already registered in your module's providers. Two things are left to you: implement verifyToken, and apply the guard to the controller.

The generated stub throws from verifyToken. Fill it in with your verification logic — here's a JWT example. Start by installing the JWT library:

Then replace the stub's verifyToken:

src/xmcp/xmcp.auth.ts

The adapter handles token extraction, error responses, and attaching auth info to the request. The guard is registered in the module already, so the only wiring left is applying it to the controller with @UseGuards:

src/xmcp/xmcp.controller.ts

Inside a tool, the auth info is available through the extra argument:

src/tools/whoami.ts

For the full list of guard options, see the NestJS adapter docs.

Lifecycle and Logging

Because the adapter runs as a real Nest service, it plays by Nest's rules. XmcpService implements OnModuleInit and OnModuleDestroy, so it initializes and shuts down with the rest of your application, and every internal log goes through Nest's Logger. That means MCP traffic shows up in the same logs, with the same formatting, as the rest of your app, no separate logging setup required.

Test It

With the server running, send a request to the /mcp endpoint:

Conclusion

Now your NestJS app has an MCP server. Tools are auto-discovered, served through a module you fully control, and able to reuse the services and data you already have.

For the full reference, check the NestJS adapter docs.

One framework to rule them all