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

# FrontMcpInstance

> FrontMcpInstance is the main entry point for creating and managing FrontMCP servers. It provides multiple factory methods for different deployment scenarios.

## Class Definition

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
export class FrontMcpInstance implements FrontMcpInterface {
  config: FrontMcpConfigType;
  readonly ready: Promise<void>;
}
```

## Properties

| Property | Type | Description |
| - | - | - |
| `config` | `FrontMcpConfigType` | Parsed server configuration |
| `ready` | `Promise<void>` | Promise that resolves when fully initialized |

## Factory Methods

### bootstrap(options)

Create and start an HTTP server.

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
static async bootstrap(
  options: FrontMcpConfigInput | FrontMcpConfigType
): Promise<void>
```

Best for: Standalone HTTP server deployments.

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
import { FrontMcpInstance } from '@frontmcp/sdk';
import config from './server';

await FrontMcpInstance.bootstrap(config);
// Server running on configured port
```

### createHandler(options)

Create a serverless handler without starting a server.

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
static async createHandler(options: FrontMcpConfigInput | FrontMcpConfigType): Promise<unknown>
```

Best for: Serverless deployments (Vercel, AWS Lambda).

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
// api/mcp.ts (Vercel)
import { FrontMcpInstance } from '@frontmcp/sdk';
import config from '../src/server';

export default FrontMcpInstance.createHandler(config);
```

### createFetchHandler(options)

Create a Web-standard `fetch` handler, `(request: Request) => Promise<Response>`, for runtimes without Node `req`/`res`: Cloudflare Workers, Deno and Bun.

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
static async createFetchHandler(options: FrontMcpConfigInput | FrontMcpConfigType): Promise<WebFetchHandler>
```

It accepts the same config as `@FrontMcp()`. A server the startup checks refuse (an `approval` or `featureFlag` field no installed plugin enforces, `authorities` without the `authorities` option, a missing secret) rejects here, as with `createDirect()`. On an edge isolate (Cloudflare Workers, Vercel Edge, Deno) the instance is built on the first request instead, because isolates forbid timers and I/O at module evaluation: the checks the config's metadata settles still reject here, and a failed build is answered, never thrown: a configuration fault (a missing secret, a startup check, a config the schema refuses) with a `500` `{ "error": "server_misconfigured", "code", "message" }` body, anything else (a remote that refused the connection, a package that failed to load) with a `503` `{ "error": "server_unavailable", "code": "SERVER_START_FAILED" }` body and `Retry-After`. A failed build is kept until a retry delay passes (1 s, doubling up to 60 s); the first request after it builds again. Requests run through the same `http:request` flow as the Express host, with the same request context: the user agent, `x-frontmcp-*` headers, `traceparent` and the MCP 2026-07-28 `_meta` client info.

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
// worker entry
const handler = await FrontMcpInstance.createFetchHandler(config);
export default { fetch: (request: Request) => handler(request) };

// Deno / Bun: forward the runtime's second argument so the handler sees the client IP
Deno.serve((request, info) => handler(request, info));
Bun.serve({ fetch: (request, server) => handler(request, server) });
```

The client IP comes from Deno's `info.remoteAddr`, Bun's `server.requestIP(request)`, or, only on Cloudflare Workers, the `CF-Connecting-IP` header.

The handler is stateless: session-based (2025-06-18) clients get no `Mcp-Session-Id` and every request stands alone. See [Cloudflare Worker](/frontmcp/deployment/cloudflare-worker) for stateful sessions with Durable Objects.

### createDirect(options)

Create a DirectMcpServer for programmatic access.

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
static async createDirect(options: FrontMcpConfigInput): Promise<DirectMcpServer>
```

Best for: Testing, embedding, CLI tools, agent backends.

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
import { FrontMcpInstance } from '@frontmcp/sdk';
import config from './server';

const server = await FrontMcpInstance.createDirect(config);

// Use programmatically
const tools = await server.listTools();
const result = await server.callTool('my_tool', { arg: 'value' });

// Cleanup
await server.dispose();
```

### createForGraph(options)

Create an instance for introspection without starting server.

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
static async createForGraph(options: FrontMcpConfigInput): Promise<FrontMcpInstance>
```

Best for: Graph visualization, introspection, analysis.

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
import { FrontMcpInstance } from '@frontmcp/sdk';
import config from './server';

const instance = await FrontMcpInstance.createForGraph(config);
const scopes = instance.getScopes();

// Analyze registries
scopes.forEach(scope => {
  console.log('Tools:', scope.tools.getTools().length);
  console.log('Resources:', scope.resources.getResources().length);
});
```

### runStdio(optionsOrClass)

Run the server over **stdio** (stdin/stdout JSON-RPC). **No HTTP/TCP port is bound** — the HTTP server is disabled for this entry point.

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
static async runStdio(optionsOrClass: ConfigOrServerClass): Promise<void>
```

Best for: Claude Desktop, Claude Code, Cursor, and other stdio MCP clients.

Accepts **either** a `@FrontMcp`-decorated class **or** the same config object you pass to `@FrontMcp()`.

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
// stdio.ts — config kept in its own module (no @FrontMcp decorator imported here)
import { FrontMcpInstance } from '@frontmcp/sdk';
import { serverConfig } from './server-config';

await FrontMcpInstance.runStdio(serverConfig);
// Never returns until the connection closes
```

<Warning>
  Importing a `@FrontMcp`-decorated class starts an HTTP server at import time
  unless `FRONTMCP_STDIO=1` is set **before** the import. For a hand-written stdio
  entry, keep the config object in its own module (as above) so no decorated class
  is evaluated. For built servers, use the `--stdio` runner (`./dist/node/<name> --stdio`) or a `--target cli` binary (`<bin> --stdio`) — both set the flag for
  you, so the decorated server connects over stdio and binds no port.
</Warning>

## Instance Methods

### getConfig()

Get the server configuration.

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
getConfig(): FrontMcpConfigType
```

### getScopes()

Get all initialized scopes.

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
getScopes(): ScopeEntry[]
```

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
const instance = await FrontMcpInstance.createForGraph(config);
const scopes = instance.getScopes();

scopes.forEach(scope => {
  console.log('Scope ID:', scope.id);
  console.log('Tools:', scope.tools.getTools().map(t => t.name));
});
```

### getPrimaryScope()

Get the scope that holds the server's own apps. `createDirect`, `createFetchHandler`, `runStdio` and `connect()` serve
this scope.

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
getPrimaryScope(): ScopeEntry | undefined
```

A `standalone` app, such as `DashboardApp`, gets a scope of its own that comes first in `getScopes()`, so the first
scope is not always the server's. When no app shares the server's scope (every app is standalone, or `splitByApp`),
this is the first scope.

<Note>
  Up to 1.8.2, those entry points served the first scope: with `DashboardApp` in `apps` they served the dashboard's
  tools instead of the server's.
</Note>

### start()

Start the HTTP server (called internally by bootstrap).

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
start(): Promise<void>
```

## Initialization Sequence

```
Constructor
  ↓ sets this.ready = this.initialize()
initialize()
  ↓
1. Initialize ProviderRegistry (global providers)
2. Initialize LoggerRegistry (depends on providers)
3. Initialize ScopeRegistry (creates Scope instances)
  ↓
ready Promise resolves
```

## Usage Examples

### Development Server

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
// src/index.ts
import { FrontMcpInstance } from '@frontmcp/sdk';
import config from './server';

async function main() {
  await FrontMcpInstance.bootstrap(config);
  console.log('Server started');
}

main().catch(console.error);
```

### Serverless (Vercel)

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
// api/mcp/[[...slug]].ts
import { FrontMcpInstance } from '@frontmcp/sdk';
import config from '../../src/server';

export default FrontMcpInstance.createHandler(config);
```

### Testing

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
import { FrontMcpInstance } from '@frontmcp/sdk';
import config from './server';

describe('MCP Server', () => {
  let server: DirectMcpServer;

  beforeAll(async () => {
    server = await FrontMcpInstance.createDirect(config);
  });

  afterAll(async () => {
    await server.dispose();
  });

  test('list tools', async () => {
    const tools = await server.listTools();
    expect(tools.length).toBeGreaterThan(0);
  });

  test('call tool', async () => {
    const result = await server.callTool('my_tool', { input: 'test' });
    expect(result).toBeDefined();
  });
});
```

### Claude Desktop Integration

```json theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
// claude_desktop_config.json
{
  "mcpServers": {
    "my-server": {
      "command": "node",
      "args": ["dist/stdio.js"],
      "cwd": "/path/to/server"
    }
  }
}
```

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
// src/server-config.ts — a plain object; do NOT add @FrontMcp here
export const serverConfig = {
  info: { name: 'my-server', version: '1.0.0' },
  apps: [MyApp],
};
```

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
// src/stdio.ts — imports only the config, so nothing auto-starts an HTTP server
import { FrontMcpInstance } from '@frontmcp/sdk';
import { serverConfig } from './server-config';

await FrontMcpInstance.runStdio(serverConfig);
```

<Tip>
  Keep `serverConfig` separate from your `@FrontMcp`-decorated `main.ts`. The
  decorator starts an HTTP server when its module is imported, so a stdio entry
  that imports the decorated class would bind a port alongside stdio. Importing
  just the config object avoids that.
</Tip>

## Related

<CardGroup cols={2}>
  <Card title="@FrontMcp" icon="at" href="/frontmcp/sdk-reference/decorators/frontmcp">
    Server decorator
  </Card>

  <Card title="Scope" icon="layer-group" href="/frontmcp/sdk-reference/core/scope">
    Registry access
  </Card>

  <Card title="DirectClient" icon="plug" href="/frontmcp/sdk-reference/core/direct-client">
    Programmatic access
  </Card>

  <Card title="Deployment" icon="rocket" href="/frontmcp/deployment/production-build">
    Deployment guides
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.