this.get
this.get() hands a tool, resource or prompt the instance of a 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.
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.
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);
}
}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.) |
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:
- The request's own instances: the
CONTEXTproviders the class can see, andFRONTMCP_CONTEXT. - The providers of the class's app, in
@App({ providers }). - 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 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 is the same object. (Changed in 1.9.2: before, PromptContext had no this.context, so prompts used the token.) |
Caveats
- A provider must be registered in a
providersarray. Decorating the class with@Providerisn'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. Usethis.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, likeprivate store = this.get(TicketStore), and aCONTEXTprovider 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'sinject(see@Provider).
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 }).
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);
}
}Starting FrontMCP in your browser…
FrontMCP starts when this example comes into view.
Getting a provider in a resource or a prompt
ResourceContext and PromptContext have the same this.get().
Other entries
Example 1 of 2
Resource
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) }] };
}
}Starting FrontMCP in your browser…
FrontMCP starts when this example comes into view.
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.
Scope and registration
Example 1 of 4
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.
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 };
}
}Starting FrontMCP in your browser…
FrontMCP starts when this example comes into view.
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.
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" };
}
}Starting FrontMCP in your browser…
FrontMCP starts when this example comes into view.
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.
Tokens
Example 1 of 2
Abstract class
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 {}Starting FrontMCP in your browser…
FrontMCP starts when this example comes into view.
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.
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 } }] };
}
}Starting FrontMCP in your browser…
FrontMCP starts when this example comes into view.
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.
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 {}Starting FrontMCP in your browser…
FrontMCP starts when this example comes into view.
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.
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.
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 {}Starting FrontMCP in your browser…
FrontMCP starts when this example comes into view.
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: 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. 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.