UAT: MCPToolAdapter.register_tools() infers resource slots but never wires them into domain Tool objects or the database — resource bindings are silently lost #2524

Open
opened 2026-04-03 18:45:48 +00:00 by freemo · 1 comment
Owner

Metadata

  • Branch: fix/mcp-adapter-resource-slots-wiring
  • Commit Message: fix(tool): wire MCPToolAdapter inferred resource slots into domain Tool objects and persist to tool_resource_bindings
  • Milestone: v3.7.0
  • Parent Epic: #392

Description

MCPToolAdapter.register_tools() in src/cleveragents/mcp/adapter.py calls self.infer_resource_slots() to infer resource slots from MCP tool parameter schemas (e.g., file_path → file resource slot). However, the inferred slots are only stored in source_metadata["resource_slots"] on the ToolSpec object — they are never wired into the domain Tool.resource_slots field or persisted to the database.

The code itself acknowledges this with a TODO comment (lines 591–596):

# TODO(#882): resource_slots are stored in source_metadata but
# nothing downstream reads them yet.  The ToolRegistry persists
# resource bindings via domain Tool.resource_slots, and the DB
# migration (c1_001) stores them in tool_resource_bindings.
# A follow-up ticket should wire inferred slots into the domain
# Tool objects so the registry and DB actually consume them.

Issue #882 (which this TODO references) has been closed, but the TODO was never resolved — the code still stores resource slots only in source_metadata and never creates ResourceSlot domain objects or persists them to tool_resource_bindings.

There is also a field name mismatch: infer_resource_slots() stores slots under source_metadata["resource_slots"] but ToolRegistry.find_tools_for_resource() reads from source_metadata["resource_bindings"], so even the in-memory lookup is broken.

Expected Behaviour (per spec)

MCP tools discovered via MCPToolAdapter should have their inferred resource slots stored as ResourceSlot domain objects in the Tool.resource_slots field, and these should be persisted to the tool_resource_bindings table in the database. This enables polymorphic tool matching via ToolRegistry.find_tools_for_resource().

Actual Behaviour

infer_resource_slots() returns ResourceSlot objects, but they are immediately converted to plain dicts and stored only in source_metadata. The ToolSpec created by register_tools() does not have resource_slots populated. ToolRegistry.find_tools_for_resource() reads from source_metadata.get("resource_bindings", []) (not resource_slots), so even the in-memory lookup is broken.

Code Locations

  • src/cleveragents/mcp/adapter.py lines 580–616 (register_tools() method)
  • src/cleveragents/tool/registry.py lines 99–135 (find_tools_for_resource() method)
  • src/cleveragents/domain/models/core/tool.pyResourceSlot class

Subtasks

  • Write a TDD issue-capture Behave scenario (@tdd_expected_fail) demonstrating that MCPToolAdapter.register_tools() does not populate Tool.resource_slots
  • Write a TDD issue-capture Behave scenario (@tdd_expected_fail) demonstrating that ToolRegistry.find_tools_for_resource() returns empty results for MCP tools with inferred slots
  • Fix the field name mismatch: align source_metadata key between infer_resource_slots() ("resource_slots") and find_tools_for_resource() ("resource_bindings")
  • Update MCPToolAdapter.register_tools() to convert inferred ResourceSlot dicts back into ResourceSlot domain objects and assign them to Tool.resource_slots
  • Ensure ToolRegistry persists the wired resource_slots to the tool_resource_bindings table via the existing DB migration (c1_001)
  • Remove the stale TODO(#882) comment from adapter.py lines 591–596
  • Update/add unit tests (Behave) to cover the full slot-inference → domain-wiring → DB-persistence path
  • Verify ToolRegistry.find_tools_for_resource() correctly returns MCP tools after the fix
  • Run nox (all sessions) and confirm all quality gates pass

Definition of Done

  • TDD issue-capture scenarios exist and initially fail (@tdd_expected_fail), then pass after the fix
  • MCPToolAdapter.register_tools() populates Tool.resource_slots with properly typed ResourceSlot domain objects
  • ToolRegistry.find_tools_for_resource() returns MCP tools whose inferred slots match the queried resource
  • Resource slots are persisted to tool_resource_bindings in the database
  • Field name mismatch between "resource_slots" and "resource_bindings" is resolved
  • Stale TODO(#882) comment removed
  • All nox stages pass
  • Coverage >= 97%

Automated by CleverAgents Bot
Supervisor: UAT Testing | Agent: ca-new-issue-creator

## Metadata - **Branch**: `fix/mcp-adapter-resource-slots-wiring` - **Commit Message**: `fix(tool): wire MCPToolAdapter inferred resource slots into domain Tool objects and persist to tool_resource_bindings` - **Milestone**: v3.7.0 - **Parent Epic**: #392 ## Description `MCPToolAdapter.register_tools()` in `src/cleveragents/mcp/adapter.py` calls `self.infer_resource_slots()` to infer resource slots from MCP tool parameter schemas (e.g., `file_path` → file resource slot). However, the inferred slots are only stored in `source_metadata["resource_slots"]` on the `ToolSpec` object — they are never wired into the domain `Tool.resource_slots` field or persisted to the database. The code itself acknowledges this with a TODO comment (lines 591–596): ```python # TODO(#882): resource_slots are stored in source_metadata but # nothing downstream reads them yet. The ToolRegistry persists # resource bindings via domain Tool.resource_slots, and the DB # migration (c1_001) stores them in tool_resource_bindings. # A follow-up ticket should wire inferred slots into the domain # Tool objects so the registry and DB actually consume them. ``` Issue #882 (which this TODO references) has been closed, but the TODO was never resolved — the code still stores resource slots only in `source_metadata` and never creates `ResourceSlot` domain objects or persists them to `tool_resource_bindings`. There is also a **field name mismatch**: `infer_resource_slots()` stores slots under `source_metadata["resource_slots"]` but `ToolRegistry.find_tools_for_resource()` reads from `source_metadata["resource_bindings"]`, so even the in-memory lookup is broken. ### Expected Behaviour (per spec) MCP tools discovered via `MCPToolAdapter` should have their inferred resource slots stored as `ResourceSlot` domain objects in the `Tool.resource_slots` field, and these should be persisted to the `tool_resource_bindings` table in the database. This enables polymorphic tool matching via `ToolRegistry.find_tools_for_resource()`. ### Actual Behaviour `infer_resource_slots()` returns `ResourceSlot` objects, but they are immediately converted to plain dicts and stored only in `source_metadata`. The `ToolSpec` created by `register_tools()` does not have `resource_slots` populated. `ToolRegistry.find_tools_for_resource()` reads from `source_metadata.get("resource_bindings", [])` (not `resource_slots`), so even the in-memory lookup is broken. ### Code Locations - `src/cleveragents/mcp/adapter.py` lines 580–616 (`register_tools()` method) - `src/cleveragents/tool/registry.py` lines 99–135 (`find_tools_for_resource()` method) - `src/cleveragents/domain/models/core/tool.py` — `ResourceSlot` class ## Subtasks - [ ] Write a TDD issue-capture Behave scenario (`@tdd_expected_fail`) demonstrating that `MCPToolAdapter.register_tools()` does not populate `Tool.resource_slots` - [ ] Write a TDD issue-capture Behave scenario (`@tdd_expected_fail`) demonstrating that `ToolRegistry.find_tools_for_resource()` returns empty results for MCP tools with inferred slots - [ ] Fix the field name mismatch: align `source_metadata` key between `infer_resource_slots()` (`"resource_slots"`) and `find_tools_for_resource()` (`"resource_bindings"`) - [ ] Update `MCPToolAdapter.register_tools()` to convert inferred `ResourceSlot` dicts back into `ResourceSlot` domain objects and assign them to `Tool.resource_slots` - [ ] Ensure `ToolRegistry` persists the wired `resource_slots` to the `tool_resource_bindings` table via the existing DB migration (`c1_001`) - [ ] Remove the stale `TODO(#882)` comment from `adapter.py` lines 591–596 - [ ] Update/add unit tests (Behave) to cover the full slot-inference → domain-wiring → DB-persistence path - [ ] Verify `ToolRegistry.find_tools_for_resource()` correctly returns MCP tools after the fix - [ ] Run `nox` (all sessions) and confirm all quality gates pass ## Definition of Done - [ ] TDD issue-capture scenarios exist and initially fail (`@tdd_expected_fail`), then pass after the fix - [ ] `MCPToolAdapter.register_tools()` populates `Tool.resource_slots` with properly typed `ResourceSlot` domain objects - [ ] `ToolRegistry.find_tools_for_resource()` returns MCP tools whose inferred slots match the queried resource - [ ] Resource slots are persisted to `tool_resource_bindings` in the database - [ ] Field name mismatch between `"resource_slots"` and `"resource_bindings"` is resolved - [ ] Stale `TODO(#882)` comment removed - [ ] All nox stages pass - [ ] Coverage >= 97% --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: ca-new-issue-creator
freemo added this to the v3.7.0 milestone 2026-04-03 18:46:19 +00:00
Author
Owner

Issue triaged by project owner:

  • State: Verified
  • MoSCoW: Should Have — Spec compliance or quality improvement that should be included in the milestone.

Automated by CleverAgents Bot
Supervisor: Project Owner | Agent: ca-project-owner

Issue triaged by project owner: - **State**: Verified - **MoSCoW**: Should Have — Spec compliance or quality improvement that should be included in the milestone. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: ca-project-owner
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Blocks
#392 Epic: Actor YAML & Compiler
cleveragents/cleveragents-core
Reference
cleveragents/cleveragents-core#2524
No description provided.