> ## 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.

# The FrontMCP Server

> The core FrontMCP server — start with the minimum and scale up with HTTP, sessions, logging, providers, and authentication.

FrontMCP servers are defined with a single decorator, `@FrontMcp({ ... })`. This page shows the **minimal config** and then every **top-level option** you can use. Deep dives live in the pages listed under *Servers*.

## Minimal server

```ts theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
import { FrontMcp } from '@frontmcp/sdk';
import MyApp from './my.app';

@FrontMcp({
  info: { name: 'My Server', version: '0.1.0' },
  apps: [MyApp],
})
export default class Server {}
```

**Required:**

* `info.name` (string)
* `info.version` (string)
* `apps` (at least one app)

Everything else is optional with sensible defaults.

***

## Full configuration (at a glance)

```ts theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
@FrontMcp({
  /** Required */
  info: {
    name: 'Expense MCP Server',
    version: '1.0.0',
    title?: 'Human title',
    websiteUrl?: 'https://example.com',
    icons?: Icon[], // MCP Icon[]
  },
  apps: [/* App classes */],
```

**Info field descriptions:**

| Field        | Description                           |
| ------------ | ------------------------------------- |
| `name`       | Server name shown in MCP discovery    |
| `version`    | Semantic version for clients to track |
| `title`      | Optional human-readable title         |
| `websiteUrl` | Link to documentation or homepage     |
| `icons`      | MCP Icon array for visual branding    |

```ts theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
@FrontMcp({
  /** Optional */
  serve?: true,                 // default true (auto-boot)
  splitByApp?: false,           // app composition mode
  providers?: [/* provider classes/factories/values */],

  http?: {
    port?: 3001,                // default 3001
    entryPath?: '',             // MUST match PRM resourcePath in .well-known
    hostFactory?: /* custom host */,
  },

  /** Transport & session lifecycle (NEW in v0.6) */
  transport?: {
    // Session lifecycle
    sessionMode?: 'stateful' | 'stateless',     // default 'stateful'
    transportIdMode?: 'uuid' | 'jwt',           // default 'uuid'
    platformDetection?: { customOnly?: boolean },

    // Protocol switches
    enableLegacySSE?: false,
    enableSseListener?: true,
    enableStreamableHttp?: true,
    enableStatelessHttp?: false,
    enableStatefulHttp?: false,
    requireSessionForStreamable?: true,

    // Session persistence (Redis-backed)
    persistence?: {
      enabled?: false,
      defaultTtlMs?: 3600000,   // 1 hour
    },
  },

  /** Shared Redis config (NEW in v0.6) */
  redis?: {
    host: 'localhost',
    port?: 6379,
    password?: string,
    db?: 0,
    tls?: false,
    keyPrefix?: 'mcp:',
    defaultTtlMs?: 3600000,
  },

  logging?: {
    level?: LogLevel.Info,      // Debug | VERBOSE | Info | Warn | Error | Off
    enableConsole?: true,       // default true
    prefix?: string,
    transports?: [/* custom log transports */],
  },

  /** Server-level default auth (omit if splitByApp: true) */
  auth?: (
    | { type: 'remote', name: string, baseUrl: string, ... }
    | { type: 'local',  id: string,   name: string,   ... }
  ),
})
```

***

## Composition mode

FrontMCP can host **many apps**. Choose how they’re exposed:

* **Multi-App (default)**: `splitByApp: false`
  One server scope. You *may* configure **server-level `auth`** and all apps inherit it (apps can still override with app-level auth).

* **Split-By-App**: `splitByApp: true`
  Each app is isolated under its own scope/base path (for example `/billing`). Streamable HTTP, the `/message` SSE endpoint, and OAuth issuers reuse that scope automatically. **Server-level `auth` is disallowed**; configure auth per app. (See *Authentication → Overview*.)

<Tip>If you’re offering multiple products or tenants, `splitByApp: true` gives clean separation and per-app auth.</Tip>

***

## HTTP transport

```ts theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
http: {
  port?: number;      // default 3001
  entryPath?: string; // default ''; MUST match the PRM resourcePath in .well-known
  hostFactory?: FrontMcpServer | ((cfg) => FrontMcpServer);
}
```

| Field         | Description                                             |
| ------------- | ------------------------------------------------------- |
| `port`        | HTTP listening port (default: 3001)                     |
| `entryPath`   | JSON-RPC entry path; must match `.well-known` discovery |
| `hostFactory` | Custom host implementation for advanced setups          |

* **Port**: listening port for Streamable HTTP.
* **entryPath**: your MCP JSON-RPC entry (`''` or `'/mcp'`). Must align with discovery.
* **hostFactory**: advanced — provide/construct a custom host implementation.
* **Split-by-app scopes**: when `splitByApp` is enabled, clients hit `<entryPath>/<appId>` (for example `/mcp/billing`) and subscribe via `<entryPath>/<appId>/message`; FrontMCP handles the prefixing.

***

## Transport

<Info>
  **New in v0.6**: Transport configuration has moved from `auth.transport` and `session` to a dedicated top-level `transport` property. This separates transport/session lifecycle concerns from authentication. See [Migration](#migration-from-authttransport) below.
</Info>

The `transport` config controls session lifecycle, protocol switches, and session persistence. Configure it at the server level or per-app when using `splitByApp: true`.

```ts theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
@FrontMcp({
  transport: {
    // Session lifecycle
    sessionMode: 'stateful',
    transportIdMode: 'uuid',
    platformDetection: { customOnly: false },

    // Protocol switches
    enableLegacySSE: false,
    enableSseListener: true,
    enableStreamableHttp: true,
    enableStatelessHttp: false,
    enableStatefulHttp: false,
    requireSessionForStreamable: true,

    // Session persistence
    persistence: {
      enabled: true,
      defaultTtlMs: 3600000,
    },
  },
})
```

### Session Lifecycle

| Option              | Default      | Description                                                                 |
| ------------------- | ------------ | --------------------------------------------------------------------------- |
| `sessionMode`       | `'stateful'` | `'stateful'` (server-side store) or `'stateless'` (JWT-based)               |
| `transportIdMode`   | `'uuid'`     | `'uuid'` (per-node identity) or `'jwt'` (signed, distributed)               |
| `platformDetection` | `undefined`  | Platform detection config; set `customOnly: true` to skip built-in mappings |

<CodeGroup>
  ```ts Stateful Sessions theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
  transport: {
    sessionMode: 'stateful',    // Server-side session store
    transportIdMode: 'uuid',    // Random UUID per transport
  }
  ```

  ```ts Stateless Sessions theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
  transport: {
    sessionMode: 'stateless',   // JWT-based sessions (client-portable)
    transportIdMode: 'jwt',     // Signed transport IDs for distributed setups
  }
  ```

  ```ts Dynamic (per issuer) theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
  transport: {
    sessionMode: (issuer) => issuer === 'internal' ? 'stateful' : 'stateless',
    transportIdMode: (issuer) => issuer === 'internal' ? 'uuid' : 'jwt',
  }
  ```
</CodeGroup>

### Protocol Switches

Choose which MCP transports to enable based on your deployment:

| Option                        | Default | When to enable                                          | Notes                                                                            |
| ----------------------------- | ------- | ------------------------------------------------------- | -------------------------------------------------------------------------------- |
| `enableStreamableHttp`        | `true`  | Modern MCP clients (Claude Desktop, Cursor, Rendezvous) | Primary transport; streams JSON-RPC over HTTP.                                   |
| `enableStatefulHttp`          | `false` | Local previews, OAuth consent screens, Jest suites      | JSON-only endpoint for requests without SSE—handy for testing and health checks. |
| `enableStatelessHttp`         | `false` | Public mode or CI agents that cannot run `initialize`   | Singleton transports that skip initialization handshake.                         |
| `enableSseListener`           | `true`  | Manual SSE subscribers or dashboards                    | Controls `GET /message` endpoint. Disable to reduce long-lived sockets.          |
| `enableLegacySSE`             | `false` | Supporting pre-Streamable clients temporarily           | Legacy HTTP + SSE combo—plan to remove once clients upgrade.                     |
| `requireSessionForStreamable` | `true`  | Public demos or scripted tests                          | Set `false` to let Streamable HTTP requests bootstrap themselves.                |

<Tip>
  Leave `enableStatelessHttp` off in production unless you fully trust the client surface. Stateless transports reuse process-wide connections, which is perfect for CI but can bypass fine-grained session teardown.
</Tip>

```ts theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
@FrontMcp({
  transport: {
    enableStreamableHttp: true,
    enableStatefulHttp: true,      // JSON fallback for previews
    enableStatelessHttp: false,    // keep anonymous traffic scoped
    requireSessionForStreamable: false,
  },
})
```

### Session Persistence

Enable Redis-backed session persistence for distributed deployments or session recovery:

```ts theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
@FrontMcp({
  redis: {
    host: 'redis.example.com',
    port: 6379,
  },
  transport: {
    persistence: {
      enabled: true,
      defaultTtlMs: 7200000, // 2 hours
    },
  },
})
```

| Option         | Default   | Description                          |
| -------------- | --------- | ------------------------------------ |
| `enabled`      | `false`   | Enable session persistence           |
| `defaultTtlMs` | `3600000` | Session TTL in milliseconds (1 hour) |

<Info>
  Session persistence uses the top-level `redis` config. Configure `redis` once and reference it from both `transport.persistence` and `auth.tokenStorage`.
</Info>

You can apply different transport policies per app when `splitByApp: true`. Sensitive apps stay stream-only with strict session IDs, while demo or health-check apps can enable stateful/stateless HTTP for easier automation.

***

## Redis

<Info>
  **New in v0.6**: Redis configuration has moved to a dedicated top-level `redis` property, shared by both `transport.persistence` and `auth.tokenStorage`.
</Info>

Configure Redis once at the server level for use across features:

```ts theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
@FrontMcp({
  redis: {
    host: 'redis.example.com',
    port: 6379,
    password: 'secret',
    db: 0,
    tls: true,
    keyPrefix: 'mcp:',
    defaultTtlMs: 3600000,
  },
})
```

| Option         | Default    | Description                          |
| -------------- | ---------- | ------------------------------------ |
| `host`         | (required) | Redis server hostname                |
| `port`         | `6379`     | Redis server port                    |
| `password`     | -          | Optional authentication password     |
| `db`           | `0`        | Redis database index                 |
| `tls`          | `false`    | Enable TLS/SSL connection            |
| `keyPrefix`    | `'mcp:'`   | Prefix for all Redis keys            |
| `defaultTtlMs` | `3600000`  | Default TTL for cached data (1 hour) |

### Usage with Features

The `redis` config is automatically used by:

* **Session persistence** (`transport.persistence`) — stores session state for recovery
* **Token storage** (`auth.tokenStorage: { type: 'redis' }`) — stores refresh tokens securely

```ts theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
@FrontMcp({
  redis: {
    host: 'localhost',
    keyPrefix: 'myapp:',
  },
  transport: {
    persistence: { enabled: true },
  },
  auth: {
    mode: 'orchestrated',
    type: 'local',
    tokenStorage: { type: 'redis' },
  },
})
```

***

## Migration from `auth.transport`

<Warning>
  **Deprecated**: The `auth.transport` and `session` properties are deprecated and will be removed in v1.0.0. Migrate to the top-level `transport` config.
</Warning>

FrontMCP automatically migrates old configs at runtime with a deprecation warning. Update your config manually to remove the warning:

<CodeGroup>
  ```ts Before (deprecated) theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
  @FrontMcp({
    session: {
      sessionMode: 'stateful',
      transportIdMode: 'uuid',
    },
    auth: {
      mode: 'orchestrated',
      type: 'local',
      transport: {
        enableStreamableHttp: true,
        enableStatefulHttp: true,
        recreation: {
          enabled: true,
          redis: { host: 'localhost' },
        },
      },
    },
  })
  ```

  ```ts After (v0.6+) theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
  @FrontMcp({
    redis: {
      host: 'localhost',
    },
    transport: {
      sessionMode: 'stateful',
      transportIdMode: 'uuid',
      enableStreamableHttp: true,
      enableStatefulHttp: true,
      persistence: {
        enabled: true,
      },
    },
    auth: {
      mode: 'orchestrated',
      type: 'local',
    },
  })
  ```
</CodeGroup>

### Migration Mapping

| Old Path                                     | New Path                                |
| -------------------------------------------- | --------------------------------------- |
| `session.sessionMode`                        | `transport.sessionMode`                 |
| `session.transportIdMode`                    | `transport.transportIdMode`             |
| `session.platformDetection`                  | `transport.platformDetection`           |
| `auth.transport.enableLegacySSE`             | `transport.enableLegacySSE`             |
| `auth.transport.enableSseListener`           | `transport.enableSseListener`           |
| `auth.transport.enableStreamableHttp`        | `transport.enableStreamableHttp`        |
| `auth.transport.enableStatelessHttp`         | `transport.enableStatelessHttp`         |
| `auth.transport.enableStatefulHttp`          | `transport.enableStatefulHttp`          |
| `auth.transport.requireSessionForStreamable` | `transport.requireSessionForStreamable` |
| `auth.transport.recreation`                  | `transport.persistence`                 |
| `auth.transport.recreation.redis`            | `redis` (top-level)                     |

***

## Logging

```ts theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
logging: {
  level?: LogLevel;        // default Info
  enableConsole?: boolean; // default true
  prefix?: string;
  transports?: LogTransportType[]; // custom sinks via @FrontMcpLogTransport
}
```

| Field           | Description                                               |
| --------------- | --------------------------------------------------------- |
| `level`         | Minimum log level: Debug, Verbose, Info, Warn, Error, Off |
| `enableConsole` | Whether to output to stdout (default: true)               |
| `prefix`        | Optional prefix for all log messages                      |
| `transports`    | Custom log transport implementations                      |

Use custom log transports for shipping logs to external systems; console remains on by default.

***

## Global providers

```ts theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
providers: [
  /* Provider classes/factories/values */
];
```

Define DI-style singletons available to all apps (and their tools/plugins). Scopes are supported at the provider level (`GLOBAL`, `SESSION`, `REQUEST`).

***

## Authentication (server level)

Server-level `auth` sets the **default** auth for all apps (unless `splitByApp: true`, where auth must be per-app).

### Remote OAuth (encapsulated external IdP)

```ts theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
auth: {
  type: 'remote',
  name: 'frontegg',
  baseUrl: 'https://auth.example.com',
  dcrEnabled?: boolean,
  clientId?: string | ((info) => string), // for non-DCR via local proxy
  mode?: 'orchestrated' | 'transparent',
  allowAnonymous?: boolean,
  consent?: boolean,
  scopes?: string[],
  grantTypes?: ['authorization_code','refresh_token'],
  authEndpoint?: string,
  tokenEndpoint?: string,
  registrationEndpoint?: string,
  userInfoEndpoint?: string,
  jwks?: JSONWebKeySet,
  jwksUri?: string,
}
```

### Local OAuth (built-in AS)

```ts theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
auth: {
  type: 'local',
  id: 'local',
  name: 'Local Auth',
  scopes?: string[],
  grantTypes?: ['authorization_code','refresh_token'],
  allowAnonymous?: boolean,  // default true
  consent?: boolean,         // show tool/resource/prompt consent
  jwks?: JSONWebKeySet,      // inline keys (optional)
  signKey?: JWK | Uint8Array // private key (optional; auto-gen if omitted)
}
```

<Info>
  Apps can also define their own `auth` (and mark themselves `standalone`) to expose an isolated auth surface — useful
  when mixing public and private apps under one server.
</Info>

***

## Bootstrapping & discovery

* **Version safety**: on boot, FrontMCP checks that all `@frontmcp/*` packages are aligned and throws a clear “version mismatch” error otherwise.

<Warning>If you disable `serve`, you’re responsible for calling the core bootstrap yourself.</Warning>

***

## Common starting points

* **Single app, default everything**: minimal sample above.
* **Multiple apps, shared auth**: omit `splitByApp`, set server-level `auth`.
* **Isolated apps with per-app auth**: set `splitByApp: true`, configure `auth` in each app.

***

## Best Practices

**Do:**

* Start with minimal config and add options as needed
* Use `splitByApp: true` for multi-tenant deployments
* Use top-level `transport` config (not `auth.transport` or `session`)
* Configure `redis` at top-level for shared use across features
* Use `stateful` session mode with Redis for production deployments
* Enable `persistence` for distributed or high-availability setups
* Set log level to `Info` or higher in production

**Don't:**

* Configure server-level `auth` when using `splitByApp: true`
* Use deprecated `auth.transport` or `session` — migrate to `transport`
* Disable `serve` unless you're managing bootstrap manually
* Use `stateless` session mode with short-lived upstream tokens
* Enable `enableStatelessHttp` in production without trust boundaries
* Leave `enableConsole: true` in containerized production (use transports)

***

Next up: learn how to structure **Apps**, **Tools**, **Resources**, and **Prompts** in the *Core Components* section.
