ClineToolSet: tool definitions and schema conversion
Responsibilities
ClineToolSet is the hub where Cline unifies the concept of "tool" across three layers. The first is "registration": every tool is registered as a ClineToolSpec per model family (ModelFamily), with the Generic family as a fallback (register:19). The second is "selection": getEnabledTools filters the currently enabled tools by the variant's declared tool id list plus context requirements (getEnabledTools:87). The third is "conversion": getNativeConverter picks a converter by providerId and translates the ClineToolSpec into an Anthropic Tool / OpenAI ChatCompletionTool / Google FunctionDeclaration (getNativeConverter:151).
Its output has two paths. The "text path" stitches the tool schema into an XML-style section <tool_name>...<param>...</param></tool_name> and embeds it in the system prompt, for models that do not support native tool calling (PromptBuilder.tool:146). The "native path" passes the converted schema array as the tools argument of createMessage to the ApiHandler (getNativeTools:170).
Design motivation
- Dual schema outlets: the same
ClineToolSpeccan be converted into either XML text or a native tool schema, because some models Cline supports have native function calling (Anthropic / OpenAI / Gemini) while others do not (many local models); the latter can only be made to emit structured output by injecting XML into the system prompt. - Variant fallback chain:
getToolByNameWithFallbackfirst looks up the exact family, then GENERIC, then iterates over all variants (fallback:48), so a tool registered only in next-gen can still be used by the generic variant. - Dynamic contextRequirements filtering: a tool can declare
contextRequirements: (ctx) => boolean; for examplebrowser_actionrequiressupportsBrowserUse=true, and if the context does not satisfy it the tool is filtered out (ctx filter:101). This is more flexible than hardcoding variant lists. - Dynamic subagent tools:
getDynamicSubagentToolSpecsgenerates multiple variants of theUSE_SUBAGENTStool at runtime based on subagent configs loaded byAgentConfigLoader(dynamic subagent:108), one name per subagent. The toolset is therefore not static. - MCP tools fold into the toolset:
mcpToolToClineToolSpecconverts tools exposed by an MCP server into theClineToolSpecformat. The id is alwaysuse_mcp_tooland the name isserverUid__mcp__toolName(mcp name:238). MCP tools are managed through the same mechanism as built-in tools. - Name length fallback: MCP tool names longer than 64 characters are skipped and not registered (
length check:243), because provider APIs reject tool names that are too long.
Key files
ClineToolSet class:8— Holds the static registryvariants: Map<ModelFamily, Set<ClineToolSet>>.register:19— Static method; creates an instance and stores it in the Map by family, deduplicating by id.getToolByNameWithFallback:48— Three-level lookup: exact family → GENERIC → full table scan.getToolsForVariantWithFallback:73— Batch resolves by id list, deduplicating.getEnabledTools:87— variant.tools list + contextRequirements filter.getDynamicSubagentToolSpecs:108— When subagents are enabled and this is not itself a subagent run, generates USE_SUBAGENTS variants from AgentConfigLoader.getEnabledToolSpecs:136— Merges static tools with dynamic subagent tools; removes the static USE_SUBAGENTS when subagents are generated dynamically.getNativeConverter:151— Picks a converter by providerId: anthropic/bedrock/minimax → inputSchema, OpenAI-compatible → functionDefinition, gemini → functionDeclarations.getNativeTools:170— Returns the native schema array only whenvariant.labels.use_native_tools === 1andcontext.enableNativeToolCallsis true.mcpToolToClineToolSpec:198— Translates an MCP server's inputSchema into ClineToolSpec.parameters, preserving extra fields like enum / format.ClineDefaultTool enum:8— Enumeration of all built-in tool ids: execute_command / read_file / write_to_file / replace_in_file / search_files etc.ClineToolSpec:10— Tool spec type: id / name / description / parameters / contextRequirements.toolSpecFunctionDefinition:52— Converts to OpenAI ChatCompletionTool, withstrict: falseandadditionalProperties: false.toolSpecInputSchema:145— Converts to Anthropic Tool; the field name isinput_schemarather thanparameters.toolSpecFunctionDeclarations:243— Converts to Google FunctionDeclaration; types use uppercase constants like STRING / NUMBER / BOOLEAN.registerClineToolSets:32— Registers all tool variants into ClineToolSet once at startup.
Data flow
A tool goes through four steps from "registration" to "used by ApiHandler": register → variant declaration → enable filter → schema conversion. Registration happens during PromptRegistry construction:
// apps/vscode/src/core/prompts/system-prompt/tools/init.ts
export function registerClineToolSets(): void {
const allToolVariants = [
...access_mcp_resource_variants,
...act_mode_respond_variants,
// ...all 22 tools' variants arrays
...apply_patch_variants,
]
allToolVariants.forEach((v) => {
ClineToolSet.register(v)
})
}Each tool file exports a _variants array containing ClineToolSpecs written for different ModelFamilies (allToolVariants:34). After registration, each variant declares which tool ids it wants:
// apps/vscode/src/core/prompts/system-prompt/variants/generic/config.ts
.tools(
ClineDefaultTool.BASH,
ClineDefaultTool.FILE_READ,
ClineDefaultTool.FILE_NEW,
ClineDefaultTool.FILE_EDIT,
ClineDefaultTool.SEARCH,
ClineDefaultTool.LIST_FILES,
ClineDefaultTool.LIST_CODE_DEF,
ClineDefaultTool.BROWSER,
ClineDefaultTool.MCP_USE,
ClineDefaultTool.MCP_ACCESS,
ClineDefaultTool.ASK,
ClineDefaultTool.ATTEMPT,
ClineDefaultTool.PLAN_MODE,
ClineDefaultTool.MCP_DOCS,
ClineDefaultTool.TODO,
ClineDefaultTool.GENERATE_EXPLANATION,
ClineDefaultTool.USE_SKILL,
ClineDefaultTool.USE_SUBAGENTS,
)The generic variant lists 18 tool ids (generic tools:58). getEnabledTools takes this list, resolves each id via getToolByNameWithFallback, and applies the contextRequirements filter. Finally, if native tool calling is used, the converter turns the ClineToolSpec into the corresponding provider's schema:
// apps/vscode/src/core/prompts/system-prompt/spec.ts
export function toolSpecInputSchema(tool: ClineToolSpec, context: SystemPromptContext): AnthropicTool {
// ...
const toolInputSchema: AnthropicTool = {
name: tool.name,
description: replacer(tool.description, context),
input_schema: {
type: "object",
properties,
required,
},
}
return toolInputSchema
}Note that the replacer function substitutes template variables like / / (replacer:404); a tool's description can carry these placeholders and they are filled from context at runtime.
Boundaries and failure modes
- Duplicate tool registration: the same family + id is not added to the Set twice; the code explicitly checks
some(t => t.config.id === config.id)(dedup:25). - MCP tool name too long:
mcpToolName.length > 64is skipped outright (length check:243); the tool never appears in the toolset, so the model cannot call it. - Variant declares no tools: when
variant.toolsis empty,getEnabledToolsreturns an empty array (empty tools:89), meaning that variant runs pure text conversation with no tools. - Subagent nesting:
getDynamicSubagentToolSpecsreturns empty whencontext.isSubagentRunis true (subagent guard:109), preventing a subagent from spawning further subagent tools and avoiding infinite recursion. - use_native_tools label not set: by default, when
variant.labels.use_native_tools !== 1,getNativeToolsreturns undefined (label gate:175), even ifcontext.enableNativeToolCallsis true; the variant must opt in explicitly. - Converter throws: converters like
toolSpecInputSchemathrow"Tool X does not meet context requirements"whentool.contextRequirementsis not satisfied (contextRequirements throw:55). In theorygetEnabledToolshas already filtered these out, so this is a safety net. - MCP server.disabled: when fetching MCP tools, the code first runs
filter(s => s.disabled !== true)(disabled filter:183); tools from disabled servers never enter the toolset.
Summary
ClineToolSet is a three-in-one "central registry + selector + schema translator" for tools. The key design is that a single ClineToolSpec can serve both outlets — the "text XML section" and the "native tool schema" — so Cline can serve models with native function calling as well as local models that can only emit text. MCP tools are converted into the same format as built-in tools and managed through the same pipeline; subagent tools are generated dynamically from runtime config. Together these make the toolset a dynamically constructed structure rather than a static table.
- How tool prompts become XML sections:
/prompts/prompt-builder - Tool-availability differences between plan / act modes:
/prompts/mode - How the handler consumes the tools argument:
/providers/anthropic