Skip to main content

Tools

A tool is an atomic operation with a typed input schema, optional output schema, and a handler function. Every tool has a path (dot-separated lowercase identifier like github.issues.create) and a name (Title Case like “Create Issue”). Tools are the fundamental unit of the Toolshed catalog. Agents discover tools via search_tools, inspect them via read_tool, and invoke them inside sandbox scripts.

Plugins

A plugin groups related tools with shared authentication. Plugins are defined using the SDK’s definePlugin and defineTool functions:
import { definePlugin, defineTool } from "@toolshed/sdk";

const myPlugin = definePlugin({
  id: "my-service",
  name: "My Service",
  description: "Tools for My Service",
  authProviders: [{ id: "my-service", type: "oauth2", provider: "my-service", scopes: ["read"] }],
  tools: [
    defineTool({
      path: "my_service.items.list",
      name: "List Items",
      description: "List items from My Service",
      inputSchema: z.object({ limit: z.number().default(10) }),
      async handler(ctx, input) {
        const token = await ctx.auth.getToken("my-service");
        // call API...
      },
    }),
  ],
});
See Writing Plugins for a full walkthrough.

Sources

A source is a unit of tool registration. Sources are how external APIs get imported into the Toolshed catalog. Four adapter types are supported:
TypeWhat it does
OpenAPIFetches an OpenAPI/Swagger spec and auto-generates tools from endpoints
GraphQLIntrospects a GraphQL schema and generates tools from queries and mutations
MCPConnects to an external MCP server and imports its tools
PluginWraps a hand-written plugin as a registry-compatible source
See Adding Sources for configuration details.

Roles and Policy

A role defines which tools a user can access using glob patterns:
{
  "id": "developer",
  "name": "Developer",
  "patterns": ["github.**", "linear.issues.*", "slack.channels.list"]
}
Pattern syntax:
  • github.issues.* — matches one segment (github.issues.create, github.issues.list)
  • github.** — matches any depth under github
  • * — matches everything (admin)
The policy engine filters the tool catalog at runtime so each user only sees tools their role permits. See Policy and Roles.

Elicitation

Destructive tools (those that create, update, or delete data) require human approval before executing. When a sandbox script calls a destructive tool:
  1. Execution pauses and returns a paused result with an executionId
  2. The agent presents the pending action to the user
  3. The user approves or denies via the resume MCP tool
  4. Execution continues or rejects based on the decision
This ensures a human is always in the loop for irreversible operations. See Elicitation Guide.

The Tools Proxy

Inside sandbox scripts, tools are accessed through a property-chain proxy:
// Discover tools
const results = await tools.search({ query: "email" });

// Inspect a tool
const schema = await tools.describe.tool({ path: "gmail.messages.list" });

// Call a tool
const emails = await tools.gmail.messages.list({ query: "from:acme" });
The proxy translates tools.gmail.messages.list(args) into an invocation of tool path gmail.messages.list. Agents cannot enumerate the proxy — they must use tools.search() to discover available tools.