A2A agents
Publish Scrydon workflows as A2A 1.0 agents, invoke them from Cortex or another A2A client, and call external agents from a workflow.
Scrydon supports the Agent2Agent (A2A) protocol in both directions:
- Publish a workflow as its own A2A agent.
- Use the A2A block to discover and call an external agent.
The supported A2A 1.0 bindings are JSON-RPC and HTTP+JSON, including streaming over SSE. Optional A2A 0.3 compatibility is available for existing clients and agents. Scrydon does not advertise or claim the gRPC binding.
Publish a workflow as an agent
Each workflow publication is one independently addressable A2A agent. An organization can publish any number of workflows, and each gets its own stable Agent ID, Agent Card, task namespace, visibility, and pinned deployment version.
The Deployments panel contains one Agent endpoints section per workflow — not one per environment. A Serves environment field in the A2A configuration selects which environment's deployment the agent executes (defaults to the highest deployed environment; the development draft can be selected explicitly). Published agents appear as rows in Agent endpoints: A2A Agent · <visibility> · serves <environment>. When nothing is published yet, a single quiet row with a Publish button is shown instead.
- Open the workflow in the editor. The workflow must contain an enabled Response block.
- Click Deploy in the editor toolbar to open the Deployments panel. The panel shows a vertical pipeline stepper — one row per environment with version, time, deployed-by, and a promote button.
- If no deployment exists for the target environment yet, click the Promote button on the relevant environment row.
- Scroll to the Agent endpoints section at the bottom of the panel and click Publish (or click an existing A2A agent row to reconfigure it).
- In the A2A configuration, choose the Serves environment, configure the basic Agent Card (and optionally an extended Agent Card), and choose API-key and/or bearer-token authentication.
- Keep the default Private visibility, or explicitly make the agent public and discoverable.
- Save, then copy the Agent Card or protocol endpoint shown in the view.
Publishing always pins an immutable deployment snapshot. Editing the workflow canvas does not change the running agent. Promote a newer version and update the pinned deployment in the A2A configuration when you are ready to republish.
Agent icons
Scrydon generates a unique monogram icon for every published agent automatically. The icon appears in the Agent Card returned to external A2A clients. Custom icon URLs can still be set programmatically via the publication API (basicCard.iconUrl), but are no longer part of the UI.
Workspace environments are user-defined. Their names and read-only setting do not determine A2A visibility: a workflow in any writable or read-only environment may be disabled, private, or public. Credentials remain bound to the publication's exact workspace environment.
Visibility
| Visibility | Agent Card | Public catalog | Protocol operations |
|---|---|---|---|
| Disabled | Unavailable | Hidden | Unavailable |
| Private (default) | Requires authentication | Hidden | Requires authentication and workflow authorization |
| Public | Public basic card | Listed | Still requires authentication and workflow authorization |
Public visibility makes discovery public; it does not make workflow execution or task data public. An authenticated extended Agent Card is never returned by public discovery.
The public organization catalog is paginated at:
GET /api/a2a/catalog/{organizationId}?pageSize=25&pageToken=...The authenticated A2A panel also lists the organization's publications across all environments, including disabled and private agents.
Agent Cards and endpoints
The A2A configuration view provides these URLs:
| Endpoint | Purpose |
|---|---|
/api/a2a/agents/{agentId}/.well-known/agent-card.json | Basic Agent Card discovery |
/api/a2a/agents/{agentId} | A2A 1.0 JSON-RPC |
/api/a2a/agents/{agentId}/... | A2A 1.0 HTTP+JSON resources and methods |
/api/a2a/jwks | Public keys for Agent Card signature verification |
The basic card describes the agent's name, version, provider, documentation, supported media types, skills, security schemes, bindings, and capabilities. Enable the extended card when authenticated callers need a richer description than public discovery should expose.
Cards are signed with ES256 and include their JWK Set URL. Public cards support ETag, Last-Modified, and cache revalidation. Private cards use private, no-store caching.
Authentication and task isolation
Enable at least one publication authentication scheme:
- API key: send the environment-bound workspace key in
X-API-Key. - Bearer: send an OAuth/OIDC token in
Authorization: Bearer …. Read operations requireworkflows:read; mutations and execution requireworkflows:write.
Every task is scoped to the publication and the authenticated principal. A different principal, organization, workspace, or workspace environment receives the same not-found response as a nonexistent task. Task IDs therefore cannot be used to enumerate another caller's work.
Call the agent
Every protocol request should send the selected interface's advertised version:
curl -X POST 'https://scrydon.example/api/a2a/agents/AGENT_ID' \
-H 'A2A-Version: 1.0' \
-H 'Content-Type: application/json' \
-H 'X-API-Key: YOUR_WORKSPACE_KEY' \
-d '{
"jsonrpc": "2.0",
"id": "request-1",
"method": "SendMessage",
"params": {
"message": {
"role": "ROLE_USER",
"messageId": "message-1",
"parts": [{ "text": "Create the quarterly summary", "mediaType": "text/plain" }]
}
}
}'The equivalent HTTP+JSON call uses the same protocol base URL:
curl -X POST 'https://scrydon.example/api/a2a/agents/AGENT_ID/message:send' \
-H 'A2A-Version: 1.0' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-d '{
"message": {
"role": "ROLE_USER",
"messageId": "message-1",
"parts": [{ "text": "Create the quarterly summary", "mediaType": "text/plain" }]
}
}'SendMessage returns either a task or a direct agent message. For a task, poll GET /tasks/{taskId}, subscribe with POST /tasks/{taskId}:subscribe, or use a push-notification configuration.
Prove interoperability with the official JavaScript SDK
This is the strongest independent smoke test for a private publication because it discovers the Agent Card, negotiates an advertised transport, and sends an A2A 1.0 message without using a Scrydon session cookie.
- Create an API key in the same workspace environment as the publication.
- Copy the Protocol URL from the A2A configuration view.
- In an empty directory, install the stable official SDK:
bun add @a2a-js/sdk@1.0.0- Save this as
a2a-proof.mjs:
import { randomUUID } from "node:crypto";
import {
Message,
Role,
SendMessageConfiguration,
Task,
} from "@a2a-js/sdk";
import {
ClientFactory,
ClientFactoryOptions,
DefaultAgentCardResolver,
JsonRpcTransportFactory,
RestTransportFactory,
} from "@a2a-js/sdk/client";
const agentUrl = process.env.A2A_AGENT_URL;
const apiKey = process.env.A2A_API_KEY;
if (!agentUrl || !apiKey) {
throw new Error("Set A2A_AGENT_URL and A2A_API_KEY");
}
const authenticatedFetch = async (input, init) => {
const original =
input instanceof Request ? new Request(input, init) : new Request(input, init);
const headers = new Headers(original.headers);
headers.set("X-API-Key", apiKey);
return fetch(new Request(original, { headers, redirect: "error" }));
};
const factory = new ClientFactory(
ClientFactoryOptions.createFrom(ClientFactoryOptions.default, {
cardResolver: new DefaultAgentCardResolver({
fetchImpl: authenticatedFetch,
}),
transports: [
new JsonRpcTransportFactory({ fetchImpl: authenticatedFetch }),
new RestTransportFactory({ fetchImpl: authenticatedFetch }),
],
}),
);
const client = await factory.createFromUrl(`${agentUrl.replace(/\/$/, "")}/`);
const card = await client.getAgentCard();
console.log(
"Negotiated",
client.protocolVersion,
card.supportedInterfaces.map((item) => item.protocolBinding),
);
const result = await client.sendMessage({
tenant: "",
message: Message.fromJSON({
messageId: randomUUID(),
role: Role.ROLE_USER,
parts: [
{
text: "Run the A2A interoperability proof",
mediaType: "text/plain",
},
],
}),
configuration: SendMessageConfiguration.fromJSON({
acceptedOutputModes: ["application/json", "text/plain"],
returnImmediately: false,
}),
});
console.dir(
"id" in result ? Task.toJSON(result) : Message.toJSON(result),
{ depth: null },
);- Run it:
A2A_AGENT_URL='https://scrydon.example/api/a2a/agents/AGENT_ID' \
A2A_API_KEY='YOUR_WORKSPACE_KEY' \
bun run a2a-proof.mjsThe first line should report protocol 1.0 and the advertised JSONRPC and HTTP+JSON bindings. The final value is either an A2A task or a direct agent message. A blocking workflow normally returns a task whose final state is TASK_STATE_COMPLETED.
The official A2A Inspector is useful for viewing an Agent Card, basic validation, and inspecting raw JSON-RPC. Its authentication support is not complete, so it cannot currently prove an authenticated Scrydon execution by itself. Use the official SDK example above or Cortex for the end-to-end invocation.
Invoke published agents from Cortex
Cortex can discover and call Scrydon-published agents directly. It uses the active workspace as the discovery boundary and the active workspace environment as the calling boundary; it does not accept arbitrary external A2A URLs.
- Publish one or more workflows as Private or Public A2A agents. Disabled agents are excluded.
- Switch Cortex to the same workspace. Agents published for any environment in that workspace are visible.
- Ask Cortex to find the agent by name, description, skill, or tag and tell it what to do. For example:
Find the A2A agent named "Quarterly reporting" and ask it to create the Q2 summary.- Cortex first runs
a2a_agent_search. Callable agents (serving the active environment) appear in the main results. Agents published for other environments are listed separately underelsewhere; Cortex will suggest switching the active environment to reach them. - Approve the
a2a_agent_callconfirmation. Calling an agent executes its pinned workflow deployment. - Inspect the returned A2A task or message in the conversation.
Cortex discovers both Private and Public publications across all environments of the active workspace because the signed-in user is already authorized there. Only agents whose publication serves the active workspace environment are callable; agents serving a different environment are reported but cannot be called until the user switches to that environment. Cortex revalidates the selected Agent ID immediately before each call.
Supported server operations
| Operation | JSON-RPC method | HTTP+JSON |
|---|---|---|
| Send a message | SendMessage | POST /message:send |
| Send and stream | SendStreamingMessage | POST /message:stream |
| Get a task | GetTask | GET /tasks/{id} |
| List tasks | ListTasks | GET /tasks |
| Cancel a task | CancelTask | POST /tasks/{id}:cancel |
| Subscribe to a task | SubscribeToTask | POST /tasks/{id}:subscribe |
| Create push configuration | CreateTaskPushNotificationConfig | POST /tasks/{id}/pushNotificationConfigs |
| Get push configuration | GetTaskPushNotificationConfig | GET /tasks/{id}/pushNotificationConfigs/{configId} |
| List push configurations | ListTaskPushNotificationConfigs | GET /tasks/{id}/pushNotificationConfigs |
| Delete push configuration | DeleteTaskPushNotificationConfig | DELETE /tasks/{id}/pushNotificationConfigs/{configId} |
| Get the extended card | GetExtendedAgentCard | GET /extendedAgentCard |
Both bindings use the A2A 1.0 task states, pagination, history controls, message continuation, artifacts, service parameters, extensions, canonical errors, and google.rpc.ErrorInfo details. Streaming uses text/event-stream and preserves the binding's response envelope.
When 0.3 compatibility is enabled, the Agent Card also advertises compatible JSON-RPC and HTTP+JSON interfaces and translates legacy methods and payloads through the official SDK.
Workflow input and output
The workflow receives the normalized request under a2a:
{
"a2a": {
"message": { "messageId": "message-1", "role": "ROLE_USER", "parts": [] },
"configuration": {},
"metadata": {}
}
}The selected Response block becomes the agent response:
- A string becomes a
text/plainagent message. - Any other JSON value becomes an
application/jsondata part when the caller accepts it. - For complete control, return
{ "a2a": { "message": ..., "artifacts": [...] } }as the Response data. - A Response status of 400 or higher fails the task without exposing internal node output.
Workflow pauses and human-review steps project to TASK_STATE_INPUT_REQUIRED. Continue the same task by sending another message with its taskId and matching contextId. Terminal tasks reject follow-up messages and subscriptions with the canonical A2A error.
Inbound messages and projected output pass through the organization's DLP policy. Execution, cancellation, publication changes, push configuration changes, and dead-letter delivery are audit logged without message bodies or credentials.
Payload limits
| Limit | Value |
|---|---|
| Serialized request or response | 6 MiB |
| Parts per message or artifact | 32 |
| Total response parts | 128 |
| Artifacts per response | 32 |
| Text or raw bytes per part | 1 MiB |
| Raw bytes per request or response | 5 MiB |
| Raw-file storage per task | 20 MiB |
| Metadata object | 64 KiB, maximum nesting depth 12 |
| Returned history | 0–100 messages |
Raw file parts are moved to the execution file store before durable scheduling and rehydrated only inside the authorized task scope.
Push notifications
Push configurations support a callback token or an authentication scheme and credentials. In production, callbacks must use HTTPS. Scrydon resolves and pins public DNS targets, blocks private, loopback, link-local, and cloud-metadata destinations, and revalidates delivery targets to prevent DNS rebinding.
Delivery preserves per-configuration ordering, retries retryable failures three times with backoff, and then marks the configuration dead-lettered. Callback secrets are encrypted at rest and never appear in audit logs.
Call external A2A agents
Add an A2A block to a workflow and choose one of the same discovery, messaging, streaming, task, subscription, push, or extended-card operations. Enter the agent's base or protocol URL; Scrydon tries canonical A2A 1.0 discovery first and the 0.3 discovery locations as compatibility fallbacks.
Outbound authentication supports:
- API keys in a header, query parameter, or cookie
- HTTP Basic
- Bearer tokens
- OAuth 2.0 access tokens
- OpenID Connect access tokens
You can also require a signed Agent Card, set a 100 ms–300 s timeout, and send non-reserved service parameters and A2A extension URIs. Mutual TLS is detected and rejected with a clear unsupported-authentication error.
Production outbound calls require HTTPS unless the operator explicitly enables A2A_ALLOW_INSECURE_HTTP=true. Every discovery URL, interface URL, redirect, and JWK Set URL is DNS-pinned and checked against private-address and metadata-host restrictions. Credentials and custom service headers are stripped on cross-origin redirects.
Operator configuration
Production deployments must configure Agent Card signing with one of:
A2A_CARD_SIGNING_PRIVATE_JWKS: a JSON JWK Set or array. This supports key overlap and rotation.A2A_CARD_SIGNING_PRIVATE_JWK: a single private P-256 EC JWK for compatibility.
Set A2A_CARD_SIGNING_KEY_ID to select the active private key. Keys marked revoked, expired, or not yet active are not published or selected. A2A_PAGE_TOKEN_SECRET may be set to a dedicated secret of at least 32 characters; otherwise the configured platform auth secret signs scoped catalog and task page tokens.
Troubleshooting
| Symptom | Check |
|---|---|
401 Authentication required | Send one of the schemes advertised by the Agent Card. |
| Task or agent returns not found | Confirm the credential belongs to the publication's exact organization, workspace, and workspace environment. |
JSON-RPC -32005 or HTTP 415 | The message part's media type is not listed in the Agent Card input modes. |
JSON-RPC -32009 or HTTP 400 | Send an A2A-Version advertised by the selected interface. |
| Agent disappears | Confirm the publication is Private or Public rather than Disabled. |
| Workflow edits do not appear | Publish a new deployment version and repin the A2A publication. |
| Push callback is refused | Use a public HTTPS endpoint; private and metadata addresses are blocked. |