Cross-platform library for building AI agents on Android and iOS with tool calling and MCP (Model Context Protocol) support.
- Tool Interface - Define and execute tools/functions for AI agents
- Tool Registry - Manage, validate, and lookup tools
- Agent Parser - Parse LLM responses for tool calls and final answers
- Agent Executor - Execute tools with validation and error handling
- MCP Client - Connect to MCP servers for remote tool discovery and invocation
- Cross-Platform - Native implementations for Android (Kotlin) and iOS (Swift)
// In your app's build.gradle.kts
dependencies {
implementation("com.vanespark:mobile-ai-agent-lib:1.0.0")
}// In your Package.swift
dependencies: [
.package(url: "https://github.com/scottgl9/mobile-ai-agent-lib.git", from: "1.0.0")
]Or add via Xcode: File → Add Packages → Enter repository URL
Kotlin:
class CalculatorTool : Tool {
override val name = "calculator"
override val description = "Performs arithmetic calculations"
override val parameters = listOf(
ToolParameter("expression", "Math expression to evaluate", ParameterType.STRING)
)
override suspend fun execute(arguments: Map<String, Any>): ToolResult {
val expr = arguments["expression"]?.toString()
?: return ToolResult.error("Missing expression")
// Evaluate expression...
return ToolResult.success(result.toString())
}
}Swift:
struct CalculatorTool: Tool {
let name = "calculator"
let description = "Performs arithmetic calculations"
let parameters = [
ToolParameter(name: "expression", description: "Math expression", type: .string)
]
func execute(arguments: [String: Any]) async throws -> ToolResult {
guard let expr = arguments["expression"] as? String else {
return .error("Missing expression")
}
// Evaluate expression...
return .success(result)
}
}Kotlin:
// Create executor and register tools
val executor = AgentExecutor()
executor.registerTool(CalculatorTool())
executor.registerTool(WebSearchTool())
// Get tool definitions for LLM prompt
val systemPrompt = """
You are a helpful assistant.
${executor.getToolDefinitionsForPrompt()}
"""
// Process LLM response
val llmResponse = """{"name": "calculator", "parameters": {"expression": "2 + 2"}}"""
val result = executor.processToolCall(llmResponse)
if (result != null) {
println("Tool: ${result.toolName}")
println("Result: ${result.data}")
// Feed observation back to LLM
val observation = executor.formatObservation(result.result)
}Swift:
// Create executor and register tools
let executor = AgentExecutor()
try executor.registerTool(CalculatorTool())
try executor.registerTool(WebSearchTool())
// Get tool definitions for LLM prompt
let systemPrompt = """
You are a helpful assistant.
\(executor.getToolDefinitionsForPrompt())
"""
// Process LLM response
let llmResponse = #"{"name": "calculator", "parameters": {"expression": "2 + 2"}}"#
let result = await executor.processToolCall(llmResponse)
if let result = result {
print("Tool: \(result.toolName)")
print("Result: \(result.data)")
// Feed observation back to LLM
let observation = executor.formatObservation(result.result)
}Kotlin:
// Use MCP-enabled executor
val executor = McpAgentExecutor()
// Add MCP server (tools are automatically registered)
val toolCount = executor.addMcpServer(
serverUrl = "https://my-mcp-server.com/mcp",
transport = McpTransport.HTTP,
headers = mapOf("Authorization" to "Bearer token")
)
println("Added $toolCount tools from MCP server")
// Now both local and MCP tools can be used
val result = executor.processToolCall(llmResponse)
// Remove server when done
executor.removeMcpServer("https://my-mcp-server.com/mcp")Swift:
// Create MCP client
let client = McpClient()
try await client.connect(
url: "https://my-mcp-server.com/mcp",
headers: ["Authorization": "Bearer token"]
)
// List and wrap tools
let mcpTools = try await client.listTools()
let wrappedTools = mcpTools.toWrappedTools(
serverUrl: "https://my-mcp-server.com/mcp",
mcpClient: client
)
// Register with executor
for tool in wrappedTools {
try executor.registerTool(tool)
}The Tool interface defines a callable function for AI agents:
| Property | Description |
|---|---|
name |
Unique identifier (alphanumeric + underscores) |
description |
Human-readable description for LLM |
parameters |
List of ToolParameter definitions |
execute() |
Async function that executes the tool |
Results include categorized errors to help LLMs self-correct:
| Error Type | Description |
|---|---|
TOOL_NOT_FOUND |
Tool doesn't exist - check available tools |
INVALID_ARGUMENTS |
Wrong types or missing required params |
EXECUTION_FAILED |
Runtime error - try different approach |
NETWORK_ERROR |
Service unavailable - retry or inform user |
TIMEOUT |
Request timed out |
Two formats are supported for tool definitions:
- JSON (default) - Compatible with Google AI and OpenAI function calling
- XML - Compatible with Claude's tool use format
// JSON format (default)
val jsonPrompt = registry.getToolDefinitionsForPrompt(ToolPromptFormat.JSON)
// XML format
val xmlPrompt = registry.getToolDefinitionsForPrompt(ToolPromptFormat.XML)The library implements the Model Context Protocol for remote tool servers:
- Transport: HTTP and SSE (Server-Sent Events)
- Protocol: JSON-RPC 2.0
- Operations:
tools/list,tools/call - Authentication: Custom headers support
┌─────────────────────────────────────────┐
│ Your Application │
└───────────────┬─────────────────────────┘
│
┌───────────────▼─────────────────────────┐
│ AgentExecutor │
│ (or McpAgentExecutor for MCP) │
└───────────────┬─────────────────────────┘
│
┌───────────────▼─────────────────────────┐
│ ToolRegistry │
│ • Local Tools │
│ • MCP Tool Wrappers │
└───────────────┬─────────────────────────┘
│
┌───────┴───────┐
│ │
┌───────▼───────┐ ┌─────▼───────┐
│ Local Tools │ │ McpClient │
│ (in-process) │ │ (HTTP/SSE) │
└───────────────┘ └─────┬───────┘
│
┌───────▼───────┐
│ MCP Server │
│ (remote) │
└───────────────┘
Licensed under the Apache License, Version 2.0. See LICENSE for details.
Contributions welcome! Please see CONTRIBUTING.md for guidelines.