> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agentfront.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuration File

> Configure FrontMCP projects with frontmcp.config.ts for multi-target builds, server settings, security headers, and HA

FrontMCP uses a typed configuration file to define project settings, deployment targets, server configuration, and security policies. The file supports TypeScript, JavaScript, and JSON formats with full IDE autocomplete.

## Quick Start

Create `frontmcp.config.ts` in your project root:

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
import { defineConfig } from 'frontmcp';

export default defineConfig({
  name: 'my-server',
  deployments: [{ target: 'node' }],
});
```

The `defineConfig()` helper is a pass-through that enables IDE type hints and autocomplete.

## File Resolution Order

FrontMCP locates the config file in this precedence order (issue #400):

1. Explicit `--config <path>` flag on any command.
2. `FRONTMCP_CONFIG` env var.
3. Upward walk from `cwd` to the nearest ancestor containing a `frontmcp.config.*` file (caps at 10 levels — monorepo nested apps no longer require `cd <repo-root>`).
4. Fallback: derives minimal config from `package.json` (name, default node target).

Within a directory, the matching extensions are tried in this order:

1. `frontmcp.config.ts`
2. `frontmcp.config.js`
3. `frontmcp.config.json`
4. `frontmcp.config.mjs`
5. `frontmcp.config.cjs`

## Override precedence

For every CLI option that's also expressible in the config, the effective value is computed as:

```
explicit CLI flag  >  FRONTMCP_<NAME> env var  >  frontmcp.config field  >  built-in default
```

Example: `frontmcp dev --port 5000` always wins, regardless of `transport.http.port` in the config. With no flag, the resolver reads `transport.http.port`, then falls back to the framework default (3000).

<Note>
  When using JSON format, add `"$schema"` for autocomplete in VS Code and WebStorm:

  ```json theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
  {
    "$schema": "./node_modules/@frontmcp/cli/frontmcp.schema.json",
    "name": "my-server",
    "deployments": [{ "target": "node" }]
  }
  ```
</Note>

## Top-Level Fields

| Field         | Type                | Required | Description                                                                                 |
| ------------- | ------------------- | -------- | ------------------------------------------------------------------------------------------- |
| `name`        | string              | Yes      | Server name (kebab-case, no spaces)                                                         |
| `version`     | string              | No       | Server version                                                                              |
| `entry`       | string              | No       | Custom entry file path (consumed by `dev`, `inspector`, `pm start/socket`)                  |
| `nodeVersion` | string              | No       | Target Node.js version                                                                      |
| `deployments` | DeploymentTarget\[] | Yes      | One or more deployment targets                                                              |
| `build`       | object              | No       | Build-specific options (esbuild config, dependencies)                                       |
| `transport`   | TransportConfig     | No       | Per-protocol defaults consumed by `dev` / `inspector` / `pm` (issue #400)                   |
| `env`         | EnvOverlays         | No       | `shared` ⊕ `dev` / `test` / `ship` overlays merged into the spawned child env (issue #400)  |
| `clients`     | ClientsConfig       | No       | Per-client connection snippets emitted by `frontmcp eject-mcp-config <client>` (issue #400) |
| `test`        | TestConfig          | No       | `frontmcp test` defaults overridden by CLI flags (issue #400)                               |
| `skills`      | SkillsCliConfig     | No       | `frontmcp skills install` / `export` defaults (issue #400)                                  |

### Per-command consumption (issue #400)

| Command                           | Config fields consumed                                                                           |
| --------------------------------- | ------------------------------------------------------------------------------------------------ |
| `build`                           | `name`, `version`, `entry`, `deployments`, `build`, `nodeVersion`                                |
| `dev`                             | `entry`, `transport.http.port`, `env.shared` ⊕ `env.dev`                                         |
| `test`                            | `test.timeoutMs`, `test.runInBand`, `test.coverage`, `test.testMatch`, `env.shared` ⊕ `env.test` |
| `inspector`                       | `transport.default`, `transport.http.port`, `transport.stdio.command/args`                       |
| `pm start` / `socket` / `service` | `name`, `entry`, `transport.http.port`, `transport.http.socketPath`, `env.shared` ⊕ `env.ship`   |
| `skills install` / `export`       | `skills.provider`, `skills.bundle`, `skills.install`, `skills.exportTarget`                      |
| `eject-mcp-config <client>`       | `clients.<client>`, `name`, `transport`, `env.ship`                                              |

## Transport defaults

```ts theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
transport: {
  default: 'http',                     // 'http' | 'sse' | 'stdio'
  http: { port: 3000, path: '/mcp', host: '127.0.0.1' },
  stdio: { command: 'node', args: ['dist/main.js'] },
}
```

## Env overlays

`shared` applies everywhere; mode overlays (`dev`, `test`, `ship`) layer on top:

```ts theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
env: {
  shared: { LOG_LEVEL: 'info' },
  dev:    { NODE_ENV: 'development' },
  test:   { NODE_ENV: 'test', JEST_WORKER_ID: '1' },
  ship:   { NODE_ENV: 'production' },
}
```

Note: `.env` and `.env.local` (loaded by `dev`) still win over config overlays — file-based env is the deployment escape hatch.

## Client snippets

```ts theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
clients: {
  'claude-code':    { name: 'my-server', transport: 'http', url: 'http://127.0.0.1:3000/mcp' },
  'claude-desktop': { transport: 'stdio', command: 'npx', args: ['-y', 'my-server'] },
  cursor:           { transport: 'http', url: 'http://127.0.0.1:3000/mcp' },
  windsurf:         { transport: 'stdio', command: 'npx', args: ['-y', 'my-server'] },
  vscode:           { transport: 'stdio', command: 'npx', args: ['-y', 'my-server'] },
}
```

Emit a ready-to-paste snippet:

```bash theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
frontmcp eject-mcp-config claude-code              # prints to stdout
frontmcp eject-mcp-config claude-code --out ~/.config/claude/mcp.json
frontmcp eject-mcp-config claude-code --out ~/.config/claude/mcp.json --dry-run
```

## Deployment Targets

Each entry in `deployments` defines a build target with independent settings:

| Target        | Description                                                | Transport                   | Storage               |
| ------------- | ---------------------------------------------------------- | --------------------------- | --------------------- |
| `node`        | Standalone Node.js server                                  | Streamable HTTP, SSE, stdio | Redis, SQLite, memory |
| `distributed` | Multi-pod with HA                                          | Streamable HTTP             | Redis (required)      |
| `vercel`      | Vercel Functions                                           | Streamable HTTP             | Vercel KV             |
| `lambda`      | AWS Lambda                                                 | Streamable HTTP             | DynamoDB, ElastiCache |
| `cloudflare`  | Cloudflare Workers                                         | Streamable HTTP             | KV, Durable Objects   |
| `browser`     | Browser bundle                                             | In-memory                   | Memory only           |
| `cli`         | Standalone binary                                          | stdio                       | SQLite, memory        |
| `sdk`         | Library for embedding                                      | Direct (in-process)         | Configurable          |
| `mcpb`        | MCP Bundle archive (see [MCPB](/frontmcp/deployment/mcpb)) | stdio                       | SQLite, memory        |

### Deployment Target Fields

| Field    | Type         | Description                                               |
| -------- | ------------ | --------------------------------------------------------- |
| `target` | string       | One of the 9 target types above                           |
| `server` | ServerConfig | HTTP, CORS, CSP, and security header settings             |
| `ha`     | HaConfig     | HA settings (distributed target only)                     |
| `cli`    | CliConfig    | CLI-specific settings (cli target only)                   |
| `js`     | boolean      | Generate .js bundle instead of native binary (cli target) |
| `env`    | Record       | Per-target environment variables                          |

### MCPB-Only Fields

The `mcpb` target supports additional fields for [MCP Bundle](/frontmcp/deployment/mcpb) metadata:

| Field                | Type                       | Description                                                                               |
| -------------------- | -------------------------- | ----------------------------------------------------------------------------------------- |
| `displayName`        | string                     | Human-friendly bundle title shown in the installer                                        |
| `longDescription`    | string                     | Markdown description for the extension details page                                       |
| `author`             | `{ name, email?, url? }`   | Overrides parsed `package.json.author`                                                    |
| `license`            | string                     | SPDX license identifier                                                                   |
| `homepage`           | string                     | Project homepage URL                                                                      |
| `repository`         | string \| `{ type, url }`  | Source repository                                                                         |
| `documentation`      | string                     | Documentation URL                                                                         |
| `support`            | string                     | Support / issues URL                                                                      |
| `icon`               | string                     | Icon path relative to project root (PNG)                                                  |
| `keywords`           | string\[]                  | Keywords for client search                                                                |
| `privacyPolicies`    | string\[]                  | Privacy policy URLs for external services this server talks to                            |
| `compatibility`      | object                     | `{ claude_desktop?, platforms?, runtimes? }` constraints                                  |
| `userConfig`         | Record                     | MCPB `user_config` overrides (type, min/max, etc.) — merged with translated `setup.steps` |
| `sea`                | `{ enabled?, mergeFrom? }` | Build SEA binary for the host and/or merge pre-built binaries                             |
| `includeNodeModules` | boolean                    | Include `server/node_modules/` in the archive (off by default)                            |
| `deterministic`      | boolean                    | Produce byte-identical archives across runs (defaults to `true`)                          |

## Server Configuration

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
export default defineConfig({
  name: 'my-server',
  deployments: [{
    target: 'node',
    server: {
      http: {
        port: 3000,
        socketPath: '/tmp/mcp.sock',  // Unix socket (alternative to port)
        entryPath: '/mcp',
        cors: {
          origins: ['https://app.example.com'],
          credentials: true,
          maxAge: 600,
        },
      },
      csp: {
        enabled: true,
        directives: {
          'default-src': "'self'",
          'script-src': "'self' https://cdn.example.com",
        },
        reportUri: 'https://report.example.com/csp',
        reportOnly: false,
      },
      headers: {
        hsts: 'max-age=31536000; includeSubDomains',
        contentTypeOptions: 'nosniff',
        frameOptions: 'DENY',
      },
      cookies: {
        affinity: '__frontmcp_node',
        domain: 'example.com',
        sameSite: 'Lax',
      },
    },
  }],
});
```

### HTTP Options

| Field             | Type             | Default                   | Description                                                                                                                                                                                                                                                              |
| ----------------- | ---------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `port`            | number           | 3000                      | HTTP listen port (node / distributed only)                                                                                                                                                                                                                               |
| `socketPath`      | string           | ---                       | Unix socket path (alternative to port; node / distributed only)                                                                                                                                                                                                          |
| `entryPath`       | string           | `''`                      | Base path for the MCP endpoint (e.g. `'/mcp'`)                                                                                                                                                                                                                           |
| `cors`            | object           | ---                       | CORS configuration — `{ origins?, credentials?, maxAge? }`                                                                                                                                                                                                               |
| `bodyLimit`       | number \| string | `'4mb'`                   | Max body size for `express.json()`. Bytes (number) or body-parser string (`'4mb'`, `'500kb'`, …). Oversized requests get HTTP 413 with a JSON-RPC envelope. See [Transport Security → Request Body Limits](/frontmcp/deployment/transport-security#request-body-limits). |
| `urlencodedLimit` | number \| string | falls back to `bodyLimit` | Max body size for `application/x-www-form-urlencoded`.                                                                                                                                                                                                                   |

### CSP Options

| Field        | Type    | Default | Description                                                          |
| ------------ | ------- | ------- | -------------------------------------------------------------------- |
| `enabled`    | boolean | false   | Enable CSP headers                                                   |
| `directives` | Record  | ---     | Directive name to value(s) map (e.g., `{ 'default-src': "'self'" }`) |
| `reportUri`  | string  | ---     | URI for CSP violation reports                                        |
| `reportOnly` | boolean | false   | Use `Content-Security-Policy-Report-Only` header                     |

### Security Headers

| Field                | Type   | Default   | Description                       |
| -------------------- | ------ | --------- | --------------------------------- |
| `hsts`               | string | ---       | `Strict-Transport-Security` value |
| `contentTypeOptions` | string | `nosniff` | `X-Content-Type-Options` value    |
| `frameOptions`       | string | `DENY`    | `X-Frame-Options` value           |

### HA Configuration

| Field                   | Type   | Default   | Description                   |
| ----------------------- | ------ | --------- | ----------------------------- |
| `heartbeatIntervalMs`   | number | 10000     | Heartbeat write interval      |
| `heartbeatTtlMs`        | number | 30000     | Heartbeat TTL (2-3x interval) |
| `takeoverGracePeriodMs` | number | 5000      | Grace period before takeover  |
| `redisKeyPrefix`        | string | `mcp:ha:` | Redis key prefix              |

## Multi-Target Example

Deploy the same server to Node.js, distributed, and Vercel:

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
import { defineConfig } from 'frontmcp';

export default defineConfig({
  name: 'my-server',
  version: '1.0.0',
  deployments: [
    {
      target: 'node',
      server: { http: { port: 3000 } },
    },
    {
      target: 'distributed',
      ha: { heartbeatIntervalMs: 5000 },
      server: {
        csp: {
          enabled: true,
          directives: { 'default-src': "'self'", 'upgrade-insecure-requests': '' },
        },
        headers: { hsts: 'max-age=31536000; includeSubDomains' },
      },
    },
    {
      target: 'vercel',
    },
  ],
});
```

Build each target independently:

```bash theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
frontmcp build --target node
frontmcp build --target distributed
frontmcp build --target vercel
```

## Project-Defined CLI Commands

The optional `cli.commands` block registers project-specific verbs that
ship alongside the built-in `frontmcp` commands. Each verb spawns a
runner module from the project (TS or JS) as a child process, so the
project's own code stays out of the CLI's process.

Verb names must match `/^[a-zA-Z][a-zA-Z0-9:_-]*$/` — start with a letter,
then letters, digits, `:`, `_`, or `-`. Examples: `deploy`, `db-migrate`,
`project:init`. Names that match a built-in verb (see [Reserved Verbs](#reserved-verbs)
below) are rejected at config load.

Each command entry accepts:

| Field         | Type    | Required | Description                                                                                                                                               |
| ------------- | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `entry`       | string  | yes      | Path to the runner module (TS or JS).                                                                                                                     |
| `description` | string  | no       | Shown in `frontmcp --help` and `--list-commands`.                                                                                                         |
| `arguments`   | array   | no       | Positional argument definitions (variadic must be last).                                                                                                  |
| `options`     | array   | no       | Long/short flag definitions with optional defaults.                                                                                                       |
| `hidden`      | boolean | no       | When `true`, the verb still runs but is omitted from help output and `--list-commands`. Useful for internal scripts you don't want surfaced to end users. |

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
// frontmcp.config.ts
import { defineConfig } from 'frontmcp';

export default defineConfig({
  name: 'my-server',
  deployments: [{ target: 'node' }],
  cli: {
    commands: {
      deploy: {
        entry: './scripts/deploy.ts',
        description: 'Push the current build to staging',
        arguments: [{ name: 'env', required: true, description: 'Target env' }],
        options: [
          { flags: '-n, --dry-run', description: 'Skip writes' },
          { flags: '-c, --concurrency <num>', default: 4 },
        ],
      },
      'db-migrate': {
        entry: './scripts/migrate.ts',
        description: 'Run pending database migrations',
      },
      'internal:reindex': {
        entry: './scripts/reindex.ts',
        description: 'Rebuild local search index',
        hidden: true, // omitted from --help and --list-commands
      },
    },
  },
});
```

After saving the config, the new verbs show up under **Project Commands**
in `frontmcp --help`:

```bash theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
frontmcp deploy prod --concurrency 8
frontmcp db-migrate
frontmcp --list-commands   # Lists every verb with [built-in]/[project] tag
```

### Reserved Verbs

Verb names that collide with a built-in command (`dev`, `build`, `test`,
`start`, `skills`, etc.) are rejected at config-load time with a helpful
message. Use a project-namespaced prefix (e.g. `project:init`,
`db-migrate`) to avoid the collision.

### Runner Selection

| Entry extension               | Runner                      |
| ----------------------------- | --------------------------- |
| `.ts`, `.tsx`, `.mts`, `.cts` | `node --import tsx <entry>` |
| `.js`, `.mjs`, `.cjs`         | `node <entry>`              |

The runner receives the parsed positionals as argv plus a
`FRONTMCP_PROJECT_COMMAND` env var containing a JSON payload with
`verb`, `positionals`, `options`, and `cwd` for richer scripting.

## Helper Functions

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
import { defineConfig, loadFrontMcpConfig, findDeployment, getDeploymentTargets } from 'frontmcp';

// Load config from a directory
const config = await loadFrontMcpConfig(process.cwd());

// Find a specific deployment target
const distributed = findDeployment(config, 'distributed');

// List all configured targets
const targets = getDeploymentTargets(config); // ['node', 'distributed', 'vercel']
```

## Related

<CardGroup cols={2}>
  <Card title="Production Build" icon="rocket" href="/frontmcp/deployment/production-build">
    Build and deploy guide
  </Card>

  <Card title="High Availability" icon="server" href="/frontmcp/deployment/high-availability">
    Multi-pod deployment with session failover
  </Card>

  <Card title="Security Headers" icon="shield-halved" href="/frontmcp/deployment/security-headers">
    CSP and security header configuration
  </Card>

  <Card title="Runtime Modes" icon="layer-group" href="/frontmcp/deployment/runtime-modes">
    Standalone, distributed, and serverless modes
  </Card>
</CardGroup>
