# this.get

> Get a provider, like a ticket store or your configuration, inside a tool, resource or prompt.

Source: https://frontmcp.dev/reference/sdk/get

`this.get()` hands a tool, resource or prompt the instance of a [provider](https://frontmcp.dev/reference/sdk/provider): a shared service like a ticket store, an API client or your configuration. You name the provider by its token, usually its class, and FrontMCP returns the instance for the current call. `this.tryGet()` does the same, but returns `undefined` when there's no such provider.

```ts
const service = this.get(token)
const maybe = this.tryGet(token)
```

---

## Reference

### `this.get(token)`

Call `this.get()` in a class that extends `ToolContext`, `ResourceContext` or `PromptContext`. The provider must be registered where that class can see it: see [where FrontMCP looks](#where-frontmcp-looks).

```ts get-ticket.tool.ts
import { Tool, ToolContext, z } from "@frontmcp/sdk";
import { TicketStore } from "./ticket-store";

@Tool({ name: "get_ticket", description: "Get one support ticket by id", inputSchema: { id: z.string() } })
export class GetTicket extends ToolContext {
  async execute({ id }: { id: string }) {
    const store = this.get(TicketStore);
    return store.find(id);
  }
}
```

[See more examples below.](#usage)

#### Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| `token` | `Token<T>` | Which provider to get: a `@Provider` class, or the `provide` of a factory, which can be a class, an abstract class, a symbol or a string. |

#### Returns

The provider's instance, typed from the token: `this.get(TicketStore)` is a `TicketStore`, and `this.get(DeskConfig)` for an abstract class `DeskConfig` is a `DeskConfig`. A string or symbol token carries no type, so the result is `unknown` until you pass one: `this.get<number>(SLA_HOURS)`.

Which instance you get depends on the provider's scope, and on where it's registered:

| Provider | What `this.get()` returns |
| --- | --- |
| `ProviderScope.GLOBAL` (the default), in `@App({ providers })` | The same instance on every call, in every tool, resource and prompt of that app. Another app that registers the same class gets an instance of its own. |
| `ProviderScope.GLOBAL`, in `@FrontMcp({ providers })` | The same instance on every call, in every app. |
| `ProviderScope.CONTEXT` | The same instance for the whole request, however often you call `this.get()`, and a new one for the next request. (Clients on MCP versions before 2026-07-28 keep one per session: see [scopes](https://frontmcp.dev/reference/sdk/provider#scopes).) |

#### Throws

`ProviderNotAvailableError`, with `code` `PROVIDER_NOT_AVAILABLE`, when no provider for `token` is registered where the class can see it. The message names the class, `Provider "TicketStore" is not available: not found in local or parent registries`, or says `Provider "[ref]"` for a string or symbol token.

Unless you catch it, the error ends the request. What the client gets depends on where it happened:

| In a | The client gets |
| --- | --- |
| Tool | An `isError` result with `_meta.code` `TOOL_EXECUTION_ERROR`. In development its text is `Tool "get_ticket" execution failed: Provider "TicketStore" is not available: …`, in production "Internal FrontMCP error" and an error ID. |
| Resource | JSON-RPC error `-32603`. In development its message is `Resource "tickets://T-1" read failed: Provider "TicketStore" is not available: …`, in production "Internal FrontMCP error" and an error ID. |
| Prompt | JSON-RPC error `-32603`. In development its message is `Prompt execution failed: Provider "TicketStore" is not available: …`, in production "Internal FrontMCP error" and an error ID. |

#### `this.tryGet(token)`

The same lookup, with the same parameter. It returns the instance, or `undefined` if there's no provider for `token`, and never throws. Each miss writes a warning to the server's log: `Failed to get provider …`.

#### Where FrontMCP looks

For each call, FrontMCP looks for the token in this order and returns the first match:

1. The request's own instances: the `CONTEXT` providers the class can see, and [`FRONTMCP_CONTEXT`](#built-in-tokens).
2. The providers of the class's app, in `@App({ providers })`.
3. The server's providers, in `@FrontMcp({ providers })`.

Nothing else. A provider registered in another app isn't found, and an app provider with the same token as a server provider [takes its place](#one-instance-per-request-app-or-server) in that app.

#### Built-in tokens

| Token | What `this.get()` returns |
| --- | --- |
| `FRONTMCP_CONTEXT` | The current request's `FrontMcpContext`: its `requestId`, `traceContext`, `authInfo` and HTTP `metadata`. In tools, resources, prompts, agents and jobs, [`this.context`](https://frontmcp.dev/reference/sdk/context) is the same object. (Changed in 1.9.2: before, `PromptContext` had no `this.context`, so prompts [used the token](#reading-the-request-in-a-prompt).) |

#### Caveats

- A provider must be **registered** in a `providers` array. Decorating the class with `@Provider` isn't enough.
- The token is matched exactly. Another class with the same name, or `"sla_hours"` for `"SLA_HOURS"`, is a different token. Export tokens as constants, or use classes, so a typo fails to compile instead.
- `this.tryGet()` hides every lookup failure, so a mistyped token looks the same as a provider that isn't registered. Use `this.get()` for anything the class can't work without.
- FrontMCP builds a new tool, resource or prompt object for every call, after the providers are ready. So `this.get()` also works in a field initializer, like `private store = this.get(TicketStore)`, and a `CONTEXT` provider got that way still belongs to the current request.
- Providers don't have `this.get()`. They receive other providers through constructor injection or a factory's `inject` (see [`@Provider`](https://frontmcp.dev/reference/sdk/provider#constructor-injection)).

---

## Usage

### Getting a provider in a tool

Both tools get the same `TicketStore`, so a ticket `close_ticket` closes is closed for `get_ticket` too. Exported providers are registered in the example's app for you; in a project, list them in `@App({ providers })`.

```ts tickets.tool.ts active
import { Tool, ToolContext, z } from "@frontmcp/sdk";
import { TicketStore } from "./ticket-store";

@Tool({ name: "close_ticket", description: "Close a support ticket", inputSchema: { id: z.string() } })
export class CloseTicket extends ToolContext {
  async execute({ id }: { id: string }) {
    const store = this.get(TicketStore);
    store.close(id);
    return store.find(id);
  }
}

@Tool({ name: "get_ticket", description: "Get one support ticket by id", inputSchema: { id: z.string() } })
export class GetTicket extends ToolContext {
  async execute({ id }: { id: string }) {
    return this.get(TicketStore).find(id);
  }
}
```

```ts ticket-store.ts
import { Provider } from "@frontmcp/sdk";

@Provider({ name: "TicketStore" })
export class TicketStore {
  private tickets = new Map([
    ["T-1", { id: "T-1", title: "Cannot log in", status: "open" }],
    ["T-2", { id: "T-2", title: "Invoice total is wrong", status: "open" }],
  ]);

  find(id: string) {
    return this.tickets.get(id) ?? { id, title: "(no such ticket)", status: "unknown" };
  }

  close(id: string) {
    const ticket = this.tickets.get(id);
    if (ticket) ticket.status = "closed";
  }
}
```

```ts tickets.test.ts
import { test, expect } from "@frontmcp/testing";

test("get_ticket sees what close_ticket did", async ({ mcp }) => {
  await mcp.tools.call("close_ticket", { id: "T-2" });
  const result = await mcp.tools.call("get_ticket", { id: "T-2" });
  expect(result.json()).toEqual({ id: "T-2", title: "Invoice total is wrong", status: "closed" });
});
```

### Getting a provider in a resource or a prompt

`ResourceContext` and `PromptContext` have the same `this.get()`.

<Examples title="Other entries">

#### Example: Resource
```ts ticket.resource.ts active
import { ResourceContext, ResourceTemplate } from "@frontmcp/sdk";
import { TicketStore } from "./ticket-store";

@ResourceTemplate({ name: "ticket", uriTemplate: "tickets://{id}", mimeType: "application/json" })
export class Ticket extends ResourceContext<{ id: string }> {
  async execute(uri: string, { id }: { id: string }) {
    const ticket = this.get(TicketStore).find(id);
    return { contents: [{ uri, mimeType: "application/json", text: JSON.stringify(ticket) }] };
  }
}
```

```ts ticket-store.ts
import { Provider } from "@frontmcp/sdk";

@Provider({ name: "TicketStore" })
export class TicketStore {
  find(id: string) {
    return { id, title: "Cannot log in", status: "open" };
  }
}
```

#### Example: Prompt
```ts summarize.prompt.ts active
import { Prompt, PromptContext, type GetPromptResult } from "@frontmcp/sdk";
import { TicketStore } from "./ticket-store";

@Prompt({
  name: "summarize_ticket",
  description: "Summarize a ticket for a handover",
  arguments: [{ name: "id", description: "Ticket id, like T-1", required: true }],
})
export class SummarizeTicket extends PromptContext {
  async execute({ id }: Record<string, string>): Promise<GetPromptResult> {
    const ticket = this.get(TicketStore).find(id);
    const text = `Summarize ticket ${ticket.id}, "${ticket.title}" (${ticket.status}), for the next agent on shift.`;
    return { messages: [{ role: "user", content: { type: "text", text } }] };
  }
}
```

```ts ticket-store.ts
import { Provider } from "@frontmcp/sdk";

@Provider({ name: "TicketStore" })
export class TicketStore {
  find(id: string) {
    return { id, title: "Cannot log in", status: "open" };
  }
}
```

### One instance per request, app or server

What `this.get()` returns depends on the provider's scope and on where it's registered. Each tab's test shows which instances are shared.

<Examples title="Scope and registration">

#### Example: Per request
A `CONTEXT` provider is shared by every `this.get()` in one request, and replaced for the next. `ProviderScope.GLOBAL` here would count 2, then 4.

```ts triage.tool.ts active
import { Tool, ToolContext, z } from "@frontmcp/sdk";
import { StepCounter } from "./step-counter";

@Tool({ name: "triage_ticket", description: "Triage a support ticket", inputSchema: { id: z.string() } })
export class TriageTicket extends ToolContext {
  async execute({ id }: { id: string }) {
    this.get(StepCounter).count++; // checked the ticket
    this.get(StepCounter).count++; // set its priority
    return { id, steps: this.get(StepCounter).count };
  }
}
```

```ts step-counter.ts
import { Provider, ProviderScope } from "@frontmcp/sdk";

@Provider({ name: "StepCounter", scope: ProviderScope.CONTEXT })
export class StepCounter {
  count = 0;
}
```

```ts step-counter.test.ts
import { test, expect } from "@frontmcp/testing";

test("each request starts with a new instance", async ({ mcp }) => {
  expect((await mcp.tools.call("triage_ticket", { id: "T-1" })).json()).toEqual({ id: "T-1", steps: 2 });
  expect((await mcp.tools.call("triage_ticket", { id: "T-2" })).json()).toEqual({ id: "T-2", steps: 2 });
});
```

#### Example: Per app
Two apps register the same class, so each gets its own instance. The ticket the desk app closed is still open in the reports app.

```ts server.ts active
import { App, FrontMcp, Tool, ToolContext, z } from "@frontmcp/sdk";
import { TicketStore } from "./ticket-store";

@Tool({ name: "close_ticket", description: "Close a support ticket", inputSchema: { id: z.string() } })
export class CloseTicket extends ToolContext {
  async execute({ id }: { id: string }) {
    this.get(TicketStore).close(id);
    return { closed: id };
  }
}

@Tool({ name: "count_open", description: "Count open tickets", inputSchema: {} })
export class CountOpen extends ToolContext {
  async execute() {
    return { open: this.get(TicketStore).openCount() };
  }
}

@App({ id: "desk", name: "Desk", tools: [CloseTicket], providers: [TicketStore] })
class Desk {}

@App({ id: "reports", name: "Reports", tools: [CountOpen], providers: [TicketStore] })
class Reports {}

@FrontMcp({ info: { name: "Help desk", version: "1.0.0" }, apps: [Desk, Reports] })
export class Server {}
```

```ts ticket-store.ts
import { Provider } from "@frontmcp/sdk";

@Provider({ name: "TicketStore" })
export class TicketStore {
  private open = new Set(["T-1", "T-2"]);

  close(id: string) {
    this.open.delete(id);
  }

  openCount() {
    return this.open.size;
  }
}
```

```ts apps.test.ts
import { test, expect } from "@frontmcp/testing";

test("the reports app has its own TicketStore", async ({ mcp }) => {
  await mcp.tools.call("close_ticket", { id: "T-1" });
  expect((await mcp.tools.call("count_open", {})).json()).toEqual({ open: 2 });
});
```

#### Example: Per server
Register the provider on the server instead, and every app gets the same instance.

```ts server.ts active
import { App, FrontMcp, Tool, ToolContext, z } from "@frontmcp/sdk";
import { TicketStore } from "./ticket-store";

@Tool({ name: "close_ticket", description: "Close a support ticket", inputSchema: { id: z.string() } })
export class CloseTicket extends ToolContext {
  async execute({ id }: { id: string }) {
    this.get(TicketStore).close(id);
    return { closed: id };
  }
}

@Tool({ name: "count_open", description: "Count open tickets", inputSchema: {} })
export class CountOpen extends ToolContext {
  async execute() {
    return { open: this.get(TicketStore).openCount() };
  }
}

@App({ id: "desk", name: "Desk", tools: [CloseTicket] })
class Desk {}

@App({ id: "reports", name: "Reports", tools: [CountOpen] })
class Reports {}

@FrontMcp({ info: { name: "Help desk", version: "1.0.0" }, apps: [Desk, Reports], providers: [TicketStore] })
export class Server {}
```

```ts ticket-store.ts
import { Provider } from "@frontmcp/sdk";

@Provider({ name: "TicketStore" })
export class TicketStore {
  private open = new Set(["T-1", "T-2"]);

  close(id: string) {
    this.open.delete(id);
  }

  openCount() {
    return this.open.size;
  }
}
```

```ts apps.test.ts
import { test, expect } from "@frontmcp/testing";

test("both apps share the server's TicketStore", async ({ mcp }) => {
  await mcp.tools.call("close_ticket", { id: "T-1" });
  expect((await mcp.tools.call("count_open", {})).json()).toEqual({ open: 1 });
});
```

#### Example: Overridden in one app
An app provider with the same token as a server provider wins inside that app. Here VIP tickets get a shorter reply deadline than the server's default.

```ts server.ts active
import { App, FrontMcp, Tool, ToolContext } from "@frontmcp/sdk";

export abstract class DeskConfig {
  abstract replyWithinHours: number;
}

@Tool({ name: "reply_due", description: "Hours we have to reply to a ticket", inputSchema: {} })
export class ReplyDue extends ToolContext {
  async execute() {
    return { hours: this.get(DeskConfig).replyWithinHours };
  }
}

@Tool({ name: "vip_reply_due", description: "Hours we have to reply to a VIP ticket", inputSchema: {} })
export class VipReplyDue extends ToolContext {
  async execute() {
    return { hours: this.get(DeskConfig).replyWithinHours };
  }
}

@App({ id: "desk", name: "Desk", tools: [ReplyDue] })
class Desk {}

@App({
  id: "vip",
  name: "VIP desk",
  tools: [VipReplyDue],
  providers: [{ provide: DeskConfig, name: "VipDeskConfig", inject: () => [], useFactory: () => ({ replyWithinHours: 4 }) }],
})
class Vip {}

@FrontMcp({
  info: { name: "Help desk", version: "1.0.0" },
  apps: [Desk, Vip],
  providers: [{ provide: DeskConfig, name: "DeskConfig", inject: () => [], useFactory: () => ({ replyWithinHours: 24 }) }],
})
export class Server {}
```

```ts override.test.ts
import { test, expect } from "@frontmcp/testing";

test("the vip app gets its own DeskConfig", async ({ mcp }) => {
  expect((await mcp.tools.call("vip_reply_due", {})).json()).toEqual({ hours: 4 });
});

test("other apps get the server's", async ({ mcp }) => {
  expect((await mcp.tools.call("reply_due", {})).json()).toEqual({ hours: 24 });
});
```

### Using a provider only if it's registered

`this.tryGet()` lets a tool work with or without a provider. Here a deployment can register an `SlaPolicy`; without one, every ticket gets the default of 24 hours. Add `SlaPolicy` to the app's `providers`, and a high-priority ticket is due in 4.

```ts reply-due.tool.ts active
import { Tool, ToolContext, z } from "@frontmcp/sdk";
import { SlaPolicy } from "./sla-policy";

@Tool({
  name: "reply_due",
  description: "Hours we have to reply to a ticket of this priority",
  inputSchema: { priority: z.enum(["low", "normal", "high"]) },
})
export class ReplyDue extends ToolContext {
  async execute({ priority }: { priority: "low" | "normal" | "high" }) {
    const policy = this.tryGet(SlaPolicy);
    return { hours: policy?.hoursFor(priority) ?? 24, policy: policy ? "custom" : "default" };
  }
}
```

```ts help-desk.app.ts
import { App } from "@frontmcp/sdk";
import { ReplyDue } from "./reply-due.tool";

@App({ id: "help-desk", name: "Help desk", tools: [ReplyDue], providers: [] })
export class HelpDesk {}
```

```ts sla-policy.ts
import { Provider } from "@frontmcp/sdk";

@Provider({ name: "SlaPolicy" })
export class SlaPolicy {
  hoursFor(priority: "low" | "normal" | "high") {
    return { low: 48, normal: 24, high: 4 }[priority];
  }
}
```

```ts reply-due.test.ts
import { test, expect } from "@frontmcp/testing";

test("without SlaPolicy, the default applies", async ({ mcp }) => {
  const result = await mcp.tools.call("reply_due", { priority: "high" });
  expect(result.json()).toEqual({ hours: 24, policy: "default" });
});
```

The Logs tab shows the warning `this.tryGet()` writes for the missing provider.

### Tokens that aren't classes

A factory can register any value under an abstract class, a symbol or a string. An abstract class gives `this.get()` a type to return; a symbol or string doesn't, so pass the type yourself.

<Examples title="Tokens">

#### Example: Abstract class
```ts help-desk.app.ts active
import { App, Tool, ToolContext } from "@frontmcp/sdk";

export abstract class DeskConfig {
  abstract replyWithinHours: number;
}

@Tool({ name: "reply_due", description: "Hours we have to reply to a ticket", inputSchema: {} })
export class ReplyDue extends ToolContext {
  async execute() {
    const config = this.get(DeskConfig); // typed as DeskConfig
    return { hours: config.replyWithinHours };
  }
}

@App({
  id: "help-desk",
  name: "Help desk",
  tools: [ReplyDue],
  providers: [{ provide: DeskConfig, name: "DeskConfig", inject: () => [], useFactory: () => ({ replyWithinHours: 24 }) }],
})
export class HelpDesk {}
```

#### Example: Symbol
```ts help-desk.app.ts active
import { App, Tool, ToolContext } from "@frontmcp/sdk";

export const REPLY_WITHIN_HOURS = Symbol("REPLY_WITHIN_HOURS");

@Tool({ name: "reply_due", description: "Hours we have to reply to a ticket", inputSchema: {} })
export class ReplyDue extends ToolContext {
  async execute() {
    const hours = this.get<number>(REPLY_WITHIN_HOURS); // unknown without <number>
    return { hours };
  }
}

@App({
  id: "help-desk",
  name: "Help desk",
  tools: [ReplyDue],
  providers: [{ provide: REPLY_WITHIN_HOURS, name: "REPLY_WITHIN_HOURS", inject: () => [], useFactory: () => 24 }],
})
export class HelpDesk {}
```

### Reading the request in a prompt

A prompt reads the request with `this.context`, as a tool does. `FRONTMCP_CONTEXT` is the token for the same object, so `this.get(FRONTMCP_CONTEXT)` returns it too: that's how prompts read it before 1.9.2, when `PromptContext` had no `this.context`, and that code still works. Here the handover note carries the request id, to find the request in the logs later.

```ts handover.prompt.ts
import { FRONTMCP_CONTEXT, Prompt, PromptContext, type GetPromptResult } from "@frontmcp/sdk";

@Prompt({
  name: "handover_note",
  description: "Write a handover note for a ticket",
  arguments: [{ name: "id", description: "Ticket id, like T-1", required: true }],
})
export class HandoverNote extends PromptContext {
  async execute({ id }: Record<string, string>): Promise<GetPromptResult> {
    const { requestId } = this.context;
    const sameRequest = this.get(FRONTMCP_CONTEXT) === this.context;
    const text = `Write a handover note for ticket ${id}. End it with "ref ${requestId}".`;
    return { description: `Same request object: ${sameRequest}`, messages: [{ role: "user", content: { type: "text", text } }] };
  }
}
```

```ts handover.test.ts
import { test, expect } from "@frontmcp/testing";

test("each request has its own id", async ({ mcp }) => {
  const text = (result: { messages: any[] }) => result.messages[0].content.text as string;
  const first = text(await mcp.prompts.get("handover_note", { id: "T-1" }));
  const second = text(await mcp.prompts.get("handover_note", { id: "T-1" }));
  expect(first).toMatch(/ref [0-9a-f-]{36}"\.$/);
  expect(first).not.toBe(second);
});

test("the token and this.context are the same object", async ({ mcp }) => {
  expect((await mcp.prompts.get("handover_note", { id: "T-1" })).raw.description).toBe("Same request object: true");
});
```

---

## Troubleshooting

### `Provider "Directory" is not available: not found in local or parent registries`

No provider with that token is registered where the tool, resource or prompt can see it. If it's registered somewhere, it's probably in **another app**: apps don't see each other's providers.

```ts server.ts active
import { App, FrontMcp, Provider, Tool, ToolContext } from "@frontmcp/sdk";

@Provider({ name: "Directory" })
export class Directory {
  onDuty() {
    return { team: "EMEA support", lead: "Nour" };
  }
}

@Tool({ name: "whoami", description: "Which support team is on duty", inputSchema: {} })
export class WhoAmI extends ToolContext {
  async execute() {
    return this.get(Directory).onDuty();
  }
}

@App({ id: "desk", name: "Desk", tools: [WhoAmI] })
class Desk {}

// 🚩 Directory is registered in the billing app, not in the desk app
@App({ id: "billing", name: "Billing", providers: [Directory] })
class Billing {}

@FrontMcp({ info: { name: "Help desk", version: "1.0.0" }, apps: [Desk, Billing] })
export class Server {}
```

Register it in the app that uses it, or in `@FrontMcp({ providers })` to share one instance with every app. If it isn't registered anywhere, see [the same error on `@Provider`](https://frontmcp.dev/reference/sdk/provider#provider-ticketstore-is-not-available-not-found-in-local-or-parent-registries).

### `Provider "[ref]" is not available`

The token is a string or a symbol, so the message can't name it. Look for a typo, or for a symbol created twice: two `Symbol("SLA")` calls make two different tokens.

```ts help-desk.app.ts active
import { App, Tool, ToolContext } from "@frontmcp/sdk";

@Tool({ name: "reply_due", description: "Hours we have to reply to a ticket", inputSchema: {} })
export class ReplyDue extends ToolContext {
  async execute() {
    return { hours: this.get<number>("REPLY_WITHIN_HOUR") }; // 🚩 missing the S
  }
}

@App({
  id: "help-desk",
  name: "Help desk",
  tools: [ReplyDue],
  providers: [{ provide: "REPLY_WITHIN_HOURS", name: "REPLY_WITHIN_HOURS", inject: () => [], useFactory: () => 24 }],
})
export class HelpDesk {}
```

Define the token once, export it, and import it everywhere, or use an abstract class, which also gives `this.get()` a type.

### `this.tryGet()` returns `undefined` for a provider I registered

`this.tryGet()` returns `undefined` for any lookup that fails, so check the same things as for [the error above](#provider-directory-is-not-available-not-found-in-local-or-parent-registries): that the provider is registered in this app or on the server, and that the token is the same value. The server log has the reason, in a warning that starts `Failed to get provider`. While you're debugging, switch to `this.get()` to get the error in the result.

### Two tools see different data from the same provider

They're in different apps, and each app registered the provider, so each has its own instance. Register it once, in `@FrontMcp({ providers })`. See [Per app](#one-instance-per-request-app-or-server). If the provider is `CONTEXT`-scoped, each request gets a new instance anyway: use `GLOBAL` for state that lasts.

### TypeScript says `Type 'unknown' is not assignable to type 'number'`

The token is a string or a symbol, which carries no type. Pass the type, `this.get<number>(REPLY_WITHIN_HOURS)`, or register the value under an abstract class instead.
