Skip to main content
MCP Apps SDK
import { App } from "@modelcontextprotocol/ext-apps";

Overview

oncalltool is a request handler that receives tool calls from the host directed at your app. This enables bidirectional tool communication — in addition to calling server tools, the host (or model) can call tools that the View implements. To use oncalltool, you must declare the tools capability when constructing the App. The host discovers available tools through onlisttools, then calls them through this handler. Because this is a request handler, the host waits for your response. Return a result object containing content blocks, or throw an error to signal failure.

Signature

app.oncalltool = async (params: {
  name: string;
  arguments?: Record<string, unknown>;
}) => Promise<CallToolResult>;

Parameters

params
object
required
The tool call parameters sent by the host.
name
string
required
Name of the tool being called. Must match one of the tools declared in onlisttools.
arguments
Record<string, unknown>
Tool arguments as key-value pairs. The shape corresponds to the tool’s inputSchema.
Register handlers before calling connect() to avoid missing notifications during the initialization handshake.

Usage

Declare tools capability and handle calls

const app = new App(
  { name: "MyApp", version: "1.0.0" },
  { tools: { listChanged: true } },
);

app.oncalltool = async (params) => {
  if (params.name === "get-selection") {
    return { content: [{ type: "text", text: selectedText }] };
  }
  throw new Error(`Unknown tool: ${params.name}`);
};

await app.connect();

Handle multiple tools with structured results

app.oncalltool = async (params) => {
  switch (params.name) {
    case "get-selection":
      return {
        content: [{ type: "text", text: getSelectedText() }],
      };

    case "get-form-data":
      return {
        content: [{ type: "text", text: JSON.stringify(collectFormData()) }],
      };

    case "set-highlight": {
      const { selector, color } = params.arguments as {
        selector: string;
        color: string;
      };
      highlightElement(selector, color);
      return {
        content: [{ type: "text", text: "Highlighted successfully" }],
      };
    }

    default:
      throw new Error(`Unknown tool: ${params.name}`);
  }
};

Return errors without throwing

For expected failures, return an error result instead of throwing:
app.oncalltool = async (params) => {
  if (params.name === "get-file") {
    const file = files.get(params.arguments?.id as string);
    if (!file) {
      return {
        isError: true,
        content: [{ type: "text", text: `File not found: ${params.arguments?.id}` }],
      };
    }
    return { content: [{ type: "text", text: file.contents }] };
  }
  throw new Error(`Unknown tool: ${params.name}`);
};