---
title: Dependency Injection
slug: features/dependency-injection
icon: syringe
description: Type-safe dependency injection with @Provider and scoped containers
keywords: ['frontmcp', 'mcp', 'model context protocol', 'features', 'framework', 'di', 'dependency injection', 'ioc', 'typescript']
---

FrontMCP includes a built-in dependency injection system. Define services with `@Provider`, inject them into tools, resources, prompts, and agents with `this.get()`.

## Defining Providers

Create a provider with a name and (optional) scope:

```ts
import { Provider, ProviderScope } from '@frontmcp/sdk';

@Provider({
  name: 'ConfigProvider',
  scope: ProviderScope.GLOBAL,
})
export class ConfigProvider {
  readonly apiKey = process.env.API_KEY!;
  readonly baseUrl = process.env.BASE_URL!;
}
```

To inject by interface, register with a token (a class, abstract class, or symbol). The class itself is the most common token:

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

abstract class ConfigService {
  abstract readonly apiKey: string;
}

class EnvConfigService extends ConfigService {
  readonly apiKey = process.env.API_KEY!;
}

@App({
  name: 'app',
  providers: [{ provide: ConfigService, useClass: EnvConfigService }],
})
class MyApp {}
```

## Provider Scopes

| Scope       | Lifetime                                   | Use Case                            |
| ----------- | ------------------------------------------ | ----------------------------------- |
| `global`    | One instance per server (default)          | Configuration, database connections |
| `context`   | One instance per execution context         | Per-request state, logging, caches  |

`'session'` and `'request'` are kept as deprecated aliases of `'context'`.

## Injecting Providers

Use `this.get()` or `this.tryGet()` inside any context class:

```ts
@Tool({
  name: 'fetch-data',
  inputSchema: { url: z.string() },
})
class FetchDataTool extends ToolContext {
  async execute({ url }: { url: string }) {
    const config = this.get(ConfigService);   // Throws if not found
    const cache = this.tryGet(CacheService);  // Returns undefined if not found

    const response = await this.fetch(url, {
      headers: { Authorization: `Bearer ${config.apiKey}` },
    });

    return response.json();
  }
}
```

## Registering Providers

Register providers at the server or app level:

```ts
// Server-level — available to all apps
@FrontMcp({
  info: { name: 'Server', version: '1.0.0' },
  apps: [MyApp],
  providers: [ConfigProvider, DatabaseProvider],
})
class Server {}

// App-level — available only within this app
@App({
  id: 'crm',
  name: 'CRM',
  tools: [CreateLeadTool],
  providers: [CrmServiceProvider],
})
class CrmApp {}
```

<Info>
Server-level providers are shared across all apps. App-level providers are isolated to their app.
</Info>

## Learn More

<CardGroup cols={2}>
  <Card title="Providers Guide" icon="syringe" href="/frontmcp/extensibility/providers">
    Full guide to defining, scoping, and composing providers
  </Card>
  <Card title="@Provider Reference" icon="code" href="/frontmcp/sdk-reference/decorators/provider">
    Complete decorator API reference
  </Card>
</CardGroup>
