Skip to content

tools/list emits draft-07 schemas with array-form nullable types — Anthropic API rejects all 524 tools #37

@neue-supply

Description

@neue-supply

Bug

tools/list emits inputSchema documents with $schema: draft-07 and properties using array-form nullable types ("type": ["string", "null"]). Anthropic's MCP-tool schema validator (which validates against JSON Schema 2020-12) treats this as invalid and rejects the entire tools payload, so a single bad schema breaks the whole server for Anthropic-API-backed clients (Claude Code, Claude Desktop on Pro/Team plans, the Anthropic SDK with MCP enabled).

Repro

DOKPLOY_URL=https://your-dokploy.example DOKPLOY_API_KEY=xxx npx -y @dokploy/mcp
# then send: {"jsonrpc":"2.0","id":1,"method":"initialize",...}
#            {"jsonrpc":"2.0","method":"notifications/initialized"}
#            {"jsonrpc":"2.0","id":2,"method":"tools/list"}

The server returns 524 tools. 71 of them use array-form nullable type somewhere in their schema, including the first one Anthropic stops at: application-saveGiteaProvider (server-order index 13).

Offending schema (verbatim from tools/list)

{
  "name": "application-saveGiteaProvider",
  "inputSchema": {
    "type": "object",
    "properties": {
      "applicationId":   { "type": "string" },
      "giteaBranch":     { "type": ["string", "null"] },
      "giteaBuildPath":  { "type": ["string", "null"] },
      "giteaOwner":      { "type": ["string", "null"] },
      "giteaRepository": { "type": ["string", "null"] },
      "giteaId":         { "type": ["string", "null"] },
      "enableSubmodules": { "type": "boolean" },
      "watchPaths": {
        "anyOf": [
          { "type": "array", "items": { "type": "string" } },
          { "type": "null" }
        ]
      }
    },
    "required": ["applicationId","giteaBranch","giteaBuildPath","giteaOwner","giteaRepository","giteaId"],
    "additionalProperties": false,
    "$schema": "http://json-schema.org/draft-07/schema#"
  }
}

Anthropic's API responds with tools.13.input_schema: ... and refuses to register any of the 524 tools.

Why it matters

This makes @dokploy/mcp unusable from any Anthropic-backed MCP client until at least one of:

  1. The 71 affected tools are filtered out (impossible on the official package — DOKPLOY_ENABLED_TAGS is allow-list only at category granularity, and several affected tools are in categories users actually need: application-saveEnvironment, postgres-create, postgres-saveExternalPort, application-saveBuildType, etc.)
  2. The schemas are fixed at the source.

Workaround filtering also doesn't cover affected *-create, *-update, and *-saveEnvironment tools across most resource categories — the bug is systemic.

Affected tools (full list, 71)

71 tools with type: [..., "null"] anywhere in their schema
application-create
application-saveEnvironment
application-saveBuildType
application-saveGithubProvider
application-saveGitlabProvider
application-saveBitbucketProvider
application-saveGiteaProvider
application-saveDockerProvider
application-saveGitProvider
application-update
backup-create
backup-update
certificates-create
compose-create
compose-update
compose-saveEnvironment
destination-create
destination-testConnection
destination-update
domain-create
domain-update
gitea-create
gitea-update
gitlab-create
gitlab-update
libsql-create
libsql-saveExternalPorts
libsql-saveEnvironment
libsql-update
mariadb-create
mariadb-saveExternalPort
mariadb-saveEnvironment
mariadb-update
mongo-create
mongo-saveExternalPort
mongo-saveEnvironment
mongo-update
mounts-create
mounts-update
mysql-create
mysql-saveExternalPort
mysql-saveEnvironment
mysql-update
postgres-create
postgres-saveExternalPort
postgres-saveEnvironment
postgres-update
project-create
project-update
redis-create
redis-saveExternalPort
redis-saveEnvironment
redis-update
registry-create
registry-update
registry-testRegistry
server-create
server-update
settings-updateLogCleanup
sshKey-create
sshKey-update
user-update
whitelabeling-update
schedule-create
schedule-update
volumeBackups-create
volumeBackups-update
tag-create
tag-update
patch-create
patch-update

Proposed fix

Two changes upstream in the schema generator:

  1. Convert "type": ["string", "null"] (and other 2-tuple null forms) to { "anyOf": [{ "type": "string" }, { "type": "null" }] }. This is what Zod's own .nullable() already emits when targeted at draft 2020-12, and what the same generator already does for watchPaths in the example above.
  2. Bump the emitted $schema from http://json-schema.org/draft-07/schema# to https://json-schema.org/draft/2020-12/schema. The Anthropic validator ignores the $schema declaration in practice but the mismatch is what's tripping Zod-to-JSON-Schema in array-type mode.

Both changes are localized to whichever zod-to-json-schema (or equivalent) path generates the tRPC procedure schemas at server boot.

Confirmed downstream impact

The same bug is present in the dokploy-mcp (tacticlaunch) fork, which is generated from the same upstream procedures — 15 of its 55 tools are affected. Users have no working Anthropic-compatible Dokploy MCP today.

Environment

  • Server: @dokploy/mcp v0.29.x (server reports serverInfo.version: "2.0.0")
  • Client: any Anthropic-backed MCP client (Claude Code 2.x, Anthropic SDK + MCP)
  • Discovered while attempting to call postgres-create and application-saveEnvironment from Claude Code; the entire server registration fails before any individual tool is invoked.

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