Skip to content

[deep-review] A2: MCP tools/list ships permissive inputSchema for every tool #355

Description

@codemonkeychris

Summary

Every tool advertised by tools/list carries the same input schema:

{ "type": "object", "additionalProperties": true }

There is no per-parameter type information, no required-fields list, no enum constraints, no example values. Argument shape is conveyed only through the description string in McpToolBridge.CommandDescriptions (prose).

Where

  • src/OpenClaw.Shared/Mcp/McpToolBridge.cs:158-163 (the permissive schema)
  • src/OpenClaw.Shared/Mcp/McpToolBridge.cs:184-273 (the descriptions table)
  • Capability arg shapes are scattered across src/OpenClaw.Shared/Capabilities/*.cs (read each capability's ExecuteAsync body to find what args it reads via GetStringArg / GetIntArg / GetArg<T>).

Why it matters

This is the single biggest deviation from public MCP / OpenAPI / Adaptive Cards / iOS App Intents comparables. Effects on agent cold-start:

  • An agent must read the description prose to learn parameter shape, then guess types.
  • Validation errors come back from the capability layer (InvalidOperationException("maxWidth must be 16-4096")) rather than the schema layer. The agent learns by trying.
  • Auto-completion and structured argument suggestion in MCP clients (Cursor, Claude Desktop) can't help users authoring tool calls.

Reference: Adaptive Cards's per-element schema (AdaptiveTextInput.maxLength, AdaptiveNumberInput.min/max, etc.) is the gold standard for declarative-action manifests.

Proposed fix

  1. Define a per-capability typed input schema. Two options:
    • Inline JSON schemas alongside each CommandDescriptions entry. Simple, no codegen, easy to read.
    • Source generator that walks each capability's ExecuteAsync body, collects GetStringArg/GetIntArg/GetArg<T> calls, and emits a schema. More work, but stays in sync.
  2. tools/list ships the per-tool schema in inputSchema.
  3. Add a runtime check (toggleable by OPENCLAW_MCP_VALIDATE_INPUT=1) that validates inbound args against the schema before dispatch. Off by default; on in dev/test.

Test: assert every tool in tools/list has at least one named property in inputSchema.properties.

Severity

High — highest-leverage AI-ergonomics fix. Closes the cold-start gap for the bulk of tools.

Metadata

Metadata

Labels

Type

No type

Fields

Priority

None yet

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions