惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V2EX - 技术
V2EX - 技术
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Threat Research - Cisco Blogs
T
The Exploit Database - CXSecurity.com
S
Schneier on Security
S
Securelist
P
Privacy & Cybersecurity Law Blog
Scott Helme
Scott Helme
T
Threatpost
C
Cybersecurity and Infrastructure Security Agency CISA
L
LINUX DO - 热门话题
Cyberwarzone
Cyberwarzone
Cisco Talos Blog
Cisco Talos Blog
量子位
博客园 - Franky
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Latest news
Latest news
T
Troy Hunt's Blog
N
News | PayPal Newsroom
Google Online Security Blog
Google Online Security Blog
Apple Machine Learning Research
Apple Machine Learning Research
N
Netflix TechBlog - Medium
小众软件
小众软件
P
Palo Alto Networks Blog
Spread Privacy
Spread Privacy
C
Cyber Attacks, Cyber Crime and Cyber Security
C
Check Point Blog
aimingoo的专栏
aimingoo的专栏
WordPress大学
WordPress大学
L
Lohrmann on Cybersecurity
L
LINUX DO - 最新话题
D
Darknet – Hacking Tools, Hacker News & Cyber Security
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
The Last Watchdog
The Last Watchdog
S
Security @ Cisco Blogs
P
Privacy International News Feed
Last Week in AI
Last Week in AI
Microsoft Security Blog
Microsoft Security Blog
T
Tailwind CSS Blog
博客园_首页
云风的 BLOG
云风的 BLOG
V
Vulnerabilities – Threatpost
D
DataBreaches.Net
Recent Announcements
Recent Announcements
酷 壳 – CoolShell
酷 壳 – CoolShell
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
罗磊的独立博客
Engineering at Meta
Engineering at Meta
Forbes - Security
Forbes - Security
T
Tenable Blog

Nx Blog

Sharing Tailwind CSS Styles Across Apps in a Monorepo | Nx Blog How SiriusXM Stays Competitive by Iterating and Getting to Market Fast | Nx Blog Agentic Experience Is the New Developer Experience | Nx Blog Nx Joins the Linux Foundation and the Agentic AI Foundation | Nx Blog A Monorepo Is NOT a Monolith | Nx Blog Why we deleted (most of) our MCP tools | Nx Blog Teach Your AI Agent How to Work in a Monorepo | Nx Blog How Broadcom stays efficient and nimble with monorepos | Nx Blog Why Monorepos are King in the Age of AI | Nx Blog Nx 2026 Roadmap: Expanding Agent Autonomy, Improving Performance, Better Polyglot and More | Nx Blog End to End Autonomous AI Agent Workflows with Nx | Nx Blog Autonomous Agents at Scale | Nx Blog Scaling 700+ Projects: How Nx Became a 'No-Brainer' for Caseware | Nx Blog Configure Tailwind v4 with Angular in an Nx Monorepo | Nx Blog The Missing Multiplier for AI Agent Productivity | Nx Blog A Year of Nx Webinars | Nx Blog Wrapping Up 2025 | Nx Blog Nx 22.3 Release: Angular 21 Support, tsgo Compiler, and Prettier v3 | Nx Blog Nx Cloud Release: Agent Resource Usage | Nx Blog Nx Platform Outperforms DIY Cache by 5x | Nx Blog An Nx Carol: Past, Present, and Future of Your Monorepo | Nx Blog Nx 22.1 Release: Terminal UI on Windows, Storybook 10, Vitest 4, and more! | Nx Blog The Compounding Effect: How Nx Features Multiply Performance Gains | Nx Blog 10 Monorepo Myths Debunked: Separating Fact from Fiction | Nx Blog Nx Cloud Release: Enterprise Task Analytics | Nx Blog Watch and Rebuild Storybook Dependencies with Nx | Nx Blog Book - React for Enterprise: Timeless Architecture for Enterprise Apps | Nx Blog Beyond Remote Cache: Unlock 70% More CI Performance | Nx Blog Nx 22 Release: Expanding the build platform | Nx Blog What's the Point of Generating All This Code If You Can't Merge It? | Nx Blog What's New in Nx Self-Healing CI | Nx Blog Nx Highlights: Smarter AI integration, all-new graph UI, and big new versions of your favorite tools | Nx Blog Making the Case for Smarter Monorepos, and How to Not Get Fooled by Myths | Nx Blog Integrating Biome in 20 Minutes | Nx Blog S1ngularity - What Happened, How We Responded, What We Learned | Nx Blog Stop Babysitting Your PRs: Self-Healing CI Cuts Time to Green by 50% | Nx Blog UKG Unifies Their Codebase and Eliminates CI Overhead to Focus on Customer Value | Nx Blog How Git Worktrees Changed My AI Agent Workflow | Nx Blog Nx Cloud Workspace Graph: See Your Organization's Code Structure Like Never Before | Nx Blog Seamless Java Deployment in Nx Using Docker | Nx Blog Getting Mobile Into Your Monorepo: Android + Nx | Nx Blog Polyglot Projects Made Easy: Integrating Spring Boot into an Nx Workspace | Nx Blog The Journey of the Nx Plugin for Gradle: From Prototype to Production | Nx Blog Combining Predictability and Intelligence With Nx Generators and AI | Nx Blog A New UI For The Humble Terminal | Nx Blog Continuous tasks are a huge DX improvement | Nx Blog New and Improved Module Federation Experience with Nx | Nx Blog A New UI for Nx Migration | Nx Blog Custom Task Runners and Self-Hosted Caching Changes | Nx Blog Enterprise Angular Monorepo Patterns | Nx Blog Using Rspack with Angular | Nx Blog Angular Architecture Guide To Building Maintainable Applications at Scale | Nx Blog Modern Angular Testing with Nx | Nx Blog Nx Update: 20.5 | Nx Blog Are Monorepos the Answer to Better AI-Assisted Development? | Nx Blog Making Cursor Smarter with an MCP Server For Nx Monorepos | Nx Blog React Development for 2025 | Nx Blog Using Apollo GraphQL in an Nx Workspace | Nx Blog Angular State Management for 2025 | Nx Blog Tailoring Nx for Your Organization | Nx Blog Nx Cloud Pipelines Come To Nx Console | Nx Blog Define the relationship with monorepos | Nx Blog See your affected project graph in Nx Cloud | Nx Blog Handling CORS In Your Workspace | Nx Blog Improve your architecture and CI pipeline times with Nx projects | Nx Blog Announcing Nx 20 | Nx Blog Introducing Nx Powerpack | Nx Blog Nx 19.5 is here! Stackblitz, Bun, Incremental Builds for Vite, Gradle Test Atomizer | Nx Blog Introducing Explain with AI | Nx Blog Nx Enterprise Podcast Episode 2: Tine Kondo | Nx Blog Monorepos and CI can be a Mess - Here's How Nx and Nx Cloud Fixed It | Nx Blog Nx Enterprise Podcast Episode 1: Hicham El Hammouchi | Nx Blog Nx 19.0 Release!! | Nx Blog Manage Your Gradle Project using Nx | Nx Blog Making the Argument for Monorepos | Nx Blog Reliable CI. A new execution model fixing both flakiness and slowness | Nx Blog Monorepos - Why Speed Matters | Nx Blog Nx Agents Walkthrough: Effortlessly Fast CI Built for Monorepos | Nx Blog Launch Nx Week Recap | Nx Blog Versioning and Releasing Packages in a Monorepo | Nx Blog Fast, Effortless CI | Nx Blog Introducing @nx/nuxt Enhanced Nuxt.js Support in Nx | Nx Blog What if Nx Plugins Were More Like VSCode Extensions | Nx Blog Monorepos: the Benefits, Challenges, and Importance of Tooling Support | Nx Blog Nx — Highlights of 2023 | Nx Blog Nx 17.2 Update | Nx Blog Unit Testing Expo Apps With Jest | Nx Blog Nx Docs AI Assistant | Nx Blog State Management Nx React Native/Expo Apps with TanStack Query and Redux | Nx Blog Nx 17 has Landed | Nx Blog Nx Conf 2023 — Recap | Nx Blog Nx Raises $16M Series A | Nx Blog Introducing Playwright Support for Nx | Nx Blog Nx 16.8 Release!!! | Nx Blog Step-by-Step Guide to Creating an Expo Monorepo with Nx | Nx Blog Qwikify your Development with Nx | Nx Blog Create Your Own create-react-app CLI | Nx Blog Storybook Interaction Tests in Nx | Nx Blog Evergreen Tooling — More than Just CodeMods | Nx Blog A Practical Guide on Effective AI Use - AI as Your Peer Programmer | Nx Blog
Building an MCP Server with Nx | Nx Blog
Max Kless · 2025-05-30 · via Nx Blog

Since the Model Context Protocol (MCP) was released by Anthropic in late 2024, it has quickly become an important part of the AI ecosystem. The MCP provides an open standard for connecting AI agents to the rest of the world - the web, software systems and developer tools, just to name a few examples.

We've been busy building the Nx MCP server, which gives LLMs deep access to your monorepo's structure. It helps AI tools to better understand your workspace architecture, browse the Nx docs and even trigger actions in your IDE like executing generators or visualizing the graph.

There are many examples of MCP servers for popular tools popping up all over the place. Check out the official MCP repo to see a long list of reference servers as well as official and community integrations.

Whatever you're building, it's becoming more and more important to ensure that AI systems can interact with your software. So let's learn how to build your very own MCP server to make your technology be usable for AI - all from an Nx monorepo!


In this series of blog posts, we'll be using a fictional startup as an example: Astra Arcana - a bewitched SaaS company that lets you cast spells from anywhere with a few simple clicks.

Screenshot of the Astra Arcana app visualizing a spell

You can go and try casting some spells right away at https://astra-arcana.pages.dev/

Of course, like any modern software company, they need to be ready for the coming shift towards AI - let's help them by building an MCP server that lets you browse ingredients and cast spells directly from your AI chat!


Setting up the Server

Astra Arcana is built in an Nx monorepo, where the web app and api live. There's also a shared types library as well as the Typescript SDK, which lets users programmatically cast spells.

apps
 ├── web
 └── api
libs
 ├── spellcasting-types
 └── spellcasting-sdk

We will create a new Node application that contains our MCP server and use the Typescript SDK to power it.

Creating the MCP Server

MCP are JSON-RPC servers that communicate with clients via stdio or http. Thankfully, the official Typescript SDK abstracts away large pieces of the implementation, making it easier to get started - let's get started by installing it.

npm install @modelcontextprotocol/sdk

We'll continue by installing the @nx/node plugin and using it to generate a new Node application:

npx nx generate @nx/node:application --directory=apps/mcp-server --framework=none --no-interactive

This generates a basic node application:

UPDATE package.json
CREATE apps/mcp-server/src/assets/.gitkeep
CREATE apps/mcp-server/src/main.ts
CREATE apps/mcp-server/tsconfig.app.json
CREATE apps/mcp-server/tsconfig.json
UPDATE nx.json
CREATE apps/mcp-server/package.json
UPDATE tsconfig.json

In package.json, you'll see that Nx has configured a build and serve target for our app that uses webpack. Now that our setup is ready, let's implement the actual server.

First, let's import some things and set up an instance of McpServer. This is part of the MCP SDK and will take care of actually implementing the Protocol Layer of the MCP specification, for example how to communicate with the client.

apps/mcp-server/src/main.ts

import { SpellcastingSDK } from '@astra-arcana/spellcasting-sdk';
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';

const server = new McpServer({
  name: 'Astra Arcana',
  version: '1.0.0',
});

Next, we'll register a set of MCP tools. A tool is essentially a function that the AI model can call, passing some input parameters if necessary. Instead of constructing API calls manually, our tools will expose three main parts of casting a spell with the Spellcasting SDK: Ingredients, Incantations and Recipes. This is really the core piece of the MCP server, as it defines what it can do. There are other features you can implement, but currently, tools are by far the most widely supported and important part.

apps/mcp-server/src/main.ts

const sdk = new SpellcastingSDK();

server.tool('get-ingredients', async () => {
  const ingredients = await sdk.getIngredients();
  return {
    content: [{ type: 'text', text: JSON.stringify(ingredients) }],
  };
});

server.tool('get-incantations', async () => {
  const incantations = await sdk.getIncantations();
  return {
    content: [{ type: 'text', text: JSON.stringify(incantations) }],
  };
});

server.tool('get-recipes', async () => {
  const recipes = await sdk.getRecipes();
  return {
    content: [{ type: 'text', text: JSON.stringify(recipes) }],
  };
});

Finally, let's implement the Transport Layer, letting the MCP server listen to and send messages via process inputs and outputs (stdio). It's only a few lines of code:

apps/mcp-server/src/main.ts

const transport = new StdioServerTransport();
(async () => {
  await server.connect(transport);
})();

And just like that, we've built our very own MCP server! Let's make sure it works.

Testing with the MCP Inspector

Anthropic has not just come up with the protocol, they've also created a great ecosystem around it: Various SDKs, reference servers and a visual testing tool: The MCP Inspector.

Let's modify our serve target to use the Inspector, letting us explore our newly created server. First, delete the existing serve target in apps/mcp-server/package.json , as it doesn't really apply to our use case. Replace it with this

apps/mcp-server/package.json

"serve": {
  "command": "npx -y @modelcontextprotocol/inspector node ./apps/mcp-server/dist/main.js",
  "dependsOn": ["build"],
  "continuous": true
}

Let's break it down:

  • the command runs the Inspector, pointing to the build output location of our MCP server
  • "dependsOn": ["build"] tells nx to always run the build before this target, making sure that the bundled javascript is available
  • "continuous": true marks the serve as a continuous task so that will work properly in more complex task pipelines

You can see the result by running npx nx serve mcp-server and looking at the website it spins up (usually on http://localhost:6274 ).

The sidebar contains all the information required to start the server - here the STDIO transport is correctly preselected as well as the command needed to start the server.

Screenshot of the MCP Inspector sidebar

After clicking on the Connect button, the server is started in the background and you'll be able to see the available tools and call them under the Tools tab.

Screenshot of the MCP Inspector showing the available tools

Agents that can take actions

The get-* tools that we've built are already super useful and budding spellcasters will be glad to have help in perfecting their concoctions and learning ancient incantations. However, where the power of AI agents really starts to shine is when they go beyond just reading data and start taking actions. Let's give AI the ability to cast spells. 🪄

We'll register another tool in apps/mcp-server/src/main.ts

apps/mcp-server/src/main.ts

import { z } from 'zod';

// ... previous tools

server.tool(
  'cast-spell',
  'Lets the user cast a spell via the Astra Arcana API.',
  { ingredients: z.array(z.string()), incantations: z.array(z.string()) },
  async ({ ingredients, incantations }) => {
    const result = await sdk.castSpell(ingredients, incantations);
    return {
      content: [{ type: 'text', text: JSON.stringify(result) }],
    };
  }
);

There are two key differences in this tool definition:

  • We've passed a description string as the second argument. You can do this for every tool in order to describe what to use it for and what will happen when the agent calls it. cast-spell is sort of self-explanatory but it's still good practice to add a description and increase the model's chances of picking the right tool for the job. You can even add more annotations to mark a tool as read-only, destructive or more.
  • We've passed an object that defines the shape of the input using zod. This lets the agent know how to structure the inputs that are passed to the tool. ingredients and incantations as arrays of strings aren't very complicated, but you could also add descriptions to each individual option to explain what it does. The full feature set of zod is available to define exactly what's possible with each tool.

Now, let's try it out in an actual agent. I'll use VSCode & GitHub Copilot for this but any agent implementation with MCP support will do. I really like Windsurf or Cursor, for example.

Register the MCP server by editing .vscode/mcp.json (or using the built-in command):

{
  "servers": {
    "astra-arcana": {
      "command": "node",
      "args": ["/path/astra-arcana/apps/mcp-server/dist/main.js"]
    }
  }
}

Once you open a Copilot chat in Agent mode, the MCP server will start automatically and you should see all four tools available

Screenshot of the VSCode quickinput listing available MCP tools

Let's try to cast a spell! For obvious reasons, I want to make sure that I'm writing high-quality blog posts and could use a magic boost. You can see that the AI agent uses all the tools to figure out what's available and then tries to cast the spell. Some models might ask for permission first or ask follow up questions to make sure they're getting it right.

Screenshot of a conversation with Copilot that uses the built MCP tools

After casting, you can head over to https://astra-arcana.pages.dev/ and check the logs to see your spell! 🎉

Screenshot of the Astra Arcana app showing the cast spell in the browser

Publishing to npm

Of course, now that we've built our magical MCP server, we want to make sure people can use it easily. Let's go through the process of publishing an executable file to the npm registry. In the future, anyone will be able to run npx @astra-arcana/mcp-server and spin it up immediately!

Learn More About nx release

This section goes over the release process of this specific example. If you want to learn how to use nx release in detail, I recommend checking out Juri's great course on the topic: https://www.epicweb.dev/tutorials/versioning-and-releasing-npm-packages-with-nx

Publishing Pre-Requisites

In order to have our bundled code be executable via npx, we need to add a shebang (#!/usr/bin/env node) to the first line of the file. We'll make sure this is added in a new script in the apps/mcp-server directory called setup-publish.js.

apps/mcp-server/setup-publish.js

import path from 'path';
import fs from 'fs';

const distDir = path.resolve(import.meta.dirname, './dist');
const distMainJsPath = path.resolve(distDir, 'main.js');
const mainJsContent = fs.readFileSync(distMainJsPath, 'utf8');
const shebang = '#!/usr/bin/env node\n';

if (!mainJsContent.startsWith(shebang)) {
  fs.writeFileSync(distMainJsPath, shebang + mainJsContent);
  console.log('Shebang added');
}

console.log('Setup completed successfully!');

We'll also set up a target that calls this script after making sure the main bundle is built.

apps/mcp-server/package.json

"setup-publish": {
  "command": "node apps/mcp-server/setup-publish.js",
  "dependsOn": ["build"]
}

While we're in package.json , let's also make sure that our package is publishable and let npx and similar tools know where to find the executable javascript file.

apps/mcp-server/package.json

{
  "name": "@astra-arcana/mcp-server",
  "version": "0.0.1",
- "private": true,
+ "private": false,
+ "bin": "./main.js",
  // ...

Local Publishing with Verdaccio

Publishing

Keep in mind that the @astra-arcana/mcp-server package already exists on the official npm registry, so we will only publish to a local registry.

At Nx, we use an awesome open-source tool called Verdaccio. It's a lightweight implementation of a local npm registry - let's use it to test out our publishing flow.

You can add verdaccio to the repo by running the setup-verdaccio generator:

npx nx g @nx/js:setup-verdaccio

This will create a verdaccio config and an nx target to spin it up at the root of our workspace. Start the local registry by running.

npx nx run @astra-arcana/source:local-registry

On http://localhost:4873/ , you'll see an instance of verdaccio running with no packages published yet. Let's change that!

Configuring Nx Release

Now that everything is set up, let's configure nx release to actually version our package, generate changelogs and publish to npm.

There are a couple of things we want to configure. Check out the comprehensive release documentation to learn more about the different configuration options.

  • Since we're in a monorepo with different kinds of packages, we have to let nx release know which ones to configure releases for - in this case, only the mcp-server app
  • When releasing, we need to make sure that not only is the version in the repo's package.json is incremented, but also the version in the dist folder that we'll actually release from. We can do this by setting manifestRootsToUpdate.
  • We have to make sure the dist folder exists, so we'll run our new setup-publish action first by specifying the command in preVersionCommand .
  • Since our mcp server will be released independently, we configure the changelogs to be generated per-project instead of for the entire workspace.
"release": {
  "projects": ["mcp-server"],
  "version": {
    "manifestRootsToUpdate": [
      "{projectRoot}",
      "{projectRoot}/dist"
    ],
    "preVersionCommand": "npx nx run mcp-server:setup-publish"
  },
  "changelog": {
    "projectChangelogs": true,
    "workspaceChangelog": false
  }
}

This is enough to configure nx release for our exact use case. With this, we can run npx nx release --dry-run . Nx will run the setup-publish target, prompt you for the kind of version change that's happening and give you a preview of what the result would be.

Screenshot of the version prompt asked by nx release

If you're happy with the results, rerun the command without --dry-run and watch as nx release does its magic. The versions will be updated across both package.json files, and a changelog file, a git commit and tag will be created.

In order to release to npm, we have to add some final configuration to nx.json .

"targetDefaults": {
  // ... other config
  "nx-release-publish": {
    "options": {
      "packageRoot": "{projectRoot}/dist"
    }
  }
}

This will tell the automatically generated nx-release-publish target where to find the built files so that it can publish them to npm (or verdaccio, in our case). After running npx nx release publish , refresh Verdaccio to see the successfully published package! 🎉 You can spin up the MCP server using the published version by running npx @astra-arcana/mcp-server and try it out.

That's it! You can view the @astra-arcana/mcp-server package on npm here: https://www.npmjs.com/package/@astra-arcana/mcp-server

Looking back and into the Future

We've come a long way. Looking back, we've

  • learned about the Model Context Protocol
  • set up a node application and built an MCP server with it
  • used the MCP Inspector to test and debug our implementation
  • used AI agents to cast spells 🪄
  • learned how to publish an executable package to npm

The next post in this series will dive into implementing a different MCP transport layer in streamable HTTP and hosting our server on Cloudflare!


Learn more: