Skip to content

feat: integrate A2A agents into plugin framework for header handling and RBAC (ICACF-43)#4775

Open
MohanLaksh wants to merge 12 commits into
mainfrom
feature/icacf-43-a2a-plugin-integration
Open

feat: integrate A2A agents into plugin framework for header handling and RBAC (ICACF-43)#4775
MohanLaksh wants to merge 12 commits into
mainfrom
feature/icacf-43-a2a-plugin-integration

Conversation

@MohanLaksh
Copy link
Copy Markdown
Collaborator

Summary

A2A (Agent-to-Agent) agents previously bypassed the plugin pipeline entirely, preventing plugins like VaultPlugin from functioning with A2A tools. This PR integrates A2A agents into the plugin framework for full feature parity with MCP tools.

Before: MCP tools → fire pre/post-invoke hooks → VaultPlugin works; A2A agents → no hooks → VaultPlugin unusable
After: A2A agents fire AGENT_PRE_INVOKE and AGENT_POST_INVOKE hooks, enabling header injection, RBAC validation, and response transformation via plugins.

What Changed

Core Plugin Integration

  • Added AGENT_PRE_INVOKE and AGENT_POST_INVOKE hooks to A2AAgentService.invoke_agent() (a2a_service.py)
  • Created PydanticA2AAgent schema exposing agent metadata (tags, oauth_config, passthrough_headers, auth_type, auth_value, content_type) to plugins via GlobalContext.metadata[A2A_AGENT_METADATA]
  • Added content_type and request_headers parameters to invoke_agent() for plugin context
  • Both A2A endpoint handlers (invoke_a2a_agent, invoke_a2a_agent_by_id) in main.py now extract and forward inbound headers

Database & Schema

  • Created A2AAgentPluginBinding ORM model mirroring ToolPluginBinding structure (db.py)
  • Idempotent Alembic migration b29af8761e97 with inspector-based guards
  • Pydantic schemas: A2AAgentPluginBindingRequest, A2AAgentPluginBindingResponse, A2AAgentPluginBindingListResponse

Admin API & UI

  • REST router (routers/a2a_agent_plugin_bindings.py): POST upsert, GET list, GET by team, DELETE by ID, DELETE by reference
  • Binding service (services/a2a_agent_plugin_binding_service.py): full CRUD with specificity-wins wildcard semantics
  • Admin UI: sidebar tab, HTMX partial with team filter, create/delete forms

Testing

  • 4 new test files (2,152 lines): binding service, invoke hooks, API router, admin endpoints
  • All 17971 existing tests pass — no regressions
  • Total coverage: 97% | Diff coverage: 97% (threshold: 93%)

All 5 Gaps from ICACF-43 Addressed

Gap Issue Status
1 A2A bypasses plugin pipeline ✅ AGENT_PRE/POST_INVOKE hooks added
2 No agent identification in GlobalContext ✅ server_id = make_context_id(team_id, agent_name)
3 Agent config not exposed to plugins ✅ PydanticA2AAgent in metadata
4 No per-agent binding mechanism ✅ A2AAgentPluginBinding table + CRUD
5 Headers not forwarded to plugins ✅ content_type/request_headers threaded through

Related

Breaking Changes

None — all changes are additive and backward compatible.

- Add A2AAgentPluginBinding model to mcpgateway/db.py with team_id, agent_name, plugin_id, mode, priority, config, binding_reference_id, and on_error fields
- Create unique constraint on (team_id, agent_name, plugin_id) to enforce one-binding-per-plugin-per-agent rule
- Add Alembic migration b29af8761e97 to create a2a_agent_plugin_bindings table with proper indexes and constraints
- Add Pydantic schemas for A2A agent plugin binding request/response (A2AAgentPluginBindingRequest, A2AAgentPluginBindingResponse, A2AAgentPluginBindingListResponse)
- Add PydanticA2AAgent helper schema for plugin context metadata

This mirrors ToolPluginBinding but for A2A agents, enabling per-agent plugin policies.
Closes ICACF-43

Signed-off-by: Mohan Lakshmaiah <[email protected]>
- Add A2AAgentPluginBindingService with CRUD operations (upsert, list, delete)
- Add A2A agent plugin bindings router (POST/GET/DELETE endpoints)
- Register router in main.py
- Add plugin hooks (PRE_INVOKE, POST_INVOKE) to a2a_service.invoke_agent()
- Extract A2A agent metadata (team_id, visibility, tags, oauth, passthrough) before DB release
- Create GlobalContext with A2A_AGENT_METADATA for plugin context
- Handle pre-invoke modifications to parameters and headers
- Handle post-invoke with non-blocking error mode

Signed-off-by: Mohan Lakshmaiah <[email protected]>
The auto-generated migration tried to recreate 19 pre-existing tables
(global_config, gateways, servers, tools, etc.) alongside the new
a2a_agent_plugin_bindings table. This would fail on any real database.

- Rewrite migration to only create a2a_agent_plugin_bindings table
- Add inspector-based idempotency guards (per AGENTS.md pattern)
- Add 4 test files (1971 lines): binding service, invoke hooks,
  API router, and admin endpoints

Signed-off-by: Mohan Lakshmaiah <[email protected]>
…ugin bindings (ICACF-43)

- Add admin.py endpoints: HTMX partial, create, delete for A2A plugin bindings
- Add sidebar tab + panel in admin.html for A2A Plugin Bindings
- Add content_type/request_headers extraction in main.py handlers (invoke_a2a_agent,
  invoke_a2a_agent_by_id)
- Add content_type field to PydanticA2AAgent schema
- Add content_type/request_headers params to a2a_service.invoke_agent()
- Fix: safe agent.oauth_config access via getattr
- Fix: correlation_id None handling in GlobalContext
- Fix: tenant_id type guard for non-string team_ids
- Fix: use request_headers (not prepared.headers) in pre-invoke hook payload

Signed-off-by: Mohan Lakshmaiah <[email protected]>
…ributeError in existing tests (ICACF-43)

Signed-off-by: Mohan Lakshmaiah <[email protected]>
…refix with _ to suppress pylint W0613

Signed-off-by: Mohan Lakshmaiah <[email protected]>
…hip transfer (ICACF-43)

Add 8 new tests to push diff coverage from 92% to 97% (above 93% CI threshold):

- admin: partial render error, create service error, delete forbidden and generic error
- a2a_service: metadata build exception swallowed
- router: ValueError converted to HTTP 400
- binding service: binding_reference_id ownership transfer warning

Signed-off-by: Mohan Lakshmaiah <[email protected]>
…value-double-quotes error

Signed-off-by: Mohan Lakshmaiah <[email protected]>
…ependency

CI has cpex v0.1.0 which predates the A2A_AGENT_METADATA constant.
Defined the constant in mcpgateway.schemas and redirected imports from
the production code and tests to use it, removing the cpex dependency.

Signed-off-by: Mohan Lakshmaiah <[email protected]>
…le module docstrings warning

Signed-off-by: Mohan Lakshmaiah <[email protected]>
…e triple-quoted string with comment

Signed-off-by: Mohan Lakshmaiah <[email protected]>
@brian-hussey brian-hussey added the ica ICA related issues label May 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ica ICA related issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants