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
/mcpendpoint 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.tswith 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.jsonsobuildrunsxmcp buildbefore your Nest build. - Updated
tsconfig.jsonwith the@xmcp/*path alias andxmcp-env.d.ts. - Updated
.gitignoreto ignore the generated.xmcpfolder. - Installed
xmcpandzodwith 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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
Inside a tool, the auth info is available through the extra argument:
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.