Swiftmcp — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Swiftmcp (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
A Swift Package that implements an MCP (Model Context Protocol) client for iOS and macOS, enabling native API integration through a JSON-RPC interface. The package also includes an OpenAI-compatible function calling bridge.
Add the following dependency to your Package.swift file:
dependencies: [
.package(url: "https://github.com/compiler-inc/SwiftMCP.git", from: "1.0.0")
]import SwiftMCP
// Create a tool registry
let registry = ToolRegistry()
// Create an MCP client with a response handler
let client = MCPClient(toolRegistry: registry) { response in
print("Received response: \(response)")
}
// Register tools
do {
let healthKitTool = try HealthKitTool()
registry.register(tool: healthKitTool)
} catch {
print("Failed to initialize HealthKit tool: \(error)")
}This example demonstrates:
The flow allows OpenAI to:
getData actiongetWorkouts actionimport SwiftMCP
import OpenAI
// 1. Set up MCP client and tools
let registry = ToolRegistry()
let client = MCPClient(toolRegistry: registry) { response in
print("Received response: \(response)")
}
// Initialize HealthKit tool
let healthKitTool = try HealthKitTool()
registry.register(tool: healthKitTool)
// 2. Set up OpenAI bridge
let openAIRegistry = OpenAIToolRegistry()
let healthKitSchema = JSONSchema(
type: .object,
properties: [
"action": .init(type: .string, enum: ["getData", "getWorkouts"]),
"dataType": .init(type: .string, description: "Type of health data to retrieve (e.g., stepCount, heartRate)"),
"timeRange": .init(type: .string, enum: ["today", "yesterday", "this_week", "last_week"]),
"workoutType": .init(type: .string, enum: ["running", "cycling", "walking"]),
"includeRoutes": .init(type: .boolean)
],
required: ["action"]
)
// Register the HealthKit tool with its schema
openAIRegistry.registerTool(healthKitTool, schema: healthKitSchema)
// 3. Get OpenAI function definitions
let functions = try openAIRegistry.getOpenAIFunctions()
// 4. Create OpenAI client and chat request
let openAI = OpenAI(apiToken: "your-api-key")
let query = "What was my step count today and how many calories did I burn in my last run?"
let chatRequest = ChatRequest(
model: .gpt4o,
messages: [
.init(role: .user, content: query)
],
functions: functions,
functionCall: "auto"
)
// 5. Send request to OpenAI
let result = try await openAI.chat(request: chatRequest)
// 6. Handle any tool calls from OpenAI
if let toolCalls = result.choices.first?.message.toolCalls {
// Process each tool call through MCP
let toolResponses = try await openAIRegistry.handleToolCalls(toolCalls)
// 7. Send follow-up request to OpenAI with tool results
let followUpRequest = ChatRequest(
model: .gpt4,
messages: [
.init(role: .user, content: query),
result.choices.first!.message,
.init(role: .assistant, content: nil, toolCalls: toolResponses)
]
)
// 8. Get final summarized response
let finalResult = try await openAI.chat(request: followUpRequest)
print(finalResult.choices.first?.message.content ?? "No response")
}Note: Make sure to handle errors appropriately and replace "your-api-key" with your actual OpenAI API key.
// Create and set up the OpenAI bridge
let openAIRegistry = OpenAIToolRegistry()
// Register your MCP tools with their schemas
openAIRegistry.registerTool(healthKitTool, schema: healthKitToolSchema)
// Get OpenAI function definitions
let functions = try openAIRegistry.getOpenAIFunctions()
// Handle OpenAI tool calls
let toolCalls: [OpenAIBridge.ToolCall] = ... // from OpenAI response
let toolResponses = try await openAIRegistry.handleToolCalls(toolCalls)// Example JSON-RPC request for health data
let request = JSONRPCRequest(
jsonrpc: "2.0",
method: "healthKit",
params: [
"action": .string("getData"),
"dataType": .string("stepCount"),
"timeRange": .string("today")
],
id: "1"
)
// Example JSON-RPC request for workouts
let workoutRequest = JSONRPCRequest(
jsonrpc: "2.0",
method: "healthKit",
params: [
"action": .string("getWorkouts"),
"workoutType": .string("running"),
"includeRoutes": .bool(true),
"timeRange": .string("last_week")
],
id: "2"
)
if let data = try? JSONEncoder().encode(request) {
try await client.handleIncomingMessage(data: data)
}class CustomTool: MCPTool {
let methodName = "custom/method"
func handle(params: [String: JSON]) async throws -> [String: JSON] {
// Implement your custom functionality here
return [
"status": .string("success"),
"result": .object(["data": .string("your data here")])
]
}
}Provides comprehensive access to HealthKit data through the MCP interface.
#### Methods
healthKitgetData: Retrieve health metricsdataType: Type of health data to retrieve (e.g., "stepCount", "heartRate")timeRange (optional): Predefined range ("today", "yesterday", "this_week", etc.)duration (optional): ISO 8601 duration string (e.g., "P7D" for 7 days)dataType: The type of data retrievedunit: The unit of measurementsamples: Array of data points with values and timestampsgetWorkouts: Retrieve workout dataworkoutType (optional): Type of workout to filter by (e.g., "running", "cycling")includeRoutes (optional): Boolean to include GPS route datatimeRange (optional): Predefined rangeduration (optional): ISO 8601 duration stringworkouts: Array of workout data including:type: Workout typestartDate: Start timestampendDate: End timestampduration: Duration in secondsdistance (optional): Distance in meterscalories (optional): Energy burned in kilocaloriesroute (optional): Array of GPS coordinates with timestampsThe package uses the MCPError type for error handling, which includes:
toolNotFound: When the requested method doesn't existinvalidParams: When the request parameters are invalidtoolError: Generic error case for tool-specific errors with a descriptive messagejsonParsingError: When JSON parsing failsinvalidRequest: When the JSON-RPC request format is invalidI want to add as many iOS APIs as possible to this repo. The goal is to create a comprehensive collection of MCP-compatible tools for iOS development.
Any contributions are welcome! Please feel free to submit a PR.
This project is licensed under the MIT License - see the LICENSE file for details.
SwiftMCP now includes support for function calling (tool use) with MLX models running locally on-device. This feature allows you to leverage the power of local large language models with tool use capabilities without relying on external API services.
To use MLX Swift function calling, first add the MLX Swift dependency to your project:
dependencies: [
.package(url: "https://github.com/compiler-inc/SwiftMCP.git", from: "1.0.0")
.package(url: "https://github.com/ml-explore/mlx-swift", from: "0.21.0")
]This example demonstrates:
import SwiftMCP
import MLX
// 1. Set up MLX Tool Registry
let mlxRegistry = MLXToolRegistry()
// 2. Register tools
let weatherTool = WeatherTool()
mlxRegistry.registerTool(weatherTool, schema: WeatherTool.getJSONSchema())
// 3. Create model handler and load model
let modelType = MLXModelFactory.detectModelType(from: modelURL)
let modelHandler = MLXModelFactory.createModelHandler(
modelType: modelType,
toolRegistry: mlxRegistry
)
try await modelHandler.loadModel(from: modelURL)
// 4. Generate text with function calling
let prompt = "What's the weather like in San Francisco?"
let response = try await modelHandler.generateWithFunctionCalling(
prompt: prompt,
systemPrompt: "You are a helpful assistant with access to weather information.",
parameters: [
"temperature": 0.7,
"max_tokens": 1024
]
)
print(response)The MLX integration currently supports the following model architectures:
Models need to be in the MLX format, which can be obtained by converting models from Hugging Face using the MLX conversion tools. For detailed instructions, visit the MLX repository.
Creating tools for MLX models follows the same pattern as other tools in SwiftMCP:
class CustomTool: MCPTool {
let methodName = "custom/method"
func handle(params: [String: JSON]) async throws -> [String: JSON] {
// Implement your custom functionality here
return [
"status": .string("success"),
"result": .object(["data": .string("your data here")])
]
}
static func getJSONSchema() -> String {
return """
{
"type": "function",
"function": {
"name": "custom_method",
"description": "Performs a custom operation",
"parameters": {
"type": "object",
"properties": {
"param1": {
"type": "string",
"description": "First parameter"
},
"param2": {
"type": "number",
"description": "Second parameter"
}
},
"required": ["param1"]
}
}
}
"""
}
}~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.