Tools

A tool is a function the model can call. The important distinction is where its implementation runs, because that determines what it can reach and who holds its credentials.

KindRuns onReachesConfigured with
HostedCoresourceHosted services and public MCP endpointsmcpServers, imageModel, derived or explicit allowlist
Custom handlerYour processWhatever your process can reachtools
Runtime catalogYour processYour filesystem, shell, networkregisterRuntimeTools()
Local MCPYour processMCP servers reachable from your processregisterMcpServer()

Hosted tools such as web_search, understand_image, and hosted MCP connections need no callback into your application. Custom handlers, the runtime catalog, and locally registered MCP clients execute through your SDK process.

SDK-hosted tools#

Pass functions in tools and the model calls them by name. When the model calls one, Coresource sends the call over the connection your SDK process holds (the bridge), runs your handler locally, and returns its result to the run.

TypeScript
import { createAgent } from '@coresourceai/sdk';

const agent = createAgent({
  type: 'agent',
  systemPrompt: 'Use the available business data. Never guess an amount.',
  tools: [
    {
      name: 'lookup_invoice',
      description: 'Look up an invoice by ID. Returns vendor, amount, and status.',
      inputSchema: {
        type: 'object',
        properties: { id: { type: 'string' } },
        required: ['id'],
        additionalProperties: false
      },
      handler: async (input, { signal }) => {
        signal.throwIfAborted();
        return lookupInvoice(String(input.id), { signal });
      }
    }
  ]
});

const result = await agent.run('Summarise invoice INV-123.');
await agent.close();

declare function lookupInvoice(id: string, options: { signal: AbortSignal }): Promise<unknown>;

Connect your own tools covers schema design, cancellation, deadlines, and error handling properly. This page is about how tools are resolved.

Name collisions#

Tool names must match ^[A-Za-z][A-Za-z0-9_-]{0,63}$. A letter, then up to 63 letters, digits, underscores, or hyphens. A name that does not is rejected with a TypeError when the agent is created, because provider APIs will not accept it.

Two of your own tools sharing a name is also a TypeError; that is a mistake, not a configuration choice.

A tool of yours sharing a name with a runtime-catalog tool is not an error. Yours wins. That is the supported way to substitute your own implementation:

TypeScript
import { createAgent } from '@coresourceai/sdk';

const agent = createAgent({
  type: 'agent',
  tools: [
    {
      name: 'execute',
      description: 'Run a command inside the job sandbox.',
      inputSchema: {
        type: 'object',
        properties: { command: { type: 'string' } },
        required: ['command'],
        additionalProperties: false
      },
      handler: (input) => runInSandbox(String(input.command))
    }
  ]
});

// Replaces the catalog's `execute`; every other catalog tool is untouched.
agent.registerRuntimeTools();

await agent.close();

declare function runInSandbox(command: string): Promise<string>;

The allowlist#

toolAllowlist is the list of tool names the model may see. Leave it unset and the SDK derives one from your configuration:

ConfigurationAdds
Custom toolsEach custom tool name
Runtime tools registeredEach runtime-catalog tool name plus web_search
skills presentlist_skills, invoke_skill
mcpServers present<alias>/*, list_mcp_capabilities, list_mcp_resources, read_mcp_resource
imageModel setunderstand_image
Local MCP registered<namespace>/*, where namespace defaults to the server name

Set it explicitly to narrow things further:

TypeScript
import { createAgent } from '@coresourceai/sdk';

const agent = createAgent({
  type: 'agent',
  imageModel: 'makora/kimi-2.7-code',
  // Read-only: the agent may look at files and images, but not write or execute.
  toolAllowlist: ['file_read', 'glob', 'grep', 'understand_image'],
  maxTools: 8
});

agent.registerRuntimeTools();
await agent.close();

If an agent stubbornly refuses to use a tool you configured, check the allowlist first. An explicit list that omits the tool is the usual cause.

maxTools caps how many tools the runtime may expose. It is separate from toolAllowlist: the allowlist selects eligible names, while maxTools limits the resulting catalog.