feat(tool): implement BuiltinAdapter class and MCP automatic resource slot creation #964
No reviewers
Labels
No labels
auto/needs-reevaluation
controller-managed
auto/blocked-by-deps
auto/ci-timeout
auto/claimed-implementer
auto/claimed-merge
auto/claimed-reviewer
auto/driver-down
auto/invariant-violation
auto/last-attempt-tier-0
auto/last-attempt-tier-1
auto/last-attempt-tier-2
auto/last-attempt-tier-min
Automation Tracking
auto/needs-conflict-resolution
auto/needs-implementer
auto/postmortem
auto/ready-to-merge
auto/restart-throttled
auto/revert
auto/sentinel
auto/stale-inactivity
auto/unstable
Blocked
Bounty
$100
Bounty
$1000
Bounty
$10000
Bounty
$20
Bounty
$2000
Bounty
$250
Bounty
$50
Bounty
$500
Bounty
$5000
Bounty
$750
MoSCoW
Could have
MoSCoW
Must have
MoSCoW
Should have
Needs Feedback
Points
1
Points
13
Points
2
Points
21
Points
3
Points
34
Points
5
Points
55
Points
8
Points
88
Priority
Backlog
Priority
CI Blocker
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Signed-off: Owner
Signed-off: Scrum Master
Signed-off: Tech Lead
Spike
State
Completed
State
Duplicate
State
In Progress
State
In Review
State
Paused
State
Unverified
State
Verified
State
Wont Do
Type
Automation
Type
Bug
Type
Discussion
Type
Documentation
Type
Epic
Type
Feature
Type
Legendary
Type
Refactor
Type
Support
Type
Task
Type
Testing
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
cleveragents/cleveragents-core!964
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feature/m5-builtin-adapter-mcp-slots"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Implement
BuiltinAdapterclass and MCP automatic resource slot creation. Two main changes:1. BuiltinAdapter Class (
tool/builtins/adapter.py)Formal adapter implementing the tool adapter lifecycle pattern for built-in tools:
discover()— returns all built-in tool descriptors (file, git, subplan tools)register(registry)— registers all tools in a ToolRegistry, returns registered namesactivate()/deactivate()— no-ops (built-in tools are always available)ALL_FILE_TOOLS,ALL_GIT_TOOLS,ALL_SUBPLAN_TOOLSlists2. MCP Resource Slot Inference (
mcp/adapter.py)New
infer_resource_slots()static method onMCPToolAdapter:ResourceSlotobjects with appropriate type, access mode, binding modefile_path→file(rw),directory→directory(ro),repo_path→git-checkout(rw)source_metadata["resource_slots"]on registeredToolSpecobjectsQuality Gates
nox -s lintnox -s typechecknox -s unit_testsnox -s integration_testsnox -s coverage_reportCloses #882
77c7b07b5ab9c4b4646fPM Triage — Day 36 (2026-03-16)
feat(tool): implement BuiltinAdapter class and MCP automatic resource slot creation — M6 (v3.5.0), Points/5, Should have.
Status: New PR submitted Day 36, 0 reviews. This implements #882 (BuiltinAdapter).
Reviewer assignment: @aditya — you have the MCP/tool adapter domain expertise. Please review for spec compliance. Target: Day 38 EOD.
Note: @brent.edwards — please confirm this is ready for review and list any upstream dependencies.
PM Day 36 Triage: BuiltinAdapter and MCP resource slot creation. Closes #882. Reviewer needed: @aditya (MCP domain expertise). M6 scope. Verify BuiltinAdapter aligns with ADR-011 tool lifecycle and ADR-029 MCP adoption.
Status Update — Day 37
@freemo — Confirmed: PR #964 is ready for review. Master has been merged in today (conflicts in robot timeout files resolved).
Upstream dependencies: None.
BuiltinAdapterwraps the existingregister_file_tools()/register_git_tools()functions already on master.infer_resource_slots()is a new static method onMcpAdapterthat works independently.Ready for @aditya's review.
PM Status — Day 37
Reviewers assigned. This PR needs at least 2 approving reviews per
CONTRIBUTING.mdbefore merge.Author: Please ensure this PR is rebased on latest
masterand all quality gates pass before requesting merge.PM status — Day 37
Code Review — PR #964
Verdict: Request Changes (1 Major, 4 Minor, 3 Nit)
Scope: 7 files, +669/−2 (three-dot diff excluding master merge). Lint PASS, Typecheck PASS.
Major
BUG-1:
_FILE_PARAMSincludes overly generic"path"— false-positive slot creationsrc/cleveragents/mcp/adapter.py:541_FILE_PARAMScontains{"file_path", "file", "path"}. The"path"pattern is too broad — many MCP tools usepathfor URL routes, API endpoints, config key paths, etc. This will silently create spurious file resource slots for those tools.Recommendation: Remove
"path"or narrow to"file_path"/"filepath"only. If broad matching is needed, add a secondary heuristic (e.g., check the schema property description for "file").Minor
CODE-1: No argument validation in
BuiltinAdapter.register()src/cleveragents/tool/builtins/adapter.py:76Per CONTRIBUTING.md, all public methods must validate arguments as the first guard.
register(registry)doesn't check forNone, which would produce anAttributeErrordeep in the loop instead of at the boundary.TEST-1: Missing boundary/negative tests for
infer_resource_slotsfeatures/builtin_adapter.featureNo scenarios for:
propertieskey"path"parameter specificallySPEC-1: Issue #882 subtask "Refactor registration functions to use adapter" not done
The adapter wraps
ALL_*_TOOLSlists but the existingregister_file_tools()/register_git_tools()/register_subplan_tool()functions remain independent. The adapter is additive, not a refactor. Either update the functions to delegate, or update the issue subtask to reflect the actual (backward-compatible) approach.PROCESS-1: Missing CHANGELOG entry
No entry for #882 in the Unreleased section. Required per PR Process item 6.
Nit
State/In Reviewlabel (issue has it).if/elifblocks ininfer_resource_slots(lines 566–630) are near-identical and could be driven by a mapping dict (~65 lines → ~20).Code Review — Round 2 (new findings only)
Critical
BUG-2:
infer_resource_slotsoutput is dead code —source_metadata["resource_slots"]has zero consumerssrc/cleveragents/mcp/adapter.py:519-540The slot inference pipeline writes to a key that nothing reads:
infer_resource_slots()createsResourceSlotobjectssource_metadata["resource_slots"](line 540)source_metadata["resource_slots"]— confirmed via codebase-wide grepfind_by_resource_type()reads a different key:source_metadata.get("resource_bindings", [])(tool/registry.py:127)source_metadatais not a persisted column; the DB readsresource_slotsfrom domainToolobjects, not fromToolSpec.source_metadatatool showdisplaysresource_slotsfromTool.as_cli_dict()(domain model), not fromToolSpec.source_metadata~100 lines of
infer_resource_slots,_FILE_PARAMS,_DIR_PARAMS,_REPO_PARAMS, and the slot-to-dict serialization produce write-only data.Recommendation: Either wire into the consumption path (bridge
resource_slots→resource_bindings, or populate domainTool.resource_slotsfromToolSpec.source_metadataduring persistence), or remove until a consumer exists.Major
BUG-3:
BuiltinAdapter.register()raisesToolErroron second call with same registrysrc/cleveragents/tool/builtins/adapter.py:91-95ToolRegistry.register()raisesToolErroron name collision (tool/registry.py:49-53). MCPToolAdapter guards against this by pre-removing existing tools (mcp/adapter.py:496-498). BuiltinAdapter does no such check — callingregister()twice on the same registry raisesToolErroron every tool. No test covers this path.BUG-4: Lifecycle method names diverge from MCPToolAdapter — docstring is misleading
src/cleveragents/tool/builtins/adapter.py:9-10The docstring says the adapter "follows the same structural pattern as MCPToolAdapter" but the method names are different:
connect()activate()activate()disconnect()deactivate()deactivate()discover_tools(tool_filter)discover()discover()register_tools(registry, namespace, tool_filter)register(registry)No shared ABC or Protocol enforces a common interface. The adapter actually follows AgentSkillLoader's naming, not MCPToolAdapter's. The
register()signature also omitsnamespacewhich MCPToolAdapter requires.Updated Combined Summary (Round 1 + Round 2)
check comments
Response to @hamza.khyari's Review (Rounds 1+2) — PR #964
Thank you for the deep analysis, Hamza. The dead-code finding (BUG-2) is particularly impactful — great catch tracing the full consumption path.
Critical
BUG-2 (Dead code —
resource_slotshas zero consumers): Confirmed. Theinfer_resource_slotspipeline writes tosource_metadata["resource_slots"]but nothing reads it — the registry readsresource_bindings, the DB reads from domainToolobjects, and the CLI reads fromTool.as_cli_dict(). I'll wire the slots into the domainTool.resource_slotsfield during MCP adapter registration, bridgingToolSpec.source_metadata → Tool.resource_slots. This makes the inference actually functional.Major
BUG-1 (
"path"too broad): Agreed —"path"matches too many unrelated parameters. Will remove it from_FILE_PARAMSand keep only"file_path","filepath","file".BUG-3 (BuiltinAdapter.register raises on double-call): Will add a pre-check: skip already-registered tools (matching the MCPToolAdapter pattern of pre-removing existing tools).
BUG-4 (Lifecycle method naming divergence): Fair point. Will update the docstring to accurately reference the AgentSkillLoader naming convention and note the deliberate omission of
namespace(builtin tools are always in the default namespace).Minor
CODE-1 (No argument validation): Will add
if registry is None: raise ValueError(...).TEST-1 (Missing boundary tests): Will add scenarios for empty schema, no properties, multiple matches, and the
"path"parameter specifically.SPEC-1 (Issue subtask): Will update the issue subtask to reflect the actual backward-compatible additive approach.
PROCESS-1 (Missing CHANGELOG): Will add entry.
Nit
PROCESS-2 (Missing label): Will add
State/In Review.CODE-2 (Mapping dict): Good suggestion — will refactor the 3
if/elifblocks into a mapping-driven loop.CODE-3 (Commit body): Will clarify that the test modifications came from the merge commit.
Working on all fixes now.
Review Fixes Applied — commit
98ba57f2All actionable findings from @hamza.khyari's review (Rounds 1+2) have been addressed:
"path"from_FILE_PARAMS; replaced with"filepath"to avoid false-positive slot creationBuiltinAdapter.register()is now idempotent — skips already-registered tools instead of raisingToolErrorAgentSkillLoadernaming, notMCPToolAdapterif registry is None: raise ValueError(...)guard at top ofregister()if/elifblocks (~65 lines) ininfer_resource_slotsinto a mapping-driven loop (~20 lines)__all__to bothmcp/adapter.pyandtool/builtins/adapter.pyQuality Gates
nox -s lint— PASS (all checks passed)nox -s typecheck— PASS (0 errors, 1 pre-existing warning in unrelated file)2f4b54561817325a6c1e17325a6c1efe59ca823dReview Fixes Applied — Commit
fe59ca82Branch rebased and squashed onto
origin/master(ad98d41d). 6 of 8 findings were already resolved from the prior fix round (preserved through squash-rebase). 2 new fixes applied._FILE_PARAMStoo broad)file_path,filepath,fileresource_slots)register()idempotent)ValueErroronNoneregistry_SLOT_MAPiterationQuality Gates
nox -s lint— PASSnox -s typecheck— PASS (0 errors)Code Review — PR #964
BuiltinAdapter and MCP auto resource slot creation. Proper labels, milestone, and issue linkage (#882). Approved.
fe59ca823d94076ec844New commits pushed, approval review dismissed automatically according to repository settings
Rebased onto
origin/master(79b0a2c5). CHANGELOG conflict resolved (kept master, re-added PR entry).nox -s lintPASS,nox -s typecheckPASS (0 errors). Commit94076ec8.94076ec844e02e396738Fixed the
benchmark_regressionfailure and merged latestmaster.Root cause:
RollbackSuite.time_rollbackinbenchmarks/checkpoint_rollback_bench.pyregistered a sandbox with the fake path"sandbox-path". Aftercheckpoint_service.pywas updated (commitec4c39ae) to validate that the sandbox path is a real directory containing a.gitrepo, the benchmark started failing withBusinessRuleViolation: sandbox path does not exist.Fix: Updated
RollbackSuite.setup()to create a real temporary directory withgit init, and added ateardown()to clean it up. The benchmark now exercises the actual rollback code path.Also merged latest
origin/masterinto the branch (resolved a CHANGELOG conflict).