Nx plugin
@frontmcp/nx is FrontMCP's plugin for Nx workspaces. It adds generators that write FrontMCP apps, libraries, deployment shells and component classes (nx g @frontmcp/nx:app tickets), and executors that run the frontmcp CLI as Nx targets (nx dev tickets). It doesn't infer targets: a project gets its targets from the project.json its generator writes. nx add @frontmcp/nx runs an init generator that installs FrontMCP and makes the executors cacheable. Use it when several servers share code and you want Nx's project graph, caching and affected commands; for one server, frontmcp create without --nx is simpler. In 1.9.2 the projects the generators write work as generated: apps build, apps and libraries type-check and pass the test they come with, server shells build and type-check, and UI packages build and pass their tests. That holds in a workspace made by frontmcp create --nx, and in one made by create-nx-workspace --preset=ts too.
npx frontmcp create help-desk-platform --nx # a new workspace
npx nx add @frontmcp/nx@1.9.3 # or, in a workspace you have
npx nx g @frontmcp/nx:app tickets
npx nx dev ticketsReference
What it adds
$ npx nx list @frontmcp/nx
NX Capabilities in @frontmcp/nx:
GENERATORS
init : Prepare an existing Nx workspace for FrontMCP (dependencies and cacheable executors)
workspace : Scaffold a full FrontMCP Nx monorepo with apps/, libs/, and servers/ directories
app : Generate a FrontMCP application in apps/
lib : Generate a shared library in libs/
server : Generate a deployment shell in servers/
tool : Generate a @Tool class
…
EXECUTORS/BUILDERS
build : Compile a FrontMCP project using frontmcp build
build-exec : Build a distributable bundle using frontmcp build --target node
dev : Start a development server using frontmcp dev
serve : Start a supervised production server using frontmcp start
test : Run E2E tests using frontmcp test
inspector : Launch MCP Inspector using frontmcp inspector
deploy : Deploy to a target platform (node/vercel/lambda/cloudflare)
| Kind | Names | In 1.9.2 |
|---|---|---|
| Structural generators | init, workspace, app, lib, server | All five work. Every app and library they write has a typecheck target and a starter test that pass as generated, for all four library types too, and an app builds. A server builds and type-checks, has a dev target, and its Dockerfile, vercel.json and template.yaml name the files the build writes. Since 1.9.3 server runs your install after writing the shell, so its Docker image builds at once, with a health check. |
| Component generators | tool, resource, prompt, skill, skill-dir, job, workflow, agent, provider, plugin, adapter, auth-provider, flow | All thirteen write classes that type-check against @frontmcp/sdk 1.9.2, and an app that lists the eleven @App takes starts. |
| UI generators | ui-component, ui-page, ui-shell | Write a package under ui/, add React and MUI (or @frontmcp/uipack) to package.json, and install them. The packages build, pass their tests, and type-check with tsc, in a --preset=ts workspace too (since 1.9.2). |
| Executors | build, build-exec, dev, serve, test, inspector, deploy | All seven work for an app. |
No generator adds your class to its app: after nx g @frontmcp/nx:tool, list the tool in the app's @App({ tools }) yourself.
Installing it
Either let frontmcp create make the workspace, or add the plugin to a workspace you have.
frontmcp create <name> --nx
- Writes
<name>/package.jsonwith the Nx tooling and@frontmcp/nx, and installs them. - Runs the plugin's
workspacegenerator with a sampledemoapp. - Installs the dependencies the generator wrote, and commits everything as
Initial commit.
--pm yarn or --pm pnpm uses that package manager; create's other flags are ignored. All three installs finish, and the demo app builds, type-checks and passes its test with each. With npm, step 3 failed with ERESOLVE on @swc/core before 1.8.7; the workspace pins @swc/core ~1.15.8.
nx add @frontmcp/nx in an existing workspace
npx nx add @frontmcp/nx@1.9.3Installing @frontmcp/nx@1.9.3...
Initializing @frontmcp/nx...
NX Generating @frontmcp/nx:init
UPDATE nx.json
UPDATE package.json
…
NX Package @frontmcp/nx added successfully.
nx add runs the plugin's init generator, which does two things:
package.json: adds@frontmcp/sdk,frontmcp,reflect-metadata,zodandtslibtodependencies, and@frontmcp/nx,@frontmcp/testing,jest,@swc/jestand@types/jesttodevDependencies, then installs. A version you already have stays.nx.json: addstargetDefaultsfor@frontmcp/nx:buildand@frontmcp/nx:build-execwithcache: trueanddependsOn: ["^build"](andinputs: ["production", "^production"]when the workspace definesproduction), and for@frontmcp/nx:testwithcache: trueand Nx's default inputs. So those targets are cached whatever theirproject.jsonsays, and changing a test file runs the tests again.
Before 1.8.7 the plugin had no init: nx add changed nothing but devDependencies, and you installed FrontMCP yourself. If you added the package with npm install instead of nx add, run npx nx g @frontmcp/nx:init. It changes nothing the second time, and keeps targetDefaults you already have.
Workspace layout
The generators and executors assume this layout, which the workspace generator writes:
| Path | What it's for | Notes |
|---|---|---|
apps/<name>/ | One FrontMCP app per folder: src/main.ts (a @FrontMcp server), src/<name>.app.ts (the @App), src/tools/hello.tool.ts and its hello.tool.spec.ts, project.json, a minimal package.json, three tsconfig files and jest.config.cjs. | The component generators write into <project root>/src/<kind>/. |
libs/<name>/ | Shared code, made by the lib generator. | Imported through an alias in tsconfig.base.json (Monorepo patterns). |
servers/<name>/ | Deployment shells: a @FrontMcp server that lists apps from apps/, and the files for one target. | Named server-<name> in Nx. |
ui/components/, ui/pages/, ui/shells/ | Written by the UI generators. | Nx projects ui-components, ui-pages and ui-shells, made by the first generator that needs them. |
tsconfig.base.json | Every generated tsconfig.json extends it, with as many ../ as the project is deep. | apps/team/billing works: ../../../tsconfig.base.json. |
package.json | The root one holds the dependencies. | A project's own package.json is name, version 0.0.1 and private. The CLI names the bundle after it. |
Every executor runs the CLI from the project's folder, with absolute paths as options (--entry /Users/you/help-desk-platform/apps/tickets/src/main.ts). So the CLI reads the project's own package.json, tsconfig.json, .env and frontmcp.config.*, and a bundle is named after the project (tickets.bundle.js). Executors has the details.
Each generated tsconfig.json sets what a FrontMCP project needs whatever the base config says: module commonjs, moduleResolution bundler on TypeScript 6 and later (node10 on TypeScript 5), rootDir at the workspace root, composite, declarationMap and emitDeclarationOnly false, decorators on, and "nx": { "addTypecheckTarget": false }, so Nx's TypeScript plugin, where there is one, doesn't add a typecheck of its own.
What frontmcp create --nx writes
| Path | Contents |
|---|---|
package.json | workspaces: ["apps/*", "libs/*", "servers/*"]; scripts build, test and lint (nx run-many -t …); @frontmcp/sdk, frontmcp, reflect-metadata, zod, tslib; and, as dev dependencies, @frontmcp/nx and @frontmcp/testing (~1.9.3), nx, @nx/devkit, @nx/js, @nx/eslint, @nx/jest, @nx/esbuild and @nx/workspace (22.6.4), @swc/core ~1.15.8, @swc/jest, @swc/helpers, @swc-node/register, Jest 30, Prettier and TypeScript ~5.9.2. |
nx.json | The @nx/eslint/plugin and @nx/jest/plugin plugins; targetDefaults that cache build (depending on ^build) and the three FrontMCP executors, and make test depend on ^build. |
tsconfig.base.json | target es2022, module esnext, moduleResolution node, baseUrl and rootDir ., decorators on, empty paths. |
apps/demo/ | A sample app with a hello tool and its test. |
apps/.gitkeep, libs/.gitkeep, servers/.gitkeep | |
README.md, AGENTS.md and other agent-instruction files, .mcp.json, .gitignore, .nvmrc, .prettierrc |
Since 1.9, nx.json has no @nx/js/typescript plugin. That plugin inferred a build and a typecheck for every project: the typecheck failed with TS5069, and the build it gave each library needed a root tsconfig.json. Projects now carry their own typecheck target instead, and a library needs no build of its own, since the app's bundle compiles it in.
Upgrading a 1.8.7 workspace
The generators of 1.9.2 assume a workspace without @nx/js/typescript, and they never edit a project's files, only add new ones. In a workspace made by frontmcp create --nx at 1.8.7:
- Remove the
@nx/js/typescriptentry frompluginsinnx.json. While it's there, a library made bylibkeeps an inferredbuild, andnx buildof an app that imports the library stops with[@nx/js:typescript-sync]: Missing root "tsconfig.json". - In a workspace where you ran
nx add @frontmcp/nxat 1.8.7, delete theinputsline fromtargetDefaults["@frontmcp/nx:test"], if there is one. It was["production", "^production"], which leaves test files out, so a changed test could be answered from the cache.
Projects generated with 1.8.7 keep their project.json and tsconfig files. Compare them with a project you generate with 1.9.2 to pick up its typecheck target and tsconfig.json settings.
Usage
Creating a workspace
npx frontmcp create help-desk-platform --nx
cd help-desk-platform
npx nx show projects
npx nx dev demo["demo"]
> nx run demo:dev
Running: frontmcp dev --entry /Users/you/help-desk-platform/apps/demo/src/main.ts (in /Users/you/help-desk-platform/apps/demo)
[dev] using entry: src/main.ts
[dev] listening on port: 3000
[dev] starting tsx --watch and tsc --noEmit --watch (async type-checker)
…
MCP HTTP (Express) on 127.0.0.1:3000
[10:31:39 PM] Found 0 errors. Watching for file changes.
The demo server answers at http://localhost:3000/, at the root. To serve it at /mcp and pick the port, put a frontmcp.config.ts in apps/demo/: the executors run the CLI there, so it reads that file (Executors).
import { defineConfig } from "frontmcp";
export default defineConfig({
name: "demo",
deployments: [{ target: "node" }],
transport: { default: "http", http: { port: 4100, path: "/mcp" } },
});nx test demo runs the app's test, nx typecheck demo checks the app and its tests, and nx build demo writes apps/demo/dist/node/demo.bundle.js.
Adding the plugin to a workspace you have
In a workspace made with create-nx-workspace (--preset=ts, which made Nx 23.2.0 with TypeScript 6.0.3):
npx nx add @frontmcp/nx@1.9.3
npx nx g @frontmcp/nx:app support
npx nx run-many -t build typecheck test -p support
npx nx dev support NX Generating @frontmcp/nx:app
CREATE apps/support/jest.config.cjs
CREATE apps/support/package.json
CREATE apps/support/project.json
CREATE apps/support/src/support.app.ts
CREATE apps/support/src/main.ts
CREATE apps/support/src/tools/hello.tool.spec.ts
CREATE apps/support/src/tools/hello.tool.ts
CREATE apps/support/tsconfig.json
CREATE apps/support/tsconfig.lib.json
CREATE apps/support/tsconfig.spec.json
…
NX Successfully ran targets build, typecheck, test for project support
That workspace's tsconfig.base.json is a TypeScript-solution one (composite, emitDeclarationOnly, declarationMap, customConditions, module nodenext), and the app's tsconfig.json overrides what a FrontMCP app can't use:
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "bundler",
"rootDir": "../../",
"composite": false,
"declarationMap": false,
"emitDeclarationOnly": false
}
}(Only the options that matter are shown.) nx dev support's type checker reports Found 0 errors. A library from the lib generator works there too: its alias takes the workspace's npm scope, from the root package.json's @org/source, and is written "@org/util": ["./libs/util/src/index.ts"], with the ./ TypeScript needs when the base config has no baseUrl. That workspace keeps its @nx/js/typescript plugin, so the library also gets an inferred build (tsc --build tsconfig.lib.json), which works because the preset made a root tsconfig.json. Once the app imports the library, nx build support stops with The workspace is out of sync until you run npx nx sync, which adds the project references to the root tsconfig.json; then it runs the library's build first (Running target build for project support and 1 task it depends on). The UI generators work there too (UI generators). In 1.8.7 the app's tsconfig.json needed these overrides by hand (TS5098, then no JavaScript emitted), and the alias needed its ./ (TS5090).
Seeing what an app runs
An app's targets are the ones its generator wrote in project.json:
{
"name": "tickets",
"sourceRoot": "apps/tickets/src",
"projectType": "application",
"tags": ["scope:apps"],
"targets": {
"build": {
"executor": "@frontmcp/nx:build",
"cache": true,
"outputs": ["{projectRoot}/dist"],
"options": { "entry": "{projectRoot}/src/main.ts", "outputPath": "{projectRoot}/dist" }
},
"dev": { "executor": "@frontmcp/nx:dev", "options": { "entry": "{projectRoot}/src/main.ts" } },
"serve": { "executor": "@frontmcp/nx:serve", "options": { "entry": "{projectRoot}/src/main.ts" } },
"test": { "executor": "@frontmcp/nx:test", "cache": true, "options": {} },
"typecheck": {
"executor": "nx:run-commands",
"cache": true,
"options": {
"commands": ["tsc --noEmit -p tsconfig.lib.json", "tsc --noEmit -p tsconfig.spec.json"],
"parallel": false,
"cwd": "{projectRoot}"
}
},
"inspector": { "executor": "@frontmcp/nx:inspector", "options": {} }
}
}npx nx show project tickets --json shows them as Nx runs them: build also gets dependsOn: ["^build"] and the production inputs from nx.json's targetDefaults. typecheck checks the app's code with tsconfig.lib.json and its tests with tsconfig.spec.json.
Troubleshooting
The "frontmcp" CLI is not installed in …
An executor found no node_modules/frontmcp in the workspace root, and doesn't download one. Run npx nx g @frontmcp/nx:init, or npm install --save-dev frontmcp at the version of your @frontmcp/sdk.
Cannot find module '@frontmcp/sdk'
The workspace doesn't have FrontMCP installed. nx add @frontmcp/nx and nx g @frontmcp/nx:init install it; if you ran init with --skipPackageJson or added the plugin with npm install, run init without it.
error TS5098: Option 'customConditions' can only be used when 'moduleResolution' is set to …
An app generated before 1.9, in a workspace whose tsconfig.base.json is a TypeScript-solution one. Give its tsconfig.json the compilerOptions the 1.9.2 generator writes: Adding the plugin to a workspace you have.
error TS5069: Option 'emitDeclarationOnly' cannot be specified without specifying option 'declaration' or option 'composite'
From nx typecheck on a project generated before 1.9, which has no typecheck target of its own, so Nx's TypeScript plugin infers one that can't work with that project's tsconfig.json. Add the typecheck target a 1.9.2 project has (Seeing what an app runs), or check types with npx tsc -p apps/<app>/tsconfig.lib.json --noEmit.
The workspace is probably out of sync because a sync generator failed to run
With [@nx/js:typescript-sync]: Missing root "tsconfig.json". nx.json still lists @nx/js/typescript, as a workspace made with 1.8.7 does, which gives each library an inferred build that needs a root tsconfig.json. Remove the plugin from nx.json (Upgrading a 1.8.7 workspace), or add a root tsconfig.json: Monorepo patterns.