🐞 Bug Summary
Deleting an A2A agent (or its associated tool) from the Admin UI fails with sqlite3.IntegrityError: FOREIGN KEY constraint failed because the server_tool_association rows referencing the tool are not cleaned up before the tool row is deleted.
🧩 Affected Component
🔁 Steps to Reproduce
- Register an A2A agent (which auto-creates a corresponding tool and may associate it with a virtual server)
- Attempt to delete the A2A agent from the Admin UI A2A agents list
- Alternatively, attempt to delete the associated tool from the Admin UI tools list
Both paths fail with the same FK constraint error.
🤔 Expected Behavior
The A2A agent and its associated tool should be deleted successfully, with all dependent rows in server_tool_association cleaned up first.
📓 Logs / Error Output
ERROR [mcpgateway.services.structured_logger] [tool_service] Tool deletion failed
ERROR [mcpgateway.admin] Error deleting A2A agent: Failed to delete tool: (sqlite3.IntegrityError) FOREIGN KEY constraint failed
[SQL: DELETE FROM tools WHERE tools.id = ?]
[parameters: ('f9cb07ad1b29483ca06c25ad61d7d4b5',)]
(Background on this error at: https://sqlalche.me/e/20/gkpj)
🧠 Environment Info
| Key |
Value |
| Runtime |
Python 3.11+ |
| Database |
SQLite |
🧩 Additional Context (optional)
Root cause: ToolService.delete_tool() in tool_service.py uses a Core SQL DELETE statement (delete(DbTool).where(...)) which bypasses SQLAlchemy ORM cascade rules. The server_tool_association table has a FK to tools.id with no ondelete cascade at the DB level, so the delete is rejected by SQLite's FK enforcement.
Other FK references to tools.id are fine:
tool_metrics — explicitly purged before deletion, and has ORM cascade="all, delete-orphan"
tool_metrics_hourly — has ondelete="SET NULL" at DB level
a2a_agents.tool_id — has ondelete="SET NULL" at DB level
Fix: delete_tool() must delete server_tool_association rows for the tool before executing the tool DELETE. The gateway service already uses this pattern (e.g., gateway_service.py:1605).
🐞 Bug Summary
Deleting an A2A agent (or its associated tool) from the Admin UI fails with
sqlite3.IntegrityError: FOREIGN KEY constraint failedbecause theserver_tool_associationrows referencing the tool are not cleaned up before the tool row is deleted.🧩 Affected Component
mcpgateway- APImcpgateway- UI (admin panel)🔁 Steps to Reproduce
Both paths fail with the same FK constraint error.
🤔 Expected Behavior
The A2A agent and its associated tool should be deleted successfully, with all dependent rows in
server_tool_associationcleaned up first.📓 Logs / Error Output
🧠 Environment Info
🧩 Additional Context (optional)
Root cause:
ToolService.delete_tool()intool_service.pyuses a Core SQLDELETEstatement (delete(DbTool).where(...)) which bypasses SQLAlchemy ORM cascade rules. Theserver_tool_associationtable has a FK totools.idwith noondeletecascade at the DB level, so the delete is rejected by SQLite's FK enforcement.Other FK references to
tools.idare fine:tool_metrics— explicitly purged before deletion, and has ORMcascade="all, delete-orphan"tool_metrics_hourly— hasondelete="SET NULL"at DB levela2a_agents.tool_id— hasondelete="SET NULL"at DB levelFix:
delete_tool()must deleteserver_tool_associationrows for the tool before executing the tool DELETE. The gateway service already uses this pattern (e.g.,gateway_service.py:1605).