Bug #22: Parameter Normalization
Status: RESOLVED in v4.0.2 Category: Parameter Normalization Severity: High (tools fail silently or with cryptic errors) Resolution Date: 2026-03-16
Problem
Section titled “Problem”Claude Desktop sends MCP tool parameters in formats that don’t match the tool schema:
| Pattern | What Claude Sends | What the Tool Expects |
|---|---|---|
| Wrong param name | old_str: "hello" | old_text: "hello" |
| Wrong param name | new_str: "world" | new_text: "world" |
| String boolean | force: "true" | force: true |
| String boolean | count_only: "true" | count_only: true |
| String boolean | dry_run: "true" | dry_run: true |
| Raw JSON array | edits_json: [{...}] | edits_json: "[{...}]" |
| Wrong field name | pipeline step type: "search" | action: "search" |
These mismatches caused tools to fail with “missing required parameter” or type assertion panics.
Root Cause
Section titled “Root Cause”Claude Desktop’s tool calling doesn’t always match the declared JSON schema precisely. Parameter names get abbreviated (old_text → old_str), boolean parameters arrive as strings, and JSON payloads arrive as raw objects instead of serialized strings.
Solution: Self-Learning Request Normalizer
Section titled “Solution: Self-Learning Request Normalizer”Instead of patching each tool handler individually (which is what Bug #18 did), we implemented a data-driven normalization engine that sits between the MCP transport and tool handlers.
Architecture
Section titled “Architecture”Claude Desktop → MCP Transport → auditWrap() → Normalizer → Tool Handler ↓ Audit Logger (normalizer_stats.json)Rule Types (6)
Section titled “Rule Types (6)”| Type | Description | Example |
|---|---|---|
param_alias | Rename parameter | old_str → old_text |
param_default | Add missing parameter with default value | Missing id → auto-generated |
type_coerce | Convert string to correct type | "true" → true (bool) |
json_accept_both | Accept raw JSON or string | [{...}] → "[{...}]" |
nested_alias | Rename field inside JSON payload | pipeline step type → action |
nested_default | Add missing field inside JSON payload | pipeline step missing id → auto-generated |
Built-in Rules (14)
Section titled “Built-in Rules (14)”The normalizer ships with 14 rules covering all known Claude Desktop patterns:
edit-old_str—old_str→old_text(edit_file)edit-new_str—new_str→new_text(edit_file)multi_edit-old_str—old_str→old_text(multi_edit)multi_edit-new_str—new_str→new_text(multi_edit)force-bool-coerce—force: "true"→force: true(all tools)count_only-bool-coerce—count_only: "true"→count_only: true(all tools)dry_run-bool-coerce—dry_run: "true"→dry_run: true(all tools)permanent-bool-coerce—permanent: "true"→permanent: true(all tools)recursive-bool-coerce—recursive: "true"→recursive: true(all tools)multi_edit-edits-coerce— raw JSON array → JSON string (multi_edit)pipeline-type-alias— steptype→action(batch_operations)pipeline-step-id-default— auto-generate missing stepid(batch_operations)batch-type-alias— steptype→action(batch_operations)batch-step-id-default— auto-generate missing stepid(batch_operations)
External Rules
Section titled “External Rules”Custom rules can be added via --normalizer-rules rules.json:
[ { "id": "custom-alias", "tools": ["read_file"], "type": "param_alias", "from": "filename", "to": "path" }]Dashboard Monitoring
Section titled “Dashboard Monitoring”Two new dashboard pages track normalizer activity:
- Normalizer: Total processed/normalized, by-tool breakdown, by-rule hits, recent normalizations feed
- Error Patterns: Groups recurring errors by tool and pattern, shows trends, suggests new normalizer rules
Stats Persistence
Section titled “Stats Persistence”Normalizer stats are written to normalizer_stats.json every 30 seconds (when --log-dir is set), preserving data across server restarts.
Files Changed
Section titled “Files Changed”| File | Change |
|---|---|
core/normalizer.go | New: 563-line normalizer engine |
core/engine.go | Normalizer initialization |
core/audit_logger.go | Normalizations field in audit entries |
main.go | auditWrap() middleware, --normalizer-rules flag |
cmd/dashboard/main.go | /api/normalizer and /api/error-patterns endpoints |
cmd/dashboard/static/index.html | Normalizer and Error Patterns pages |
cmd/dashboard/static/app.js | Dashboard rendering functions |
Testing
Section titled “Testing”go test ./tests/ -run TestNormalizer -v # 15 normalizer testsgo test ./tests/ -run TestBug22 -v # Bug #22 regression testsTest files: tests/normalizer_test.go, tests/bug22_multi_edit_test.go