> ## Documentation Index
> Fetch the complete documentation index at: https://docs-mcp.phake.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Tool context

> Reference for the ToolContext object passed to every tool handler, including authentication, session, cancellation, and Cloudflare bindings.

## 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.

```typescript theme={null}
handler: async (args: z.infer<TSchema>, context: ToolContext) => { ... }
```

When using `createMCPServer<TEnv>`, the context includes your typed environment bindings:

```typescript theme={null}
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

<ParamField body="sessionId" type="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.
</ParamField>

<ParamField body="bindings" type="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.
</ParamField>

<ParamField body="signal" type="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.

  ```typescript theme={null}
  handler: async (args, context) => {
    const res = await fetch("https://api.example.com/data", {
      signal: context.signal,
    });
    return res.json();
  },
  ```
</ParamField>

<ParamField body="meta" type="{ 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.
</ParamField>

<ParamField body="authStrategy" type="'oauth' | 'bearer' | 'api_key' | 'custom' | 'none' | undefined">
  The active authentication strategy for this server instance.

  | Value     | Description                                                                   |
  | --------- | ----------------------------------------------------------------------------- |
  | `oauth`   | Full OAuth 2.1 PKCE flow; `providerToken` is the mapped provider access token |
  | `bearer`  | Static bearer token from `BEARER_TOKEN` env var                               |
  | `api_key` | Static API key from `API_KEY` env var                                         |
  | `custom`  | Arbitrary headers from `CUSTOM_HEADERS` env var                               |
  | `none`    | No authentication configured                                                  |
</ParamField>

<ParamField body="providerToken" type="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.
</ParamField>

<ParamField body="provider" type="ProviderInfo | undefined">
  OAuth provider details. Only populated when `authStrategy` is `oauth`.

  ```typescript theme={null}
  interface ProviderInfo {
    accessToken: string;
    refreshToken?: string;
    expiresAt?: number;
    scopes?: string[];
    idTokenClaims?: Record<string, unknown>;  // Decoded from provider's id_token
  }
  ```
</ParamField>

<ParamField body="resolvedHeaders" type="Record<string, string> | undefined">
  Ready-to-use HTTP headers for forwarding authentication to external APIs.
  The exact headers depend on the active strategy:

  | Strategy  | Header                                                      |
  | --------- | ----------------------------------------------------------- |
  | `oauth`   | `Authorization: Bearer <provider-token>`                    |
  | `bearer`  | `Authorization: Bearer <BEARER_TOKEN>`                      |
  | `api_key` | `<API_KEY_HEADER>: <API_KEY>` (default header: `x-api-key`) |
  | `custom`  | All headers from `CUSTOM_HEADERS` env var                   |

  Spread or pass this object directly to `fetch`:

  ```typescript theme={null}
  handler: async (args, context) => {
    const response = await fetch("https://api.example.com/me", {
      headers: context.resolvedHeaders,
    });
    return response.json();
  },
  ```
</ParamField>

<ParamField body="authHeaders" type="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.
</ParamField>

## 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.

```typescript theme={null}
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.

```typescript theme={null}
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`.

```typescript theme={null}
interface AuthenticatedToolContext extends ToolContext {
  providerToken: string;
}
```

You can also use `assertProviderToken` to narrow the type manually:

```typescript theme={null}
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

```typescript theme={null}
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

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

### Inspect auth strategy

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