Skip to content

fix: accept camelCase tool arguments (calendarId, timeMin, ...) via normalization middleware - #921

Open
Bortlesboat wants to merge 1 commit into
taylorwilsdon:mainfrom
Bortlesboat:fix/camelcase-tool-arguments
Open

fix: accept camelCase tool arguments (calendarId, timeMin, ...) via normalization middleware#921
Bortlesboat wants to merge 1 commit into
taylorwilsdon:mainfrom
Bortlesboat:fix/camelcase-tool-arguments

Conversation

@Bortlesboat

@Bortlesboat Bortlesboat commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Fixes #918

Every tool declares snake_case parameters with additionalProperties: false, so callers that mirror the Google API field names (calendarId, timeMin, maxResults, ...) fail schema validation before the request ever reaches Google — including the Hermes google-workspace skill wrapper mentioned in the issue.

This adds a small FastMCP middleware on the call_tool path that renames an argument key only when all of these hold:

  • the key isn't itself a declared parameter of the tool,
  • its snake_case conversion is a declared parameter, and
  • the caller didn't also pass the snake_case key explicitly.

Ambiguous input (two spellings normalizing to the same parameter, e.g. iCalUid + iCalUID) is left untouched so validation still rejects it instead of silently picking a winner. Tools that genuinely declare camelCase params are unaffected, and unknown arguments keep failing exactly as before.

Went with the middleware so it covers all tools at once rather than aliasing the calendar ones — happy to scope it down to explicit calendar aliases instead if you'd rather keep argument handling strict.

Tested with the reproduction from #918 through an in-memory client — 8 tests in tests/core/test_camel_case_middleware.py covering the camelCase path, snake_case passthrough, explicit-key precedence, collisions, declared-camelCase params, and unknown tools/args. ruff check and ruff format clean; tests/core + tests/gcalendar pass locally.

Summary by CodeRabbit

  • New Features

    • Tool calls now accept camelCase argument names when the corresponding parameters use snake_case.
    • Existing snake_case arguments remain unchanged.
    • Declared camelCase parameters are preserved without modification.
    • Ambiguous or conflicting argument names continue to be rejected safely.
  • Tests

    • Added coverage for conversions, validation, conflicts, unknown arguments, and unknown tools.

Callers that mirror Google API field names (calendarId, timeMin,
maxResults) fail schema validation because every tool declares
snake_case parameters with additionalProperties: false. Add a FastMCP
middleware that renames a camelCase argument to its snake_case
equivalent when the tool declares the snake_case parameter and the
caller did not pass it explicitly. Fixes taylorwilsdon#918
@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fc1ef3d8-0a14-4154-b1f8-f15418aa3f32

📥 Commits

Reviewing files that changed from the base of the PR and between 3f19c7d and 7138480.

📒 Files selected for processing (3)
  • core/camel_case_middleware.py
  • core/server.py
  • tests/core/test_camel_case_middleware.py

📝 Walkthrough

Walkthrough

Adds CamelCaseArgumentsMiddleware to normalize eligible camelCase tool arguments to declared snake_case parameters, registers it on the server, and tests conversion, pass-through, validation, unknown tools, and collision handling.

Changes

CamelCase argument handling

Layer / File(s) Summary
Argument normalization middleware
core/camel_case_middleware.py
Adds camelCase conversion and schema-aware argument rewriting, preserving explicit snake_case keys and rejecting ambiguous mappings through normal validation.
Server middleware registration
core/server.py
Imports and registers the middleware after AuthInfoMiddleware.
Normalization and validation coverage
tests/core/test_camel_case_middleware.py
Tests conversion, unchanged keys, conflicts, unknown arguments and tools, declared camelCase parameters, and colliding normalized names.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant CamelCaseArgumentsMiddleware
  participant FastMCPToolSchema
  participant Tool
  Client->>CamelCaseArgumentsMiddleware: Submit tool arguments
  CamelCaseArgumentsMiddleware->>FastMCPToolSchema: Read declared properties
  FastMCPToolSchema-->>CamelCaseArgumentsMiddleware: Return parameter names
  CamelCaseArgumentsMiddleware->>Tool: Forward normalized arguments
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: camelCase tool arguments are normalized through middleware.
Description check ✅ Passed The description covers the fix, motivation, issue link, and testing, though the template's checklist/type sections are not filled in.
Linked Issues check ✅ Passed The middleware and tests satisfy #918 by accepting camelCase tool args while preserving snake_case and collision behavior.
Out of Scope Changes check ✅ Passed No clear out-of-scope changes are introduced beyond the middleware and tests needed for #918.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@taylorwilsdon taylorwilsdon self-assigned this Jul 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

get_events rejects standard camelCase args (calendarId, timeMin, timeMax) — schema uses snake_case with additionalProperties:false

2 participants