Q for developers

External agents and outbound HTTP

External agents and outbound HTTP for Q integrations.

Q1.2 introduces tenant-owned A2A execution registrations and a common HTTP destination policy. This is a breaking security migration. The implementation and tests are local; production activation requires the steps below.

A2A API

OperationRequired scopeBehaviour
GET /v1/a2a/agentsa2a:readInternal Q cards plus the authenticated tenant's external cards; optional capability filter
POST /v1/a2a/agentsa2a:writeAtomic create/replace within the authenticated tenant; returns {"registered":"agent-id"}
DELETE /v1/a2a/agents/{agent_id}a2a:writeRemoves an owned registration; returns 204
POST /v1/a2a/tasksa2a:delegateKnown internal Q agent or an owned external registration; unknown/foreign IDs return 404 before delegation
GET /v1/a2a/tasks/{task_id}a2a:readExisting tenant-scoped local Q task lookup
GET /v1/a2a/.well-known/agent.jsonPublicQ's static capabilities; no tenant registration or secret

a2a:* and the existing administrative * cover these operations. ai:*, first_party and disabling Q_ENFORCE_AI_SCOPES do not bypass them. Developer API-key issuance accepts the new scopes. Tenant identity comes from authentication, never from a registration body. JWT/session callers also need these capabilities in their authenticated scope set.

Example registration body (synthetic values):

{
  "agentId": "acme.research",
  "name": "Acme research",
  "endpoint": "https://agents.example.com/research",
  "skills": [{"name": "research", "tags": ["research"]}],
  "bearer_token": "SYNTHETIC-EXAMPLE-REPLACE-SECURELY"
}

The optional bearer_token is write-only. Q encrypts it with A2A_CREDENTIAL_KEY using Fernet and binds the encrypted payload to tenant, agent ID and canonical origin. Missing/invalid encryption configuration fails closed. Replacing a registration without a token removes its previous credential; Q never silently carries it to a new endpoint. Credential-bearing endpoints require HTTPS. Discovery contains no credential field. Public validation and registration errors do not echo submitted secrets.

Agent IDs have 1–128 ASCII alphanumeric/underscore/dot/hyphen characters and start with an alphanumeric character. The q. prefix is reserved, case-insensitively. Cards are limited to 100,000 encoded bytes. Endpoints are base HTTP(S) URLs without userinfo, query credentials or fragments. Delegation appends /tasks; task metadata cannot replace the target or authentication headers. The existing legacy task envelope remains; this work does not establish complete A2A protocol conformance or remote task polling. Discovery currently returns at most 200 external cards in agent-ID order; general pagination remains Q2.2.

q_service.external_agents uses (tenant_id, agent_id) as its primary key. Every operation applies an explicit tenant predicate and transaction-local tenant context. Forced RLS remains active independently of the older Q_ENABLE_RLS switch. Tenant A and B can use the same agent ID without overwriting or discovering each other's registration.

Destination and transport policy

The shared factory is app.services.outbound.outbound_client(purpose, ...). Adapters select a fixed purpose; public request data cannot supply a transport, proxy, TLS override or private-network grant.

  • HTTP(S) only; reject userinfo, fragments, control characters and ambiguous URL forms. Credentials belong in adapter-managed headers, not URLs.
  • Resolve every destination and inspect all returned addresses. DNS failure, empty/mixed unsafe answers and more than 32 addresses fail closed. Connect to an approved literal IP; TLS certificate verification and SNI retain the original hostname. Recheck on every request and redirect, including pooled connections.
  • Global addresses are the default. Private, loopback and non-global destinations need the server exception below. Metadata endpoints, link-local, multicast, unspecified/reserved addresses and IPv6 transition routes stay blocked. A mapped IPv6 address receives the underlying IPv4 policy.
  • Credential/custom-header requests require HTTPS and bind that client to one origin. Continuation/download URLs cannot receive that client's credentials at a different origin. Cross-origin redirects are permitted only for credential-free GET/HEAD fetches; other purposes require same-origin redirects. Adapters retain their existing redirect opt-in.
  • Environment proxies and environment TLS overrides are ignored. Connector Q_HTTP_DISABLE_SSL_VERIFY no longer weakens these clients. Injecting a non-policy client into A2AClient is rejected.
  • HTTPX request URL logs are redacted. Transport/status errors contain stable codes, not URLs. Webhook metrics use the bounded label callback; retry destinations are retained privately in the outbox, including their original query, and are revalidated on delivery.
LimitValue
Request and response body8 MiB each, including streamed/chunked bodies
Whole HTTP request, body and redirect chain60 seconds maximum
DNS lookup5 seconds maximum
Connect/read/write/pool operation10 seconds maximum; smaller adapter limits retained
Redirects5 maximum; smaller adapter limits retained
Connections per client20 total, 10 retained
EncodingRequests ask for identity; compressed responses are rejected

Streams close on size failure, timeout and cancellation. These are per-request/client limits, not total tenant quotas. Existing adapter retries may start another bounded request; connector server-supplied retry delays are capped at 120 seconds. A long-lived MCP/context SSE response exceeding these limits must reconnect or fail; there is no unlimited streaming exception.

Deliberate private connectivity

An operator can set OUTBOUND_PRIVATE_RULES as a JSON array in server configuration. Each entry requires an exact canonical origin (scheme, host and non-default port), one purpose and explicit CIDRs:

[
  {
    "purpose": "mcp",
    "origin": "https://tools.corp.example:8443",
    "cidrs": ["10.20.0.12/32"]
  }
]

Valid purposes are a2a, fetch, mcp, hooks, connectors, callbacks and context. There are no host wildcards. A different purpose, host, scheme, port or resolved address does not inherit permission. Even an explicit metadata CIDR cannot permit metadata access. Loopback exceptions are supported, including IPv6 ::1/128; HTTPS and certificate verification still apply to credential-bearing requests. Use a certificate trusted by Q's verified HTTP transport. Client requests cannot add trust roots or disable verification.

These are deployment-wide network permissions for the chosen purpose, not tenant authorisation or endpoint authentication. Grant only reviewed destinations whose application authenticates authorised tenants. MCP registration additionally retains MCP_REQUIRE_HTTPS and MCP_BLOCKED_HOSTS; an outbound exception does not override an explicit MCP host block. Configure both deliberately when supporting local MCP development.

Adapter coverage and compatibility

PurposeCovered paths
A2ATenant registration endpoint validation, delegation, direct A2A client and remote card discovery (including advertised endpoint validation)
FetchAnswer Engine fetch_url, including cache hits/revalidation and direct fetch/redirects
MCPClient manager, third-party context MCP connector, streamable HTTP, server cards, ClickUp, Google Workspace and ClickUp OAuth HTTP
HooksHook executor and handler HTTP POSTs
ConnectorsShared connector HTTP factory used by implemented GitHub, Google Drive and Jira connectors
ContextPull, streaming, federated RAG and retrieval callback validation
CallbacksWebhook delivery, HTTP notification channels and scheduled callback activities

MCP client-manager sessions include tenant/global identity, server ID, URL and authentication configuration in their reuse key. Tools queries have an explicit tenant/global predicate even when legacy RLS is disabled. Changed credentials cannot reuse an old authenticated session; failed handshakes close clients.

Hook handlers no longer fall back to aiohttp/urllib. Fetch no longer sends URLs to a remote reader that can bypass Q's destination checks. It performs bounded direct HTTP and basic text extraction; JavaScript-rendered pages, remote-reader formatting and large/compressed downloads may now be unavailable. Provider-specific document download URLs on another origin need a separately reviewed credential-free download path; Q will not forward connector credentials automatically. The remaining connector scaffolds are still scaffolds; this policy does not implement them.

This transport is not an OS-wide egress firewall. Fixed provider/gateway SDK calls, browser engines, arbitrary worker code and other service-control clients are outside this adapter inventory. Q1.1's workspace execution boundary remains in force. Production network controls must independently restrict egress. The separate catalogue-only agent marketplace is not the A2A execution registry; its persistence/permission work remains separate. Retrieval/user ACL propagation remains Q1.3 and full A2A conformance remains Q6.2.

Deployment and rollback

  1. Apply Alembic revision 20261007_120000_external_agents after the workspace-resource revision. Grant the application DB role schema usage and SELECT/INSERT/UPDATE/DELETE on the new table. Use a role without superuser or BYPASSRLS; do not run the service as the migration administrator.
  2. Provision one secret A2A_CREDENTIAL_KEY consistently across API/worker instances. Generate a Fernet key through the approved secret-management process. Do not put it in examples, source control or logs. Key rotation currently requires re-registering credentials; losing the key does not expose plaintext and makes those credentials unusable.
  3. Re-register external agents for their authenticated owners. The old process-global dictionary had no trustworthy ownership or durability, so it is not auto-imported into all tenants. Issue the required A2A scopes and update clients for asynchronous tenant-aware service calls and DELETE support.
  4. Review private integrations, HTTPS certificates, headers, redirect/download hosts, response encoding and size/stream limits. Configure only the exact server grants required. Exercise the real integrations in a controlled staging environment.
  5. Run the required release checks and full hosted CI before production promotion. SDK regeneration, UI/client qualification and existing Q1.1 migration obligations remain release requirements.

Downgrading the migration drops the registry, including encrypted credentials. Export an authorised encrypted backup before a deliberate rollback; do not restore the previous globally shared execution registry as a compatibility bypass. This task has not migrated or deployed a production environment.

On this page