Optimize MCP parameter-header processing
Summary
Parameter-header processing currently rebuilds descriptor-name validation structures and repeatedly scans the supplied headers. This PR reduces that work while retaining the existing public API and validation behavior.
Depends on #3031. This is a draft stacked on the benchmark PR. After #3031 merges, this branch should be rebased onto main so the final diff contains only the optimization, regression coverage and comparative measurements.
Changes
Descriptor validation
- Compare borrowed descriptor names instead of constructing lowercase string copies.
- Use an allocation-free duplicate scan for lists containing up to eight descriptors.
- Retain ordered-set validation for larger lists, using borrowed views and case-insensitive comparison.
- Continue validating descriptors on every call; no public descriptor cache or new lifetime requirements are introduced.
Header lookup
- Avoid constructing prefixed header-name strings on successful validation paths.
- For larger requests-more than eight descriptors and sixteen supplied headers—build a sorted index of borrowed mirrored-header views and use binary lookup.
- Retain the linear scan for smaller requests.
- Construct full header names when needed for error responses.
Behavior preserved
- Case-insensitive descriptor and header matching.
- Per-descriptor validation and error ordering.
- Rejection of duplicate headers matching a declared parameter.
- Acceptance of duplicate unused headers as opaque input.
- Existing UTF-8 and sentinel-decoding behavior.
- Exact numeric comparison and safe-integer boundaries.
Benchmark results
Measured using the unchanged fixtures from #3031, with three alternating baseline/candidate process runs on the same local Linux runner, GCC 13.3, Release configuration and system allocator.
Values below are medians across process runs of the harness’s per-operation realTime statistic. They are not request-latency percentiles.
| Workload | Baseline | Candidate | Change |
|---|---|---|---|
| Validate headers - 2 descriptors | 418.99 ns | 222.58 ns | −46.88% |
| Validate headers - 64 descriptors | 69.47 µs | 24.61 µs | −64.58% |
| Reject headers - 2 descriptors | 1.43 µs | 1.24 µs | −13.83% |
| Reject headers - 64 descriptors | 69.55 µs | 26.16 µs | −62.39% |
| Generate headers - 2 descriptors | 496.96 ns | 396.24 ns | −20.27% |
| Generate headers - 64 descriptors | 23.46 µs | 23.94 µs | +2.06% |
All measured small-input cases improved. Large header generation was approximately 2% slower, so this PR does not claim improvement across every workload.
The complete measurement procedure and limitations are documented in benchmark/MCP-header-results.markdown.
Regression coverage
Adds an indexed-path regression case covering:
- Mixed-case header names and reversed header order.
- Unicode values requiring sentinel encoding.
- Duplicate matching headers versus duplicate unused headers.
- Incorrect argument types.
- Exact decimal values at the safe-integer boundary.
- Integers outside the safe range.
- Case-insensitive duplicate descriptor names.
Verification
- Release build passed.
- MCP unit suite: 1,421 passed, zero failed.
- Three alternating baseline/candidate benchmark comparisons completed.
- Repository clang-format checks passed.
git diff --checkpassed.
Limitations
The indexing thresholds are internal heuristics, not descriptor-count limits or a proven optimal crossover.
Measurements cover the existing 2/64-descriptor fixtures with short names. Other cardinalities, longer names, platforms and allocators may behave differently. The full repository test matrix and allocation profiling were not run.
These results describe local helper operations, not end-to-end MCP transport or LLM latency.