Xome
FeaturesHow it worksFAQDocsTry Xome →Join waitlist

Developers

Adding tools.

Three ways to extend the agent, from no-code to full integration.

No code: Skills & MCP

  • Skills cover “teach it a workflow”, instructions, not new capabilities.
  • MCP servers cover “give it new capabilities” without touching the app: stand up an MCP endpoint and add it in Connections.

In code: a new tool

Tools are plain objects. The pattern, end to end:

lib/integrations/example/example-tools.ts
import { defineTool, type Tool } from "@/lib/agent/tools/tool";
import { ConsentLevel } from "@/lib/agent/tools/consent";

export const exampleTools: Tool[] = [
  defineTool({
    name: "example_do_thing",
    description: "One clear sentence the model uses to decide when to call this.",
    parameterSchema: {
      type: "object",
      properties: { query: { type: "string", description: "What to look up." } },
      required: ["query"],
      additionalProperties: false,
    },
    consent: ConsentLevel.preApproved,   // reads: preApproved · writes: alwaysAsk
    integrationId: "example",            // gates visibility by enabled set
    group: "Example",
    invoke: async (args) => {
      try {
        return { result: await doThing(String(args.query)) };
      } catch (e) {
        return { error: "failed", message: String(e) }; // never throw
      }
    },
  }),
];
  • Register it: add the tool array in lib/agent/build-registry.ts (always-on, like device tools) or gate it behind an integration id in lib/integrations/registry.ts.
  • Network calls go through proxyFetch() (add the host to the allowlist in app/api/proxy/route.ts) or authedFetch(integration, …) for OAuth-tokened requests.
  • Results are JSON: return { error, message } on failure, the orchestrator and UI handle both shapes.
  • Consent: anything that mutates the outside world must be alwaysAsk. If it moves money, also add it to NEVER_ALWAYS_ALLOW in consent.ts.

A new connection row

OAuth-style integrations add a descriptor in lib/integrations/registry.ts (label, tagline, scopes) and reuse the standard row; bespoke flows (like Solana/Privy or the folder picker) ship their own row component in components/connections/.

House style: match the surrounding code, tools validate inputs inline, trap every exception, and keep results small (the orchestrator truncates tool output at 4,000 chars before it reaches the model).