A2A Swift SDK
April 21, 2026 · View on GitHub
A Swift library for building and consuming agentic applications following the Agent2Agent (A2A) Protocol.
✨ Features
- A2A Protocol Compliance: Build agentic applications that adhere to the Agent2Agent (A2A) v1.0 Protocol Specification.
- Client & Server SDKs: High-level APIs for both serving agentic functionality (
A2AServer) and consuming it (A2AClient). - Multi-Transport Support: Protocol bindings for REST and JSON-RPC over SSE, with automatic transport negotiation.
- Extensible & Pluggable: Extension points for custom transports, authentication middleware, and task store backends.
- v0.3 Compatibility: Transparent backward-compatibility layer for legacy A2A v0.3 servers.
Note: The SDK version is distinct from the A2A specification version. The supported protocol version is
1.0.
🚀 Getting Started
Requires Swift 5.9+, Xcode 15+, and one of: iOS 16 / macOS 13 / tvOS 16 / watchOS 9 / visionOS 1
Add the package to your Package.swift:
dependencies: [
.package(url: "https://github.com/BBC6BAE9/a2a-swift", from: "1.0.0"),
],
targets: [
// Client only
.target(name: "YourTarget", dependencies: ["A2AClient"]),
// Server only
.target(name: "YourTarget", dependencies: ["A2AServer"]),
// Both
.target(name: "YourTarget", dependencies: ["A2AClient", "A2AServer"]),
]
💡 Examples
Server
-
Implement your agent logic by conforming to
AgentExecutor:import A2AServer import A2ACore struct EchoExecutor: AgentExecutor { func execute(context: ExecutorContext) -> AsyncThrowingStream<AgentEvent, Error> { AsyncThrowingStream { continuation in var done = TaskStatusUpdateEvent() done.taskID = context.taskID done.status = TaskStatus.with { \$0.state = .completed \$0.message = context.message } continuation.yield(.statusUpdate(done)) continuation.finish() } } } -
Build the request handler and server:
let agentCard = AgentCard.with { \$0.name = "Echo Agent" \$0.description_p = "Echoes your message back" \$0.version = "1.0.0" \$0.capabilities = AgentCapabilities.with { \$0.streaming = true } } let handler = DefaultRequestHandler(executor: EchoExecutor()) let server = A2AServer(handler: handler, agentCard: agentCard) -
Dispatch requests from your HTTP framework (Vapor, Hummingbird, etc.):
let req = ServerRequest(method: method, path: path, body: body, headers: headers) let result = await server.handle(req) // Write result.statusCode / result.headers / result.body to your response
Client
-
Resolve an
AgentCardto discover how an agent is exposed:import A2AClient let resolver = AgentCardResolver(url: "https://agent.example.com") let card = try await resolver.resolve() -
Create a client — transport is negotiated automatically from the card:
let client = A2AClient(url: "https://agent.example.com") -
Send requests:
import A2ACore let msg = A2ACore.Message.with { \$0.messageID = UUID().uuidString \$0.role = .user \$0.parts = [Part.with { \$0.text = TextPart.with { \$0.text = "Hello!" } }] } let response = try await client.messageSend(msg) -
Or stream responses over SSE:
for try await event in client.messageStream(msg) { switch event.result { case .statusUpdate(let e): print("State:", e.status.state) case .artifactUpdate(let e): print("Artifact:", e.artifact.name) default: break } }
🔧 Middleware (Handlers)
Chain handlers to intercept every request/response cycle:
let client = A2AClient(
url: "https://agent.example.com",
handlers: [
LoggingHandler(level: .debug),
AuthHandler(credentialsService: myCredentialStore),
ExtensionActivator(extensionURIs:
"https://a2aprotocol.ai/extensions/thinking/v1"
),
]
)
Implement your own by extending PassthroughContextualHandler:
class RetryHandler: PassthroughContextualHandler {
override func handleRequest(_ request: A2ARequest) async throws -> [String: Any] {
// Modify or log before sending
return try await next(request)
}
}
🌐 More Examples
You can find more detailed examples in the a2a-samples repository.
🤝 Contributing
Contributions are welcome! Please open an issue to discuss your proposed approach before starting work on a new feature or significant change.
📄 License
This project is licensed under the Apache 2.0 License. See the LICENSE file for more details.