a2a-cpp C++20 Agent2Agent (A2A) SDK Documentation
a2a-cpp is a C++20 SDK for building Agent2Agent (A2A) protocol clients and servers. The current documented release focuses on production-oriented protocol coverage: REST, JSON-RPC, and gRPC transports; Agent Card discovery; task lifecycle APIs; streaming; push notification configuration APIs; authentication metadata propagation; interceptors; CMake package exports; and vcpkg-oriented packaging.
What is included
- Client API:
SendMessage,GetTask,ListTasks,CancelTask, streaming send/subscribe, and task push-notification config lifecycle calls. - Server API: executor-driven dispatch for REST, JSON-RPC, and gRPC transports.
- Discovery: public and extended Agent Card fetch plus preferred-interface resolution.
- Streaming: client observers, cancellable stream handles, and server stream sessions.
- Authentication hooks: client credential providers and server request metadata extraction.
- Operational extensions: client/server interceptors, required-extension validation, task stores, task history ordering, UUIDv7 task IDs, and optional PostgreSQL stores.
- Build integration: CMake 3.25+, C++20, installable CMake package exports, generated protobuf headers, and vcpkg overlay/public-registry preparation.
Recommended reading path
- Installation and Build for toolchain requirements and CMake options.
- Quickstart for a copy/paste example flow.
- Client Overview or Server Overview, depending on your integration role.
- Transports, Streaming, and Authentication for runtime design decisions.
- API Reference when you need generated public-header details.
Version and support notes
- See Releases and Versions for current release details and versioning guidance.
- The SDK is C++20-only and exports CMake targets under the
a2a::namespace. - Package documentation describes vcpkg workflows only.
- Examples are deterministic and are intended to run without external services unless the example README says otherwise.
Installation and Build
This page reflects the current build surface for the latest documented release.
Choose an integration method
Use the workflow that matches your application:
- Build the SDK directly from source as described below.
- Use CMake
FetchContentand pin a release tag or reviewed commit. - Install the SDK as a CMake package and consume it with
find_package. - Consume the repository-local
vcpkgoverlay port.
Prerequisites
Install these tools before configuring the repository:
- CMake 3.25 or newer.
- A C++20 compiler: GCC, Clang, AppleClang, or Visual Studio 2022.
- Protobuf with
protoc. - gRPC C++ with
grpc_cpp_plugin. - libcurl when using the built-in HTTP, JSON-RPC, or SSE clients.
clang-formatandclang-tidyfor contributor validation.- Optional: Doxygen for API reference generation.
- Optional: PostgreSQL client libraries when building PostgreSQL-backed stores.
Debian or Ubuntu
./scripts/install_build_deps.sh
cmake --version
The installer supports Debian and Ubuntu. Confirm that the installed CMake version is 3.25 or newer. Some older distributions, including Ubuntu 22.04, provide an older CMake package and require a newer CMake installation from another source.
The same script also supports Windows when run from Git Bash.
macOS
brew install cmake ninja protobuf grpc re2 abseil curl
When enabling PostgreSQL-backed stores, also install the PostgreSQL client package:
brew install libpq
Windows Git Bash
Install Visual Studio 2022 with the Desktop development with C++ workload and Git for Windows. Open Git Bash in the repository root and run:
./scripts/install_build_deps.sh
The script first checks VCPKG_ROOT, then searches for vcpkg.exe or vcpkg on PATH, and then checks $HOME/vcpkg. It clones and bootstraps vcpkg under ${VCPKG_ROOT:-$HOME/vcpkg} only when an existing installation is not found. It installs the dependencies declared by the root vcpkg.json and prints the resolved VCPKG_ROOT, target triplet, and host triplet when it finishes.
Override VCPKG_ROOT, VCPKG_TARGET_TRIPLET, or VCPKG_HOST_TRIPLET before running the script when needed. Keep the resolved VCPKG_ROOT value for the CMake configuration step below; do not reset it to $HOME/vcpkg when the script found vcpkg elsewhere.
The root manifest does not install PostgreSQL client libraries. For PostgreSQL-enabled Windows builds, use a vcpkg manifest that includes libpq, or consume the SDK through the repository overlay port with its postgres-store feature. See Build with vcpkg.
Configure from source
On Linux:
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
On macOS, use the same Homebrew prefixes validated by CI:
cmake -S . -B build -G Ninja \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-DCMAKE_PREFIX_PATH="$(brew --prefix);$(brew --prefix curl)"
When A2A_ENABLE_POSTGRES_STORE=ON, append $(brew --prefix libpq) to CMAKE_PREFIX_PATH.
On Windows Git Bash, set VCPKG_ROOT to the value printed by install_build_deps.sh or to an existing vcpkg checkout:
export VCPKG_ROOT="/path/to/vcpkg"
export VCPKG_TARGET_TRIPLET="${VCPKG_TARGET_TRIPLET:-x64-windows}"
export VCPKG_HOST_TRIPLET="${VCPKG_HOST_TRIPLET:-$VCPKG_TARGET_TRIPLET}"
cmake -S . -B build -G "Visual Studio 17 2022" -A x64 \
-DCMAKE_TOOLCHAIN_FILE="$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" \
-DVCPKG_TARGET_TRIPLET="$VCPKG_TARGET_TRIPLET" \
-DVCPKG_HOST_TRIPLET="$VCPKG_HOST_TRIPLET"
If a build directory was first configured without the vcpkg toolchain, delete it before reconfiguring. CMake caches the toolchain during the first configure.
Useful options:
| Option | Default | Purpose |
|---|---|---|
A2A_ENABLE_TESTING | ON | Builds unit and integration tests. |
A2A_BUILD_EXAMPLES | ON | Keeps the root project compatible with example-related CI messaging; curated examples are built as standalone consumers. |
A2A_BUILD_BENCHMARKS | OFF | Builds the optional Google Benchmark suite. |
A2A_ENABLE_LIBCURL | ON | Enables default outbound HTTP and SSE support when CURL::libcurl is found. |
A2A_ENABLE_POSTGRES_STORE | OFF | Builds PostgreSQL task and push-notification stores. |
Build and test
Linux or macOS:
cmake --build build --parallel
ctest --test-dir build --output-on-failure
Windows Visual Studio generators are multi-configuration; run these commands from Git Bash:
cmake --build build --config RelWithDebInfo --parallel
ctest --test-dir build -C RelWithDebInfo --output-on-failure
Generate only protobuf outputs when needed:
cmake --build build --target a2a_proto_codegen
Generated A2A headers are written under build/generated/a2a/v1/. Generated Google API annotation headers are written under build/generated/google/api/. Both sets are installed with the SDK.
Install CMake package artifacts
cmake --install build --prefix /tmp/a2a-cpp-install
On a Visual Studio build, also pass --config RelWithDebInfo.
The install tree includes public headers, generated protobuf headers, libraries, and CMake package files under ${CMAKE_INSTALL_LIBDIR}/cmake/a2a_cpp, commonly lib/cmake/a2a_cpp.
Contributor validation
For code changes in a Linux CI-compatible environment, run the canonical validation script before opening or updating a PR:
./scripts/verify_changes.sh
The script runs the same main validation categories as CI: formatting, configure/build, tests, and clang-tidy. It runs clang-format -i first and can modify tracked C and C++ files, so review git diff after it completes.
The current script assumes a Unix environment with nproc and a single-configuration build. On macOS or Windows, use the platform-specific configure, build, and test commands above and run the required formatting and clang-tidy checks separately.
For documentation-only mdBook changes, build the book:
mdbook build book
Quickstart: Build and Run Examples
The curated examples build app sources the same way downstream applications consume the SDK.
1. Install dependencies
Follow the platform instructions in Installation and Build. On Windows, run the repository helper from Git Bash before the example runner:
./scripts/install_build_deps.sh
2. Run the smallest end-to-end example
Linux or macOS:
./scripts/run_examples.sh build-example hello_agent
Windows Git Bash cleanup and rebuild:
rm -rf build-example-hello_agent
./scripts/run_examples.sh build-example hello_agent
The executable is written to build-example-hello_agent/a2a_example on single-configuration generators and to build-example-hello_agent/RelWithDebInfo/a2a_example.exe with Visual Studio.
hello_agent creates a minimal in-process client/server flow and exits deterministically.
3. Try transport-specific examples
./scripts/run_examples.sh build-example rest_server json_rpc_server grpc_server
These examples cover server transport setup and deterministic request handling across REST, JSON-RPC, and gRPC.
4. Try streaming, push, and auth examples
./scripts/run_examples.sh build-example streaming_client streaming_server push_notifications auth_policy_server
Use these when validating event streams, webhook configuration flows, or server-side auth metadata policy shapes. On Windows, the runner automatically forwards the vcpkg toolchain and locates the Visual Studio configuration output when VCPKG_ROOT is set.
5. Consume an installed SDK package
After installing the SDK into a prefix, build the same app source with find_package(a2a_cpp CONFIG REQUIRED):
cmake -S examples/installed_package_consumer -B build-installed-example \
-DCMAKE_PREFIX_PATH=/tmp/a2a-cpp-install \
-DA2A_EXAMPLE_APP=hello_agent
cmake --build build-installed-example --parallel
./build-installed-example/a2a_example
For Visual Studio, add --config RelWithDebInfo to the build and run build-installed-example/RelWithDebInfo/a2a_example.exe.
6. Validate your local checkout
./scripts/verify_changes.sh
For documentation-only edits, use mdbook build book instead of the full code validation flow.
Client Overview
Use a2a::client::A2AClient with a concrete ClientTransport to call A2A servers.
Client capabilities
SendMessageGetTaskListTasksCancelTaskSendStreamingMessageSubscribeTaskCreateTaskPushNotificationConfigGetTaskPushNotificationConfigListTaskPushNotificationConfigsDeleteTaskPushNotificationConfig- Client interceptors via
ClientInterceptor - Per-call settings through
CallOptions
Typical flow
- Fetch an Agent Card with
DiscoveryClient. - Select an endpoint with
AgentCardResolver::SelectPreferredInterface. - Construct
HttpJsonTransport,JsonRpcTransport, orGrpcTransport. - Create
A2AClientwith the transport. - Invoke task, streaming, or push-notification APIs.
- Call
Destroy()during shutdown when you need transport cleanup.
Default outbound HTTP
When libcurl is available and A2A_ENABLE_LIBCURL=ON, default constructors/factories can perform buffered outbound REST, JSON-RPC, and discovery calls. For tests, custom TLS policy, mTLS, retries, or embedded runtimes, inject your own requester/fetcher callbacks.
Runnable examples
examples/apps/hello_agent/main.cppexamples/apps/simple_client/main.cppexamples/apps/streaming_client/main.cppexamples/apps/push_notifications/main.cpp
Sending Messages
A2AClient::SendMessage starts or continues a task by sending a protobuf lf::a2a::v1::SendMessageRequest through the configured transport.
Request construction guidance
- Set a stable
message.message_idfor idempotency and diagnostics. - Let the server generate a task ID for new work unless you are intentionally continuing an existing task.
- Attach push-notification config only when the target Agent Card advertises support and your server policy allows it.
- Use
CallOptionsfor per-call deadlines, metadata, or auth settings where supported by the transport.
Response handling
The response can contain immediate task state and output data. Persist task identifiers in logs/telemetry so later GetTask, CancelTask, streaming subscription, or push-notification calls can be correlated.
Failure paths to test
- Network or HTTP/gRPC transport failure.
- Serialization or protocol validation failure.
- Auth policy rejection.
- Unsupported operation or required extension mismatch.
- Duplicate/retry behavior for repeated message IDs.
Related pages
Discovery and Agent Cards
Discovery resolves server capabilities before constructing a client transport.
Public and extended cards
DiscoveryClient supports:
Fetch(base_url)for the standard Agent Card.FetchExtendedAgentCard(base_url)for the extended Agent Card endpoint.
Fetched cards are cached for kDefaultDiscoveryCacheTtl (300 seconds) unless a different TTL is supplied.
Interface resolution
AgentCardResolver::SelectPreferredInterface(card, preferred) selects a ResolvedInterface for one of:
PreferredTransport::kRestPreferredTransport::kJsonRpcPreferredTransport::kGrpc
The result includes the transport, URL, security requirements, and security schemes needed to configure a client.
Operational guidance
- Validate and log the selected endpoint during startup.
- Prefer an explicit fallback order when cards advertise multiple transports.
- Treat discovery metadata as untrusted input until validated.
- Refresh cached cards after deployment or capability changes.
Related files
include/a2a/client/discovery.hinclude/a2a/core/agent_card/agent_card_provider.hinclude/a2a/server/agent_card/agent_card_serializer.h
Get Task and List Tasks
GetTask retrieves a single task by ID. ListTasks returns a paginated list of tasks through the client abstraction and supported transports.
GetTask flow
- Store the task ID from
SendMessageor a stream event. - Build
lf::a2a::v1::GetTaskRequest. - Call
A2AClient::GetTask. - Interpret task status, artifacts, and history according to your application policy.
ListTasks flow
a2a::client::ListTasksRequest contains:
page_sizepage_token
The response includes task values plus next_page_token.
An omitted page size requests the protocol default of at most 50 tasks. Explicit
page sizes must be between 1 and 100. Continue until next_page_token is empty:
a2a::client::ListTasksRequest request{.page_size = 50};
do {
const auto page = client.ListTasks(request);
if (!page.ok()) {
return page.error();
}
for (const auto& task : page.value().tasks) {
ProcessTask(task);
}
request.page_token = page.value().next_page_token;
} while (!request.page_token.empty());
Keep pages bounded (normally no more than 100 tasks) and request a small
history_length, often 0 or 1, unless deeper history is required. CPU cost grows
with both the returned task count and retained history. Oversized results also
increase protobuf allocations and copies, response memory, serialized payload
size, transport latency, and timeout risk. In-memory stores hold their shared
read lock longer while materializing a result, so writes may wait longer. Full
history projection can dominate the list operation.
Operational guidance
- Use bounded polling with backoff when not using streaming.
- Enforce authorization checks on server-side task visibility.
- Avoid exposing full task history to clients that do not need it.
Cancel Task
A2AClient::CancelTask asks the server to cancel in-flight work.
When to use cancellation
- A user aborts an operation.
- A deadline expires upstream.
- Supervising logic needs to reclaim compute or queue capacity.
Semantics
Cancellation is best-effort. A task can complete before the cancellation request is processed, and servers can reject cancellation for completed, unknown, or policy-protected tasks.
Recommended behavior
- Make higher-level cancellation idempotent.
- Return or display the latest task state after cancellation attempts.
- Preserve enough audit data to explain whether the task was canceled, completed, or rejected.
Server Overview
Server integrations implement a2a::server::AgentExecutor and route protocol requests through Dispatcher plus one or more transports.
Server capabilities
- REST server transport.
- JSON-RPC server transport.
- gRPC service transport.
- Public and extended Agent Card dispatch when a provider is installed.
- Required extension validation.
- Server interceptors.
- Streaming through
ServerStreamSession. - Task lifecycle helpers, in-memory task store, and optional PostgreSQL stores.
- Push-notification config CRUD and delivery service abstractions.
Core flow
- Implement an executor for task and message behavior.
- Create a
Dispatcherwith the executor and optional Agent Card provider/interceptors. - Attach REST, JSON-RPC, or gRPC transport adapters.
- Convert inbound framework requests into transport calls.
- Return structured protocol errors instead of transport-specific ad hoc errors.
Task IDs
When an incoming message does not carry message.task_id, the SDK service layer can generate server-side task IDs using UUIDv7. UUIDv7 is sortable and operationally useful, but it leaks approximate creation time. Inject a custom task ID generator if your deployment needs opaque identifiers.
Custom Executors
Implement a2a::server::AgentExecutor to define application behavior.
Required methods
Executors implement task/message operations including:
SendMessageSendStreamingMessageGetTaskListTasksCancelTask
Push-notification config methods have default PushNotificationNotSupported behavior and should be overridden only when the server actually supports them.
Request context
Every executor method receives RequestContext. Use it for auth metadata, transport metadata, and request-scoped policy decisions. Treat metadata as untrusted until validated.
Design guidance
- Keep executor methods small and deterministic.
- Validate inputs at the boundary.
- Return
a2a::core::Result<T>with structured errors. - Avoid shared mutable state unless synchronized and documented.
- Unit-test executor behavior separately from transport mapping.
REST Server Transport
RestServerTransport maps HTTP+JSON requests onto dispatcher operations.
Responsibilities
- Validate HTTP method, path, and content type.
- Parse JSON request bodies into protobuf messages.
- Populate
RequestContext, including auth metadata. - Serialize protocol responses and errors back to HTTP responses.
Supported operation shape
REST transport covers core task lifecycle operations, streaming-compatible endpoints where wired by the hosting environment, Agent Card routes, and push-notification config APIs exposed by the dispatcher/executor.
Hosting guidance
The SDK provides protocol mapping, not a full production web server framework. In production, place it behind an HTTP runtime that owns TLS, connection limits, request-size limits, access logs, and graceful shutdown.
Example
See examples/apps/rest_server/main.cpp.
JSON-RPC Server Transport
JsonRpcServerTransport maps JSON-RPC 2.0 method calls to dispatcher operations.
Responsibilities
- Validate the
jsonrpc,id,method, andparamsenvelope fields. - Route supported A2A methods to the dispatcher.
- Return JSON-RPC error objects for invalid requests, unknown methods, and executor failures.
- Preserve request metadata for auth and audit policy.
Use cases
Use JSON-RPC when method-based routing is easier to integrate than resource-oriented REST paths or when another system already standardizes on JSON-RPC 2.0.
Example
See examples/apps/json_rpc_server/main.cpp.
Storage Backends
The SDK storage layer is pluggable. TaskLifecycleService uses TaskStore, and
PushNotificationService uses PushNotificationStore.
In-memory stores
Use InMemoryStoreFactory for examples, tests, and single-process development:
a2a::server::stores::InMemoryStoreFactory factory;
auto stores = factory.CreateStoreBundle();
In-memory stores do not persist data or coordinate across processes.
PostgreSQL stores
PostgreSQL support is optional. Enable and link the PostgreSQL store target:
cmake -S . -B build-postgres -DA2A_ENABLE_POSTGRES_STORE=ON
cmake --build build-postgres
a2a::server::stores::PostgresStoreFactory factory({
.connection_string = "postgresql://a2a:a2a@127.0.0.1:5432/a2a",
.schema = "public",
.auto_create_schema = true,
.connection_pool_size = 8,
});
auto stores = factory.CreateStoreBundle();
Task and push-notification stores returned by CreateStoreBundle() share one
connection pool. Separately constructed stores own separate pools. Storage
matching uses libpq’s active connection target (selected host, resolved server
address, active port, and database) plus the configured target_session_attrs
value and schema. Exact coordinate equality confirms local authority; a
different database or schema confirms external authority; other endpoint
differences are uncertain. Separately constructed stores can set
PostgresStoreOptions::storage_authority_id: matching non-empty IDs prove local
authority, different non-empty IDs prove external authority, and a one-sided ID
remains uncertain. Database/schema differences still remain external. The ID is
a stable, non-secret deployment identifier and must reflect the real storage
authority because it affects provenance and cleanup. Passwords and raw
connection strings are not part of the identity. The effective role is tracked
as pool-consistency metadata, but matching endpoint/schema/role metadata does
not prove that independent sessions have the same row-security context. The
one-command list shortcut therefore requires the task and push stores to share
the exact connection pool and local storage authority. Separately constructed
stores validate the task through the authoritative task store first, even when
their DSNs and roles look equivalent. Do not leave pooled connections with
out-of-band session state such as SET ROLE or custom policy GUCs.
Task-aware PostgreSQL behavior
For same-storage task and push stores, create/update uses one push-store
acquisition and one PostgreSQL command. That statement calls the
SECURITY DEFINER task-lock helper, holds a shared transaction advisory lock
derived from the schema-qualified task table and complete task ID, validates task
existence, and performs the upsert atomically. Task deletion obtains the matching
exclusive advisory lock in a BEFORE DELETE trigger. It has no separate task
precheck, revalidation, compensating cleanup, or explicit multi-command
transaction. Missing tasks return TaskNotFound, and concurrent deletion cannot
leave a locally owned orphan. The local task-aware path rejects repeatable-read
and serializable transaction isolation before locking because their
transaction-scoped snapshots can remain stale after a concurrent delete commits.
Under PostgreSQL read-committed semantics, the VOLATILE helper rechecks task
existence with a fresh snapshot after a lock wait. Equal task IDs in different
schemas use different advisory keys. Hash collisions can still serialize
unrelated task IDs; data access still uses the original task ID.
PushConfig_CreateMany at fan-out eight therefore performs eight create
commands rather than sixteen.
GetConfig remains push-store-only and uses one PostgreSQL statement. List uses
one combined task/count/page statement when task and push stores share a
connection pool and local storage authority; separate pools, different storage
authority, or an external task store use the authoritative task lookup first
and then one combined push-list statement. External-authority creates are marked
with local_postgres_task=FALSE; direct non-task-aware CreateOrUpdate calls
use the same external provenance. Only locally owned rows are removed by the
task-delete cleanup trigger.
When auto_create_schema=true, the SDK installs the provenance column, shared
push-lock helper, exclusive task-delete lock helper with a BEFORE DELETE
trigger, cleanup helper with an AFTER DELETE trigger, sequences, and indexes,
removes the legacy push-to-task foreign key, and writes the
task-aware-push-config-v3 migration markers last.
Externally managed PostgreSQL schemas
When auto_create_schema=false, the push-notification store always validates
the provenance column and absence of the legacy push-to-task foreign key. If the
push-lock helper, task-delete lock helper and trigger, cleanup helper, and
cleanup trigger are all absent, construction is allowed for push-only use with
an external authoritative TaskStore; local PostgreSQL task-aware creation then
fails before writing until the migration is installed. Capability detection
happens during store construction rather than on the request path.
If any task-aware helper or trigger is present, the whole
task-aware-push-config-v3 migration is required. Validation checks all helper
implementations and markers, owner privileges, absence of PUBLIC EXECUTE, the
enabled advisory-lock BEFORE DELETE and cleanup AFTER DELETE row triggers
without WHEN clauses, and the cleanup owner’s ability to bypass any row-level
security enabled on the push-config table. Partial or stale installations fail
construction.
Apply the following migration before using local PostgreSQL task-aware
create/update. The example uses the public schema and an SDK role named
a2a_sdk; replace both names for your deployment.
Grant the push-lock helper only to roles authorized to create push configurations.
The invoking push role needs task-table SELECT plus helper EXECUTE; neither
the caller nor the helper owner needs task-table UPDATE. Push-only roles paired
with an external authoritative TaskStore do not need task-table access or helper
execution. Task-table row-level security is allowed for those external-authority
paths but is rejected when the local task-aware create helper is invoked. If
push-table row-level security is enabled, the cleanup helper owner must bypass it
via table ownership without FORCE ROW LEVEL SECURITY, or via BYPASSRLS or
superuser status, so task deletion cannot silently retain local push configurations.
BEGIN;
ALTER TABLE public.a2a_push_notification_configs
ADD COLUMN IF NOT EXISTS local_postgres_task BOOLEAN NOT NULL DEFAULT FALSE;
ALTER TABLE public.a2a_push_notification_configs
DROP CONSTRAINT IF EXISTS a2a_push_configs_task_fk;
DROP INDEX IF EXISTS public.idx_a2a_push_configs_task;
DROP INDEX IF EXISTS public.idx_a2a_push_configs_created_sequence;
CREATE OR REPLACE FUNCTION public.a2a_lock_task_for_push_config(requested_task_id TEXT)
RETURNS BOOLEAN
LANGUAGE plpgsql
VOLATILE
SECURITY DEFINER
SET search_path = pg_catalog
AS $a2a$
DECLARE
caller_role NAME;
lock_key BIGINT;
BEGIN
IF pg_catalog.current_setting('transaction_isolation') IN ('repeatable read', 'serializable') THEN
RAISE EXCEPTION USING ERRCODE = '0A000', MESSAGE =
'PostgreSQL task-aware push configuration requires read-committed transaction isolation';
END IF;
lock_key := pg_catalog.hashtextextended(
requested_task_id,
pg_catalog.hashtextextended('public.a2a_tasks', 0));
IF NOT pg_catalog.pg_try_advisory_xact_lock_shared(lock_key) THEN
PERFORM pg_catalog.pg_advisory_xact_lock_shared(lock_key);
END IF;
caller_role := NULLIF(pg_catalog.current_setting('role', true), 'none');
IF caller_role IS NULL THEN
caller_role := session_user;
END IF;
IF EXISTS (
SELECT 1 FROM pg_catalog.pg_class
WHERE oid = pg_catalog.to_regclass('public.a2a_tasks') AND relrowsecurity
) THEN
RAISE EXCEPTION USING ERRCODE = '0A000', MESSAGE =
'PostgreSQL task-aware push configuration does not support row-level security on a2a_tasks';
END IF;
IF NOT pg_catalog.has_table_privilege(caller_role, 'public.a2a_tasks', 'SELECT') THEN
RAISE EXCEPTION USING ERRCODE = '42501', MESSAGE =
'PostgreSQL push store role requires SELECT on a2a_tasks for task-aware creation';
END IF;
PERFORM 1
FROM public.a2a_tasks
WHERE id = requested_task_id;
RETURN FOUND;
END
$a2a$;
REVOKE ALL ON FUNCTION public.a2a_lock_task_for_push_config(TEXT) FROM PUBLIC;
GRANT SELECT ON public.a2a_tasks TO a2a_sdk;
GRANT EXECUTE ON FUNCTION public.a2a_lock_task_for_push_config(TEXT) TO a2a_sdk;
CREATE OR REPLACE FUNCTION public.a2a_lock_task_for_delete()
RETURNS TRIGGER
LANGUAGE plpgsql
VOLATILE
SECURITY DEFINER
SET search_path = pg_catalog
AS $a2a$
BEGIN
PERFORM pg_catalog.pg_advisory_xact_lock(
pg_catalog.hashtextextended(
OLD.id,
pg_catalog.hashtextextended('public.a2a_tasks', 0)));
RETURN OLD;
END
$a2a$;
REVOKE ALL ON FUNCTION public.a2a_lock_task_for_delete() FROM PUBLIC;
DROP TRIGGER IF EXISTS a2a_lock_task_for_delete_trigger ON public.a2a_tasks;
CREATE TRIGGER a2a_lock_task_for_delete_trigger
BEFORE DELETE ON public.a2a_tasks
FOR EACH ROW
EXECUTE FUNCTION public.a2a_lock_task_for_delete();
CREATE OR REPLACE FUNCTION public.a2a_delete_task_push_configs()
RETURNS TRIGGER
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = pg_catalog
AS $a2a$
BEGIN
DELETE FROM public.a2a_push_notification_configs
WHERE task_id = OLD.id AND local_postgres_task;
RETURN OLD;
END
$a2a$;
REVOKE ALL ON FUNCTION public.a2a_delete_task_push_configs() FROM PUBLIC;
DROP TRIGGER IF EXISTS a2a_delete_task_push_configs_trigger ON public.a2a_tasks;
CREATE TRIGGER a2a_delete_task_push_configs_trigger
AFTER DELETE ON public.a2a_tasks
FOR EACH ROW
EXECUTE FUNCTION public.a2a_delete_task_push_configs();
COMMENT ON FUNCTION public.a2a_lock_task_for_delete()
IS 'task-aware-push-config-v3';
COMMENT ON FUNCTION public.a2a_delete_task_push_configs()
IS 'task-aware-push-config-v3';
COMMENT ON FUNCTION public.a2a_lock_task_for_push_config(TEXT)
IS 'task-aware-push-config-v3';
COMMIT;
The migration markers are written last inside the transaction, so partial
migrations are rejected. Existing rows receive the conservative external or
unknown provenance value from the new column’s FALSE default. The lock-helper
owner needs schema USAGE plus task-table SELECT; the task-delete lock helper
owner needs schema USAGE; and the cleanup helper owner needs schema USAGE plus
push-table SELECT and DELETE. These are SECURITY DEFINER owner requirements,
not privileges for every push-store role.
Sensitive push-notification data
Push configurations can contain callback URLs, tokens, and authentication metadata. The SDK does not implement application-level encryption at rest; use database encryption, least-privilege access, protected backups, and appropriate audit logging.
Push Notifications
The SDK includes task push-notification configuration APIs and server-side delivery abstractions.
Client API surface
A2AClient exposes:
CreateTaskPushNotificationConfigGetTaskPushNotificationConfigListTaskPushNotificationConfigsDeleteTaskPushNotificationConfig
Use these only when the target Agent Card and server policy indicate push-notification support.
Server components
PushNotificationServicecoordinates stored configs and delivery.PushNotificationStorepersists webhook configs.PushNotificationDeliveryClientabstracts outbound delivery.HttpPushNotificationDeliveryClientprovides a simple libcurl-backed synchronous delivery path when libcurl support is enabled.
Recommended executor flow
- Persist task state in your
TaskStoreorTaskLifecycleService. - Register inline configs from
SendMessageRequestwhen present. - Call
NotifyTaskUpdated(task)after status changes. - Propagate delivery failures instead of silently dropping them.
- Override push-config CRUD executor methods only when push support is fully configured.
Production guidance
For production, prefer a durable queued delivery client with retries, backoff, webhook URL validation, SSRF controls, credential protection, and delivery telemetry. Keep TLS policy at least as strong as the built-in delivery client, which requires TLS 1.2 or newer for HTTPS URLs.
Example
See examples/apps/push_notifications/main.cpp.
Server Interceptors
Server interceptors let deployments attach cross-cutting behavior around dispatcher operations.
Common uses
- Authorization and policy checks.
- Request/response telemetry.
- Audit logging.
- Metrics and latency measurement.
- Required extension enforcement in combination with transport validators.
Design guidance
- Keep interceptors deterministic and low-latency.
- Avoid logging secrets or raw credential values.
- Use structured errors so transports can map failures consistently.
- Prefer composition: keep business behavior in
AgentExecutorand cross-cutting behavior in interceptors.
Related APIs
a2a::server::ServerInterceptora2a::server::Dispatcher::AddInterceptora2a::client::ClientInterceptorfor client-side call hooks
Transports Overview
The SDK separates protocol operations from transport adapters. Applications choose the transport that best matches their deployment boundary and interoperability needs.
Available transports
- REST: HTTP+JSON resource-oriented integration for clients and servers.
- JSON-RPC: JSON-RPC 2.0 method dispatch over HTTP-style request handling.
- gRPC: protobuf/gRPC service integration with unary and streaming RPCs.
Choosing a transport
- Choose REST when your platform already standardizes on HTTP routing, gateways, or resource-style APIs.
- Choose JSON-RPC when method-style dispatch is easier to interoperate with or proxy.
- Choose gRPC when you want protobuf-native contracts, gRPC streaming, or a service mesh that already supports gRPC well.
Shared operational concerns
Regardless of transport, define these policies explicitly:
- Authentication and authorization boundaries.
- Protocol version and required-extension handling.
- Request deadlines and payload limits.
- Retry and idempotency behavior.
- Telemetry, audit logs, and stable task/request identifiers.
REST Transport
REST is the HTTP+JSON transport path for clients and servers.
Client side
Use HttpJsonTransport with A2AClient. When libcurl is enabled and found, default outbound buffered HTTP can be used. Otherwise inject an HttpRequester implementation.
Server side
Use RestServerTransport to translate inbound framework requests into dispatcher calls.
Operational considerations
- Enforce TLS and auth policy at your edge or hosting layer.
- Set explicit request deadlines and payload limits.
- Log stable task IDs and request IDs.
- Validate protocol version headers where required.
- Prefer injected requesters for custom retry, proxy, mTLS, or observability policy.
JSON-RPC Transport
JSON-RPC transport supports A2A method dispatch over JSON-RPC 2.0 envelopes.
Client side
Use JsonRpcTransport with A2AClient. Default buffered outbound HTTP is available when libcurl is enabled and found; otherwise inject a requester.
Server side
Use JsonRpcServerTransport to decode envelopes, dispatch operations, and encode JSON-RPC responses.
Operational considerations
- Validate envelope fields strictly.
- Preserve client-provided request IDs in responses.
- Map structured SDK errors to consistent JSON-RPC error responses.
- Include auth metadata in
RequestContextonly after policy validation.
gRPC Transport
gRPC support is first-class for client and server integrations.
Client side
Use a2a::client::GrpcTransport with a resolved interface and either:
- a
std::shared_ptr<grpc::Channel>for real gRPC calls, or - a custom
GrpcTransport::RpcClientfor tests and embedded adapters.
The transport supports unary task operations, streaming send, task subscription, and push-notification config lifecycle calls.
Server side
a2a::server::GrpcServerTransport implements lf::a2a::v1::A2AService::Service and routes RPCs to the dispatcher.
It supports:
SendMessageSendStreamingMessageGetTaskListTasksCancelTaskSubscribeToTask- Push-notification config RPCs
GetExtendedAgentCard
Metadata and extensions
The server transport recognizes A2A metadata such as a2a-version and can validate required extensions through GrpcServerTransportOptions::required_extensions.
Example
See examples/apps/grpc_server/main.cpp.
Streaming
Streaming is available through all production client transports:
- gRPC native server streaming;
- HTTP+JSON SSE;
- JSON-RPC response envelopes carried in SSE
data:fields.
Servers should advertise capabilities.streaming: true in their Agent Card.
Client APIs
A2AClient::SendStreamingMessage(request, observer, options)A2AClient::SubscribeTask(request, observer, options)
Implement a2a::client::StreamObserver:
OnEvent(const StreamResponse&)for each decoded event.OnError(const core::Error&)once for transport or protocol failure.OnCompleted()once after a clean remote close.
Both calls return a StreamHandle. Call Cancel() to request cancellation and IsActive() to check handle state. Destruction also cancels the request and joins its worker.
Threading contract
Observer callbacks run on transport-managed background threads. Keep observers alive until stream completion, cancellation, or handle destruction. Callback code should be thread-safe, fast, and non-blocking.
Build the streaming client example
The SDK requires gRPC and Protobuf at configure time. The default HTTP streaming transports also require libcurl.
Linux or macOS:
./scripts/run_examples.sh build-example streaming_client
Windows Git Bash:
./scripts/install_build_deps.sh
rm -rf build-example-streaming_client
./scripts/run_examples.sh build-example streaming_client
./build-example-streaming_client/RelWithDebInfo/a2a_example.exe --help
See Installation and Build and vcpkg for dependency and toolchain details.
Server side
Executors return std::unique_ptr<ServerStreamSession> from SendStreamingMessage and, optionally, SubscribeTask. A stream session publishes StreamResponse values until it returns an empty optional or an error.
Examples
examples/apps/streaming_client/main.cppexamples/apps/streaming_server/main.cpp
Authentication and Authorization Hooks
The SDK provides hooks for carrying credentials and auth metadata. Your application remains responsible for credential storage, verification, authorization decisions, and audit policy.
Client credential providers
include/a2a/client/auth.h includes providers for:
- API key headers.
- Bearer token headers.
- Custom header credentials.
- OAuth2 bearer token extension points.
Use these with transport call options or request construction paths that support metadata injection.
Server metadata
REST, JSON-RPC, and gRPC server paths populate RequestContext with transport metadata. Executor or interceptor code can read this metadata to make authorization decisions.
Policy guidance
- Never hardcode secrets in source, examples, or tests.
- Validate credentials before trusting request metadata.
- Normalize auth failures so callers receive consistent protocol errors.
- Avoid logging raw credentials.
- Prefer short-lived tokens and managed secret storage.
- Document how TLS or mTLS identity is terminated and propagated into the SDK boundary.
Example
See examples/apps/auth_policy_server/main.cpp for an auth-policy shape.
Releases and Versions
This documentation is intended to stay version-aware without embedding a release number in every page title.
Current documented release
The current documented release is v0.4.1 and is recommended for new consumers.
Highlights since v0.4.0
- Optimized PostgreSQL push-configuration create, get, list, and cleanup paths, reducing redundant task lookups, commands, and connection acquisitions while preserving authoritative task validation and concurrent-deletion safety.
- Added optimistic revision-aware task persistence to the built-in stores so
the example/TCK
SendMessagepath can persist complete task mutations with fewer PostgreSQL round trips while preserving concurrent history updates. - Added HTTP/1.1 persistent connections and connection-scoped request buffering, eliminating per-request connection churn for ordinary unary HTTP+JSON and JSON-RPC operations.
- Optimized REST query parsing and reorganized transport implementation sources under dedicated client/server transport directories without changing public include paths.
- Optimized HTTP+JSON and JSON-RPC
ListTasksparsing and serialization through typed protobuf JSON paths, with focused parser/scanner benchmarks and CI thresholds. - Hardened typed
ListTaskscompatibility validation for null values, duplicate fields, protobuf-name aliases, nested duplicate message members, escaped JSON-RPC result keys, HTTP-status classification, and protobuf integer ranges. - Added component-level transport benchmarks for JSON-RPC envelopes, ProtoJSON,
REST query parsing, response construction, and
ListTasksclient parsing. - Isolated performance fixtures from measured operations and restructured reports around concrete workload coordinates rather than mixed scenario averages.
- Expanded PostgreSQL command-level diagnostics and documented storage, performance, and transport behavior.
- Added repository-wide Conventional Commit validation in CI.
Compatibility notes
There are no intentional public API removals in v0.4.1.
The transport source-tree reorganization is internal; installed public include paths and exported CMake targets remain unchanged.
HTTP+JSON and JSON-RPC unary traffic can now reuse HTTP/1.1 connections. Explicit
Connection: close remains supported, and the existing streaming/SSE behavior
is preserved.
Valid ListTasks responses remain compatible across HTTP+JSON and JSON-RPC.
Malformed or ambiguous JSON that protobuf 3.21 could otherwise accept with
last-value-wins or null-as-unset behavior is now rejected consistently.
PostgreSQL users should allow SDK-managed schemas to migrate and validate the task-aware push-configuration helpers. Externally managed schemas should follow the storage documentation for the required schema objects and privileges.
Previous release: v0.4.0
v0.4.0 focused on configurable PostgreSQL pool sizing, bounded protocol-facing
ListTasks pagination, optimized in-memory task listing, interruptible gRPC
stream cancellation, expanded performance validation, and centralized HTTP
server response construction.
Its important compatibility changes remain in effect:
- omitted protocol-facing
ListTasks.page_sizedefaults to50; - explicit page sizes must be between
1and100; - the PostgreSQL connection pool defaults to
4unless configured otherwise.
Earlier release: v0.3.0
v0.3.0 introduced production-ready SSE streaming for HTTP+JSON and JSON-RPC,
end-to-end streaming and subscriptions across all supported transports,
report-only performance testing, repository-local vcpkg overlay packaging, and
expanded build and platform documentation.
Its TCK validation snapshot was:
- 249 tests passed
- 16 tests skipped
- 0 executed test failures
- 100.0% compatibility for tested, non-skipped requirements
Versioning guidance
- Pin CMake
FetchContentintegrations to a release tag such asv0.4.1or to a reviewed commit. - Prefer
find_package(a2a_cpp CONFIG REQUIRED)for installed SDK packages. - Keep generated protobuf headers and linked SDK libraries from the same installed package or build tree.
- Review release notes before upgrading between versions.
Documentation policy
Page titles and navigation should remain mostly version agnostic. Release-specific notes belong on this page or in clearly marked compatibility sections.
Build with CMake
a2a-cpp is a C++20 SDK built and packaged with CMake. The project can be used directly from source with FetchContent, installed into a CMake package prefix, or built with dependencies supplied by vcpkg.
Requirements
- CMake 3.25 or newer.
- A C++20 compiler.
- Protobuf and gRPC development packages.
- Optional: libcurl for the default buffered outbound HTTP implementation.
- Optional: PostgreSQL client libraries when
A2A_ENABLE_POSTGRES_STORE=ON.
On Ubuntu-like systems, the repository helper installs the dependencies used by CI:
./scripts/install_build_deps.sh
On macOS, install equivalent packages with Homebrew:
brew install cmake ninja protobuf grpc re2 abseil curl
On Windows, install Visual Studio 2022 with the Desktop development with C++ workload and Git for Windows. Then run the repository dependency helper from Git Bash:
./scripts/install_build_deps.sh
Configure from source
The default source build enables tests, keeps the curated example apps out of the top-level build, and enables libcurl-backed HTTP support when CMake can find CURL::libcurl.
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-DA2A_ENABLE_TESTING=ON
When dependencies are installed outside standard search paths, pass a CMake prefix path:
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_PREFIX_PATH="/opt/homebrew;/opt/homebrew/opt/curl"
Build and test
Single-configuration generators:
cmake --build build --parallel
ctest --test-dir build --output-on-failure
Visual Studio generators from Git Bash:
cmake --build build --config RelWithDebInfo --parallel
ctest --test-dir build -C RelWithDebInfo --output-on-failure
For the repository’s full local code validation flow, run:
./scripts/verify_changes.sh
That script runs the same main gates expected before a code PR: formatting, configure/build, tests, and clang-tidy.
CMake options
| Option | Default | Description |
|---|---|---|
A2A_ENABLE_TESTING | ON | Builds unit and integration tests and enables CTest. |
A2A_BUILD_EXAMPLES | ON | Compatibility/message-only option for the root build today; curated examples are built as standalone consumers from examples/fetch_content_consumer or examples/installed_package_consumer. |
A2A_BUILD_BENCHMARKS | OFF | Builds benchmark targets under benchmarks/. |
A2A_ENABLE_LIBCURL | ON | Enables the default libcurl-backed outbound HTTP implementation when libcurl is found. Disable it to require injected requesters/fetchers. |
A2A_ENABLE_POSTGRES_STORE | OFF | Builds PostgreSQL-backed store targets when PostgreSQL dependencies are available. |
Generated protobuf headers
The SDK generates A2A protocol C++ sources during the build. Primary generated A2A headers are written under build/generated/a2a/v1/, and generated Google API annotation headers are written under build/generated/google/api/.
Those generated headers are installed with the SDK, so downstream projects should include headers from the installed package rather than copying build-tree generated files.
Install as a CMake package
Install the SDK to a prefix:
cmake --install build --prefix /tmp/a2a-cpp-install
The install tree includes public headers, generated protobuf headers, libraries, and package configuration files under lib/cmake/a2a_cpp.
A downstream project can then consume the installed package:
cmake_minimum_required(VERSION 3.25)
project(my_a2a_app LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
find_package(a2a_cpp CONFIG REQUIRED)
add_executable(my_a2a_app main.cpp)
target_link_libraries(my_a2a_app PRIVATE a2a::client a2a::server a2a::core)
Configure that downstream project with CMAKE_PREFIX_PATH pointing at the install prefix:
cmake -S path/to/app -B build-app \
-DCMAKE_PREFIX_PATH=/tmp/a2a-cpp-install
cmake --build build-app --parallel
FetchContent consumer
For application projects that prefer source integration, use CMake FetchContent and pin GIT_TAG to a release tag or reviewed commit:
include(FetchContent)
set(A2A_ENABLE_TESTING OFF CACHE BOOL "" FORCE)
set(A2A_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
set(A2A_BUILD_BENCHMARKS OFF CACHE BOOL "" FORCE)
set(A2A_ENABLE_POSTGRES_STORE OFF CACHE BOOL "" FORCE)
FetchContent_Declare(
a2a_cpp
GIT_REPOSITORY https://github.com/MisterVVP/a2a-cpp.git
GIT_TAG v0.4.1
)
FetchContent_MakeAvailable(a2a_cpp)
target_link_libraries(my_a2a_app PRIVATE a2a::client a2a::server a2a::core)
See examples/fetch_content_consumer/ for a minimal runnable consumer.
Exported targets
Common exported targets include:
a2a::corefor shared core types and utilities.a2a::clientfor client APIs.a2a::serverfor server APIs.a2a::httpfor HTTP support internals used by higher-level targets.a2a::proto_generatedfor generated protobuf bindings.a2a::store_postgreswhen PostgreSQL store support is enabled.
Most applications should link the smallest set they use. The examples link a2a::client, a2a::server, and a2a::core for a combined client/server sample.
Build the curated examples
Use the repository runner for FetchContent examples:
./scripts/run_examples.sh build-example hello_agent
When VCPKG_ROOT is set, the runner forwards the vcpkg toolchain and optional target/host triplets. It builds RelWithDebInfo by default and finds either build-example-hello_agent/a2a_example or the Visual Studio output at build-example-hello_agent/RelWithDebInfo/a2a_example.exe.
Windows Git Bash:
./scripts/install_build_deps.sh
rm -rf build-example-hello_agent
./scripts/run_examples.sh build-example hello_agent
Platform notes
- Linux CI configures with CMake and validates build, tests, examples, clang-format, clang-tidy, coverage, and selected sanitizer/interop flows.
- macOS CI builds with Homebrew-provided dependencies and Ninja.
- Windows CI and local Windows builds use vcpkg manifest dependencies and the Visual Studio 2022 generator. See vcpkg for the helper script, manifest, triplet, and overlay details.
Build with vcpkg
a2a-cpp provides vcpkg metadata for two related workflows:
- Manifest dependency mode for building this repository with vcpkg-supplied third-party dependencies.
- Overlay port mode for consuming
a2a-cppitself as a vcpkg package before it is available from a public registry.
The repository root vcpkg.json pins the dependency baseline and declares the SDK’s third-party dependencies: protobuf, gRPC, and curl.
Prerequisites
Install or clone vcpkg and bootstrap it:
git clone https://github.com/microsoft/vcpkg.git "$HOME/vcpkg"
"$HOME/vcpkg/bootstrap-vcpkg.sh"
On Windows PowerShell:
git clone https://github.com/microsoft/vcpkg.git C:\vcpkg
C:\vcpkg\bootstrap-vcpkg.bat
Set VCPKG_ROOT for convenience:
export VCPKG_ROOT="$HOME/vcpkg"
$env:VCPKG_ROOT = 'C:\vcpkg'
Repository helper on Windows Git Bash
From the repository root, the Bash helper clones, bootstraps, and installs the vcpkg manifest dependencies:
./scripts/install_build_deps.sh
The default vcpkg checkout is $HOME/vcpkg; no fixed C:/vcpkg location is required. Override the root or triplets with environment variables:
export VCPKG_ROOT=/d/tools/vcpkg
export VCPKG_TARGET_TRIPLET=x64-windows-static
export VCPKG_HOST_TRIPLET=x64-windows
./scripts/install_build_deps.sh
Build this repository with manifest dependencies
From the repository root, let vcpkg install the manifest dependencies and then configure CMake with the vcpkg toolchain file:
"$VCPKG_ROOT/vcpkg" install
cmake -S . -B build-vcpkg \
-DVCPKG_MANIFEST_MODE=ON \
-DCMAKE_TOOLCHAIN_FILE="$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DA2A_ENABLE_TESTING=ON
cmake --build build-vcpkg --parallel
ctest --test-dir build-vcpkg --output-on-failure
On multi-config generators such as Visual Studio, pass the configuration during build and test:
& "$env:VCPKG_ROOT\vcpkg.exe" install
cmake -S . -B build-vcpkg -G "Visual Studio 17 2022" -A x64 `
-DVCPKG_MANIFEST_MODE=ON `
-DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_ROOT\scripts\buildsystems\vcpkg.cmake"
cmake --build build-vcpkg --config RelWithDebInfo --parallel
ctest --test-dir build-vcpkg -C RelWithDebInfo --output-on-failure
Use a specific triplet
Pass the same target triplet to vcpkg and CMake. For native builds, use the same value for the host triplet so host tools such as protoc and grpc_cpp_plugin are resolved consistently:
"$VCPKG_ROOT/vcpkg" install --triplet x64-linux --host-triplet x64-linux
cmake -S . -B build-vcpkg \
-DCMAKE_TOOLCHAIN_FILE="$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" \
-DVCPKG_TARGET_TRIPLET=x64-linux \
-DVCPKG_HOST_TRIPLET=x64-linux
Windows CI uses the repository triplet triplets/ci-x64-windows-release.cmake to build release-only dependencies and reduce dependency build time:
$env:VCPKG_OVERLAY_TRIPLETS = "$PWD\triplets"
& "$env:VCPKG_ROOT\vcpkg.exe" install --triplet ci-x64-windows-release --host-triplet ci-x64-windows-release
cmake -S . -B build -G "Visual Studio 17 2022" -A x64 `
-DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_ROOT\scripts\buildsystems\vcpkg.cmake" `
-DVCPKG_TARGET_TRIPLET=ci-x64-windows-release `
-DVCPKG_HOST_TRIPLET=ci-x64-windows-release
Build standalone FetchContent examples on Windows
The example runner uses the already-installed root manifest dependencies. It automatically passes the vcpkg toolchain and triplets when VCPKG_ROOT is set:
./scripts/install_build_deps.sh
rm -rf build-example-streaming_client
./scripts/run_examples.sh build-example streaming_client
./build-example-streaming_client/RelWithDebInfo/a2a_example.exe --help
Delete a build directory that was configured before the toolchain was supplied; changing CMAKE_TOOLCHAIN_FILE in an existing CMake cache is not reliable.
Consume a2a-cpp through the repository overlay port
The repository includes an overlay port at vcpkg-overlay-ports/a2a-cpp. A downstream manifest can depend on a2a-cpp and point vcpkg at that overlay.
vcpkg.json:
{
"name": "my-a2a-app",
"version-string": "0.4.1",
"dependencies": [
"a2a-cpp"
]
}
vcpkg-configuration.json:
{
"default-registry": {
"kind": "builtin",
"baseline": "3426db05b996481ca31e95fff3734cf23e0f51bc"
},
"overlay-ports": [
"path/to/a2a-cpp/vcpkg-overlay-ports"
]
}
Then configure the application with the vcpkg toolchain file on the first CMake configure and use the installed CMake package:
find_package(a2a_cpp CONFIG REQUIRED)
target_link_libraries(my_a2a_app PRIVATE a2a::client a2a::server a2a::core)
A complete example is available in examples/installed_package_consumer/.
Enable PostgreSQL store support
The overlay port exposes a postgres-store feature. Enable it in manifest mode when your application needs PostgreSQL-backed stores:
{
"name": "my-a2a-app",
"version-string": "0.4.1",
"dependencies": [
{
"name": "a2a-cpp",
"features": ["postgres-store"]
}
]
}
When the feature is enabled, link the additional target where needed:
target_link_libraries(my_a2a_app PRIVATE a2a::store_postgres)
Classic mode smoke install
For a direct overlay smoke test, run classic mode from a directory that does not contain a vcpkg.json manifest:
mkdir -p /tmp/a2a-vcpkg-smoke
cd /tmp/a2a-vcpkg-smoke
"$VCPKG_ROOT/vcpkg" install a2a-cpp --overlay-ports=/path/to/a2a-cpp/vcpkg-overlay-ports
Add a triplet if needed:
"$VCPKG_ROOT/vcpkg" install a2a-cpp:x64-linux --overlay-ports=/path/to/a2a-cpp/vcpkg-overlay-ports
Binary caching
Large dependencies such as gRPC and protobuf can take time to build. Enable binary caching for local and CI runs:
export VCPKG_BINARY_SOURCES="clear;files,$HOME/.cache/vcpkg-binary-cache,readwrite"
mkdir -p "$HOME/.cache/vcpkg-binary-cache"
On Windows PowerShell:
$env:VCPKG_BINARY_SOURCES = 'clear;files,C:\vcpkg-binary-cache,readwrite'
New-Item -ItemType Directory -Force C:\vcpkg-binary-cache | Out-Null
Troubleshooting
- CMake cannot find gRPC or Protobuf: confirm
CMAKE_TOOLCHAIN_FILEpoints toscripts/buildsystems/vcpkg.cmakebefore the first configure. If you configured without it, delete the build directory and configure again. - Unexpected manifest behavior in classic mode: classic
vcpkg install a2a-cppshould be run outside directories containingvcpkg.json, otherwise vcpkg switches to manifest mode. - Different host and target triplets: pass both
VCPKG_TARGET_TRIPLETandVCPKG_HOST_TRIPLETwhen cross-compiling or when CI uses a custom host triplet. - Slow clean builds: enable binary caching and prefer release-only dependency triplets for CI jobs that only link release configurations.
- Example executable is not in the build root on Windows: Visual Studio is multi-configuration; use
build-example-<app>/RelWithDebInfo/a2a_example.exe, or letscripts/run_examples.shlocate and run it. - The dependency helper reports an unsupported shell on Windows: run
scripts/install_build_deps.shfrom Git Bash rather than another Windows shell.
API Reference
The generated C++ API reference is built from public headers under include/a2a/**.
Generated reference
When published with the documentation site, open:
Generate locally
./scripts/generate_api_reference.sh
The script writes generated pages to book-build/api/cpp.
Public API areas
a2a::core: results, errors, protocol constants, JSON/protobuf helpers, Agent Card support, task state helpers, and versioning.a2a::client:A2AClient, transports, discovery, auth hooks, call options, interceptors, and streaming observers.a2a::server: executor, dispatcher, transports, interceptors, task stores, task lifecycle helpers, push notifications, and Agent Card serialization.a2a::http: shared outbound HTTP client abstraction used by default REST/JSON-RPC/discovery/push paths when libcurl is enabled.