Skip to content

MCP tool names & schemas rejected by Moonshot API (HTTP 400) — sanitize client-side before sending #2531

Description

@sbdsam

Environment: kimi-cli 1.49.0 · macOS (arm64) · Model: K3 via Moonshot API

The API rejects such requests with:

Error: [provider.api_error] 400 tools.function.parameters is not a valid
moonshot flavored json schema, details: <At path 'root': when using anyOf,
type should be defined in anyOf items instead of the parent schema>

Summary

Several spec-valid MCP servers cannot be used with kimi-cli, because the Moonshot
chat-completions endpoint rejects their tool definitions with HTTP 400. The MCP
spec itself allows these names/schemas — other API consumers handle them fine.
kimi-cli (or the API) should normalize tool definitions before the request.

Problem 1: Tool names starting with a digit → HTTP 400

The MCP server @21st-dev/magic (a popular UI-component generator) exposes tools
named:

21st_magic_component_builder
21st_magic_component_inspiration
21st_magic_component_refiner
...

MCP places no constraint on the leading character of tool names. The Moonshot API,
however, rejects any request whose tools[].function.name begins with a digit:

  • Same session, same prompt, same tools — the call fails with HTTP 400 as long as
    the names start with 21st_….
  • Renaming the identical tools to m_21st_magic_* (letter first) makes the
    exact same calls succeed. No other change.

Ask: Either relax the API-side pattern (e.g. OpenAI-compatible
^[a-zA-Z0-9_-]{1,64}$, which permits leading digits), or have kimi-cli rewrite
non-conforming tool names client-side (with a stable mapping so results route back
to the correct MCP tool).

Problem 2: Strict JSON-Schema subset rejects valid MCP schemas

Example: gitnexus@1.6.9 (npx gitnexus mcp), tool api_impact, declares this
inputSchema — valid JSON Schema (2020-12):

{
  "type": "object",
  "properties": {
    "route":  { "type": "string", "description": "Route path (e.g., \"/api/grants\")" },
    "file":   { "type": "string", "description": "Handler file path (alternative to route)" },
    "method": { "type": "string" },
    "repo":   { "type": "string" },
    "branch": { "type": "string" }
  },
  "required": [],
  "anyOf": [
    { "required": ["route"] },
    { "required": ["file"] }
  ]
}

The API rejects it (HTTP 400). The offending constructs appear to be the root-level
anyOf with per-branch required, combined with the empty sibling "required": [].
Rewriting the schema to drop the empty required and resolve the anyOf (moving
the constraint into the description) makes the identical tool call succeed.

Related: some servers omit the root "type": "object" entirely; coercing it
client-side is trivial and harmless.

(For completeness: GitNexus fixed the anyOf part upstream in 1.6.10-rc via
PR #2489 — verified by auditing all 17 tool schemas on gitnexus@rc. The
client-side problem for kimi-cli remains: any spec-valid server can still hit
these rejections, e.g. digit-led tool names or other combinator patterns.)

Suggested fix (client-side, minimal)

Before sending tools to the API, kimi-cli could:

  1. Rewrite names to ^[A-Za-z][A-Za-z0-9_-]*$ (e.g. prefix m_ for leading
    digits, replace invalid chars with _), keeping a bidirectional map for the
    response path.
  2. Recursively coerce schemas: force root type: "object" when properties is
    present; when anyOf/oneOf appears alongside sibling keywords, either inline
    the siblings into each branch or drop the conflicting sibling with a note in
    description.

This is exactly what our local workaround does (a FastMCP stdio proxy between
kimi-cli and the upstream server). It works, but every user of these servers
shouldn't need to build their own proxy — the sanitization belongs in the client
(or the API validation should be relaxed).

Repro

# 1. magic (name problem)
kimi mcp add magic -- npx -y @21st-dev/magic@latest
# ask anything that loads tools -> HTTP 400

# 2. gitnexus (schema problem)
kimi mcp add gitnexus -- npx -y gitnexus@latest mcp
# ask anything that loads tools -> HTTP 400

Happy to provide the proxy source or test a fix.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions