SDKsEdge MCP

Tools

What the agent can DO — standard WebMCP registerTool with safety annotations

A tool is one operation of your app the agent is allowed to run. Registration is pure standard WebMCP — there is no Napster-specific wrapper, and any WebMCP-compatible agent can call the result:

document.modelContext.registerTool({
  name: 'checkout.placeOrder',
  description: 'Submit the cart for purchase.',
  inputSchema: {
    type: 'object',
    properties: {
      paymentMethodId: { type: 'string' },
      addressId: { type: 'string' },
    },
    required: ['paymentMethodId', 'addressId'],
  },
  annotations: {
    readOnlyHint: false,
    destructiveHint: true, // ⇒ the agent confirms with the user before calling
    idempotentHint: true,  // safe to retry
  },
  async execute({ paymentMethodId, addressId }) {
    const order = await placeOrder(paymentMethodId, addressId); // your app's own code
    return { content: [{ type: 'text', text: `Order ${order.id} placed` }] };
  },
});

The execute calls the same functions your buttons and forms already call — the toolkit doesn't replace them, it exposes the ones you choose. The return value uses the standard MCP result shape ({ content: [{ type: 'text', text }] }).

Safety annotations

Safety rides on the standard MCP annotation hints — portable to any consumer, no proprietary tiers:

HintMeaning
readOnlyHintThe tool only reads state — the agent may call it freely.
destructiveHintConvention: confirm with the user before calling. Use for anything final — payments, sends, deletions.
idempotentHintSafe to retry with the same arguments.
untrustedContentHintThe output may carry untrusted or injected content.
openWorldHintThe tool reaches beyond the site itself — external systems, the open web. Most website tools are closed-world and leave this unset.

A tool with no annotations is treated as a reversible write: the agent announces what it's doing and runs it. The rule of thumb: pure read → readOnlyHint: true; reversible write → neither hint; final/irreversible → destructiveHint: true.

Writing tools agents actually use well

  • Names are namespace.verbproducts.search, cart.add — snake or camel within segments.
  • Descriptions are the agent's manual. Say what the tool does, when to reach for it, and what it returns — the agent decides relevance from this text alone.
  • Schemas are contracts. Mark required fields, describe each property; the agent fills arguments from conversation, and a precise schema is the difference between clean calls and garbage.
  • Expose operations, not endpoints. One user-meaningful action per tool ("book a table"), not a thin wrapper per API route.

Reading the surface back (consumer side)

Only relevant if you build something that consumes tools — an inspector, a custom bridge. Two wire-contract details: getTools() returns each inputSchema as a JSON string (parse before use — that's Chromium's native contract, matched for interoperability), and executeTool(tool, argsJson) resolves with a JSON string of the result envelope. Always pass the handle getTools() returned, never a hand-built object, and re-read the list on the toolchange event.

To unregister, pass an AbortSignal when registering — registerTool(descriptor, { signal: controller.signal }) — and call controller.abort() when the tool should go away. registerTool itself returns nothing.

Next steps

On this page