FMSG-004 A2A Protocol Binding Standard¶
Status¶
This document is an initial draft. It defines an A2A protocol binding over fmsg and is not an official binding of the A2A Project.
| Revision | Date | Summary |
|---|---|---|
| v0.1.0 | 2026-08-09 | Initial threaded draft |
| v0.2.0 | 2026-08-27 | Native attachment mapping; sibling events; detached delivery on parent loss |
This revision binds A2A protocol version 1.0 to fmsg wire protocol version 1. A future revision is required to support a breaking version of either protocol.
Requirements Language¶
The key words MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, NOT RECOMMENDED, MAY, and OPTIONAL in this document are to be interpreted as described in BCP 14 (RFC 2119 and RFC 8174) when, and only when, they appear in all capitals.
Abstract¶
The Agent2Agent (A2A) protocol defines operations and data structures for communication between agents. fmsg provides federated, store-and-forward, immutable message delivery between addresses. This standard maps A2A operations to request, response, and stream-event envelopes carried as fmsg messages.
An A2A client sends each operation to the fmsg address advertised by an A2A server. The first operation is an fmsg thread root. Later operations may reply to earlier results so that task continuations form chains, related tasks branch from a context anchor, and task controls form side branches. A2A task and context identifiers remain authoritative for application continuity; fmsg parent hashes provide transport history, correlation, and integrity. Binary part content travels as native fmsg attachments rather than as base64 text. When an fmsg parent is no longer available, delivery restarts in a new fmsg thread and the A2A identifiers carry the task and context across threads.
This binding does not change the A2A data model, task state machine, Agent Card discovery rules, or extension semantics.
Introduction¶
This section is non-normative.
A2A and fmsg solve different parts of agent communication. A2A gives agents a shared vocabulary: start a task, continue it, report progress, return results, or cancel it. fmsg provides a way to deliver those operations between authenticated addresses using durable, store-and-forward, cryptographically linked messages.
For example, an assistant can ask a research agent to investigate a question.
The research agent creates an A2A task, the assistant adds a follow-up question,
and the agent sends progress updates before returning its result. With this
binding, the agents still speak standard A2A, but the exchange travels through
fmsg addresses such as @research-agent@example.com instead of requiring this
interaction to use another A2A transport.
Using fmsg means an agent does not have to be online at the same moment as its peer. Requests can survive temporary outages, task continuations form verifiable fmsg chains, related tasks can branch from a shared context, and status checks or cancellations can appear as side branches without changing the A2A task itself. Should a host no longer hold an earlier message, the exchange continues in a new fmsg thread and the A2A identifiers keep the relationship intact. Files exchanged as A2A parts are ordinary fmsg attachments, visible to any fmsg client that can read the thread.
In short, A2A gives agents a shared language; fmsg gives their conversation a durable, federated, and verifiable delivery system. An adapter can therefore place fmsg underneath an existing A2A client or server without changing the application’s task-handling code.
Normative References¶
- A2A Protocol Specification 1.0
- fmsg Specification
- FMSG-001 TCP+TLS Transport and Binding Standard
- Protocol Buffers JSON Mapping
- RFC 3986: Uniform Resource Identifier
- RFC 6838: Media Type Specifications
An implementation claiming conformance to this standard MUST also conform to the versions of A2A and fmsg identified in Status.
Terminology¶
A2A client is the agent or application initiating an A2A operation.
A2A server is the remote agent processing an A2A operation.
client address is the fmsg address from which a request is sent and to which responses are addressed.
server address is the fmsg address advertised by the A2A server.
request message is an fmsg message carrying one A2A request envelope. It is either a thread root or a reply to a conversational result.
response message is an fmsg reply carrying the single non-streaming result or error for a request.
event message is an fmsg reply carrying one item of an A2A streaming result.
mapped part is an A2A Part whose raw content is carried as an fmsg
attachment of the same message rather than inline in the JSON payload.
attachment reference is the fmsg-attachment URI placed in a mapped
part’s url member to name its attachment.
context anchor is the first successful conversational response or event known to establish an A2A context for a client/server address pair.
task head is the most recent successful conversational response or event known for an A2A task by one endpoint. Concurrent operations may create more than one valid branch from an earlier task head.
detached root is a request sent as an fmsg thread root although its A2A scope names an existing task or context, because no usable fmsg parent is available to the client.
detached result is a response or event sent as an fmsg thread root because the request message cannot be used as its parent.
transport principal is the fmsg sender address accepted by the receiving host after fmsg host and domain verification. This is distinct from an end-to-end cryptographic identity for the person or process using that address.
Binding Identification¶
The provisional protocol binding identifier for this revision is:
An Agent Card advertising this binding MUST place that exact value in the
protocolBinding field of its AgentInterface. Implementations MUST compare
the value as a case-sensitive string and MUST NOT assume that another identifier
is equivalent.
If this binding is adopted under a standards organization, a later revision MAY assign a new identifier. Implementations MUST NOT silently treat the old and new identifiers as equivalent unless that revision explicitly defines compatibility.
Agent Endpoint URI¶
The url of an AgentInterface using this binding MUST be an absolute URI with
the fmsg scheme and this form:
For an ASCII address the canonical form is, for example:
The scheme name MUST be lowercase. The decoded scheme-specific part MUST be one valid fmsg address. Octets outside the URI unreserved and permitted path characters MUST be percent-encoded using the address’s UTF-8 representation. Percent-encoded octets MUST use uppercase hexadecimal digits. URI decoders MUST decode percent-encoding exactly once before validating the fmsg address.
The URI MUST NOT contain an authority marker (//), query, or fragment. Clients
MUST reject a selected fmsg interface whose endpoint does not meet these rules.
The tenant value, when present in the selected AgentInterface, remains an
opaque A2A routing value. The client MUST copy it exactly into the tenant
field of every A2A request payload. It does not alter the fmsg address.
Agent Card Declaration and Discovery¶
Agent Cards remain JSON documents discovered through the mechanisms defined by A2A, including an HTTPS well-known URI, a registry, or direct configuration. This binding does not define Agent Card discovery over fmsg.
An interface declaration for this draft has this form:
{
"url": "fmsg:@research-agent@example.com",
"protocolBinding": "https://github.com/markmnl/fmsg/blob/main/standards/fmsg-004-a2a-binding.md",
"protocolVersion": "1.0"
}
An Agent Card MUST accurately declare streaming, pushNotifications, and
extendedAgentCard capabilities for this interface. If capabilities differ
between an HTTP interface and an fmsg interface, the server SHOULD publish
separate Agent Cards so that a client cannot infer unsupported capability from
the union of interfaces.
fmsg Message Profile¶
Common Requirements¶
Every request, response, and event defined here MUST be the data of one fmsg message with media type:
The message data MUST be UTF-8 JSON and MUST contain exactly one binding envelope. Byte order marks are forbidden. Senders SHOULD use the shortest reasonable representation and receivers MUST ignore insignificant JSON whitespace.
Binary A2A content is carried as native fmsg attachments as defined in Attachment Mapping. A message MUST NOT carry any attachment other than those that mapping produces.
The fmsg important flag MAY be set. The zlib-deflate flag MAY be used on
the message data and on any attachment and is processed at the fmsg layer
before JSON parsing. The has add to flag MUST NOT be set. Each message MUST
have exactly one recipient.
Request Message¶
A request message MUST:
- have
fromequal to the client address; - have one
tovalue equal to the server address; - have the
no replyflag clear; and - contain a request envelope.
A root request MUST have no pid and MUST have a topic of
A2A <requestId>. A threaded request MUST have pid equal to the hash of the
selected parent and MUST contain no topic. The topic carries no authority. A
receiver MUST use the envelope requestId and MUST reject a root request whose
topic does not match it or a threaded request that contains a topic.
Response Message¶
A response message MUST:
- have
fromequal to the server address; - have one
tovalue equal to the request’sfromaddress; - have
pidequal to the request message hash and no topic, or be a detached result as defined in Detached Results; - contain a response envelope; and
- use the same
requestIdandoperationas the request.
The no reply flag MUST be clear on a successful SendMessage response because
it can become a context anchor or task head. It MAY be set on errors and on
responses to non-conversational operations. A response is authoritative only
when both its fmsg relationship and envelope correlation are valid.
Event Message¶
If streaming is supported, each event message MUST meet the response message
requirements except that it contains an event envelope. Every event of a
stream therefore replies to the request message, not to the preceding event:
the events are siblings under the request, ordered by the envelope sequence
and not by fmsg linkage. Delivery of one event never depends on another, so a
single undeliverable event cannot strand the remainder of a stream.
A SendStreamingMessage event carrying a task ID MUST have the no reply flag
clear because it can become a task head. Other events MAY set it;
SubscribeToTask events are side branches.
Detached Results¶
A server MUST send a result as a reply to the request message whenever it can.
If the sending host reports fmsg REJECT code 6 (parent not found), the
client’s host no longer holds the request and the reply can never be
delivered. The server MUST then resend the result as a detached result: an
fmsg thread root with no pid, a topic of A2A <requestId>, and otherwise
identical data and attachments. A server that can no longer reply to the
request message, because its own host no longer holds it, MUST send the
result as a detached result directly. Once any result for a request has been
sent detached, every later event for that request MUST also be sent detached.
A detached result is authenticated by fmsg transport verification of its
from address and correlated by its topic and envelope; it cannot be linked
to the request by hash. A client MUST accept a detached result whose from,
recipient, topic, requestId, and operation match a request it sent, and
MUST apply the same duplicate and sequence rules as for a reply. A detached
result MAY become a task head or context anchor exactly as a reply would.
Envelope¶
Field Rules¶
All envelope property names are case-sensitive. Unknown envelope properties MUST be ignored unless a later binding revision makes them required. A receiver MUST reject duplicate JSON object property names.
bindingVersion MUST be the string "0.2" for this revision.
a2aVersion MUST be a supported A2A major and minor version and MUST equal the
A2A-Version service parameter. This revision permits only "1.0".
requestId MUST be a UUID represented in the lowercase canonical textual form
defined by RFC 9562. The request creator generates it. It is transport
correlation and is not an A2A messageId, taskId, or contextId.
operation MUST be one operation name listed in Operation Mapping.
Operation names are case-sensitive.
Request Envelope¶
{
"bindingVersion": "0.2",
"a2aVersion": "1.0",
"kind": "request",
"requestId": "018f3f6e-7c1a-7e95-8f23-6ed8b985a781",
"operation": "SendMessage",
"serviceParameters": {
"a2a-version": "1.0"
},
"payload": {}
}
The properties shown above are REQUIRED. kind MUST be "request".
serviceParameters and payload MUST be JSON objects. payload MUST be the
ProtoJSON representation of the request type specified for the operation.
An optional credentials property MAY be present as defined in
Application Authentication.
Response Envelope¶
A successful response contains payload:
{
"bindingVersion": "0.2",
"a2aVersion": "1.0",
"kind": "response",
"requestId": "018f3f6e-7c1a-7e95-8f23-6ed8b985a781",
"operation": "SendMessage",
"payload": {}
}
An unsuccessful response contains error:
{
"bindingVersion": "0.2",
"a2aVersion": "1.0",
"kind": "response",
"requestId": "018f3f6e-7c1a-7e95-8f23-6ed8b985a781",
"operation": "GetTask",
"error": {
"code": "A2A_TASK_NOT_FOUND",
"message": "The task does not exist or is not accessible",
"details": []
}
}
kind MUST be "response". Exactly one of payload or error MUST exist.
For a successful operation returning google.protobuf.Empty, payload MUST be
an empty JSON object.
Event Envelope¶
{
"bindingVersion": "0.2",
"a2aVersion": "1.0",
"kind": "event",
"requestId": "018f3f6e-7c1a-7e95-8f23-6ed8b985a781",
"operation": "SubscribeToTask",
"sequence": 0,
"final": false,
"payload": {}
}
kind MUST be "event". sequence MUST be an integer from 0 through
9,007,199,254,740,991. The first event MUST have sequence 0 and each following
event MUST increment it by one. final MUST be a Boolean. Exactly one of
payload or error MUST exist. A successful payload MUST be the ProtoJSON
representation of StreamResponse.
Exactly one event MUST have final: true, and it MUST be the last event. A
stream error is an event containing error and final: true. A server MUST NOT
send an event after the final event.
A2A Data Representation¶
The payload property uses A2A 1.0 ProtoJSON without binding-specific changes:
- field names MUST use lower camel case;
- enum values MUST use their symbolic ProtoJSON names;
- timestamps MUST be ISO 8601 UTC strings accepted by ProtoJSON;
bytesvalues MUST use ProtoJSON base64 encoding, except thatPart.rawis carried as defined in Attachment Mapping;- 64-bit integer values MUST follow ProtoJSON string representation rules;
- absent optional fields MUST remain absent; and
- oneof constraints and A2A required-field constraints MUST be enforced.
A receiver MUST validate the payload against the request or response type for
the named operation. Binding metadata MUST NOT be inserted into an A2A object’s
metadata field unless it is also application-visible A2A metadata.
An implementation MAY support A2A extensions. Extension identifiers and their
metadata remain inside the A2A data model, and extension activation MUST also be
declared through the A2A-Extensions service parameter as required by A2A.
Attachment Mapping¶
A2A carries file content by reference in Part.url or by value in Part.raw.
Part.raw is the only bytes field in the A2A 1.0 data model; the gRPC
binding transports it as octets and the JSON binding as base64 text. fmsg
carries binary content natively as attachments, so this binding transports
Part.raw as an attachment of the fmsg message that carries its envelope.
The mapping is a transport representation only. The A2A layer on either side
observes an ordinary Part whose raw member holds the content; it never
observes an attachment or an attachment reference.
Mapped Parts¶
A sender MUST map every Part with a non-empty raw value, wherever it
occurs in the payload, to one fmsg attachment, subject to
Count Limit and Inline Fallback. For each
mapped part the sender MUST:
- write the
rawoctets as the attachment data, setting the attachmentzlib-deflateflag at its discretion; - name the attachment
a2a-part-<n>, where<n>is the zero-based ordinal of the mapped part in decimal without leading zeros, numbered in the order the references appear in the serialized message data; - set the attachment type as defined in Attachment Type;
- omit
rawfrom the serializedPart; and - set the
Parturlmember to the attachment referencefmsg-attachment:a2a-part-<n>.
Every other Part member, including filename, mediaType, and metadata,
MUST be serialized unchanged. Because the reference occupies the url member
of the content oneof, the payload remains valid A2A ProtoJSON and the
A2A Data Representation rules continue to apply.
A raw value of zero length MUST remain inline as "raw": "".
Attachments belong to the fmsg message that carries them. A response and each
event of a stream carries only the attachments for its own payload; a chunked
TaskArtifactUpdateEvent therefore carries only that chunk’s octets.
Attachment Reference¶
An attachment reference is a URI whose scheme is fmsg-attachment and whose
scheme-specific part is the filename of an attachment in the same fmsg
message. The scheme name MUST be lowercase. The reference MUST NOT contain an
authority marker (//), query, fragment, or percent-encoding.
The fmsg-attachment scheme is reserved by this binding. A sender MUST reject
at its A2A API boundary any application-supplied Part.url that uses it, and
a receiver MUST treat every Part.url that uses it as an attachment
reference. A receiver MUST NOT attempt to retrieve an attachment reference as
a network resource.
Attachment Type¶
The attachment type MUST equal Part.mediaType when that value is present,
non-empty, US-ASCII, and shorter than 256 octets; otherwise it MUST be
application/octet-stream. Whether the fmsg type field is encoded as a common
media type ID or as a string is an fmsg-layer detail with no meaning in this
binding.
Part.mediaType in the JSON payload remains the A2A value. The attachment
type exists so that fmsg hosts and clients can apply media policy, display,
and storage handling to the content without parsing the envelope.
Count Limit and Inline Fallback¶
An fmsg message carries at most 255 attachments. A sender MUST map parts in
serialization order until that limit is reached; every remaining raw part
MUST be serialized inline using ProtoJSON base64 encoding.
A receiver MUST accept an inline raw value wherever a Part is valid,
regardless of how many attachments the message carries. Inline encoding is a
fallback, not an alternative: a sender MUST NOT use it for a part that this
section requires to be mapped.
Receiver Processing¶
Before validating the payload against its A2A type, a receiver MUST:
- resolve every attachment reference to the attachment whose filename matches it, compared case-insensitively as fmsg requires;
- verify that every attachment on the message is referenced exactly once;
- verify that each referenced attachment’s type is either
application/octet-streamor equal to the referencing part’smediaTypeafter ASCII case folding; and - replace the
urlmember of each referencingPartwith arawmember holding the attachment’s expanded data.
A message failing any of these checks MUST be rejected with
FMSG_A2A_ATTACHMENT_INVALID. A receiver resolves attachments by reference
only; it MUST NOT depend on the a2a-part-<n> naming for ordering or
correctness. This allows a later revision to relax attachment naming without
changing receivers.
Integrity and Size¶
The fmsg message hash covers attachment data, so a mapped part has the same
integrity, correlation, and replay properties as inline content. Attachment
data counts toward fmsg MAX_SIZE and MAX_EXPANDED_SIZE together with the
message data, without base64 expansion.
Example¶
A client sends a photograph for analysis. The fmsg message carries one
attachment named a2a-part-0 of type image/jpeg whose data is the JPEG
octets, and this message data:
{
"bindingVersion": "0.2",
"a2aVersion": "1.0",
"kind": "request",
"requestId": "018f3f75-2d0c-7a3e-9b41-7f2c5e8d9a10",
"operation": "SendMessage",
"serviceParameters": {
"a2a-version": "1.0"
},
"payload": {
"message": {
"messageId": "018f3f76-4b1e-7d92-8c53-1a9e6f7b2c44",
"role": "ROLE_USER",
"parts": [
{
"text": "What is in this photograph?",
"mediaType": "text/plain"
},
{
"url": "fmsg-attachment:a2a-part-0",
"filename": "photo.jpg",
"mediaType": "image/jpeg"
}
]
}
}
}
The receiving binding restores the second part before the A2A server sees it.
The server observes a Part whose raw member holds the JPEG octets, with
filename photo.jpg and mediaType image/jpeg, exactly as it would over
any other A2A binding.
Service Parameters¶
A2A service parameters have no native fmsg header location and therefore MUST
be carried in the request envelope’s serviceParameters object. Each value MUST
be a string. Keys MUST be serialized in lowercase and compared
case-insensitively. A receiver MUST reject two keys that become equal after
ASCII case folding.
The following parameters are defined by A2A:
| Envelope key | Requirement | Meaning |
|---|---|---|
a2a-version |
REQUIRED | A2A major and minor version; MUST equal a2aVersion |
a2a-extensions |
OPTIONAL | Comma-separated extension identifiers requested by the client |
Binding revisions MAY define additional service parameters prefixed
fmsg-a2a-. This revision defines none. Unrecognized optional parameters MUST
be ignored. A server MUST apply A2A’s required-extension validation before
executing an operation.
Operation Mapping¶
Every implementation MUST recognize every operation in this table. Support for capability-gated operations is conditional as described below.
operation |
Request payload |
Successful response payload |
|---|---|---|
SendMessage |
SendMessageRequest |
SendMessageResponse |
SendStreamingMessage |
SendMessageRequest |
Sequence of event envelopes containing StreamResponse |
GetTask |
GetTaskRequest |
Task |
ListTasks |
ListTasksRequest |
ListTasksResponse |
CancelTask |
CancelTaskRequest |
Task |
SubscribeToTask |
SubscribeToTaskRequest |
Sequence of event envelopes containing StreamResponse |
CreateTaskPushNotificationConfig |
TaskPushNotificationConfig |
TaskPushNotificationConfig |
GetTaskPushNotificationConfig |
GetTaskPushNotificationConfigRequest |
TaskPushNotificationConfig |
ListTaskPushNotificationConfigs |
ListTaskPushNotificationConfigsRequest |
ListTaskPushNotificationConfigsResponse |
DeleteTaskPushNotificationConfig |
DeleteTaskPushNotificationConfigRequest |
google.protobuf.Empty as {} |
GetExtendedAgentCard |
GetExtendedAgentCardRequest |
AgentCard |
The server MUST preserve the operation semantics, validation, task-state rules, history-length behavior, pagination behavior, idempotency, and authorization rules defined by A2A.
Non-streaming Operations¶
Each non-streaming request produces exactly one response message. For
SendMessage, configuration.returnImmediately retains its A2A meaning. If it
is false or absent, the server MUST delay its response until the task reaches a
terminal or interrupted state. If true, the server returns the current result
as soon as A2A permits. Store-and-forward delivery does not implicitly change
this field.
Streaming Operations¶
A server advertising capabilities.streaming: true for this interface MUST
support both SendStreamingMessage and SubscribeToTask through event
envelopes. A server not advertising streaming MUST return
A2A_UNSUPPORTED_OPERATION in a normal response envelope.
Before the first event, a streaming request MAY fail with one normal error response envelope. After the first event, any failure MUST be the error in a final event envelope. A server MUST NOT send both a response envelope and an event envelope for the same streaming request.
fmsg provides reliable message delivery but not a live byte stream, and sibling
events may be delivered in any order. The sequence field defines application
ordering. Clients MUST buffer out-of-order events within an
implementation-defined bounded window. A missing sequence after an
implementation-defined timeout terminates the local stream with a binding
transport error; clients MAY recover task state using GetTask or a new
SubscribeToTask request.
Receiving a terminal or interrupted TaskStatusUpdateEvent does not replace the
required final event. Stream completion is signalled only by final: true.
Push Notifications¶
Push notification configuration operations retain their A2A semantics. The
TaskPushNotificationConfig.url is the callback URL used by the A2A server;
this standard does not reinterpret it as an fmsg address. A server not
advertising capabilities.pushNotifications: true MUST return the appropriate
A2A unsupported-operation or push-notification-not-supported error.
Credentials inside TaskPushNotificationConfig.authentication are subject to
the persistence warning in Credential Persistence.
Extended Agent Card¶
A server not advertising capabilities.extendedAgentCard: true MUST return
A2A_UNSUPPORTED_OPERATION. A server advertising it MUST authenticate and
authorize the requester according to A2A and this standard before returning an
extended card.
Error Representation¶
An error object MUST have non-empty string properties code and message.
details MUST be a JSON array when present. It MAY contain structured A2A error
details and MUST NOT contain credentials or information the caller is not
authorized to know.
A2A Errors¶
The following binding codes map to A2A 1.0 error types:
Binding code |
A2A error type |
|---|---|
A2A_TASK_NOT_FOUND |
TaskNotFoundError |
A2A_TASK_NOT_CANCELABLE |
TaskNotCancelableError |
A2A_PUSH_NOTIFICATION_NOT_SUPPORTED |
PushNotificationNotSupportedError |
A2A_UNSUPPORTED_OPERATION |
UnsupportedOperationError |
A2A_CONTENT_TYPE_NOT_SUPPORTED |
ContentTypeNotSupportedError |
A2A_INVALID_AGENT_RESPONSE |
InvalidAgentResponseError |
A2A_EXTENDED_AGENT_CARD_NOT_CONFIGURED |
ExtendedAgentCardNotConfiguredError |
A2A_EXTENSION_SUPPORT_REQUIRED |
ExtensionSupportRequiredError |
A2A_VERSION_NOT_SUPPORTED |
VersionNotSupportedError |
Generic authentication, authorization, validation, not-found, rate-limit, and
internal failures MUST use UNAUTHENTICATED, PERMISSION_DENIED,
INVALID_ARGUMENT, NOT_FOUND, RESOURCE_EXHAUSTED, or INTERNAL as
appropriate. A server MUST NOT use NOT_FOUND in a way that reveals a resource
the transport principal is not authorized to discover.
Binding Errors¶
Errors detected after the server receives a correlatable request SHOULD be returned with one of these codes:
Binding code |
Meaning |
|---|---|
FMSG_A2A_INVALID_ENVELOPE |
Envelope JSON or required binding field is invalid |
FMSG_A2A_UNSUPPORTED_BINDING_VERSION |
bindingVersion is unsupported |
FMSG_A2A_UNKNOWN_OPERATION |
operation is not recognized |
FMSG_A2A_REQUEST_ID_CONFLICT |
A reused request ID has different request content |
FMSG_A2A_CORRELATION_FAILED |
fmsg relationship and envelope correlation disagree |
FMSG_A2A_ATTACHMENT_INVALID |
Attachment references, attachment set, or attachment types violate Attachment Mapping |
If the body cannot be parsed enough to determine a trustworthy requestId, the
server MUST NOT send a response. It SHOULD record the failure without logging
the body.
fmsg Delivery Failures¶
fmsg rejection and transport failures occur before an A2A server necessarily processes a request. Except for REJECT code 6 (parent not found), which the client handles as defined in Thread Topology, a client binding MUST report them as transport errors and MUST NOT fabricate an A2A response. The error SHOULD retain the fmsg response code, affected address, and whether retry may be useful.
A client-side response timeout is also a transport error. Timing out does not
cancel the remote operation. A caller wanting cancellation MUST subsequently
send CancelTask when it has a task identifier.
Thread Topology¶
A2A identifiers define application continuity and MUST be present wherever A2A requires them. The fmsg graph records how one address pair transported that continuity; it does not replace the A2A data model.
A client that has a usable canonical parent MUST choose request parents as follows:
SendMessageandSendStreamingMessagecarrying ataskIdreply to a known task head;- those operations carrying a
contextIdbut notaskIdreply to the stable context anchor, allowing related tasks to branch; GetTask,CancelTask,SubscribeToTask, and task push-notification configuration operations reply to a known head of the named task;ListTaskswith acontextIdreplies to that context anchor; and- unscoped operations are roots.
Control operations and SubscribeToTask are side branches. Their responses and
events MUST NOT become the task head. A successful SendMessage response and
each successful SendStreamingMessage event carrying a task ID, processed in
sequence order, MUST become the sender’s known task head. The first such result
observed for a context establishes its context anchor. The anchor MUST NOT move
while it remains usable; if it becomes unusable, the next such result for the
context establishes a new anchor. Whether a result was delivered as a reply or
as a detached result does not affect its eligibility.
An implementation can know only the portion of a graph available to its local
fmsg account. If the canonical parent is unknown, deleted, has no reply set,
or cannot be used, the client MUST send the operation as a detached root. A
server MUST accept a valid detached root even when its payload names an existing
task or context. This permits another authorized client address or an endpoint
that lost local graph state to continue using the A2A identifiers.
A threaded request rejected by the server’s host with fmsg REJECT code 6
(parent not found) was never received by the A2A server: the server’s host no
longer holds the parent. The client MUST resend that request as a detached
root with the same requestId and content, and MUST treat the lost parent as
unusable thereafter. The fmsg specification’s other recoveries for code 6 do
not apply here, because add to is forbidden by this binding and a client
cannot resend a message the server authored. Restarting an fmsg thread this
way does not affect the A2A task or context, whose identifiers remain in every
payload.
A threaded request parent MUST be a successful SendMessage response or
SendStreamingMessage event sent by the selected server to the requesting
client. Its A2A task or context identifier MUST match the scope of the new
request. A server MUST reject a threaded request whose parent direction, media
type, envelope kind, operation, or A2A identity does not meet these rules with
FMSG_A2A_CORRELATION_FAILED. Receivers SHOULD accept an older valid task node
because concurrent operations can legitimately branch from the same head.
Correlation, Replay, and Idempotency¶
The tuple (server address, client address, requestId) identifies one binding
request. A server MUST retain sufficient request state for at least its
documented maximum retry interval.
On first receipt, the server MUST associate the tuple with a digest of the request envelope and with every response or event it emits. The digest SHOULD be SHA-256 over an implementation’s deterministic encoding of the parsed envelope after attachment restoration, so that it covers the content of every mapped part. It MUST exclude fmsg fields such as transmission time.
If the tuple is received again:
- with equivalent request content, the server MUST NOT execute the operation a second time and SHOULD replay the stored response or events as new fmsg replies to the newly received duplicate request; or
- with different content, the server MUST return
FMSG_A2A_REQUEST_ID_CONFLICTand MUST NOT execute it.
The server MUST also apply A2A messageId idempotency semantics. A new binding
requestId does not authorize replaying an A2A message with the same
messageId as new work.
A client MUST match a response or event by all of:
- fmsg
pidequal to the request message hash, or, for a detached result, nopidand a topic ofA2A <requestId>; - fmsg
fromequal to the selected server address; - fmsg recipient equal to the original client address;
- matching
requestId; and - matching
operation.
The client MUST ignore an exact duplicate response or event. Reuse of an event sequence number with different content is a correlation failure and MUST terminate the local stream.
A2A taskId and contextId alone define A2A continuity. Implementations MUST
NOT infer either identifier from an fmsg pid or message hash, and a detached
root MUST NOT be interpreted as starting a new A2A task when its payload names
an existing one.
Authentication and Authorization¶
Transport Authentication¶
The receiving fmsg host verifies the sending host and sender domain as required
by fmsg and FMSG-001. The A2A server MUST use the request’s fmsg from address
as the transport principal and MUST authorize every operation and task against
that principal.
A server MUST NOT trust an address copied into the JSON payload as the caller’s identity. A response MUST be sent only to the authenticated request sender.
Transport authentication establishes which federated fmsg address sent the message. It does not prove that a particular human or process controlled that address, and it does not provide end-to-end payload encryption or signatures.
An Agent Card MAY have no A2A securityRequirements when authorization by fmsg
transport principal is sufficient. Operators MUST document their trust model.
Application Authentication¶
When an Agent Card declares an A2A security requirement for this interface, a
request MAY contain a credentials object. Each property name MUST equal a key
in the Agent Card’s securitySchemes map. Its value MUST be an object with a
required string value and an optional array of string scopes:
{
"credentials": {
"agentOAuth": {
"value": "opaque-short-lived-credential",
"scopes": ["tasks:write"]
}
}
}
API-key, HTTP authentication, OAuth 2.0, and OpenID Connect credentials are
carried as the opaque value; their HTTP header, query, or cookie
locations do not apply to this binding. Mutual TLS cannot be conveyed by this
object and is unsupported unless a later standard defines verifiable
end-to-end delegation. A client MUST NOT select this interface if it cannot
satisfy one complete advertised security requirement.
The server MUST validate credentials before processing the A2A payload and MUST bind successful authentication to the fmsg transport principal. Credentials do not permit a response to be redirected to another address.
Credential Persistence¶
fmsg messages are immutable and may be retained by sending and receiving hosts. Therefore application credentials placed in an envelope are also retained.
Implementations:
- MUST NOT transmit passwords, refresh tokens, or long-lived API keys;
- MUST NOT log credential values;
- MUST redact
credentialsfrom diagnostics; - SHOULD use audience-restricted, narrowly scoped, short-lived proof tokens;
- SHOULD use one-time credentials where the authentication system supports them; and
- MUST NOT advertise a security scheme over this binding when its safe use depends on credential secrecy beyond what the deployment provides.
End-to-end encrypted fmsg content is outside this revision. Deployments needing strong credential or payload confidentiality MUST add an independently specified end-to-end protection layer or MUST NOT use this binding for that traffic.
Execution and Delivery Semantics¶
Sending an fmsg request and receiving an fmsg acceptance code confirms message delivery to the receiving host, not successful execution of the A2A operation. Only a valid response or final event conveys the A2A result.
A client adapter MAY present a blocking API by waiting for correlated inbound
fmsg messages. It MUST make its local timeout and retry policy configurable.
That policy MUST NOT alter A2A returnImmediately semantics.
Requests and responses may be delayed, duplicated at an API boundary, or arrive after a local timeout. Both peers MUST persist enough correlation state to handle those cases. Implementations SHOULD process inbound messages in fmsg message-time order, but MUST use the explicit event sequence for streams.
Size and Media Handling¶
The complete fmsg message, comprising the JSON envelope and every mapped attachment, is subject to fmsg’s message size, expanded-size, attachment count, quota, and media-type limits. An adapter SHOULD check the destination’s known limits before sending but MUST still handle an fmsg rejection, including one caused by a receiving host’s attachment media-type policy.
An A2A server MUST validate every Part.mediaType against the selected skill’s
declared input modes. It MUST treat URLs in Part.url, filenames, structured
data, and raw content, whether restored from an attachment or decoded from
base64, as untrusted input.
Mapped parts carry raw content without base64 expansion; only inline
fallback parts incur it.
Security Considerations¶
Implementers MUST consider at least the following:
- Authorization: Every task lookup, list, cancellation, subscription, push configuration, and extended-card request must be scoped to the authenticated transport principal and any application credential.
- Payload confidentiality: TLS protects fmsg hops, not stored content or content end to end. Sensitive A2A data may remain in host storage.
- Replay: fmsg duplicate detection does not replace binding
requestIdand A2AmessageIdidempotency across newly encoded messages. - Resource exhaustion: JSON depth, object count, attachment count and expanded size, decoded base64 size, stream reordering buffers, concurrent requests, and retained replay state require explicit limits.
- Parser safety: Receivers must reject duplicate JSON keys, invalid UTF-8, malformed ProtoJSON, and values outside declared numeric bounds.
- Response confusion: Both fmsg parent linkage and envelope identifiers must be checked before accepting a response.
- Detached results: A detached result has no hash linkage to its request.
Its authenticity rests entirely on fmsg transport verification of
from, so a client must never accept one from an address other than the selected server address, and must apply duplicate and sequence checks as usual. - Error privacy: Errors must not disclose whether unauthorized task IDs, agent skills, extended-card data, or other principals exist.
- Agent Card integrity: Clients should retrieve Agent Cards over HTTPS and verify an Agent Card signature when one is present.
- URL retrieval: Servers resolving an A2A
Part.urlmust defend against server-side request forgery and apply scheme, host, redirect, and size policy. - Attachment references: An
fmsg-attachmentreference names content in the same fmsg message only. It must never be fetched as a network resource, and a message whose references and attachments do not correspond exactly must be rejected before any A2A processing.
The security requirements of A2A, fmsg, and FMSG-001 remain applicable.
Conformance¶
Client Conformance¶
A conforming client implementation MUST:
- parse and validate the selected fmsg
AgentInterface; - construct the fmsg profile and request envelope defined here;
- map and restore
Part.rawcontent as defined in Attachment Mapping; - support every non-capability-gated operation in the operation table;
- validate fmsg and envelope correlation for every result;
- implement duplicate response handling and configurable timeouts;
- accept detached results and resend a threaded request as a detached root on fmsg REJECT code 6; and
- expose fmsg delivery failures separately from A2A errors.
A client claiming streaming support MUST additionally implement event ordering, duplicate handling, final-event processing, and bounded recovery behavior.
Server Conformance¶
A conforming server implementation MUST:
- advertise an accurate Agent Card interface and capabilities;
- validate the fmsg profile, envelope, service parameters, and A2A payload;
- map and restore
Part.rawcontent as defined in Attachment Mapping; - recognize every operation in the operation table;
- preserve A2A operation and task semantics;
- authorize operations using the fmsg transport principal;
- implement request replay protection and idempotent duplicate handling;
- send detached results when a reply cannot be delivered; and
- return the response and error representations defined here.
A server MAY return the prescribed unsupported errors for streaming, push notifications, and extended Agent Cards only when the corresponding capability is not advertised.
Minimum Interoperability Tests¶
An implementation pair claiming interoperability SHOULD demonstrate:
- Agent Card selection and fmsg endpoint parsing.
SendMessagereturning a direct A2AMessage.SendMessagereturning aTask, followed byGetTask.- A task continuation forming an fmsg chain and a new task branching from the stable context anchor.
ListTaskspagination and authorization scoping.- Successful and rejected
CancelTaskoperations. - A2A raw bytes carried as fmsg attachments in a request and a response,
restored unchanged, and an inline base64
rawvalue accepted. - A message with an unresolvable, unreferenced, or mistyped attachment being rejected.
- An A2A-specific error and an fmsg delivery rejection remaining distinct.
- Duplicate
requestIdwith identical content executing once. - Duplicate
requestIdwith changed content being rejected. - A forged or mismatched fmsg
pid, sender, request ID, or operation being rejected. - Detached-root continuation when local graph state is unavailable.
- A threaded request rejected with fmsg code 6 being resent as a detached root, and a result rejected with code 6 being delivered as a detached result.
- A task control side branch that does not advance the task head.
- If streaming is advertised, sibling events delivered out of order, duplicate events, a missing event, and final-event handling.
- If push notifications are advertised, all configuration operations.
- If an extended Agent Card is advertised, authenticated retrieval and denial to an unauthorized transport principal.
Complete Example¶
An Agent Card contains an interface such as:
{
"name": "Research Agent",
"description": "Answers research questions",
"supportedInterfaces": [
{
"url": "fmsg:@research-agent@example.com",
"protocolBinding": "https://github.com/markmnl/fmsg/blob/main/standards/fmsg-004-a2a-binding.md",
"protocolVersion": "1.0"
}
],
"version": "1.0.0",
"capabilities": {
"streaming": false,
"pushNotifications": false,
"extendedAgentCard": false
},
"defaultInputModes": ["text/plain"],
"defaultOutputModes": ["text/plain"],
"skills": [
{
"id": "answer",
"name": "Answer questions",
"description": "Researches and answers a question",
"tags": ["research"]
}
]
}
The client @assistant@example.net sends a root fmsg message to
@research-agent@example.com with topic
A2A 018f3f6e-7c1a-7e95-8f23-6ed8b985a781 and this data:
{
"bindingVersion": "0.2",
"a2aVersion": "1.0",
"kind": "request",
"requestId": "018f3f6e-7c1a-7e95-8f23-6ed8b985a781",
"operation": "SendMessage",
"serviceParameters": {
"a2a-version": "1.0"
},
"payload": {
"message": {
"messageId": "018f3f70-56e9-7cb6-a640-4a195f5f6ae2",
"role": "ROLE_USER",
"parts": [
{
"text": "What is the capital of Australia?",
"mediaType": "text/plain"
}
]
},
"configuration": {
"returnImmediately": false
}
}
}
The server sends an fmsg reply to @assistant@example.net with pid equal to
the request hash, the no reply flag clear, and this data:
{
"bindingVersion": "0.2",
"a2aVersion": "1.0",
"kind": "response",
"requestId": "018f3f6e-7c1a-7e95-8f23-6ed8b985a781",
"operation": "SendMessage",
"payload": {
"message": {
"messageId": "018f3f73-1fe4-784a-9f01-0060ae5b13d2",
"contextId": "018f3f72-8c77-71b0-afbc-67693837d03b",
"role": "ROLE_AGENT",
"parts": [
{
"text": "Canberra is the capital of Australia.",
"mediaType": "text/plain"
}
]
}
}
}
Receipt of this response completes the binding exchange and establishes the
context anchor. A later SendMessage containing only that contextId replies
to this response and can create a new task branch. If a response instead
returned a task ID, a later SendMessage containing that taskId would reply
to the latest known result for that task, extending its chain. Each new request
still has its own request ID, and every A2A identifier remains explicit in its
A2A payload.