# Nx plugin

> @frontmcp/nx adds 21 generators and 7 executors to an Nx workspace. What it adds, the two ways to install it, the workspace layout it expects, and what to change in an older workspace.

Source: https://frontmcp.dev/reference/nx

`@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](https://frontmcp.dev/reference/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.

```bash
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 tickets
```

---

## Reference

### What it adds

```text
$ 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](https://frontmcp.dev/reference/nx/generators#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](https://frontmcp.dev/reference/nx/generators#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](https://frontmcp.dev/reference/nx/generators#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](https://frontmcp.dev/reference/nx/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.

> **Note**
**Changed in 1.9.** In 1.8.7 a `lib` of type `plugin` or `adapter` didn't type-check, `ui-shell` stopped on an npm `ERESOLVE`, a `server`'s deployment files named outputs the build doesn't write, a new app had no test, `nx typecheck` failed everywhere, a library needed a root `tsconfig.json` before an app that imports it could build, and a `create-nx-workspace --preset=ts` workspace needed hand edits to every app's `tsconfig.json`. A workspace made with 1.8.7 needs one edit to `nx.json`: [Upgrading a 1.8.7 workspace](#upgrading-a-187-workspace).

### Installing it

Either let `frontmcp create` make the workspace, or add the plugin to a workspace you have.

#### `frontmcp create <name> --nx`

1. Writes `<name>/package.json` with the Nx tooling and `@frontmcp/nx`, and installs them.
2. Runs the plugin's [`workspace` generator](https://frontmcp.dev/reference/nx/generators#workspace) with a sample `demo` app.
3. 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

```bash
npx nx add @frontmcp/nx@1.9.3
```

```text
Installing @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](https://frontmcp.dev/reference/nx/generators#init), which does two things:

- **`package.json`:** adds `@frontmcp/sdk`, `frontmcp`, `reflect-metadata`, `zod` and `tslib` to `dependencies`, and `@frontmcp/nx`, `@frontmcp/testing`, `jest`, `@swc/jest` and `@types/jest` to `devDependencies`, then installs. A version you already have stays.
- **`nx.json`:** adds `targetDefaults` for `@frontmcp/nx:build` and `@frontmcp/nx:build-exec` with `cache: true` and `dependsOn: ["^build"]` (and `inputs: ["production", "^production"]` when the workspace defines `production`), and for `@frontmcp/nx:test` with `cache: true` and Nx's default inputs. So those targets are cached whatever their `project.json` says, 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.

> **Pitfall: The workspace needs the frontmcp package**
Every executor runs the `frontmcp` CLI that's in the workspace's `node_modules`, and nothing else. It never falls back to `npx`, which would download the newest published version. In a workspace without it, a target stops with ``The "frontmcp" CLI is not installed in /Users/you/help-desk-platform. Add it to the workspace (`npm install --save-dev frontmcp`) so the executors run the version you pinned.`` `init` installs it; so does `frontmcp create --nx`.

### 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](https://frontmcp.dev/reference/nx/generators#lib). | Imported through an alias in `tsconfig.base.json` ([Monorepo patterns](https://frontmcp.dev/reference/nx/monorepo#sharing-code-in-a-library)). |
| `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](https://frontmcp.dev/reference/nx/executors#how-an-executor-runs) 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/typescript` entry from `plugins` in `nx.json`.** While it's there, a library made by `lib` keeps an inferred `build`, and `nx build` of 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/nx` at 1.8.7**, delete the `inputs` line from `targetDefaults["@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

```bash
npx frontmcp create help-desk-platform --nx
cd help-desk-platform
npx nx show projects
npx nx dev demo
```

```text
["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](https://frontmcp.dev/reference/nx/executors#how-an-executor-runs)).

```ts apps/demo/frontmcp.config.ts
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):

```bash
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
```

```text
 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:

```json apps/support/tsconfig.json
{
  "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](https://frontmcp.dev/reference/nx/generators#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`:

```json apps/tickets/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](#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](#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](#upgrading-a-187-workspace)), or add a root `tsconfig.json`: [Monorepo patterns](https://frontmcp.dev/reference/nx/monorepo#the-workspace-is-probably-out-of-sync-because-a-sync-generator-failed-to-run).
