Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.ixo.world/llms.txt

Use this file to discover all available pages before exploring further.

A tool is a function the agent calls with validated args. Return one from getTools (boot-time) or getRequestTools (per-request).
1

Build a PluginTool with the tool() helper

Use the tool() builder from @ixo/oracle-runtime. The handler gets validated args and a per-request RuntimeContext.
import { tool, z, type PluginTool, type RuntimeContext } from '@ixo/oracle-runtime';

export function buildCurrentWeatherTool(): PluginTool {
  return tool(
    async (args, ctx: RuntimeContext) => {
      const { city } = z.object({ city: z.string().min(1) }).parse(args);
      ctx.logger.log(`weather lookup by ${ctx.user.did} for ${city}`);
      const result = await fetchWeather(city, ctx.abortSignal);
      if (!result) return `Could not find weather for "${city}".`;
      return JSON.stringify(result);
    },
    {
      name: 'get_current_weather',
      description: 'Get the current weather for a city.',
      schema: z.object({
        city: z.string().min(1).describe('City name, e.g. "Berlin".'),
      }),
    },
  );
}
Canonical source: weather-tools.ts.
2

Return it from getTools(ctx) for the stable case

Pick getTools when the tool list is the same for every user — it only depends on config and identity.
import { OraclePlugin, type PluginContext, type PluginTool } from '@ixo/oracle-runtime';

export class WeatherPlugin extends OraclePlugin {
  override getTools(ctx: PluginContext): PluginTool[] {
    return [buildCurrentWeatherTool()];
  }
}
See getTools in weather.plugin.ts.
3

Return it from getRequestTools(rtCtx) when it varies per request

Use getRequestTools when the tool list depends on live state — the user, session, history, or loadedPlugins.
override getRequestTools(rtCtx: RuntimeContext): PluginTool[] {
  const tz = rtCtx.user.timezone ?? 'auto';
  return [buildForecastTool(tz)];
}
Both hooks merge — their outputs are concatenated on every build. See getRequestTools in weather.plugin.ts.
4

Override visibility per tool (optional)

A tool inherits its plugin’s manifest.visibility by default. Add a visibility field to the PluginTool to override per-tool.
const currentTool = buildCurrentWeatherTool();
currentTool.visibility = 'always';

const forecastTool = buildForecastTool();
forecastTool.visibility = 'on-demand';

return [currentTool, forecastTool];
See Set visibility for the full recipe.

What to know before shipping

  • Tool name must be unique across all loaded plugins. Boot fails on collision.
  • Throw from the handler for unexpected errors (retry middleware catches them). Return a string for expected misses (“not found”).
  • The agent expects a string; JSON.stringify structured output to keep the contract clean.
  • ctx.abortSignal propagates from the inbound request — forward it to every fetch.
  • Do not override descriptions of upstream MCP tools — pass them through verbatim and put guidance in the manifest instead.

Add a sub-agent

For multi-step tool sequences with their own prompt.

RuntimeContext reference

Every field a handler can read.