Skip to main content

Overview

Every tool handler receives a ToolContext as its second argument. It carries the current session ID, resolved authentication headers, provider token, and an abort signal for cancellation.
handler: async (args: z.infer<TSchema>, context: ToolContext) => { ... }
When using createMCPServer<TEnv>, the context includes your typed environment bindings:
interface Env {
  TOKENS: KVNamespace;
  MY_DATABASE: D1Database;
}

const server = createMCPServer<Env>({ tools: [...] });

// context.bindings is typed as Env
handler: async (args, context) => {
  const user = await context.bindings.MY_DATABASE.prepare("SELECT * FROM users").first();
}

Properties

sessionId
string
The current MCP session ID. Generated by the server on the initialize handshake. Use this to correlate tool calls to a specific client session in logs or external systems.
bindings
TEnv | undefined
Your Cloudflare environment bindings. Only available when using createMCPServer<TEnv>(). Use this to access KV namespaces, D1 databases, R2 buckets, and other Workers bindings with full type safety.
signal
AbortSignal | undefined
An AbortSignal for cooperative cancellation. When the MCP client sends a notifications/cancelled message, the server aborts the signal. Pass this to fetch or other async operations so they stop early when the client cancels.
handler: async (args, context) => {
  const res = await fetch("https://api.example.com/data", {
    signal: context.signal,
  });
  return res.json();
},
meta
{ progressToken?: string | number; requestId?: string } | undefined
Request metadata forwarded from the MCP JSON-RPC layer.
  • progressToken — opaque token the client uses to track progress notifications.
  • requestId — the JSON-RPC request ID for this call.
authStrategy
'oauth' | 'bearer' | 'api_key' | 'custom' | 'none' | undefined
The active authentication strategy for this server instance.
ValueDescription
oauthFull OAuth 2.1 PKCE flow; providerToken is the mapped provider access token
bearerStatic bearer token from BEARER_TOKEN env var
api_keyStatic API key from API_KEY env var
customArbitrary headers from CUSTOM_HEADERS env var
noneNo authentication configured
providerToken
string | undefined
The resolved access token for the authenticated user.
  • OAuth: the provider access token mapped from the RS token (e.g., a Google or GitHub token).
  • Bearer: the value of the BEARER_TOKEN environment variable.
  • API key: the value of the API_KEY environment variable.
  • Custom / none: undefined.
Use resolvedHeaders for making API calls instead of constructing the Authorization header yourself.
provider
ProviderInfo | undefined
OAuth provider details. Only populated when authStrategy is oauth.
interface ProviderInfo {
  accessToken: string;
  refreshToken?: string;
  expiresAt?: number;
  scopes?: string[];
  idTokenClaims?: Record<string, unknown>;  // Decoded from provider's id_token
}
resolvedHeaders
Record<string, string> | undefined
Ready-to-use HTTP headers for forwarding authentication to external APIs. The exact headers depend on the active strategy:
StrategyHeader
oauthAuthorization: Bearer <provider-token>
bearerAuthorization: Bearer <BEARER_TOKEN>
api_key<API_KEY_HEADER>: <API_KEY> (default header: x-api-key)
customAll headers from CUSTOM_HEADERS env var
Spread or pass this object directly to fetch:
handler: async (args, context) => {
  const response = await fetch("https://api.example.com/me", {
    headers: context.resolvedHeaders,
  });
  return response.json();
},
authHeaders
Record<string, string> | undefined
deprecated
Raw authorization headers from the incoming MCP request (before resolution). Use resolvedHeaders instead — it contains the correct auth headers for forwarding to external services regardless of the active strategy.

Helper Methods

ToolContext includes helper methods that return a { data, error } pattern for safe error handling.

getToken()

Returns the access token or an error if not available.
const { data: token, error } = context.getToken();
if (error) {
  return { content: [{ type: "text", text: error }], isError: true };
}
// Use token for API calls

getUser()

Fetches user info from the OAuth provider. Works with Google, GitHub, and other OAuth providers.
const { data: user, error } = await context.getUser();
if (error) {
  return { content: [{ type: "text", text: error }], isError: true };
}
// user.email, user.name, etc.
This is a convenience wrapper around getUser() + USERINFO_ENDPOINTS that handles the userinfo URL automatically based on the auth strategy.

AuthenticatedToolContext

AuthenticatedToolContext extends ToolContext and guarantees that providerToken is a non-optional string. The dispatcher populates this automatically for tools that declare requiresAuth: true.
interface AuthenticatedToolContext extends ToolContext {
  providerToken: string;
}
You can also use assertProviderToken to narrow the type manually:
import { assertProviderToken } from "@phake/mcp";

handler: async (_args, context) => {
  assertProviderToken(context);
  // context.providerToken is now string, not string | undefined
},

Examples

Forward auth to an external API

import { defineTool } from "@phake/mcp";
import { z } from "zod";

export const getProfileTool = defineTool({
  name: "get_profile",
  description: "Fetch the authenticated user's profile",
  inputSchema: z.object({}),
  requiresAuth: true,
  handler: async (_args, context) => {
    const response = await fetch("https://api.example.com/me", {
      headers: context.resolvedHeaders,
      signal: context.signal,
    });
    if (!response.ok) {
      return { error: `HTTP ${response.status}` };
    }
    return response.json();
  },
});

Use session ID for logging

handler: async (args, context) => {
  console.log(`[${context.sessionId}] Calling search with query: ${args.query}`);
  // ...
},

Inspect auth strategy

handler: async (args, context) => {
  if (context.authStrategy === "none") {
    return { error: "Authentication is not configured on this server" };
  }
  // continue with authenticated logic
},