You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Goal:iii worker add mcp and iii worker add a2a deliver drop-in, spec-compliant protocol surfaces built purely on iii primitives. Users compose apps, harnesses, and agents from narrow workers — no protocol glue.
Why
Current state deviates from that thesis five ways:
RBAC duplicated at handler layer.ALWAYS_HIDDEN_PREFIXES + mcp.expose / a2a.expose metadata + --expose-all + --tier all reinvent access control locally. iii-sdk already has full RBAC at iii-worker-manager (auth_function_id, expose_functions, AuthResult.{allowed,forbidden}_functions). Two policy layers = layered denials, confusing errors, drift risk.
A2A v0.3 gaps. Missing message/stream, tasks/resubscribe, all four *TaskPushNotificationConfig methods, GetExtendedAgentCard, securitySchemes/security fields, task states Submitted / InputRequired / AuthRequired / Rejected, TaskStatusUpdateEvent, TaskArtifactUpdateEvent.
Concrete bugs. Agent card advertises base_url without /a2a path suffix (spec clients 404). documentation_url points to a dead iii-connect repo. Agent identity (name, description, provider) hardcoded.
No client workers. Neither mcp-client nor a2a-client exists. iii cannot consume external MCP servers or A2A agents as tools. Cross-protocol harness building is structurally blocked.
Constraints:
No engine changes. Everything inside iii-hq/workers.
Narrow-worker idiom (~2000 LOC per crate).
Single breaking migration (Phase 1), additive afterwards.
Outcome: four Rust crates — mcp, a2a, mcp-client (new), a2a-client (new) — fully-spec-compliant server + client halves of both protocols, authorized via iii-sdk RBAC, harness-ready.
Phase 0 ships as a point release (non-breaking). Phase 1 is the single architectural gate — every subsequent phase reads from the post-RBAC iii.list_functions() worldview. Phases 2, 3, 4 run in parallel after 1 lands.
Phase 3 — A2A v0.3 spec completion: message/stream, tasks/resubscribe, four push-notification methods, GetExtendedAgentCard, full task-state lifecycle, securitySchemes/security agent-card fields.
Phase 4 — New crates: mcp-client and a2a-client (consume external servers/agents, register remote tools/skills as local iii functions under namespaced IDs). Shared iii-protocol-common crate.
Phase 5 — End-to-end harness validation: Claude Desktop → iii; iii → external MCP server; iii harness → iii harness over A2A streaming.
Key architectural decisions
Authorization: forward Authorization header into AuthInput.headers. iii-worker-manager runs deploy-configured auth_function_id. Zero crypto in worker. Example auth_function_id with JWT verification shipped as examples/oauth-passthrough.rs. Not a literal OAuth 2.1 implementation — deploys needing that write a 50-line auth function using jose.
Client workers are separate crates, not --mode flags. Server and client semantics are inverted (one-trigger-many-tools vs many-proxies-no-triggers). Separate supervision trees and deps. Matches the narrow-worker convention.
SSE primitive:ChannelWriter (reference: iii/sdk/packages/rust/iii/tests/api_triggers.rs:498). Used by MCP Streamable HTTP, MCP progress/logging, A2A message/stream, A2A tasks/resubscribe. Extracted into iii-protocol-common::sse after the first usage lands.
introspect::* stays the canonical engine-introspection surface. The old engine::* hard floor is dropped; users who want engine::*-like visibility are pointed at introspect::{functions,workers,triggers,topology,diagram,health,trace_workflow,explain} — already shipped in iii-hq/workers/introspect.
Umbrella: MCP + A2A Workers Overhaul
Goal:
iii worker add mcpandiii worker add a2adeliver drop-in, spec-compliant protocol surfaces built purely on iii primitives. Users compose apps, harnesses, and agents from narrow workers — no protocol glue.Why
Current state deviates from that thesis five ways:
ALWAYS_HIDDEN_PREFIXES+mcp.expose/a2a.exposemetadata +--expose-all+--tierall reinvent access control locally. iii-sdk already has full RBAC atiii-worker-manager(auth_function_id,expose_functions,AuthResult.{allowed,forbidden}_functions). Two policy layers = layered denials, confusing errors, drift risk.title/annotations/outputSchema, structured content, HTTP-transport authorization.message/stream,tasks/resubscribe, all four*TaskPushNotificationConfigmethods,GetExtendedAgentCard,securitySchemes/securityfields, task statesSubmitted/InputRequired/AuthRequired/Rejected,TaskStatusUpdateEvent,TaskArtifactUpdateEvent.base_urlwithout/a2apath suffix (spec clients 404).documentation_urlpoints to a deadiii-connectrepo. Agent identity (name,description,provider) hardcoded.mcp-clientnora2a-clientexists. iii cannot consume external MCP servers or A2A agents as tools. Cross-protocol harness building is structurally blocked.Constraints:
iii-hq/workers.Outcome: four Rust crates —
mcp,a2a,mcp-client(new),a2a-client(new) — fully-spec-compliant server + client halves of both protocols, authorized via iii-sdk RBAC, harness-ready.Sequence
Phase 0 ships as a point release (non-breaking). Phase 1 is the single architectural gate — every subsequent phase reads from the post-RBAC
iii.list_functions()worldview. Phases 2, 3, 4 run in parallel after 1 lands.Tracked sub-issues
serviceEndpoint/a2asuffix, deadiii-connectdoc link, configurable agent identity (--agent-name,--agent-description,--provider-org,--provider-url,--docs-url).ALWAYS_HIDDEN_PREFIXES(exceptmcp::/a2a::structural loop guard),ExposureConfig,mcp.expose/a2a.exposemetadata,--expose-all,--tier. Migration README +examples/default-secure-auth.rs.ChannelWriter+ RBAC-delegated auth.message/stream,tasks/resubscribe, four push-notification methods,GetExtendedAgentCard, full task-state lifecycle,securitySchemes/securityagent-card fields.mcp-clientanda2a-client(consume external servers/agents, register remote tools/skills as local iii functions under namespaced IDs). Sharediii-protocol-commoncrate.Key architectural decisions
Authorizationheader intoAuthInput.headers.iii-worker-managerruns deploy-configuredauth_function_id. Zero crypto in worker. Exampleauth_function_idwith JWT verification shipped asexamples/oauth-passthrough.rs. Not a literal OAuth 2.1 implementation — deploys needing that write a 50-line auth function usingjose.--modeflags. Server and client semantics are inverted (one-trigger-many-tools vs many-proxies-no-triggers). Separate supervision trees and deps. Matches the narrow-worker convention.ChannelWriter(reference:iii/sdk/packages/rust/iii/tests/api_triggers.rs:498). Used by MCP Streamable HTTP, MCP progress/logging, A2Amessage/stream, A2Atasks/resubscribe. Extracted intoiii-protocol-common::sseafter the first usage lands.introspect::*stays the canonical engine-introspection surface. The oldengine::*hard floor is dropped; users who wantengine::*-like visibility are pointed atintrospect::{functions,workers,triggers,topology,diagram,health,trace_workflow,explain}— already shipped iniii-hq/workers/introspect.Out of scope
introspect::*changes — already correctly shaped.Issue disposition
v0.4.0.