Actions

defineAction, app-only visibility, and namespaced backing tools.

Actions are backing tools the View can call. They are hidden from the model.

import { z } from "zod";
import { defineAction } from "bitmcp";

export const refresh = defineAction({
  description: "Reload forecast points",
  input: z.object({ city: z.string() }),
  async execute({ city }) {
    return { city, summary: `Updated forecast for ${city}`, points: [] };
  },
});

defineAction is defineTool with visibility: ["app"].

Naming

Place named exports in actions.ts beside the tool:

src/tools/forecast/
  tool.ts
  view.tsx
  actions.ts    export const refresh = defineAction(...)

The registered name is forecast.refresh.

From the View

callTool("forecast.refresh", { city: result.city });

Each call is a new stateless tools/call. Pass handles or ids explicitly when resuming work.

Why actions exist

Iframe clicks should not pollute tools/list with UI-only helpers. The model sees the main tool. The View sees refresh, filter, or pagination helpers.

This uses the official Apps visibility field, not a bitmcp invention.