---
title: Apps
description: Container for grouping related tools, resources, and prompts with shared auth and providers
slug: servers/apps
icon: cube
keywords: ['frontmcp', 'mcp', 'model context protocol', 'mcp server', 'server', 'components', 'apps', '@App', 'composition', 'typescript']
---

Apps are the **organizational units** for capabilities in FrontMCP. Each app groups related **tools**, **resources**, and **prompts** into a cohesive domain, along with **providers**, **adapters**, and **plugins** that support them.

## Why Apps?

In FrontMCP, apps provide domain boundaries and enable multi-tenant architectures:

| Aspect       | App                       | Server                 | Tool                 |
| ------------ | ------------------------- | ---------------------- | -------------------- |
| **Purpose**  | Group capabilities        | Host apps              | Execute actions      |
| **Scope**    | Feature/domain boundary   | Process entry point    | Single operation     |
| **Contains** | Tools, resources, prompts | Apps, global providers | Input → Output logic |

Apps are ideal for:

- **Feature domains** — billing, users, analytics as separate concerns
- **Team boundaries** — each team owns their app
- **Multi-tenant** — isolate per customer with `splitByApp: true`
- **Third-party integrations** — wrap OpenAPI adapters per service

---

## Minimal App

```ts
import { App } from '@frontmcp/sdk';

@App({
  id: 'hello',
  name: 'Hello App',
  tools: [],
})
export default class HelloApp {}
```

Add it to your server:

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

---

## App options

```ts
@App({
  id?: string,
  name: string,
  description?: string,
  providers?: ProviderType[],
  authProviders?: AuthProviderType[],
  plugins?: PluginType[],
  adapters?: AdapterType[],
  tools?: ToolType[],
  resources?: ResourceType[],
  prompts?: PromptType[],
  auth?: AuthOptions,                 // app‑default auth (overrides server auth)
  standalone?: 'includeInParent' | boolean, // isolate scope / expose separately
})
```

**Field descriptions:**

| Field           | Description                                             |
| --------------- | ------------------------------------------------------- |
| `id`            | Unique identifier; used in URLs when `splitByApp: true` |
| `name`          | Human-readable display name                             |
| `description`   | Optional description for documentation                  |
| `providers`     | DI providers scoped to this app                         |
| `authProviders` | Authentication providers for this app                   |
| `plugins`       | Plugins attached at app scope                           |
| `adapters`      | Adapters (e.g., OpenAPI) that generate tools/resources  |
| `tools`         | Tool classes registered to this app                     |
| `resources`     | Resource classes registered to this app                 |
| `prompts`       | Prompt classes registered to this app                   |
| `auth`          | App-level auth config (overrides server auth)           |
| `standalone`    | Isolation mode: `true`, `false`, or `'includeInParent'` |

**Scoping & auth**

- If the server uses **`splitByApp: true`**, each app is isolated and **must** configure its own auth (server-level `auth` is disallowed).
- `standalone: true` makes the app expose its own scope/entry; `'includeInParent'` lists it under the parent while keeping isolation.

**Dependency resolution**

- Providers resolve **tool → app → server**.
- Plugins/adapters attach at app scope; generated items inherit the app’s policies and provenance.

---

## Example: app with adapter + providers

```ts
@App({
  id: 'billing',
  name: 'Billing',
  providers: [DbProvider, CacheProvider],
  adapters: [
    // e.g. OpenAPI adapter that generates tools/resources from a spec
    BillingOpenApiAdapter,
  ],
})
export default class BillingApp {}
```

---

## Remote Apps

Connect to external MCP servers and proxy their tools, resources, and prompts through your gateway using `App.remote()`:

```ts
import { FrontMcp, App } from '@frontmcp/sdk';

@FrontMcp({
  info: { name: 'Gateway', version: '1.0.0' },
  apps: [
    // Remote MCP server connected via URL
    App.remote('https://mintlify.com/docs/mcp', {
      namespace: 'mintlify', // Tools prefixed as 'mintlify:ToolName'
      transportOptions: {
        timeout: 60000,
        retryAttempts: 2,
      },
    }),
    // Local MCP server on different port
    App.remote('http://localhost:3099/', {
      namespace: 'local',
      transportOptions: {
        timeout: 30000,
        retryAttempts: 3,
      },
    }),
  ],
})
export default class GatewayServer {}
```

### Remote App Options

`App.remote(url, options?)` accepts the MCP server URL as the first argument and an optional options object:

| Option             | Type                              | Description                                                             |
| ------------------ | --------------------------------- | ----------------------------------------------------------------------- |
| `name`             | `string`                          | Override the auto-derived app name (defaults to hostname)               |
| `namespace`        | `string`                          | Prefix for tool/resource/prompt names (e.g., `mintlify:SearchMintlify`) |
| `description`      | `string`                          | Human-readable description                                              |
| `standalone`       | `boolean \| 'includeInParent'`    | Isolation mode (default: `false`)                                       |
| `transportOptions` | `object`                          | Connection settings (timeout, retry attempts)                           |
| `remoteAuth`       | `RemoteAuthConfig`                | Authentication config for the remote server                             |
| `refreshInterval`  | `number`                          | Interval (ms) to refresh capabilities from the remote server            |
| `cacheTTL`         | `number`                          | TTL (ms) for cached capabilities                                        |
| `filter`           | `AppFilterConfig`                 | Include/exclude filter for selectively importing primitives              |

### Transport Options

```ts
transportOptions: {
  timeout: 60000,      // Request timeout in milliseconds
  retryAttempts: 3,    // Number of retry attempts on failure
}
```

### Caching Remote Tools

Remote tools don't have cache metadata, so use the `toolPatterns` option in CachePlugin:

```ts
@FrontMcp({
  apps: [
    App.remote('https://api.example.com/mcp', {
      namespace: 'api',
    }),
  ],
  plugins: [
    CachePlugin.init({
      type: 'memory',
      defaultTTL: 300,
      toolPatterns: ['api:*'], // Cache all tools from this namespace
    }),
  ],
})
```

See the [Cache Plugin documentation](/frontmcp/plugins/cache-plugin#caching-remote-tools) for more details on pattern-based caching.

### Use Cases for Remote Apps

<CardGroup cols={2}>
  <Card title="MCP Gateway" icon="diagram-project">
    Aggregate multiple MCP servers behind a single endpoint with unified authentication
  </Card>
  <Card title="Service Mesh" icon="network-wired">
    Connect to internal microservices running as separate MCP servers
  </Card>
  <Card title="Third-Party Integration" icon="plug">
    Proxy external MCP services like Mintlify, adding caching and rate limiting
  </Card>
  <Card title="Development" icon="code">
    Test against local MCP servers running on different ports
  </Card>
</CardGroup>

---

## ESM Package Apps

Load npm packages at runtime and register their tools, resources, and prompts in-process — no HTTP proxy needed — using `App.esm()`:

```ts
import { FrontMcp, App } from '@frontmcp/sdk';

@FrontMcp({
  info: { name: 'Gateway', version: '1.0.0' },
  apps: [
    App.esm('@acme/mcp-tools@^1.0.0', {
      namespace: 'acme',
      autoUpdate: { enabled: true },
    }),
    App.esm('@acme/analytics@^2.0.0', { namespace: 'analytics' }),
  ],
})
export default class Server {}
```

<Info>
Unlike [Remote Apps](#remote-apps) which proxy requests to external MCP servers over HTTP, ESM packages are fetched from a CDN, cached locally, and executed **in-process**. They support two-tier caching, background version polling with hot-reload, and private registry authentication.
</Info>

See the full [ESM Packages reference](/frontmcp/servers/esm-packages) for `App.esm()` API, caching, authentication, and auto-update configuration.

---

## Per-Primitive Loading

In addition to loading entire apps, you can load **individual primitives** (tools, resources, prompts, agents, skills, jobs) from npm packages or remote servers using static methods on each decorator:

```ts
import { FrontMcp, App, Tool, Resource, Prompt } from '@frontmcp/sdk';

@App({
  id: 'my-app',
  name: 'My App',
  tools: [
    LocalEchoTool,                                            // Local @Tool class
    Tool.esm('@acme/tools@^1.0.0', 'echo'),                  // Single tool from npm
    Tool.remote('https://api.example.com/mcp', 'search'),     // Proxy single tool from remote
  ],
  resources: [
    LocalConfig,
    Resource.esm('@acme/tools@^1.0.0', 'status'),            // Single resource from npm
  ],
  prompts: [
    Prompt.remote('https://api.example.com/mcp', 'greeting'), // Proxy single prompt
  ],
})
class MyApp {}
```

<Tip>
Per-primitive loading gives you fine-grained control. Instead of importing an entire package's tools, you can pick exactly the ones you need. See each component's documentation page ([Tools](/frontmcp/servers/tools), [Resources](/frontmcp/servers/resources), [Prompts](/frontmcp/servers/prompts), [Agents](/frontmcp/servers/agents), [Skills](/frontmcp/servers/skills), [Jobs](/frontmcp/servers/jobs)) for details.
</Tip>

---

## Best Practices

**Do:**

- Use descriptive `id` values that work as URL segments
- Group related tools, resources, and prompts in the same app
- Configure `standalone: true` when apps need isolated auth
- Use adapters to generate tools from OpenAPI specs

**Don't:**

- Put unrelated functionality in the same app
- Mix authentication strategies within a single app
- Create apps with only one tool (use the server directly)
- Use `App.esm()` for external MCP servers (use `App.remote()` instead)

**Choosing between app types:**

- **Local `@App`**: First-party code you own and maintain
- **`App.esm()`**: Community or internal packages distributed via npm
- **`App.remote()`**: External MCP servers running as separate processes
