Discover agents through explicit capability contracts
How to study this lesson
Read one section, trace the worked example, and try the knowledge check. Bookmark saves a shortcut; notes appear in My notebook. Mark lesson complete is your own assessment and does not mark its lab passed.
By the end, you can
- Explain the role of A2A Agent Cards.
- Select compatible interfaces without assuming trust.
- Pin protocol versions and preserve discovery provenance.
Interoperability begins at the boundary
Two agents can collaborate without sharing a runtime, model provider, or internal prompt format if they agree on a communication contract. A2A describes agent-to-agent interaction across such boundaries. The remote agent remains responsible for its internal workflow, while the client reasons about advertised capabilities and task outcomes. This differs from splitting functions inside one Python process, where memory and implementation details may already be shared.
Start by defining what the client actually needs: a skill, accepted input and output types, a compatible transport, authorization, and any required interaction capabilities. An agent that writes excellent reports may still be unsuitable if it cannot process the supplied media or support the required asynchronous workflow. Capability matching is a constrained selection problem, not a popularity ranking. The coordinator should record why a candidate was accepted or excluded.
Read the Agent Card as a declaration
A2A Agent Cards publish information used for discovery, including agent identity, skills, interfaces, capabilities, and authentication requirements. The documented well-known discovery path is /.well-known/agent-card.json; registries and direct configuration are other discovery approaches. [A2A agent discovery documentation](https://a2a-protocol.org/latest/topics/agent-discovery/). A card helps a client know how to interact, but its claims do not independently prove competence or authorization.
Treat a discovered endpoint like any external service. Check the trusted origin or registry, validate the card against the selected schema, and constrain which destinations the client may contact. A model-generated URL in a task description should not silently become an approved agent endpoint. If a card contains a description asking the client to expose credentials, that text remains untrusted metadata. Discovery expands the set of candidates; policy decides which candidates may receive which data.
Version the interface, not just the agent product
An agent product version and a protocol version answer different questions. Product version 4.2 can expose an A2A 1.0 interface while another endpoint supports a different protocol revision. The current A2A specification describes interface-specific protocol versions and A2A-Version negotiation. Its 1.0 schema differs from 0.3 in details such as polymorphic representations and enum serialization. Do not combine payload fragments from both versions. [A2A specification](https://a2a-protocol.org/latest/specification/).
Pin the version and binding used by each integration and include a compatibility fixture in the repository. The teaching examples use a small local capability schema and deliberately do not claim to emit valid A2A wire messages. When implementing the real protocol, generate or validate types against the pinned official schema and test actual request and response envelopes. A semantically similar dictionary is not sufficient evidence of protocol compliance.
Cache with a reason to refresh
Fetching a card on every request adds latency, while caching indefinitely can retain an obsolete endpoint or capability. Store the observation time, source URL, selected version, and a fingerprint with the cached declaration. Refresh according to the source's caching behavior and your operational needs, and revalidate when a request fails due to a capability or version mismatch. Do not silently downgrade a required feature merely to make a request succeed.
Suppose a client needs streaming plus a report skill. Agent A offers the skill without streaming; agent B offers both but only through a binding the client does not support; agent C satisfies all requirements. The correct result is C even if A has a more persuasive description. If none match, return an explicit compatibility gap rather than pretending a partial match is enough. The code makes this selection deterministic for three synthetic candidates.
Evaluate capability claims against real tasks
Discovery is only the first stage of trust. Before routing important work, use representative test tasks to measure output validity, latency, failure behavior, and adherence to data boundaries. A card can declare a report skill without defining your required quality rubric. Record observed behavior separately from declared capability, and avoid editing a third-party declaration to make it appear compatible with your expectations.
Add an integration manifest that binds the approved origin, protocol revision, accepted skill, required scopes, allowed data classes, and expected artifact schema. This manifest makes routing reviewable and limits accidental changes when a remote service evolves. In a small system, manually configured approved agents may be preferable to open-ended discovery. A2A provides useful interoperability structure, while your application still owns the decisions about who may collaborate, what they may receive, and how their results are judged.
Work through the code
This deterministic teaching simulation filters a local capability table. The fields are not an Agent Card schema and no network discovery occurs. Replace this table with validated, version-pinned official types only when implementing a real A2A client.
agents = [
{'id': 'A', 'skills': {'report'}, 'versions': {'1.0'},
'bindings': {'HTTP+JSON'}, 'streaming': False},
{'id': 'B', 'skills': {'report'}, 'versions': {'1.0'},
'bindings': {'GRPC'}, 'streaming': True},
{'id': 'C', 'skills': {'report', 'search'}, 'versions': {'1.0'},
'bindings': {'HTTP+JSON'}, 'streaming': True},
]
def compatible(agent, skill, version, binding, streaming):
return (skill in agent['skills']
and version in agent['versions']
and binding in agent['bindings']
and (not streaming or agent['streaming']))
selected = [agent['id'] for agent in agents
if compatible(agent, 'report', '1.0', 'HTTP+JSON', True)]
print('compatible:', selected)
print('credential trust: separate check')
print('schema: local teaching model')
compatible: ['C'] credential trust: separate check schema: local teaching model
Run Python snippets locally with the prerequisites named above. The module coding lab runs directly in your browser.
Pause and reason
An approved agent advertises the needed skill but changes its only interface to a protocol version your client cannot parse. What should routing do?
Check your understanding
What does an Agent Card establish by itself?
Your notes
Explain the mechanism in your own words. Add a failure you want to test.