Tools
Tools give agents the ability to act: look things up, call APIs, run code, read files. The model decides which tools to call and when.
Tool() API
Write a normal Swift function, wrap it with Tool() and a description. The tool name and parameter schema are inferred automatically from the description.
func wordCount(text: String) -> Int {
text.split(whereSeparator: \.isWhitespace).count
}
let wordCountTool = Tool(wordCount, "Count the number of words in a block of text.")
func calculator(expression: String) -> String {
guard let result = NSExpression(format: expression)
.expressionValue(with: nil, context: nil) else {
return "Error: invalid expression"
}
return "\(result)"
}
let calculatorTool = Tool(calculator, "Evaluate a mathematical expression and return the result.")
let agent = Agent(model: provider, tools: [wordCountTool, calculatorTool])
Your functions stay regular Swift functions -- you can still call them directly:
let count = wordCount(text: "hello world") // 2
Type mapping
| Swift Type | JSON Schema |
|---|---|
String | "type": "string" |
Int, Int64, … | "type": "integer" |
Double, Float | "type": "number" |
Bool | "type": "boolean" |
T? or default value | Marked optional in schema (omitted from required) |
Optional parameters and defaults
Parameters with a default value or ? type are treated as optional: included in the schema but excluded from required:
func getWeather(
city: String, // required
unit: String = "celsius", // optional (has a default)
detailed: Bool = false // optional (has a default)
) async throws -> String {
return "22°C, partly cloudy in \(city)"
}
let getWeatherTool = Tool(getWeather, "Look up current weather for a city.")
Async and throwing tools
Tools can be async, throws, or both. The generated wrapper handles await and catches errors automatically:
func searchWeb(query: String, maxResults: Int = 5) async throws -> String {
let url = URL(string: "https://api.search.example.com?q=\(query)")!
let (data, _) = try await URLSession.shared.data(from: url)
return String(data: data, encoding: .utf8) ?? "No results"
}
let searchWebTool = Tool(searchWeb, "Search the web and return a summary of the top results.")
Concurrent Tool Execution
When a model requests multiple tools in a single response, the agent runs them all concurrently using Swift structured concurrency. This means a model can call searchWeb, calculator, and getWeather simultaneously and wait for all results before continuing.
Make your tools async whenever they perform I/O (network, disk) so concurrent execution is truly parallel rather than serialized.
MCP Tool Providers
The SDK supports the Model Context Protocol (MCP). Connect any MCP server as a tool provider and all its tools become available to the agent automatically:
let mcpProvider = MCPToolProvider(serverURL: URL(string: "http://localhost:3000")!)
let tools = try await mcpProvider.tools()
let agent = Agent(model: provider, tools: tools)