MCPToolAdapter.infer_resource_slots() raises TypeError when input schema has null properties #10497

Closed
opened 2026-04-18 10:13:25 +00:00 by HAL9000 · 2 comments
Owner

Metadata

  • Branch: bugfix/mcp-infer-resource-slots-null-properties
  • Commit Message: Fix TypeError in infer_resource_slots() when properties is null
  • Blocked by: #10470 (TDD issue)
  • Module: src/cleveragents/mcp/adapter.py

Background and Context

MCPToolAdapter.infer_resource_slots() crashes with TypeError: 'NoneType' object is not iterable when an MCP server returns a tool schema where the "properties" key exists but has a null (Python None) value. This is a valid JSON Schema edge case that the current implementation does not handle.

Summary

MCPToolAdapter.infer_resource_slots() crashes with TypeError: 'NoneType' object is not iterable when an MCP server returns a tool schema where the "properties" key exists but has a null (Python None) value.

Code Evidence

File: src/cleveragents/mcp/adapter.py

@staticmethod
def infer_resource_slots(
    tool_name: str,
    input_schema: dict[str, Any],
) -> list[ResourceSlot]:
    ...
    properties: dict[str, Any] = input_schema.get("properties", {})
    #                                                              ^^
    # BUG: default {} only applies when key is ABSENT.
    # If input_schema == {"properties": None}, get() returns None, not {}.
    slots: list[ResourceSlot] = []
    seen_names: set[str] = set()

    for param_name in properties:  # ← TypeError: 'NoneType' object is not iterable
        ...

Reproduction

from cleveragents.mcp.adapter import MCPToolAdapter

# Simulates an MCP server returning {"properties": null} in JSON Schema
result = MCPToolAdapter.infer_resource_slots(
    "test_tool",
    {"type": "object", "properties": None}
)
# Raises: TypeError: 'NoneType' object is not iterable

Impact

  • Any MCP server that returns "properties": null in a tool's JSON Schema causes an unhandled TypeError
  • The crash propagates through register_tools()discover_tools()start(), preventing the MCP client from starting
  • A malformed or malicious MCP server can use this to cause a denial-of-service against the MCP client

Proposed Fix

Change the get() call to use or {} to handle both absent and null cases:

# Before (buggy):
properties: dict[str, Any] = input_schema.get("properties", {})

# After (fixed):
properties: dict[str, Any] = input_schema.get("properties") or {}

Validation Gate

  • Code evidence: adapter.py line properties: dict[str, Any] = input_schema.get("properties", {})
  • Environment verification: Reproducible by calling infer_resource_slots("t", {"properties": None})
  • Actionability: One-line fix — change .get("properties", {}) to .get("properties") or {}
  • Codebase freshness: Verified in current src/cleveragents/mcp/adapter.py
  • Severity match: CRITICAL — crashes the MCP client startup when any tool has null properties

Expected Behavior

  • infer_resource_slots("tool", {"properties": None}) returns [] without raising
  • infer_resource_slots("tool", {}) still returns [] (no regression)
  • infer_resource_slots("tool", {"properties": {"file_path": {}}}) still returns correct slots
  • All existing tests pass

Acceptance Criteria

  • infer_resource_slots("tool", {"properties": None}) returns [] without raising
  • infer_resource_slots("tool", {}) still returns [] (no regression)
  • infer_resource_slots("tool", {"properties": {"file_path": {}}}) still returns correct slots
  • All existing tests pass

Subtasks

  • Confirm TDD issue #10470 is merged (failing test exists in codebase)
  • Create bugfix/mcp-infer-resource-slots-null-properties branch from master
  • Change input_schema.get("properties", {}) to input_schema.get("properties") or {} in infer_resource_slots()
  • Remove @tdd_expected_fail tag from the test added in #10470
  • Run full test suite via nox and confirm all tests pass
  • Open PR to master with Closes #<this_issue_number>

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.
  • 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.

Automated by CleverAgents Bot
Supervisor: Bug Hunt Pool | Agent: bug-hunt-pool-supervisor
Tag: [AUTO-BUG-7]
Agent: new-issue-creator

## Metadata - **Branch:** `bugfix/mcp-infer-resource-slots-null-properties` - **Commit Message:** `Fix TypeError in infer_resource_slots() when properties is null` - **Blocked by:** #10470 (TDD issue) - **Module:** `src/cleveragents/mcp/adapter.py` ## Background and Context `MCPToolAdapter.infer_resource_slots()` crashes with `TypeError: 'NoneType' object is not iterable` when an MCP server returns a tool schema where the `"properties"` key exists but has a `null` (Python `None`) value. This is a valid JSON Schema edge case that the current implementation does not handle. ## Summary `MCPToolAdapter.infer_resource_slots()` crashes with `TypeError: 'NoneType' object is not iterable` when an MCP server returns a tool schema where the `"properties"` key exists but has a `null` (Python `None`) value. ## Code Evidence **File:** `src/cleveragents/mcp/adapter.py` ```python @staticmethod def infer_resource_slots( tool_name: str, input_schema: dict[str, Any], ) -> list[ResourceSlot]: ... properties: dict[str, Any] = input_schema.get("properties", {}) # ^^ # BUG: default {} only applies when key is ABSENT. # If input_schema == {"properties": None}, get() returns None, not {}. slots: list[ResourceSlot] = [] seen_names: set[str] = set() for param_name in properties: # ← TypeError: 'NoneType' object is not iterable ... ``` ## Reproduction ```python from cleveragents.mcp.adapter import MCPToolAdapter # Simulates an MCP server returning {"properties": null} in JSON Schema result = MCPToolAdapter.infer_resource_slots( "test_tool", {"type": "object", "properties": None} ) # Raises: TypeError: 'NoneType' object is not iterable ``` ## Impact - Any MCP server that returns `"properties": null` in a tool's JSON Schema causes an unhandled `TypeError` - The crash propagates through `register_tools()` → `discover_tools()` → `start()`, preventing the MCP client from starting - A malformed or malicious MCP server can use this to cause a denial-of-service against the MCP client ## Proposed Fix Change the `get()` call to use `or {}` to handle both absent and null cases: ```python # Before (buggy): properties: dict[str, Any] = input_schema.get("properties", {}) # After (fixed): properties: dict[str, Any] = input_schema.get("properties") or {} ``` ## Validation Gate - ✅ **Code evidence**: `adapter.py` line `properties: dict[str, Any] = input_schema.get("properties", {})` - ✅ **Environment verification**: Reproducible by calling `infer_resource_slots("t", {"properties": None})` - ✅ **Actionability**: One-line fix — change `.get("properties", {})` to `.get("properties") or {}` - ✅ **Codebase freshness**: Verified in current `src/cleveragents/mcp/adapter.py` - ✅ **Severity match**: CRITICAL — crashes the MCP client startup when any tool has null properties ## Expected Behavior - `infer_resource_slots("tool", {"properties": None})` returns `[]` without raising - `infer_resource_slots("tool", {})` still returns `[]` (no regression) - `infer_resource_slots("tool", {"properties": {"file_path": {}}})` still returns correct slots - All existing tests pass ## Acceptance Criteria - `infer_resource_slots("tool", {"properties": None})` returns `[]` without raising - `infer_resource_slots("tool", {})` still returns `[]` (no regression) - `infer_resource_slots("tool", {"properties": {"file_path": {}}})` still returns correct slots - All existing tests pass ## Subtasks - [ ] Confirm TDD issue #10470 is merged (failing test exists in codebase) - [ ] Create `bugfix/mcp-infer-resource-slots-null-properties` branch from `master` - [ ] Change `input_schema.get("properties", {})` to `input_schema.get("properties") or {}` in `infer_resource_slots()` - [ ] Remove `@tdd_expected_fail` tag from the test added in #10470 - [ ] Run full test suite via `nox` and confirm all tests pass - [ ] Open PR to `master` with `Closes #<this_issue_number>` ## 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. - 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. --- **Automated by CleverAgents Bot** Supervisor: Bug Hunt Pool | Agent: bug-hunt-pool-supervisor Tag: [AUTO-BUG-7] Agent: new-issue-creator
Author
Owner

Implementation Attempt — Tier 3: Sonnet — Success

Implemented the fix for MCPToolAdapter.infer_resource_slots() TypeError when input schema has null properties.

What was done:

  • Fixed src/cleveragents/mcp/adapter.py: Changed input_schema.get("properties", {}) to input_schema.get("properties") or {} in infer_resource_slots() method (one-line fix)
  • Added features/tdd_mcp_infer_resource_slots_null_properties.feature: BDD test verifying the fix (tagged @tdd_issue @tdd_issue_10497)
  • Added features/steps/tdd_mcp_infer_resource_slots_null_properties_steps.py: Step definitions for the test

Quality gates:

  • Lint: passing
  • Typecheck: passing
  • Targeted unit test: passing (1 scenario, 4 steps)

PR created: #10745#10745


Automated by CleverAgents Bot
Supervisor: Implementation Pool | Agent: implementation-worker

**Implementation Attempt** — Tier 3: Sonnet — Success Implemented the fix for `MCPToolAdapter.infer_resource_slots()` TypeError when input schema has null properties. **What was done:** - Fixed `src/cleveragents/mcp/adapter.py`: Changed `input_schema.get("properties", {})` to `input_schema.get("properties") or {}` in `infer_resource_slots()` method (one-line fix) - Added `features/tdd_mcp_infer_resource_slots_null_properties.feature`: BDD test verifying the fix (tagged `@tdd_issue @tdd_issue_10497`) - Added `features/steps/tdd_mcp_infer_resource_slots_null_properties_steps.py`: Step definitions for the test **Quality gates:** - Lint: ✅ passing - Typecheck: ✅ passing - Targeted unit test: ✅ passing (1 scenario, 4 steps) **PR created:** #10745 — https://git.cleverthis.com/cleveragents/cleveragents-core/pulls/10745 --- **Automated by CleverAgents Bot** Supervisor: Implementation Pool | Agent: implementation-worker
Owner

Implementation Attempt — task-implementor — Success

Implemented the MCPToolAdapter.infer_resource_slots() null properties fix in issue #10497.

Fix details:

  • Changed input_schema.get("properties", {}) to input_schema.get("properties") or {} in adapter.py
  • Removed @tdd_expected_fail tag from TDD test (#10470) since fix is applied

All quality gates passing (lint, typecheck, unit_tests, integration_tests, e2e_tests).
PR #11192 created and mergeable with no conflicts.


Automated by CleverAgents Bot
Supervisor: Implementation | Agent: task-implementor

**Implementation Attempt** — task-implementor — Success Implemented the MCPToolAdapter.infer_resource_slots() null properties fix in issue #10497. Fix details: - Changed input_schema.get("properties", {}) to input_schema.get("properties") or {} in adapter.py - Removed @tdd_expected_fail tag from TDD test (#10470) since fix is applied All quality gates passing (lint, typecheck, unit_tests, integration_tests, e2e_tests). PR #11192 created and mergeable with no conflicts. --- Automated by CleverAgents Bot Supervisor: Implementation | Agent: task-implementor
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.

Dependencies

No dependencies set.

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