Conformance¶
The SDK is checked with the official A2A Technology Compatibility Kit (TCK), run against tck/sut-agent.php (a port of the TCK's own Python system under test) on every push. The MUST level is a required CI check.
Latest results¶
A2A spec 1.0 · TCK commit 263b9cf · run 2026-09-25 · PHP-FPM (16 children) behind nginx, SQLite stores
| Level | JSON-RPC | HTTP+JSON | Agent Card | Result |
|---|---|---|---|---|
| MUST | 77 passed · 0 failed | 72 passed · 0 failed | 6 passed · 0 failed | ✅ 137 passed, 0 failed |
| SHOULD | 5 passed · 0 failed | 5 passed · 0 failed | 3 passed · 0 failed | ✅ 13 passed, 0 failed |
| MAY | 3 passed · 0 failed | 3 passed · 0 failed | 1 passed · 0 failed | ✅ 7 passed, 0 failed |
Counts are TCK test cases. gRPC isn't offered, so its tests don't run.
Laravel bridge¶
The same TCK against a real Laravel 13 app using praveendias1180/a2a-laravel with the queued runner: every executor runs on a php artisan queue:work process (8 workers, Redis queue), while PHP-FPM (16 children) behind nginx serves the HTTP side and relays each event from the Redis Streams event log. Run 2026-09-25, same TCK commit.
| Level | Result |
|---|---|
| MUST | ✅ 137 passed, 0 failed (3 runs in a row) |
| SHOULD | ✅ 13 passed, 0 failed |
| MAY | ✅ 7 passed, 0 failed |
The skipped tests are the same as for the plain-PHP SUT. A separate check (scripts/run-tck-laravel.sh long-task) streams a 20-second task from a queue worker, with an event every 2 s arriving live, and shows a task started with returnImmediately finishing on the worker after its request has ended. Both run in CI (tck-laravel job).
Skipped tests. These are the tests whose features the SUT doesn't declare, exactly as for the Python SDK's SUT: - push notifications (30) - the extended Agent Card (6) - a required extension (2) - a few that need a non-streaming agent
Comparison. On the same TCK commit, the Python SDK's SUT (a2a-sdk 1.1.5) scores:
- MUST: 135 passed, 2 failed
- SHOULD: 4 passed, 3 failed
Where the PHP SDK deliberately differs to conform¶
| Requirement | Python SDK | PHP SDK |
|---|---|---|
| CORE-CANCEL-002: cancelling a finished task over HTTP+JSON | 400 |
409 Conflict, as the TCK requires. The released v1.0.0 spec table says 400; the TCK follows the v1.0 release candidate. The TASK_NOT_CANCELABLE reason is the same either way. |
| STREAM-SUB-003: subscribing to a finished task | InvalidParamsError |
UnsupportedOperationError |
| DM-SERIAL-005: unknown fields in a request | rejected | ignored, for forward compatibility |
| CARD-CACHE-001/002: Agent Card caching | no headers | Cache-Control: max-age, ETag, Last-Modified, 304 on If-None-Match |
| CORE-SEND-002: sending to a finished task | InvalidParamsError |
UnsupportedOperationError |
Run it yourself¶
git clone https://github.com/a2aproject/a2a-tck
pip install -e ./a2a-tck
A2A_TCK_DIR="$PWD/a2a-tck" scripts/run-tck.sh must # or should, may, all
For the Laravel app: A2A_TCK_DIR="$PWD/a2a-tck" scripts/run-tck-laravel.sh must. It builds a Laravel app wired to your checkout on first use (build/tck-laravel-app), and starts Redis (if redis-server is installed), queue workers, PHP-FPM and nginx the same way.
The script starts the SUT on 127.0.0.1:9999 with its own unprivileged PHP-FPM and nginx instances (configured in a temp directory, so system services are untouched), runs the kit over JSON-RPC and HTTP+JSON, and stops everything. A2A_TCK_SERVER=php-s uses PHP's built-in server instead, but see the warning in Running agents in PHP: its workers can queue a connection behind a long stream, which makes the multi-stream tests flaky. Reports are written to a2a-tck/reports/. CI keeps them as the tck-reports artifact of the CI workflow.