Skip to main content
FrontMCP’s environment-awareness system lets you declaratively restrict when entries (tools, resources, prompts, skills, agents) are discoverable and executable, based on the runtime environment. Entries that don’t match the current environment are automatically filtered from discovery and blocked from execution.
This enables platform-specific tools (e.g., Apple Notes on macOS only), runtime-specific resources (e.g., Node.js file system), and environment-gated features (e.g., debug tools in development only).

The availableWhen Option

Add availableWhen to any entry’s metadata to constrain its availability:
@Tool({
  name: 'apple_notes_search',
  description: 'Search Apple Notes',
  inputSchema: { query: z.string() },
  availableWhen: { platform: ['darwin'] },
})
class AppleNotesSearchTool extends ToolContext {
  async execute({ query }: { query: string }) {
    // This tool only appears on macOS
  }
}

Matching Semantics

  • AND across fields — all specified fields must match
  • OR within arrays — at least one value in an array must match
  • Omitted fields — unconstrained (matches everything)
  • Empty array — matches nothing (entry is never available)
  • No availableWhen — always available (default)
// Matches: Node.js OR Bun, AND production only
availableWhen: {
  runtime: ['node', 'bun'],
  env: ['production'],
}

Available Fields

platform

Operating system, matching process.platform values:
ValueOS
'darwin'macOS
'linux'Linux
'win32'Windows
'freebsd'FreeBSD

runtime

JavaScript runtime:
ValueRuntime
'node'Node.js
'bun'Bun
'deno'Deno
'edge'Edge runtime (Vercel, CF)
'browser'Browser

deployment

Deployment mode:
ValueDescription
'standalone'Standard server
'serverless'Serverless (Lambda, Vercel)

env

NODE_ENV value:
ValueDescription
'production'Production
'development'Development
'test'Testing

Supported Entry Types

availableWhen works on all five entry types:
@Tool({
  name: 'apple_notes_search',
  inputSchema: { query: z.string() },
  availableWhen: { platform: ['darwin'] },
})
class AppleNotesSearchTool extends ToolContext { ... }

Runtime Context API

Inside execute() methods, use runtime context helpers for imperative checks:
@Tool({
  name: 'system_command',
  inputSchema: { cmd: z.string() },
})
class SystemCommandTool extends ToolContext {
  async execute({ cmd }: { cmd: string }) {
    if (this.isPlatform('win32')) {
      // Windows-specific path
      return await this.runPowershell(cmd);
    }
    // Unix path
    return await this.runBash(cmd);
  }
}

Available Methods

MethodReturnsDescription
this.isPlatform('darwin')booleanCheck OS platform
this.isRuntime('node')booleanCheck JavaScript runtime
this.isDeployment('serverless')booleanCheck deployment mode
this.isEnv('production')booleanCheck NODE_ENV
this.runtimeContextRuntimeContextFull context object
These methods are available on ToolContext, ResourceContext, PromptContext, and AgentContext.

Multi-Platform Pattern

When building tools that serve the same purpose across platforms, use separate files with availableWhen in each:
tools/
  notes/
    notes.darwin.tool.ts     # Apple Notes (macOS)
    notes.win32.tool.ts      # OneNote (Windows)
    notes.linux.tool.ts      # GNOME Notes (Linux)
    index.ts                 # Re-exports all variants
// tools/notes/notes.darwin.tool.ts
@Tool({
  name: 'notes_search',
  description: 'Search notes on this system',
  inputSchema: { query: z.string() },
  availableWhen: { platform: ['darwin'] },
})
export class AppleNotesSearchTool extends ToolContext {
  async execute({ query }) { /* Apple Notes API */ }
}
// tools/notes/index.ts
export { AppleNotesSearchTool } from './notes.darwin.tool';
export { OneNoteSearchTool } from './notes.win32.tool';
export { GnomeNotesSearchTool } from './notes.linux.tool';
Register all variants — the SDK automatically exposes only the one matching the current platform:
import { AppleNotesSearchTool, OneNoteSearchTool, GnomeNotesSearchTool } from './tools/notes';

@FrontMcp({
  tools: [AppleNotesSearchTool, OneNoteSearchTool, GnomeNotesSearchTool],
})
class MyApp {}
The multi-platform file pattern (name.platform.tool.ts) is recommended when you have platform-specific implementations of the same logical capability. For simple cases where a single tool needs a platform check, use this.isPlatform() inside execute() instead.

Error Handling

When a client tries to call a tool that exists but is unavailable in the current environment, the SDK returns an EntryUnavailableError (HTTP 403) with both the constraint and the current context:
{
  "code": -32603,
  "message": "Tool \"apple_notes_search\" is not available in the current environment (requires: {\"platform\":[\"darwin\"]}) (current: {\"platform\":\"linux\",\"runtime\":\"node\",\"deployment\":\"standalone\",\"env\":\"production\"})"
}
This is distinct from a ToolNotFoundError (404), helping clients understand why a tool is inaccessible.

How It Works: Registry-Level Filtering

availableWhen is not the same as authorization or rule-based filtering. It is evaluated at the registry level during server boot, not in HTTP request flows.
ConcernLayerWhenScope
availableWhenRegistry (boot)Server startupProcess-wide, immutable
AuthorizationHTTP flow (request)Per requestPer session/user
Rule-based filteringHTTP flow (request)Per requestDynamic, policy-driven
hideFromDiscoveryRegistry (listing)Per list callSoft hide (entry still callable)
Key differences:
  • availableWhen is a hard constraint — filtered entries cannot be listed OR called
  • It runs at registry initialization, not in HTTP flows — no per-request overhead
  • The runtime context (OS, runtime, deployment, NODE_ENV) is detected once and cached
  • Results are logged at boot time for operational visibility

Boot-Time Logging

When entries have availableWhen constraints, the SDK logs a summary at startup:
[ToolRegistry] availability: 10 total, 5 with availableWhen constraint, 3 available, 2 filtered [ctx: platform=darwin, runtime=node, deployment=standalone, env=production]
[ToolRegistry] filtered: "windows_tool" — constraint={"platform":["win32"]}, current=platform=darwin
[ToolRegistry] filtered: "browser_tool" — constraint={"runtime":["browser"]}, current=runtime=node
Empty constraint arrays trigger a warning (likely a configuration bug):
[ToolRegistry] "broken_tool" has empty availableWhen arrays for [platform] — this entry will never be available.