fix(mcp-http): ensure MCP tool schemas always include properties field#69956
fix(mcp-http): ensure MCP tool schemas always include properties field#69956Chevron7Locked wants to merge 3 commits into
Conversation
…ried on each turn When runWithModelFallback falls back to a secondary provider it writes providerOverride/modelOverride/modelOverrideSource:"auto" to the session. On subsequent turns createModelSelectionState read this stored override and passed the fallback provider directly to runWithModelFallback, so the configured primary was never retried — the session was permanently pinned to the fallback even after the primary recovered. Fix: at model-selection ingress, when the direct session override has modelOverrideSource "auto" (set by a previous automatic fallback, not a user /model command), clear the override and retry the configured primary. If the primary is still down runWithModelFallback will fall back and re-set the auto override for that turn. Once the primary recovers the override stays clear. User-selected overrides (modelOverrideSource "user" or legacy undefined+model) are preserved unchanged. Covered by four new unit tests in model-selection.test.ts: - auto-failover override cleared and primary retried - user-selected override preserved - legacy override without source field preserved - parent-session auto-override applied to child (not cleared by child logic)
…verride clearing Three corrections to the auto-failover self-healing introduced in the prior commit: 1. Reset in-memory provider/model to configured primary after clearing auto override. get-reply-directives.ts preloads provider/model from the stored override before calling createModelSelectionState, so clearing only session state still ran the current turn on the fallback. Now provider/model are reset to defaultProvider/ defaultModel so this turn retries the primary immediately, not on the next turn. 2. Remove resetModelOverride = true from the auto-heal path. That flag triggers a "Model override not allowed for this agent" system event in applyInlineDirectiveOverrides, which is incorrect: the override was valid and set by the fallback loop — it just expired once the primary recovered. Auto-heal is not an allowlist violation. 3. Add a test case that verifies the in-memory reset when the caller pre-loads the fallback provider/model (simulating the get-reply-directives.ts preload path). Known limitation (noted in comment): channel model overrides (channels.modelByChannel) are skipped on the recovery turn because hasSessionModelOverride was true when they were evaluated at preload time. They resume on the following turn once session state is clear. Fixing this cleanly requires changes to the get-reply-directives preload flow and is out of scope for this PR.
MCP servers sometimes emit no-arg tools with inputSchema {"type":"object"}
and no "properties" key. OpenAI and OpenRouter reject this as an invalid
JSON Schema — the error is "object schema missing properties" and manifests
as a 400 on every request that includes the offending tool, causing the
entire model call to fail and fall through to the next fallback.
The fix: move the `if (!raw.properties) raw.properties = {}` guard outside
the `raw.type !== "object"` condition so it applies to schemas that already
have the correct type but are missing the required properties key.
Before: only added properties:{} when type was wrong
After: always ensures properties:{} is present on any object-typed schema
Reproduces with mcpproxy-go v0.23.2 which emits {"type":"object"} for
no-argument tools like list_registries. Affects any strict OpenAI-compatible
provider (OpenRouter, direct OpenAI API).
Greptile SummaryThis PR bundles two independent fixes: (1) the titled MCP schema fix in Confidence Score: 5/5Safe to merge — both fixes are correct, tested, and non-breaking The MCP schema fix is a minimal, targeted one-liner with no risk of regression. The model-selection auto-healing logic is more substantial but includes thorough tests covering all branch conditions (user override, legacy override, parent-inherited override). All remaining findings are P2 style issues. No files require special attention Prompt To Fix All With AIThis is a comment left during a code review.
Path: src/auto-reply/reply/model-selection.test.ts
Line: 571-572
Comment:
**Duplicate comment**
The same comment is copy-pasted on consecutive lines.
```suggestion
// Provider/model should revert to the configured primary, not the fallback.
```
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "fix(mcp-http): ensure MCP tool schemas a..." | Re-trigger Greptile |
| // Provider/model should revert to the configured primary, not the fallback. | ||
| // Provider/model should revert to the configured primary, not the fallback. |
There was a problem hiding this comment.
The same comment is copy-pasted on consecutive lines.
| // Provider/model should revert to the configured primary, not the fallback. | |
| // Provider/model should revert to the configured primary, not the fallback. | |
| // Provider/model should revert to the configured primary, not the fallback. |
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/auto-reply/reply/model-selection.test.ts
Line: 571-572
Comment:
**Duplicate comment**
The same comment is copy-pasted on consecutive lines.
```suggestion
// Provider/model should revert to the configured primary, not the fallback.
```
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8167229af8
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if (isAutoSessionOverride && sessionEntry && sessionStore && sessionKey && !resetModelOverride) { | ||
| const { updated } = applyModelOverrideToSessionEntry({ |
There was a problem hiding this comment.
Respect heartbeat override before auto-clearing model fallback
This branch runs even when hasResolvedHeartbeatModelOverride is true, so heartbeat turns that intentionally selected heartbeat.model can still enter auto-heal, clear the session override, and then force provider/model back to defaultProvider/defaultModel later in the block. In that scenario the heartbeat no longer uses the configured heartbeat model and mutates session state unexpectedly; this regresses the existing skipStoredOverride contract for heartbeat runs. Add a !skipStoredOverride guard (or otherwise preserve the current provider/model) before applying this auto-clear path.
Useful? React with 👍 / 👎.
|
Related work from PRtags group Title: Open PR duplicate: MCP schema properties + auto-reset override self-heal composite
|
|
Codex maintainer rewrite landed as #70763. I kept the minimal MCP schema fix from this PR: loopback MCP object schemas now always include While verifying this, I also chased the live Docker failure path: Codex was cancelling MCP tool calls when the generated loopback server inherited local approval prompts. #70763 marks only the generated OpenClaw loopback MCP server with Codex's per-server Verified with focused tests, Thanks for spotting the MCP schema issue and for the original fix direction. |
|
Closing in favor of the narrower maintainer rewrite in #70763. Thanks again for the original MCP schema fix direction. |
Summary
inputSchema: {"type":"object"}and nopropertieskey. OpenAI and OpenRouter reject this as invalid JSON Schema (object schema missing properties), returning a 400 on every request that includes the offending tool — causing the entire model call to fail and fall through to the next fallback.if (!raw.properties) raw.properties = {}outside theraw.type !== "object"condition inbuildMcpToolSchema. Nowproperties: {}is always added to anyobject-typed schema that lacks it, regardless of whethertypeneeded correction.properties, or schemas withanyOf/oneOfthat go throughflattenUnionSchema.Root cause
Reproduces with
mcpproxy-go v0.23.2, which emits
{"type":"object"}for no-argument tools (e.g.list_registries). Affects any strict OpenAI-compatible provider.Change Type
Scope