feat(tool): implement BuiltinAdapter class and MCP automatic resource slot creation #882

Closed
opened 2026-03-13 22:59:45 +00:00 by freemo · 3 comments
Owner

Metadata

  • Commit Message: feat(tool): implement BuiltinAdapter class and MCP automatic resource slot creation
  • Branch: feature/m5-builtin-adapter-mcp-slots

Background and Context

The specification defines 3 formal tool adapters: MCPToolAdapter, AgentSkillAdapter, and BuiltinAdapter. The MCPToolAdapter and AgentSkillAdapter exist and work, but:

  1. BuiltinAdapter: No formal class exists. Built-in tools are registered procedurally via helper functions (register_file_tools(), register_git_tools(), register_subplan_tool()) in tool/builtins/__init__.py. The spec implies a formal adapter with the same connect/discover/register lifecycle as the other adapters.

  2. MCP resource slots: The MCPToolAdapter creates ToolSpec objects from MCP tool metadata and registers them in the ToolRegistry, but does NOT create resource slots from MCP tool metadata. The AgentSkillAdapter does create resource slots (AgentSkillResourceSlot). The spec says the MCPToolAdapter should also auto-create resource slots.

Expected Behavior

  • BuiltinAdapter class with discover() and register() methods that enumerate and register all built-in tools consistently with the adapter pattern
  • MCPToolAdapter extended to infer resource slots from tool parameter schemas (e.g., file_path parameters → file resource slot)

Acceptance Criteria

  • BuiltinAdapter class exists and implements the tool adapter lifecycle
  • All built-in tools are registered through BuiltinAdapter.register()
  • MCPToolAdapter creates resource slots from tool parameter schemas
  • Resource slots have correct type, access mode, and binding mode
  • Both adapters integrate with the existing Tool Registry

Subtasks

  • Create BuiltinAdapter class in tool/builtins/
  • Refactor register_file_tools, register_git_tools, register_subplan_tool to use adapter
  • Add resource slot inference to MCPToolAdapter.infer_capabilities()
  • Map MCP tool parameters to resource slot types
  • Tests (Behave): Add scenarios for BuiltinAdapter lifecycle and MCP slot creation
  • Verify coverage >= 97% via nox -s coverage_report
  • Run nox (all default sessions), fix any errors

Definition of Done

This issue is complete when:

  • All subtasks above are completed and checked off.
  • A Git commit is created where the first line of the commit message matches the Commit Message in Metadata exactly, followed by a blank line, then additional lines providing relevant details about the implementation.
  • The commit is pushed to the remote on the branch matching the Branch in Metadata exactly.
  • The commit is submitted as a pull request to master, reviewed, and merged before this issue is marked done.
## Metadata - **Commit Message**: `feat(tool): implement BuiltinAdapter class and MCP automatic resource slot creation` - **Branch**: `feature/m5-builtin-adapter-mcp-slots` ## Background and Context The specification defines 3 formal tool adapters: MCPToolAdapter, AgentSkillAdapter, and BuiltinAdapter. The MCPToolAdapter and AgentSkillAdapter exist and work, but: 1. **BuiltinAdapter**: No formal class exists. Built-in tools are registered procedurally via helper functions (`register_file_tools()`, `register_git_tools()`, `register_subplan_tool()`) in `tool/builtins/__init__.py`. The spec implies a formal adapter with the same `connect/discover/register` lifecycle as the other adapters. 2. **MCP resource slots**: The MCPToolAdapter creates `ToolSpec` objects from MCP tool metadata and registers them in the ToolRegistry, but does NOT create resource slots from MCP tool metadata. The AgentSkillAdapter does create resource slots (`AgentSkillResourceSlot`). The spec says the MCPToolAdapter should also auto-create resource slots. ## Expected Behavior - `BuiltinAdapter` class with `discover()` and `register()` methods that enumerate and register all built-in tools consistently with the adapter pattern - `MCPToolAdapter` extended to infer resource slots from tool parameter schemas (e.g., `file_path` parameters → file resource slot) ## Acceptance Criteria - [ ] `BuiltinAdapter` class exists and implements the tool adapter lifecycle - [ ] All built-in tools are registered through `BuiltinAdapter.register()` - [ ] MCPToolAdapter creates resource slots from tool parameter schemas - [ ] Resource slots have correct type, access mode, and binding mode - [ ] Both adapters integrate with the existing Tool Registry ## Subtasks - [ ] Create `BuiltinAdapter` class in `tool/builtins/` - [ ] Refactor `register_file_tools`, `register_git_tools`, `register_subplan_tool` to use adapter - [ ] Add resource slot inference to `MCPToolAdapter.infer_capabilities()` - [ ] Map MCP tool parameters to resource slot types - [ ] Tests (Behave): Add scenarios for BuiltinAdapter lifecycle and MCP slot creation - [ ] Verify coverage >= 97% via `nox -s coverage_report` - [ ] Run `nox` (all default sessions), fix any errors ## Definition of Done This issue is complete when: - All subtasks above are completed and checked off. - A Git commit is created where the **first line** of the commit message matches the Commit Message in Metadata exactly, followed by a blank line, then additional lines providing relevant details about the implementation. - The commit is pushed to the remote on the branch matching the **Branch** in Metadata exactly. - The commit is submitted as a **pull request** to `master`, reviewed, and **merged** before this issue is marked done.
freemo added this to the v3.5.0 milestone 2026-03-13 23:00:01 +00:00
Member

Implementation Notes

Architecture

BuiltinAdapter (tool/builtins/adapter.py, 103 lines): Formal adapter class wrapping existing built-in tool registration. Methods: discover() returns all built-in ToolSpec objects from ALL_FILE_TOOLS + ALL_GIT_TOOLS + ALL_SUBPLAN_TOOLS; register(registry) registers all tools and returns names; activate()/deactivate() are no-ops. Cached discovery — tools enumerated once then memoized.

MCP Resource Slot Inference (mcp/adapter.py, +121 lines): New infer_resource_slots() static method scans input_schema.properties for parameter name patterns and creates ResourceSlot objects:

  • file_path, file, pathResourceSlot(resource_type="file", access="read_write", binding="parameter")
  • directory, dir, folderResourceSlot(resource_type="directory", access="read_only", binding="parameter")
  • repo_path, repositoryResourceSlot(resource_type="git-checkout", access="read_write", binding="contextual")

Slots stored in source_metadata["resource_slots"] since ToolSpec doesn't have a resource_slots field (the domain Tool model does, but ToolSpec is the execution-layer model).

Design Decisions

  1. Backward compatible: Existing register_file_tools() etc. functions still work alongside the new adapter class
  2. Slots in source_metadata: Rather than modifying ToolSpec's schema, slots are stored in source_metadata["resource_slots"] as serialized dicts — this avoids breaking changes to the ToolSpec interface
  3. De-duplication: infer_resource_slots() deduplicates slots by (resource_type, access) tuple to avoid redundant slots from multiple similar parameters

Quality Gates

Session Result
lint PASS
typecheck PASS (0 errors)
unit_tests PASS (10,817 scenarios)
integration_tests PASS (6 new tests)
coverage_report 97%

Commit

b9c4b464 on branch feature/m5-builtin-adapter-mcp-slots

PR

PR #964

## Implementation Notes ### Architecture **BuiltinAdapter** (`tool/builtins/adapter.py`, 103 lines): Formal adapter class wrapping existing built-in tool registration. Methods: `discover()` returns all built-in `ToolSpec` objects from `ALL_FILE_TOOLS + ALL_GIT_TOOLS + ALL_SUBPLAN_TOOLS`; `register(registry)` registers all tools and returns names; `activate()`/`deactivate()` are no-ops. Cached discovery — tools enumerated once then memoized. **MCP Resource Slot Inference** (`mcp/adapter.py`, +121 lines): New `infer_resource_slots()` static method scans `input_schema.properties` for parameter name patterns and creates `ResourceSlot` objects: - `file_path`, `file`, `path` → `ResourceSlot(resource_type="file", access="read_write", binding="parameter")` - `directory`, `dir`, `folder` → `ResourceSlot(resource_type="directory", access="read_only", binding="parameter")` - `repo_path`, `repository` → `ResourceSlot(resource_type="git-checkout", access="read_write", binding="contextual")` Slots stored in `source_metadata["resource_slots"]` since `ToolSpec` doesn't have a `resource_slots` field (the domain `Tool` model does, but `ToolSpec` is the execution-layer model). ### Design Decisions 1. **Backward compatible**: Existing `register_file_tools()` etc. functions still work alongside the new adapter class 2. **Slots in source_metadata**: Rather than modifying `ToolSpec`'s schema, slots are stored in `source_metadata["resource_slots"]` as serialized dicts — this avoids breaking changes to the ToolSpec interface 3. **De-duplication**: `infer_resource_slots()` deduplicates slots by `(resource_type, access)` tuple to avoid redundant slots from multiple similar parameters ### Quality Gates | Session | Result | |---|---| | lint | PASS | | typecheck | PASS (0 errors) | | unit_tests | PASS (10,817 scenarios) | | integration_tests | PASS (6 new tests) | | coverage_report | 97% | ### Commit `b9c4b464` on branch `feature/m5-builtin-adapter-mcp-slots` ### PR [PR #964](https://git.cleverthis.com/cleveragents/cleveragents-core/pulls/964)
Author
Owner

PM Acknowledgment — Day 36

@brent.edwards — Good implementation. BuiltinAdapter and MCP resource slot inference look correct:

Architecture review:

  • BuiltinAdapter wraps existing tool registration with a formal adapter interface — good refactor
  • infer_resource_slots() uses parameter name pattern matching — reasonable heuristic
  • Slots stored in source_metadata["resource_slots"] to avoid breaking ToolSpec interface — pragmatic decision
  • Deduplication by (resource_type, access) tuple — correct

Minor concern: The pattern-matching approach for resource slot inference (file_path → file, directory → directory, repo_path → git-checkout) may produce false positives for tools with similarly-named parameters that don't actually operate on those resource types. Consider adding a mechanism to override or suppress inferred slots per tool. This is not blocking.

PR #964 is mergeable. Peer review needed. @CoreRasurae — please review PR #964 when bandwidth allows. This is v3.5.0 priority.


PM acknowledgment — Day 36

## PM Acknowledgment — Day 36 @brent.edwards — Good implementation. BuiltinAdapter and MCP resource slot inference look correct: **Architecture review:** - `BuiltinAdapter` wraps existing tool registration with a formal adapter interface — good refactor - `infer_resource_slots()` uses parameter name pattern matching — reasonable heuristic - Slots stored in `source_metadata["resource_slots"]` to avoid breaking `ToolSpec` interface — pragmatic decision - Deduplication by `(resource_type, access)` tuple — correct **Minor concern:** The pattern-matching approach for resource slot inference (`file_path` → file, `directory` → directory, `repo_path` → git-checkout) may produce false positives for tools with similarly-named parameters that don't actually operate on those resource types. Consider adding a mechanism to override or suppress inferred slots per tool. This is not blocking. PR #964 is mergeable. Peer review needed. @CoreRasurae — please review PR #964 when bandwidth allows. This is v3.5.0 priority. --- *PM acknowledgment — Day 36*
Member

Acknowledgment — PM Day 36

@freemo — Acknowledged the concern about false positives in the infer_resource_slots() parameter name matching. The current heuristic is deliberately conservative (only 3 pattern groups: file/directory/git-checkout) and works well for the built-in MCP tools we've tested against. If false positives appear in practice, adding a skip_resource_inference: true field to ToolSpec.source_metadata would be a clean per-tool override mechanism. Not blocking — will track as a follow-up if the issue materializes.

## Acknowledgment — PM Day 36 @freemo — Acknowledged the concern about false positives in the `infer_resource_slots()` parameter name matching. The current heuristic is deliberately conservative (only 3 pattern groups: file/directory/git-checkout) and works well for the built-in MCP tools we've tested against. If false positives appear in practice, adding a `skip_resource_inference: true` field to `ToolSpec.source_metadata` would be a clean per-tool override mechanism. Not blocking — will track as a follow-up if the issue materializes.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
cleveragents/cleveragents-core#882
No description provided.