{
  "$schema": "https://canimcp.io/schemas/client-registry.json",
  "$comment": "Researched client entries. Each capability carries evidence for how it is known. The previous apify-derived seed is kept at clients.apify-seed.json; entries move here as they are researched, not before.",
  "goose": {
    "title": "goose",
    "clientInfoNames": [
      "goose-desktop",
      "goose-cli"
    ],
    "url": "https://block.github.io/goose",
    "description": "Open-source agent from Block, shipping as a desktop app and a CLI from one Rust codebase. Uses rmcp as its MCP client, resolved to 3.1.4.",
    "category": "agent-framework",
    "platforms": [
      "windows",
      "macos",
      "linux"
    ],
    "protocolVersions": [
      "2025-11-25",
      "2026-07-28"
    ],
    "preferredProtocolVersion": "2026-07-28",
    "transports": {
      "stdio": {
        "status": "full",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "aaif-goose/goose",
            "date": "2026-08-23",
            "commit": "c5e5929a",
            "path": "crates/goose/src/agents/mcp_client.rs"
          }
        ]
      },
      "streamableHttp": {
        "status": "full",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "aaif-goose/goose",
            "date": "2026-08-23",
            "commit": "c5e5929a",
            "path": "crates/goose/Cargo.toml"
          }
        ]
      }
    },
    "tools": {
      "status": "full",
      "listChanged": {
        "status": "full",
        "notes": "on_tool_list_changed invalidates the tools cache and bumps a version counter, so a changed tool list is picked up mid-session.",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "aaif-goose/goose",
            "date": "2026-08-23",
            "commit": "c5e5929a",
            "path": "crates/goose/src/agents/mcp_client.rs:handle_tool_list_changed"
          }
        ]
      },
      "result": {
        "status": "full",
        "notes": "content only. Code mode also reads content text only.",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "olaservo/structured-content-research",
            "url": "https://github.com/olaservo/structured-content-research/blob/0c0395d/notes/goose-tool-result-handling.md",
            "date": "2026-11-08",
            "commit": "0c0395d",
            "path": "notes/goose-tool-result-handling.md",
            "note": "The read tier for tool result handling lives in that repo (AGENTS.md); this entry summarises its note, which read the goose source at 5bad61a."
          }
        ],
        "content": {
          "status": "full",
          "notes": "Every content block reaches the model, filtered by audience annotation. When nothing non-empty is left the placeholder text (empty result) is sent instead."
        },
        "structuredContent": {
          "status": "unsupported",
          "notes": "No provider formatter names structuredContent, so it never reaches the model. The ACP surface and the desktop app receive it for MCP Apps."
        },
        "audience": {
          "status": "full",
          "notes": "filter_for_audience drops blocks whose annotations.audience excludes the assistant before the provider sees them."
        }
      },
      "evidence": [
        {
          "tier": "declared",
          "status": "full",
          "at": "2025-03-26",
          "source": "apify/mcp-client-capabilities",
          "date": "2026-02-02",
          "commit": "4406120",
          "note": "Records tools/prompts/resources at 2025-03-26 under the wire key \"goose\", which goose never sends."
        }
      ]
    },
    "sampling": {
      "status": "full",
      "notes": "create_message is implemented and marked #[expect(deprecated)] — sampling is deprecated as of 2026-07-28 (SEP-2577), the revision goose prefers.",
      "evidence": [
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "aaif-goose/goose",
          "date": "2026-08-23",
          "commit": "c5e5929a",
          "path": "crates/goose/src/agents/mcp_client.rs:create_message"
        },
        {
          "tier": "declared",
          "status": "unsupported",
          "at": "2025-03-26",
          "source": "apify/mcp-client-capabilities",
          "date": "2026-02-02",
          "commit": "4406120",
          "note": "No sampling key on the goose record."
        }
      ]
    },
    "elicitation": {
      "status": "full",
      "notes": "Resolves a session id and a tool-call request id from the request context and returns INTERNAL_ERROR if either is missing, so elicitation only works inside a tool call. Hard 300-second timeout.",
      "form": {
        "status": "full"
      },
      "url": {
        "status": "full",
        "notes": "URL mode is flattened into the same prompt path as form mode, passed as {\"url\": url} rather than a requested schema."
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "aaif-goose/goose",
          "date": "2026-08-23",
          "commit": "c5e5929a",
          "path": "crates/goose/src/agents/mcp_client.rs:create_elicitation"
        },
        {
          "tier": "declared",
          "status": "unsupported",
          "at": "2025-03-26",
          "source": "apify/mcp-client-capabilities",
          "date": "2026-02-02",
          "commit": "4406120",
          "note": "No elicitation key on the goose record. Both form and URL mode are implemented."
        }
      ],
      "research": [
        "goose-elicitation-needs-tool-call-context"
      ]
    },
    "roots": {
      "status": "full",
      "notes": "list_roots returns roots derived from the working directory. Marked #[expect(deprecated)] at the declaration site — roots is deprecated as of 2026-07-28 (SEP-2577).",
      "listChanged": {
        "status": "full",
        "notes": "Sent on working-directory change with no protocol-version gate, including when 2026-07-28 is negotiated, where the notification no longer exists. rmcp 3.1.4 does not filter it, so it reaches the wire.",
        "research": [
          "goose-sends-removed-roots-notification"
        ]
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "aaif-goose/goose",
          "date": "2026-08-23",
          "commit": "c5e5929a",
          "path": "crates/goose/src/agents/mcp_client.rs:list_roots"
        }
      ]
    },
    "logging": {
      "status": "full",
      "notes": "on_logging_message fans notifications out to subscribers. Marked #[expect(deprecated)] — logging is deprecated as of 2026-07-28 (SEP-2577).",
      "evidence": [
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "aaif-goose/goose",
          "date": "2026-08-23",
          "commit": "c5e5929a",
          "path": "crates/goose/src/agents/mcp_client.rs:on_logging_message"
        }
      ]
    },
    "instructions": {
      "status": "full",
      "notes": "Server instructions are carried through into the system prompt as a per-extension block.",
      "evidence": [
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "aaif-goose/goose",
          "date": "2026-08-23",
          "commit": "c5e5929a",
          "path": "crates/goose/src/agents/mcp_client.rs:get_instructions"
        }
      ]
    },
    "extensions": {
      "io.modelcontextprotocol/ui": {
        "status": "partial",
        "notes": "Declared by goose Desktop, not by goose CLI. Advertised with mimeTypes [\"text/html;profile=mcp-app\"]. An embedder passing explicit host extensions overrides the default either way.",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "aaif-goose/goose",
            "date": "2026-08-23",
            "commit": "c5e5929a",
            "path": "crates/goose/src/agents/agent.rs:414-421"
          }
        ],
        "research": [
          "goose-client-name-varies-by-surface"
        ]
      }
    },
    "research": [
      "goose-client-name-varies-by-surface"
    ],
    "metadata": {
      "vendor": "Block",
      "openSource": true,
      "license": "Apache-2.0",
      "sourceUrl": "https://github.com/aaif-goose/goose",
      "lastVerified": "2026-08-23",
      "source": {
        "repo": "https://github.com/aaif-goose/goose.git",
        "ref": "main",
        "checkedCommit": "c5e5929a641ffc0edbccad476e18f726e9024f70",
        "commitDate": "2026-08-23T23:27:17Z",
        "checkedAt": "2026-08-23",
        "paths": [
          "crates/goose/src/agents/mcp_client.rs",
          "crates/goose/src/agents/extension_manager.rs",
          "crates/goose/src/agents/agent.rs"
        ]
      },
      "sdk": {
        "name": "rmcp",
        "language": "rust",
        "official": true,
        "declared": "3.0.0",
        "resolved": "3.1.4",
        "patched": false,
        "notes": "The workspace declares rmcp \"3.0.0\" as a caret requirement and the lockfile resolves it to 3.1.4, so behavioural claims cite 3.1.4. The lockfile also holds rmcp 1.8.0, pulled in by the pctx_code_execution_runtime, pctx_config and pctx_registry crates; that copy is unrelated to goose's own MCP client. [patch.crates-io] exists but covers agent-client-protocol, v8 and cudaforge, not rmcp. goose names ProtocolVersion::V_2026_07_28 itself rather than inheriting a version from rmcp, using rmcp's ProtocolVersion::LATEST only as the legacy fallback.",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "aaif-goose/goose",
            "date": "2026-08-24",
            "commit": "c5e5929a",
            "path": "Cargo.toml:23,115-119"
          },
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "aaif-goose/goose",
            "date": "2026-08-24",
            "commit": "c5e5929a",
            "path": "Cargo.lock"
          },
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "aaif-goose/goose",
            "date": "2026-08-24",
            "commit": "c5e5929a",
            "path": "crates/goose/src/agents/mcp_client.rs:677-695"
          }
        ]
      }
    }
  },
  "openai-codex": {
    "title": "Codex CLI",
    "clientInfoNames": [
      "codex-mcp-client"
    ],
    "url": "https://openai.com/codex",
    "description": "OpenAI's coding agent, shipping as a CLI and an app-server. Rust, using rmcp 3.1.3 as its MCP client through a codex-rmcp-client wrapper crate. Codex also runs as an MCP server, which is a separate code path and not described here.",
    "category": "cli",
    "platforms": [
      "windows",
      "macos",
      "linux"
    ],
    "protocolVersions": [
      "2025-06-18",
      "2026-07-28"
    ],
    "preferredProtocolVersion": "2025-06-18",
    "transports": {
      "stdio": {
        "status": "full",
        "notes": "Three stdio paths: a local child process, an in-process transport, and an executor process transport for sandboxed and remote environments.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-06-18",
            "source": "openai/codex",
            "date": "2026-08-24",
            "commit": "b705b6b0",
            "path": "codex-rs/rmcp-client/src/rmcp_client.rs:409"
          }
        ]
      },
      "sse": {
        "status": "unsupported",
        "notes": "rmcp is built without transport-sse-client. Only transport-child-process, transport-async-rw and the streamable HTTP client and server are enabled.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-06-18",
            "source": "openai/codex",
            "date": "2026-08-24",
            "commit": "b705b6b0",
            "path": "codex-rs/rmcp-client/Cargo.toml"
          }
        ]
      },
      "streamableHttp": {
        "status": "full",
        "notes": "Carries OAuth, a bearer token, or neither, with session-expiry retry on 404 and a configurable redirect policy.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-06-18",
            "source": "openai/codex",
            "date": "2026-08-24",
            "commit": "b705b6b0",
            "path": "codex-rs/rmcp-client/src/rmcp_client.rs:483"
          },
          {
            "tier": "declared",
            "status": "unsupported",
            "at": "2025-06-18",
            "source": "apify/mcp-client-capabilities",
            "date": "2026-02-02",
            "commit": "4406120",
            "note": "Records stdio only. Streamable HTTP with OAuth is a large part of the client crate."
          }
        ]
      }
    },
    "authentication": {
      "oauth": {
        "status": "full",
        "notes": "Prefers CIMD over DCR when the authorization server advertises it, using a ChatGPT-hosted client identifier. PKCE and the token exchange are rmcp's AuthorizationManager and were not read at this commit.",
        "clientIdMetadataDocument": true,
        "dynamicRegistration": true,
        "resourceIndicators": true,
        "protectedResourceMetadata": true,
        "issuerIdentification": true,
        "grantTypes": [
          "authorization_code",
          "refresh_token"
        ],
        "evidence": [
          {
            "tier": "read",
            "at": "2025-06-18",
            "source": "openai/codex",
            "date": "2026-08-24",
            "commit": "b705b6b0",
            "path": "codex-rs/rmcp-client/src/oauth_client_registration.rs:32"
          },
          {
            "tier": "read",
            "at": "2025-06-18",
            "source": "openai/codex",
            "date": "2026-08-24",
            "commit": "b705b6b0",
            "path": "codex-rs/rmcp-client/src/oauth/issuer_binding.rs:11",
            "note": "issuerIdentification: rejects an authorization endpoint that cannot be bound to its issuer, honouring authorization_response_iss_parameter_supported. Two hardcoded compatibility exceptions, for Figma and Robinhood."
          },
          {
            "tier": "read",
            "at": "2025-06-18",
            "source": "openai/codex",
            "date": "2026-08-24",
            "commit": "b705b6b0",
            "path": "codex-rs/rmcp-client/src/perform_oauth_login.rs:585-589",
            "note": "resourceIndicators: a resource parameter is appended to the authorization URL. Whether it also reaches the token endpoint is rmcp's, not read."
          },
          {
            "tier": "read",
            "at": "2025-06-18",
            "source": "openai/codex",
            "date": "2026-08-24",
            "commit": "b705b6b0",
            "path": "codex-rs/rmcp-client/src/auth_status.rs:195",
            "note": "protectedResourceMetadata: discovery goes through rmcp's AuthorizationManager. Codex's own test drives a WWW-Authenticate resource_metadata challenge end to end, so the behaviour holds, but the implementation was not read."
          }
        ],
        "research": [
          "codex-prefers-a-chatgpt-hosted-client-identifier"
        ]
      },
      "header": {
        "status": "full",
        "notes": "Per-server http_headers, env_http_headers, bearer_token_env_var, and an http_headers_helper command whose stdout supplies headers.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-06-18",
            "source": "openai/codex",
            "date": "2026-08-24",
            "commit": "b705b6b0",
            "path": "codex-rs/rmcp-client/src/http_headers.rs"
          }
        ]
      }
    },
    "tools": {
      "status": "full",
      "notes": "In the shipped default mode nextCursor from tools/list is discarded, so only the first page of a server's tool catalog is read.",
      "listChanged": {
        "status": "partial",
        "notes": "The notification is received and written to the tracing log. Nothing re-lists, so a tool added mid-session is not picked up.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-06-18",
            "source": "openai/codex",
            "date": "2026-08-24",
            "commit": "b705b6b0",
            "path": "codex-rs/rmcp-client/src/logging_client_handler.rs:86"
          }
        ]
      },
      "result": {
        "status": "full",
        "notes": "structuredContent replaces content. Every payload is prefixed with a Wall time header.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-06-18",
            "source": "olaservo/structured-content-research",
            "url": "https://github.com/olaservo/structured-content-research/blob/0c0395d/notes/codex-tool-result-handling.md",
            "date": "2026-11-08",
            "commit": "0c0395d",
            "path": "notes/codex-tool-result-handling.md",
            "note": "The read tier for tool result handling lives in that repo (AGENTS.md); this entry summarises its note, which read the Codex CLI source at 748ab55."
          }
        ],
        "structuredContent": {
          "status": "full",
          "notes": "Serialized compact JSON of structuredContent is the whole tool output whenever it is non-null, including {}."
        },
        "content": {
          "status": "partial",
          "notes": "Dropped whenever structuredContent is non-null. Reaches the model only when structuredContent is absent or null, or when a block carries the private _meta key codex/encryptedContent."
        },
        "audience": {
          "status": "unsupported",
          "notes": "convert_mcp_content_to_items reads text, data, mimeType and _meta only, so annotations.audience is not read on the model path."
        }
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2025-06-18",
          "source": "openai/codex",
          "date": "2026-08-24",
          "commit": "b705b6b0",
          "path": "codex-rs/codex-mcp/src/rmcp_client.rs:618"
        },
        {
          "tier": "declared",
          "status": "full",
          "at": "2025-06-18",
          "source": "apify/mcp-client-capabilities",
          "date": "2026-02-02",
          "commit": "4406120"
        }
      ],
      "research": [
        "codex-reads-one-page-of-tools"
      ]
    },
    "resources": {
      "status": "full",
      "notes": "list, templates and read are all implemented, and all three are exposed to the model as built-in tools rather than through a host-side picker.",
      "listChanged": {
        "status": "partial",
        "notes": "Received and logged only, like tools/list_changed."
      },
      "subscribe": {
        "status": "unsupported",
        "notes": "No resources/subscribe call. resources/updated notifications are logged if they arrive."
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2025-06-18",
          "source": "openai/codex",
          "date": "2026-08-24",
          "commit": "b705b6b0",
          "path": "codex-rs/rmcp-client/src/rmcp_client.rs:711-770"
        }
      ]
    },
    "prompts": {
      "status": "unsupported",
      "notes": "No prompts/list or prompts/get on the client path. The handlers by those names live in codex-rs/mcp-server, where Codex is the server.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-06-18",
          "source": "openai/codex",
          "date": "2026-08-24",
          "commit": "b705b6b0",
          "path": "codex-rs/rmcp-client/src/rmcp_client.rs"
        }
      ]
    },
    "completions": {
      "status": "unsupported",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-06-18",
          "source": "openai/codex",
          "date": "2026-08-24",
          "commit": "b705b6b0",
          "path": "codex-rs/rmcp-client/src/rmcp_client.rs"
        }
      ]
    },
    "sampling": {
      "status": "unsupported",
      "notes": "Not in the declared capabilities and no create_message handler. The word appears in the codebase only for Codex's own model calls.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-06-18",
          "source": "openai/codex",
          "date": "2026-08-24",
          "commit": "b705b6b0",
          "path": "codex-rs/codex-mcp/src/rmcp_client.rs:1006"
        }
      ]
    },
    "elicitation": {
      "status": "full",
      "notes": "The only capability Codex declares by default. Form and URL modes are added when the auth_elicitation feature is on, which is stable and default-enabled; without it an empty elicitation object is declared.",
      "form": {
        "status": "full"
      },
      "url": {
        "status": "full"
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2025-06-18",
          "source": "openai/codex",
          "date": "2026-08-24",
          "commit": "b705b6b0",
          "path": "codex-rs/core/src/config/mod.rs:1742-1750"
        },
        {
          "tier": "declared",
          "status": "full",
          "at": "2025-06-18",
          "source": "apify/mcp-client-capabilities",
          "date": "2026-02-02",
          "commit": "4406120"
        }
      ]
    },
    "roots": {
      "status": "unsupported",
      "notes": "Not in the declared capabilities and no list_roots handler, so a server cannot learn the working directory this way. ready_selected_capability_roots in the same crates is a Codex-internal concept, unrelated to MCP roots.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-06-18",
          "source": "openai/codex",
          "date": "2026-08-24",
          "commit": "b705b6b0",
          "path": "codex-rs/rmcp-client/src/logging_client_handler.rs"
        }
      ],
      "research": [
        "goose-sends-removed-roots-notification"
      ]
    },
    "logging": {
      "status": "partial",
      "notes": "notifications/message is mapped onto tracing levels and written to Codex's own log, not shown in the UI. logging/setLevel is never sent, and neither is the io.modelcontextprotocol/logLevel _meta key that replaces it, so on a 2026-07-28 session a conforming server sends nothing and the handler is unreachable.",
      "evidence": [
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "openai/codex",
          "date": "2026-08-24",
          "commit": "b705b6b0",
          "path": "codex-rs/rmcp-client/src/logging_client_handler.rs:96"
        }
      ]
    },
    "instructions": {
      "status": "full",
      "notes": "Server instructions are read from the initialize result and attached to each of that server's tools when the catalog is built.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-06-18",
          "source": "openai/codex",
          "date": "2026-08-24",
          "commit": "b705b6b0",
          "path": "codex-rs/codex-mcp/src/rmcp_client.rs:967"
        }
      ]
    },
    "icons": {
      "status": "partial",
      "notes": "Server icons are parsed from the initialize result and carried into McpServerInfo. No rendering path was found in the crates read, and tool-level icons are not handled.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-06-18",
          "source": "openai/codex",
          "date": "2026-08-24",
          "commit": "b705b6b0",
          "path": "codex-rs/codex-mcp/src/rmcp_client.rs:1041"
        }
      ]
    },
    "tasks": {
      "status": "unsupported",
      "notes": "No tasks/* calls at this commit.",
      "evidence": [
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "openai/codex",
          "date": "2026-08-24",
          "commit": "b705b6b0",
          "path": "codex-rs/rmcp-client/src/rmcp_client.rs"
        }
      ]
    },
    "extensions": {
      "openai/form": {
        "status": "partial",
        "notes": "A vendor elicitation extension. An openai/form request carries message and requestedSchema and is routed into the same elicitation path as elicitation/create. Declared only when the app-server host asks for it, or when the legacy form-elicitation flag is set.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-06-18",
            "source": "openai/codex",
            "date": "2026-08-24",
            "commit": "b705b6b0",
            "path": "codex-rs/rmcp-client/src/elicitation_client_service.rs:31"
          }
        ]
      },
      "openai/standard-form-input": {
        "status": "partial",
        "notes": "Client-only extension, never projected to downstream servers.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-06-18",
            "source": "openai/codex",
            "date": "2026-08-24",
            "commit": "b705b6b0",
            "path": "codex-rs/protocol/src/mcp.rs:76"
          }
        ]
      },
      "io.modelcontextprotocol/ui": {
        "status": "partial",
        "notes": "Forwarded to servers only when the app-server host declares it. Codex keeps just the three extension namespaces it knows and drops anything else the host declares.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-06-18",
            "source": "openai/codex",
            "date": "2026-08-24",
            "commit": "b705b6b0",
            "path": "codex-rs/codex-mcp/src/client_capabilities.rs:14"
          }
        ]
      }
    },
    "bonusFeatures": {
      "modelInitiatedResourceRead": {
        "status": "full",
        "notes": "list_mcp_resources, list_mcp_resource_templates and read_mcp_resource are registered as built-in tools whenever any MCP server is configured, with no feature gate. Pagination cursors are passed to and from the model.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-06-18",
            "source": "openai/codex",
            "date": "2026-08-24",
            "commit": "b705b6b0",
            "path": "codex-rs/core/src/tools/spec_plan.rs:1001"
          }
        ],
        "research": [
          "model-initiated-resource-read"
        ]
      }
    },
    "research": [
      "codex-defaults-to-2025-06-18",
      "codex-reads-one-page-of-tools",
      "codex-prefers-a-chatgpt-hosted-client-identifier"
    ],
    "metadata": {
      "vendor": "OpenAI",
      "openSource": true,
      "license": "Apache-2.0",
      "sourceUrl": "https://github.com/openai/codex",
      "lastVerified": "2026-08-24",
      "source": {
        "repo": "https://github.com/openai/codex.git",
        "ref": "main",
        "checkedCommit": "b705b6b076c64e5d66d6b340a32b07ae32d20486",
        "commitDate": "2026-08-24T17:07:21Z",
        "checkedAt": "2026-08-24",
        "paths": [
          "codex-rs/rmcp-client/src",
          "codex-rs/codex-mcp/src",
          "codex-rs/core/src/tools/handlers/mcp_resource",
          "codex-rs/core/src/config/mod.rs",
          "codex-rs/features/src/lib.rs"
        ]
      },
      "sdk": {
        "name": "rmcp",
        "language": "rust",
        "official": true,
        "declared": "=3.1.3",
        "resolved": "3.1.3",
        "patched": false,
        "notes": "Pinned exactly with '=', so the declared requirement and the resolved version agree. codex-rs/patches/ holds twenty-odd build-toolchain patches (v8, llvm, windows link flags) and none touch rmcp, and the [patch.crates-io] rmcp override is commented out as a local-debug escape hatch. Codex selects 2025-06-18 through its own protocol mode rather than inheriting a version from rmcp.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-06-18",
            "source": "openai/codex",
            "date": "2026-08-24",
            "commit": "b705b6b0",
            "path": "codex-rs/Cargo.toml:401,587-597"
          },
          {
            "tier": "read",
            "at": "2025-06-18",
            "source": "openai/codex",
            "date": "2026-08-24",
            "commit": "b705b6b0",
            "path": "codex-rs/Cargo.lock"
          }
        ]
      }
    }
  },
  "opencode": {
    "title": "opencode",
    "clientInfoNames": [
      "opencode"
    ],
    "url": "https://opencode.ai",
    "description": "Open-source terminal coding agent, TypeScript on the official MCP TypeScript SDK. Ships a patched copy of SDK 1.29.0, so its transport behaviour is not stock.",
    "category": "cli",
    "platforms": [
      "windows",
      "macos",
      "linux"
    ],
    "protocolVersions": [
      "2024-11-05",
      "2025-03-26",
      "2025-06-18",
      "2025-11-25"
    ],
    "preferredProtocolVersion": "2025-11-25",
    "transports": {
      "stdio": {
        "status": "full",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "anomalyco/opencode",
            "date": "2026-08-24",
            "commit": "7cde8329",
            "path": "packages/opencode/src/mcp/index.ts:347"
          },
          {
            "tier": "declared",
            "status": "full",
            "at": "2025-06-18",
            "source": "apify/mcp-client-capabilities",
            "date": "2026-02-02",
            "commit": "4406120",
            "note": "Records stdio, agreeing with the read."
          }
        ]
      },
      "sse": {
        "status": "full",
        "notes": "Tried as a fallback when Streamable HTTP fails to connect, against the same URL. A remote server is configured by URL alone, with no transport field to choose between them.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "anomalyco/opencode",
            "date": "2026-08-24",
            "commit": "7cde8329",
            "path": "packages/opencode/src/mcp/index.ts:269-284"
          },
          {
            "tier": "declared",
            "status": "unsupported",
            "at": "2025-06-18",
            "source": "apify/mcp-client-capabilities",
            "date": "2026-02-02",
            "commit": "4406120",
            "note": "Records stdio only, at 2025-06-18, on platform \"web\". opencode is a terminal agent on the three desktop platforms and negotiates 2025-11-25, and every remote server it connects to uses Streamable HTTP or SSE."
          }
        ]
      },
      "streamableHttp": {
        "status": "full",
        "notes": "Tried first for every remote server.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "anomalyco/opencode",
            "date": "2026-08-24",
            "commit": "7cde8329",
            "path": "packages/opencode/src/mcp/index.ts:269-278"
          },
          {
            "tier": "declared",
            "status": "unsupported",
            "at": "2025-06-18",
            "source": "apify/mcp-client-capabilities",
            "date": "2026-02-02",
            "commit": "4406120",
            "note": "Records stdio only, at 2025-06-18, on platform \"web\". opencode is a terminal agent on the three desktop platforms and negotiates 2025-11-25, and every remote server it connects to uses Streamable HTTP or SSE."
          }
        ]
      }
    },
    "authentication": {
      "oauth": {
        "status": "full",
        "notes": "Dynamic Client Registration is the default path; a clientId can be pinned in config instead. token_endpoint_auth_method is none unless a clientSecret is configured. The callback is a loopback server on port 19876 by default.",
        "clientIdMetadataDocument": false,
        "dynamicRegistration": true,
        "grantTypes": [
          "authorization_code",
          "refresh_token"
        ],
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "anomalyco/opencode",
            "date": "2026-08-24",
            "commit": "7cde8329",
            "path": "packages/opencode/src/mcp/oauth-provider.ts:43-51"
          }
        ]
      },
      "header": {
        "status": "full",
        "notes": "A headers map on a remote server is passed through as requestInit headers on both transports.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "anomalyco/opencode",
            "date": "2026-08-24",
            "commit": "7cde8329",
            "path": "packages/opencode/src/mcp/index.ts:274,281"
          }
        ]
      }
    },
    "tools": {
      "status": "full",
      "notes": "tools/list is only called when the server declares a tools capability. Fully paginated, with a duplicate-cursor guard and a 1000-page cap. A tool result carrying only structuredContent is stringified into a text block before it reaches the model.",
      "listChanged": {
        "status": "full",
        "notes": "Re-lists the catalog and publishes a ToolsChanged event, so a changed catalog is picked up mid-session. The handler is registered only when the server declared tools.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "anomalyco/opencode",
            "date": "2026-08-24",
            "commit": "7cde8329",
            "path": "packages/opencode/src/mcp/index.ts:461-470"
          }
        ]
      },
      "result": {
        "status": "full",
        "notes": "Code Mode is the default route: MCP tools are reachable only through the execute script tool, scripts receive structuredContent, and the model sees the script return value. The direct path applies with codemode: false.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "olaservo/structured-content-research",
            "url": "https://github.com/olaservo/structured-content-research/blob/0c0395d/notes/opencode-tool-result-handling.md",
            "date": "2026-11-08",
            "commit": "0c0395d",
            "path": "notes/opencode-tool-result-handling.md",
            "note": "The read tier for tool result handling lives in that repo (AGENTS.md); this entry summarises its note, which read the opencode source at a98e3fa."
          }
        ],
        "content": {
          "status": "full",
          "notes": "On the direct path (codemode: false, or execute wholly denied) the content blocks reach the model; media blocks become data URIs or saved-file notes."
        },
        "structuredContent": {
          "status": "partial",
          "notes": "On the direct path it fills in as one text block of JSON.stringify(structuredContent) only when content is empty, and is otherwise held in a tool output field that is not persisted. On the default Code Mode route scripts receive it directly."
        }
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "anomalyco/opencode",
          "date": "2026-08-24",
          "commit": "7cde8329",
          "path": "packages/opencode/src/mcp/catalog.ts:18-35,143-160"
        },
        {
          "tier": "declared",
          "status": "full",
          "at": "2025-06-18",
          "source": "apify/mcp-client-capabilities",
          "date": "2026-02-02",
          "commit": "4406120",
          "note": "Records tools and tools.listChanged as full, agreeing with the read."
        }
      ],
      "research": [
        "opencode-retries-tools-list-without-output-schema"
      ]
    },
    "resources": {
      "status": "full",
      "notes": "Exposed to the model as three built-in tools rather than a host-side picker, each behind a permission ask. Registered only when some connected server declares resources. A user can also attach a resource to a message directly.",
      "listChanged": {
        "status": "unsupported",
        "notes": "No resources/list_changed handler is registered.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "anomalyco/opencode",
            "date": "2026-08-24",
            "commit": "7cde8329",
            "path": "packages/opencode/src/mcp/index.ts:457-462"
          }
        ]
      },
      "subscribe": {
        "status": "unsupported",
        "notes": "No resources/subscribe call and no resources/updated handler.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "anomalyco/opencode",
            "date": "2026-08-24",
            "commit": "7cde8329",
            "path": "packages/opencode/src/mcp/index.ts:457-462"
          }
        ]
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "anomalyco/opencode",
          "date": "2026-08-24",
          "commit": "7cde8329",
          "path": "packages/opencode/src/session/tools.ts:27-31,136-139"
        }
      ],
      "research": [
        "model-initiated-resource-read"
      ]
    },
    "prompts": {
      "status": "partial",
      "notes": "Every server prompt becomes a slash command. Only text content survives: a prompt message carrying an image or an embedded resource maps to an empty string and is joined into the template. Arguments are filled positionally as $1, $2 regardless of their names.",
      "listChanged": {
        "status": "unsupported",
        "notes": "No prompts/list_changed handler is registered."
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "anomalyco/opencode",
          "date": "2026-08-24",
          "commit": "7cde8329",
          "path": "packages/opencode/src/command/index.ts:105-130"
        }
      ],
      "research": [
        "opencode-drops-non-text-prompt-content"
      ]
    },
    "completions": {
      "status": "unsupported",
      "notes": "No completion/complete call at this commit.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "anomalyco/opencode",
          "date": "2026-08-24",
          "commit": "7cde8329",
          "path": "packages/opencode/src/mcp"
        }
      ]
    },
    "sampling": {
      "status": "unsupported",
      "notes": "Present in the capability object but commented out, against issue 11948. The client never declares it, so a server cannot ask.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "anomalyco/opencode",
          "date": "2026-08-24",
          "commit": "7cde8329",
          "path": "packages/opencode/src/mcp/index.ts:41-42"
        }
      ],
      "research": [
        "opencode-declares-only-roots"
      ]
    },
    "elicitation": {
      "status": "unsupported",
      "notes": "Commented out against issue 23066.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "anomalyco/opencode",
          "date": "2026-08-24",
          "commit": "7cde8329",
          "path": "packages/opencode/src/mcp/index.ts:43-44"
        }
      ],
      "research": [
        "opencode-declares-only-roots"
      ]
    },
    "roots": {
      "status": "full",
      "notes": "The only capability opencode declares. list_roots returns exactly one root, the file URL of the instance directory.",
      "listChanged": {
        "status": "unsupported",
        "notes": "Declared as a bare roots:{} with no listChanged, and nothing sends notifications/roots/list_changed. The single root is fixed at client creation."
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "anomalyco/opencode",
          "date": "2026-08-24",
          "commit": "7cde8329",
          "path": "packages/opencode/src/mcp/index.ts:46,76-80"
        }
      ]
    },
    "logging": {
      "status": "partial",
      "notes": "Receives notifications/message and routes them to the server log. Never calls logging/setLevel, so the level is whatever the server defaults to.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "anomalyco/opencode",
          "date": "2026-08-24",
          "commit": "7cde8329",
          "path": "packages/opencode/src/mcp/index.ts:457-459"
        }
      ]
    },
    "instructions": {
      "status": "full",
      "notes": "Server instructions are trimmed and carried per server.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "anomalyco/opencode",
          "date": "2026-08-24",
          "commit": "7cde8329",
          "path": "packages/opencode/src/mcp/index.ts:399"
        }
      ]
    },
    "icons": {
      "status": "unsupported",
      "notes": "No icon handling anywhere in the client.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "anomalyco/opencode",
          "date": "2026-08-24",
          "commit": "7cde8329",
          "path": "packages/opencode/src/mcp"
        }
      ]
    },
    "tasks": {
      "status": "unsupported",
      "notes": "Commented out against issue 28567, though SDK 1.29.0 carries an experimental tasks client.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "anomalyco/opencode",
          "date": "2026-08-24",
          "commit": "7cde8329",
          "path": "packages/opencode/src/mcp/index.ts:47-48"
        }
      ],
      "research": [
        "opencode-declares-only-roots"
      ]
    },
    "bonusFeatures": {
      "modelInitiatedResourceRead": {
        "status": "full",
        "notes": "list_mcp_resources, list_mcp_resource_templates and read_mcp_resource - the same three tool names Codex uses, arrived at independently on a different SDK and language. Each is permission-gated; blobs are capped at 10MB.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "anomalyco/opencode",
            "date": "2026-08-24",
            "commit": "7cde8329",
            "path": "packages/opencode/src/session/tools.ts:27-31"
          }
        ],
        "research": [
          "model-initiated-resource-read"
        ]
      },
      "patchedSdkSessionRecovery": {
        "status": "full",
        "notes": "opencode patches SDK 1.29.0 so a 404 on a request carrying a session id clears the session, fires onsessionexpired and retries once. Stock 1.29.0 has no recovery path. The patch also treats a JSON-RPC error over SSE as a response, and stops a stale session id from overwriting a newer one.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "anomalyco/opencode",
            "date": "2026-08-24",
            "commit": "7cde8329",
            "path": "patches/@modelcontextprotocol%2Fsdk@1.29.0.patch"
          }
        ],
        "research": [
          "opencode-patches-its-sdk-for-session-recovery"
        ]
      }
    },
    "research": [
      "opencode-declares-only-roots",
      "opencode-patches-its-sdk-for-session-recovery"
    ],
    "metadata": {
      "vendor": "Anomaly",
      "openSource": true,
      "license": "MIT",
      "sourceUrl": "https://github.com/anomalyco/opencode",
      "lastVerified": "2026-08-24",
      "source": {
        "repo": "https://github.com/anomalyco/opencode.git",
        "ref": "dev",
        "checkedCommit": "7cde8329bc33801248d6aafa2a4dd46dc86e5683",
        "commitDate": "2026-08-24T17:19:53Z",
        "checkedAt": "2026-08-24",
        "paths": [
          "packages/opencode/src/mcp/index.ts",
          "packages/opencode/src/mcp/catalog.ts",
          "packages/opencode/src/mcp/oauth-provider.ts",
          "packages/opencode/src/session/tools.ts",
          "packages/opencode/src/command/index.ts",
          "packages/core/src/v1/config/mcp.ts",
          "patches/@modelcontextprotocol%2Fsdk@1.29.0.patch"
        ]
      },
      "sdk": {
        "name": "@modelcontextprotocol/sdk",
        "language": "typescript",
        "official": true,
        "declared": "1.29.0",
        "resolved": "1.29.0",
        "patched": true,
        "pinsProtocolVersion": "2025-11-25",
        "notes": "Pinned exactly, then patched. bun.lock registers a patch against the resolved package that changes four runtime files - client/index.js, client/streamableHttp.js, client/auth.js and shared/protocol.js - so the published 1.29.0 does not describe what runs. The SDK is also where opencode's protocol version comes from: 1.29.0 pins LATEST_PROTOCOL_VERSION at 2025-11-25 and lists support back to 2024-10-07, a revision this registry does not track because it was never published.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "anomalyco/opencode",
            "date": "2026-08-24",
            "commit": "7cde8329",
            "path": "packages/opencode/package.json:83"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "anomalyco/opencode",
            "date": "2026-08-24",
            "commit": "7cde8329",
            "path": "bun.lock:595,1070,1832"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "modelcontextprotocol/typescript-sdk",
            "date": "2026-08-24",
            "commit": "e12cbd70",
            "path": "src/types.ts:4-6",
            "note": "Tag v1.29.0 is commit e12cbd70, committed 2026-03-30. LATEST_PROTOCOL_VERSION = '2025-11-25'; SUPPORTED_PROTOCOL_VERSIONS lists 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05, 2024-10-07."
          }
        ],
        "research": [
          "opencode-patches-its-sdk-for-session-recovery"
        ]
      }
    }
  },
  "cline": {
    "title": "Cline",
    "clientInfoNames": [
      "Cline",
      "@cline/core"
    ],
    "url": "https://cline.bot/",
    "description": "Open-source coding agent shipping as a VS Code extension and a CLI from one monorepo. Both surfaces use the official TypeScript SDK unpatched, except the CLI's stdio path, which is a hand-written JSON-RPC client fixed at 2024-11-05.",
    "category": "ide",
    "platforms": [
      "windows",
      "macos",
      "linux"
    ],
    "protocolVersions": [
      "2024-11-05",
      "2025-03-26",
      "2025-06-18",
      "2025-11-25"
    ],
    "preferredProtocolVersion": "2025-11-25",
    "transports": {
      "stdio": {
        "status": "full",
        "notes": "Two implementations. The extension uses the SDK's StdioClientTransport. The CLI uses a hand-written client that tries newline-delimited framing first and respawns the server with LSP-style Content-Length framing if initialize fails, a framing MCP's stdio transport does not define.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "cline/cline",
            "date": "2026-08-25",
            "commit": "110138b5",
            "path": "apps/vscode/src/services/mcp/McpHub.ts:484-493"
          },
          {
            "tier": "read",
            "at": "2024-11-05",
            "source": "cline/cline",
            "date": "2026-08-25",
            "commit": "110138b5",
            "path": "sdk/packages/core/src/extensions/mcp/client.ts:214-238"
          },
          {
            "tier": "declared",
            "status": "full",
            "at": "2025-06-18",
            "source": "apify/mcp-client-capabilities",
            "date": "2026-02-02",
            "commit": "4406120",
            "note": "Records stdio, agreeing with the read."
          }
        ],
        "research": [
          "cline-hand-rolls-stdio-in-its-cli"
        ]
      },
      "sse": {
        "status": "full",
        "notes": "Chosen by an explicit type in config, with no fallback probing. It is also what a URL server with no type resolves to on both surfaces, so the deprecated transport is the accidental default.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "cline/cline",
            "date": "2026-08-25",
            "commit": "110138b5",
            "path": "apps/vscode/src/services/mcp/McpHub.ts:574-577"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "cline/cline",
            "date": "2026-08-25",
            "commit": "110138b5",
            "path": "sdk/packages/core/src/extensions/mcp/oauth.ts:439-451"
          },
          {
            "tier": "declared",
            "status": "unsupported",
            "at": "2025-06-18",
            "source": "apify/mcp-client-capabilities",
            "date": "2026-02-02",
            "commit": "4406120",
            "note": "Records stdio only. The extension and the CLI both build SSE and Streamable HTTP transports from a url config, and both ship an OAuth flow that only applies to them."
          }
        ],
        "research": [
          "cline-defaults-a-url-server-to-sse"
        ]
      },
      "streamableHttp": {
        "status": "full",
        "notes": "Reached only by setting type explicitly. The extension wraps fetch to rewrite a 404 on the transport's SSE probe GET into a 405, because the SDK only handles 405 and many servers answer 404.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "cline/cline",
            "date": "2026-08-25",
            "commit": "110138b5",
            "path": "apps/vscode/src/services/mcp/McpHub.ts:598-622"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "cline/cline",
            "date": "2026-08-25",
            "commit": "110138b5",
            "path": "sdk/packages/core/src/extensions/mcp/oauth.ts:454-458"
          },
          {
            "tier": "declared",
            "status": "unsupported",
            "at": "2025-06-18",
            "source": "apify/mcp-client-capabilities",
            "date": "2026-02-02",
            "commit": "4406120",
            "note": "Records stdio only. The extension and the CLI both build SSE and Streamable HTTP transports from a url config, and both ship an OAuth flow that only applies to them."
          }
        ],
        "research": [
          "cline-defaults-a-url-server-to-sse"
        ]
      }
    },
    "authentication": {
      "oauth": {
        "status": "full",
        "notes": "One flow shared by both surfaces: the extension delegates to @cline/core's authorizeMcpServerOAuth, the same call the CLI makes. Tokens live in the shared settings file under each server's oauth key, so an authorization completed in the CLI is picked up by an open extension window. token_endpoint_auth_method is none unless a clientSecret is configured. The callback binds a loopback server, first free port of 1456-1461. Discovery, PKCE and protected-resource metadata are the SDK's auth() and were not read.",
        "clientIdMetadataDocument": false,
        "dynamicRegistration": true,
        "grantTypes": [
          "authorization_code",
          "refresh_token"
        ],
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "cline/cline",
            "date": "2026-08-25",
            "commit": "110138b5",
            "path": "sdk/packages/core/src/extensions/mcp/oauth.ts:98-106"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "cline/cline",
            "date": "2026-08-25",
            "commit": "110138b5",
            "path": "apps/vscode/src/services/mcp/McpOAuthManager.ts:108-116,242-269"
          }
        ]
      },
      "header": {
        "status": "full",
        "notes": "A headers map on a remote server is passed through as requestInit headers on both transports. A configured Authorization header suppresses the OAuth prompt: a 401 is reported as a rejected header rather than a sign-in.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "cline/cline",
            "date": "2026-08-25",
            "commit": "110138b5",
            "path": "apps/vscode/src/services/mcp/McpHub.ts:546-548,618-620"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "cline/cline",
            "date": "2026-08-25",
            "commit": "110138b5",
            "path": "sdk/packages/core/src/extensions/mcp/client.ts:712-720"
          }
        ]
      }
    },
    "tools": {
      "status": "full",
      "notes": "One page of tools/list, no cursor, on both surfaces. Every tool is flattened into a model-facing tool named <server>__<tool>, sanitized to [A-Za-z0-9_-] and truncated to 64 characters with an 8-character sha1 suffix when it does not fit. outputSchema and structuredContent appear nowhere in the codebase, so a tool's structured output is dropped even though the extension negotiates a revision that defines it.",
      "listChanged": {
        "status": "partial",
        "notes": "The extension registers a handler and refreshes the cached list, coalescing a burst into one refresh and retrying a failed refresh three times with backoff. The CLI registers no handler, so a catalog change is invisible to it until restart.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "cline/cline",
            "date": "2026-08-25",
            "commit": "110138b5",
            "path": "apps/vscode/src/services/mcp/McpHub.ts:767-769,1009-1027"
          },
          {
            "tier": "read",
            "at": "2024-11-05",
            "source": "cline/cline",
            "date": "2026-08-25",
            "commit": "110138b5",
            "path": "sdk/packages/core/src/extensions/mcp/client.ts",
            "note": "No notification handler of any kind in either the stdio or the URL client."
          }
        ]
      },
      "result": {
        "status": "full",
        "notes": "The whole CallToolResult is JSON.stringified into one text block. No placeholder for an empty content array.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "olaservo/structured-content-research",
            "url": "https://github.com/olaservo/structured-content-research/blob/0c0395d/notes/cline-tool-result-handling.md",
            "date": "2026-11-08",
            "commit": "0c0395d",
            "path": "notes/cline-tool-result-handling.md",
            "note": "The read tier for tool result handling lives in that repo (AGENTS.md); this entry summarises its note, which read the Cline source at 94eecbb."
          }
        ],
        "content": {
          "status": "full",
          "notes": "Inside the stringified envelope, text blocks still nested as {\"type\":\"text\",\"text\":...}."
        },
        "structuredContent": {
          "status": "full",
          "notes": "Inside the stringified envelope next to content, with no duplicate check against the text."
        },
        "isError": {
          "status": "full",
          "notes": "Inside the stringified envelope."
        },
        "_meta": {
          "status": "full",
          "notes": "Inside the stringified envelope."
        },
        "media": {
          "status": "partial",
          "notes": "Image and audio blocks are stringified with their base64 intact inside the text block, so they reach the model as text, not as native media parts."
        }
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "cline/cline",
          "date": "2026-08-25",
          "commit": "110138b5",
          "path": "apps/vscode/src/services/mcp/McpHub.ts:884-900"
        },
        {
          "tier": "read",
          "at": "2024-11-05",
          "source": "cline/cline",
          "date": "2026-08-25",
          "commit": "110138b5",
          "path": "sdk/packages/core/src/extensions/mcp/client.ts:256-282"
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "cline/cline",
          "date": "2026-08-25",
          "commit": "110138b5",
          "path": "sdk/packages/core/src/extensions/mcp/name-transform.ts:1-35"
        },
        {
          "tier": "declared",
          "status": "full",
          "at": "2025-06-18",
          "source": "apify/mcp-client-capabilities",
          "date": "2026-02-02",
          "commit": "4406120",
          "note": "Records tools and tools.listChanged as full. The read agrees on tools and finds listChanged on the extension only."
        }
      ]
    },
    "resources": {
      "status": "partial",
      "notes": "The extension lists resources and resource templates and shows them in the server configuration UI. Nothing reads one: there is no resources/read call and no readResource anywhere, and the access_mcp_resource tool id survives in the tool enum with no registration and no handler. The CLI does not list them at all.",
      "listChanged": {
        "status": "full",
        "notes": "Extension only, same debounced refresh as tools.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "cline/cline",
            "date": "2026-08-25",
            "commit": "110138b5",
            "path": "apps/vscode/src/services/mcp/McpHub.ts:770-772"
          }
        ]
      },
      "subscribe": {
        "status": "unsupported",
        "notes": "No resources/subscribe call and no resources/updated handler on either surface.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "cline/cline",
            "date": "2026-08-25",
            "commit": "110138b5",
            "path": "apps/vscode/src/services/mcp/McpHub.ts:767-784"
          }
        ]
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "cline/cline",
          "date": "2026-08-25",
          "commit": "110138b5",
          "path": "apps/vscode/src/services/mcp/McpHub.ts:915-971"
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "cline/cline",
          "date": "2026-08-25",
          "commit": "110138b5",
          "path": "apps/vscode/src/shared/tools.ts:20"
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "cline/cline",
          "date": "2026-08-25",
          "commit": "110138b5",
          "path": "apps/vscode/webview-ui/src/components/mcp/configuration/tabs/installed/server-row/ServerRow.tsx:323-363"
        },
        {
          "tier": "declared",
          "status": "full",
          "at": "2025-06-18",
          "source": "apify/mcp-client-capabilities",
          "date": "2026-02-02",
          "commit": "4406120",
          "note": "Records resources as full. The read finds a list and a UI tab, and no path from either to the model or to the resource contents."
        }
      ],
      "research": [
        "cline-lists-resources-and-prompts-but-never-reads-them"
      ]
    },
    "prompts": {
      "status": "partial",
      "notes": "Same shape as resources: the extension lists prompts and renders name, title, description and arguments in a UI tab. There is no prompts/get call anywhere, so a listed prompt cannot be run. The CLI does not list them.",
      "listChanged": {
        "status": "full",
        "notes": "Extension only, same debounced refresh as tools.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "cline/cline",
            "date": "2026-08-25",
            "commit": "110138b5",
            "path": "apps/vscode/src/services/mcp/McpHub.ts:773-775"
          }
        ]
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "cline/cline",
          "date": "2026-08-25",
          "commit": "110138b5",
          "path": "apps/vscode/src/services/mcp/McpHub.ts:974-1007"
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "cline/cline",
          "date": "2026-08-25",
          "commit": "110138b5",
          "path": "apps/vscode/webview-ui/src/components/mcp/configuration/tabs/installed/server-row/ServerRow.tsx:365-386"
        }
      ],
      "research": [
        "cline-lists-resources-and-prompts-but-never-reads-them"
      ]
    },
    "completions": {
      "status": "unsupported",
      "notes": "No completion/complete call at this commit.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "cline/cline",
          "date": "2026-08-25",
          "commit": "110138b5",
          "path": "apps/vscode/src/services/mcp"
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "cline/cline",
          "date": "2026-08-25",
          "commit": "110138b5",
          "path": "sdk/packages/core/src/extensions/mcp"
        }
      ]
    },
    "sampling": {
      "status": "unsupported",
      "notes": "Both surfaces initialize with a literally empty capabilities object, and no CreateMessageRequestSchema handler exists.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "cline/cline",
          "date": "2026-08-25",
          "commit": "110138b5",
          "path": "apps/vscode/src/services/mcp/McpHub.ts:464-472"
        },
        {
          "tier": "read",
          "at": "2024-11-05",
          "source": "cline/cline",
          "date": "2026-08-25",
          "commit": "110138b5",
          "path": "sdk/packages/core/src/extensions/mcp/client.ts:209-213"
        }
      ],
      "research": [
        "cline-declares-no-client-capabilities"
      ]
    },
    "elicitation": {
      "status": "unsupported",
      "notes": "Not declared and not implemented. No ElicitRequestSchema handler anywhere in the repo.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "cline/cline",
          "date": "2026-08-25",
          "commit": "110138b5",
          "path": "apps/vscode/src/services/mcp/McpHub.ts:464-472"
        },
        {
          "tier": "read",
          "at": "2024-11-05",
          "source": "cline/cline",
          "date": "2026-08-25",
          "commit": "110138b5",
          "path": "sdk/packages/core/src/extensions/mcp/client.ts:209-213"
        }
      ],
      "research": [
        "cline-declares-no-client-capabilities"
      ]
    },
    "roots": {
      "status": "unsupported",
      "notes": "Not declared and not implemented, despite the extension knowing the workspace roots for its own file tools.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "cline/cline",
          "date": "2026-08-25",
          "commit": "110138b5",
          "path": "apps/vscode/src/services/mcp/McpHub.ts:464-472"
        },
        {
          "tier": "read",
          "at": "2024-11-05",
          "source": "cline/cline",
          "date": "2026-08-25",
          "commit": "110138b5",
          "path": "sdk/packages/core/src/extensions/mcp/client.ts:209-213"
        }
      ],
      "research": [
        "cline-declares-no-client-capabilities"
      ]
    },
    "logging": {
      "status": "partial",
      "notes": "The extension handles notifications/message and routes it to the active task, or buffers it when no task is running. It never calls logging/setLevel, so the level is whatever the server defaults to. Any other notification is written to the extension log. The CLI handles no notifications.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "cline/cline",
          "date": "2026-08-25",
          "commit": "110138b5",
          "path": "apps/vscode/src/services/mcp/McpHub.ts:722-784"
        },
        {
          "tier": "read",
          "at": "2024-11-05",
          "source": "cline/cline",
          "date": "2026-08-25",
          "commit": "110138b5",
          "path": "sdk/packages/core/src/extensions/mcp/client.ts:366-394"
        }
      ]
    },
    "instructions": {
      "status": "unsupported",
      "notes": "The initialize result's instructions field is never read on either surface.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "cline/cline",
          "date": "2026-08-25",
          "commit": "110138b5",
          "path": "apps/vscode/src/services/mcp/McpHub.ts:659-790"
        },
        {
          "tier": "read",
          "at": "2024-11-05",
          "source": "cline/cline",
          "date": "2026-08-25",
          "commit": "110138b5",
          "path": "sdk/packages/core/src/extensions/mcp/client.ts:199-241"
        }
      ]
    },
    "icons": {
      "status": "unsupported",
      "notes": "No icon handling in either MCP implementation.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "cline/cline",
          "date": "2026-08-25",
          "commit": "110138b5",
          "path": "apps/vscode/src/services/mcp"
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "cline/cline",
          "date": "2026-08-25",
          "commit": "110138b5",
          "path": "sdk/packages/core/src/extensions/mcp"
        }
      ]
    },
    "tasks": {
      "status": "unsupported",
      "notes": "Not declared and not implemented, though SDK 1.30.0 carries an experimental tasks client.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "cline/cline",
          "date": "2026-08-25",
          "commit": "110138b5",
          "path": "apps/vscode/src/services/mcp/McpHub.ts:464-472"
        }
      ]
    },
    "bonusFeatures": {
      "mcpRemoteProxyRewrite": {
        "status": "full",
        "notes": "The CLI recognizes a stdio config of exactly `npx [-y] mcp-remote <url>` with no env and no extra arguments, and rewrites it to a native Streamable HTTP transport. Cline's own OAuth then handles the server, instead of a child process opening a browser as a side effect of enabling the server. The extension does not do this rewrite, so the same settings file means different things to the two surfaces.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "cline/cline",
            "date": "2026-08-25",
            "commit": "110138b5",
            "path": "sdk/packages/core/src/extensions/mcp/remote-proxy.ts:19-53"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "cline/cline",
            "date": "2026-08-25",
            "commit": "110138b5",
            "path": "sdk/packages/core/src/extensions/mcp/config-loader.ts:756"
          }
        ],
        "research": [
          "cline-rewrites-mcp-remote-proxy-configs"
        ]
      },
      "sharedSettingsFile": {
        "status": "full",
        "notes": "The extension, the CLI and the JetBrains plugin read and write one settings file at ~/.cline/data/settings/cline_mcp_settings.json, under a cross-process lock with atomic replace. The extension watches it and fingerprints the connection-relevant content, so OAuth churn from another process does not trigger a reconnect loop but a token written elsewhere does.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "cline/cline",
            "date": "2026-08-25",
            "commit": "110138b5",
            "path": "apps/vscode/src/services/mcp/McpOAuthManager.ts:1-18"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "cline/cline",
            "date": "2026-08-25",
            "commit": "110138b5",
            "path": "apps/vscode/src/services/mcp/McpHub.ts:87-108"
          }
        ]
      }
    },
    "research": [
      "cline-hand-rolls-stdio-in-its-cli",
      "cline-lists-resources-and-prompts-but-never-reads-them",
      "cline-declares-no-client-capabilities",
      "cline-defaults-a-url-server-to-sse",
      "cline-rewrites-mcp-remote-proxy-configs"
    ],
    "metadata": {
      "vendor": "Cline Bot Inc.",
      "openSource": true,
      "license": "Apache-2.0",
      "sourceUrl": "https://github.com/cline/cline",
      "lastVerified": "2026-08-25",
      "source": {
        "repo": "https://github.com/cline/cline.git",
        "ref": "main",
        "checkedCommit": "110138b54056e4e6b13c9d767aec81e9a94e4165",
        "commitDate": "2026-08-25T22:19:29Z",
        "checkedAt": "2026-08-25",
        "paths": [
          "apps/vscode/src/services/mcp/McpHub.ts",
          "apps/vscode/src/services/mcp/McpOAuthManager.ts",
          "apps/vscode/src/services/mcp/schemas.ts",
          "apps/vscode/src/shared/mcp.ts",
          "apps/vscode/src/shared/tools.ts",
          "apps/vscode/src/sdk/vscode-runtime-builder.ts",
          "apps/vscode/webview-ui/src/components/mcp/configuration/tabs/installed/server-row/ServerRow.tsx",
          "sdk/packages/core/src/extensions/mcp/client.ts",
          "sdk/packages/core/src/extensions/mcp/oauth.ts",
          "sdk/packages/core/src/extensions/mcp/config-loader.ts",
          "sdk/packages/core/src/extensions/mcp/remote-proxy.ts",
          "sdk/packages/core/src/extensions/mcp/name-transform.ts",
          "sdk/packages/core/src/extensions/mcp/tools.ts",
          "sdk/packages/core/src/runtime/orchestration/runtime-builder.ts",
          "apps/vscode/package.json",
          "sdk/packages/core/package.json",
          "package.json",
          "bun.lock"
        ]
      },
      "sdk": {
        "name": "@modelcontextprotocol/sdk",
        "language": "typescript",
        "official": true,
        "declared": "^1.29.0",
        "resolved": "1.30.0",
        "patched": false,
        "pinsProtocolVersion": "2025-11-25",
        "notes": "Two workspaces declare it and disagree: sdk/packages/core asks for ^1.29.0 and apps/vscode for ^1.25.1. bun.lock hoists one copy, so both run 1.30.0. patchedDependencies covers @opentui-ui/dialog and ollama-ai-provider-v2 and not the SDK, which is the answer to the question opencode raised: Cline is on the same SDK and does not patch it. The protocol version is the SDK's on every path except one - 1.30.0 pins LATEST_PROTOCOL_VERSION at 2025-11-25 - but the CLI's stdio client does not use the SDK at all and sends 2024-11-05 of its own accord.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "cline/cline",
            "date": "2026-08-25",
            "commit": "110138b5",
            "path": "apps/vscode/package.json:471"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "cline/cline",
            "date": "2026-08-25",
            "commit": "110138b5",
            "path": "sdk/packages/core/package.json:55"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "cline/cline",
            "date": "2026-08-25",
            "commit": "110138b5",
            "path": "bun.lock:375,653,1660"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "cline/cline",
            "date": "2026-08-25",
            "commit": "110138b5",
            "path": "package.json:92-95",
            "note": "patchedDependencies lists two packages, neither of them the MCP SDK."
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "modelcontextprotocol/typescript-sdk",
            "date": "2026-08-25",
            "commit": "2d889f2b",
            "path": "src/types.ts:4-6",
            "note": "1.30.0 was published 2026-07-27 from commit 2d889f2b and is not tagged in the repository. LATEST_PROTOCOL_VERSION = '2025-11-25'; SUPPORTED_PROTOCOL_VERSIONS lists 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05, 2024-10-07."
          }
        ],
        "research": [
          "cline-hand-rolls-stdio-in-its-cli"
        ]
      }
    }
  },
  "fast-agent": {
    "title": "fast-agent",
    "clientInfoNames": [
      "fast-agent-mcp"
    ],
    "url": "https://fast-agent.ai/",
    "description": "Python framework and CLI for building and running agents, from the maintainer of the SEP-2640 skills proposal and the HF client telemetry feed. The first client read here that leads with the 2026-07-28 stateless era: it probes server/discover before falling back to the initialize handshake, and behaves differently on each.",
    "category": "agent-framework",
    "platforms": [
      "windows",
      "macos",
      "linux"
    ],
    "protocolVersions": [
      "2024-11-05",
      "2025-03-26",
      "2025-06-18",
      "2025-11-25",
      "2026-07-28"
    ],
    "preferredProtocolVersion": "2026-07-28",
    "transports": {
      "stdio": {
        "status": "full",
        "notes": "The SDK's stdio_client, wrapped in a tracking layer that records every frame on the transport timeline. Child environment is built from the SDK's default environment plus the server entry's env and cwd. Server stderr is routed line by line into fast-agent's logger.",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/client_gateway.py:287-305"
          },
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/stdio_tracking_simple.py:8-13"
          }
        ]
      },
      "sse": {
        "status": "full",
        "notes": "Reached only by setting transport: sse explicitly. A url with no transport resolves to http, not sse, so the deprecated transport is never the accidental default. Rejected in config validation when combined with protocol_mode: modern, since discover has no SSE path.",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/client_gateway.py:341-347"
          },
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/config.py:720-745",
            "note": "validate_transport_inference: a url with no explicit transport becomes http."
          },
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/config.py:776-777"
          }
        ],
        "research": [
          "fast-agent-leads-with-the-modern-discover-probe"
        ]
      },
      "streamableHttp": {
        "status": "full",
        "notes": "The default for any url server. fast-agent supplies its own httpx client so it can hang request and response hooks off it, which is where the transport timeline, the 401 escalation signal and the discover-response accounting come from. Redirects are followed. Timeouts fall back to the SDK defaults unless configured.",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/client_gateway.py:349-359"
          },
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/client_gateway.py:397-488"
          }
        ]
      }
    },
    "authentication": {
      "oauth": {
        "status": "full",
        "notes": "Escalated rather than assumed: a remote server is tried unauthenticated first, and OAuth is only enabled on a second attempt after a 401. auth.oauth: true forces it, auth.oauth: false and a configured Authorization header both suppress it. Tokens persist in the OS keyring under service fast-agent-mcp, with an in-memory fallback and a printed warning when no keyring backend is available. The callback is a local loopback server, with a paste fallback.",
        "version": "2.1",
        "pkce": true,
        "dynamicRegistration": true,
        "clientIdMetadataDocument": true,
        "resourceIndicators": true,
        "grantTypes": [
          "authorization_code",
          "refresh_token"
        ],
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/client_gateway.py:93-111,183-249"
          },
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/oauth_client.py:643-671",
            "note": "CIMD is preferred over DCR when a client metadata URL is set and the authorization server accepts one."
          },
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/oauth_client.py:875-915,1178-1202",
            "note": "Keyring-backed token storage and the no-backend warning."
          },
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "modelcontextprotocol/python-sdk",
            "date": "2026-08-25",
            "path": "mcp/client/auth/oauth2.py:116-124,391-405,459,511",
            "note": "mcp 2.0.0. PKCE S256 and the RFC 8707 resource indicator on authorize, token and refresh are the SDK's, not fast-agent's."
          }
        ]
      },
      "header": {
        "status": "full",
        "notes": "A headers map on a remote server is passed through on both HTTP transports. An Authorization or X-HF-Authorization header suppresses the OAuth escalation entirely. auth.forward: huggingface injects the local HF token as a header for Hugging Face endpoints and disables OAuth for that server.",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/client_gateway.py:491-541"
          },
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/hf_auth.py"
          }
        ]
      }
    },
    "tools": {
      "status": "full",
      "notes": "One page of tools/list, no cursor, on both eras — the SDK accepts a cursor and the aggregator never passes one. Tools are flattened into <server>__<tool>, truncated to 64 characters. When a server does not declare a tools capability fast-agent calls tools/list anyway and treats a method-not-found as the answer, so an undeclared-but-present tool list is still found.",
      "listChanged": {
        "status": "full",
        "notes": "Modern: requested through the subscriptions/listen filter when the server advertises it. Legacy: the ToolListChangedNotification handler refreshes that server's tools. The only notification wired up on the handshake path.",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/mcp_connection_manager.py:525-556"
          },
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/client_callback_runtime.py:252-271"
          },
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/mcp_aggregator.py:3508-3524"
          }
        ],
        "research": [
          "fast-agent-subscribes-only-on-the-modern-path"
        ]
      },
      "result": {
        "status": "full",
        "notes": "structuredContent replaces content. The ACP channel receives content blocks only; tools with app-only visibility are hidden from the model.",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "olaservo/structured-content-research",
            "url": "https://github.com/olaservo/structured-content-research/blob/0c0395d/notes/fast-agent-tool-result-handling.md",
            "date": "2026-11-08",
            "commit": "0c0395d",
            "path": "notes/fast-agent-tool-result-handling.md",
            "note": "The read tier for tool result handling lives in that repo (AGENTS.md); this entry summarises its note, which read the fast-agent source at d89956d."
          }
        ],
        "structuredContent": {
          "status": "full",
          "notes": "Compact, key-sorted JSON of structuredContent replaces every text block whenever the field is present, {} and [] included."
        },
        "content": {
          "status": "partial",
          "notes": "Text blocks reach the model only when structuredContent is absent. Non-text blocks always stay."
        },
        "media": {
          "status": "full",
          "notes": "Image, resource and resource-link blocks stay next to the JSON; audio is dropped or rendered as an unsupported-content note depending on the provider converter."
        }
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "evalstate/fast-agent",
          "date": "2026-08-25",
          "commit": "1b58e686",
          "path": "src/fast_agent/mcp/mcp_aggregator.py:839-866",
          "note": "The optimistic tools/list call when the server declared no tools capability."
        },
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "evalstate/fast-agent",
          "date": "2026-08-25",
          "commit": "1b58e686",
          "path": "src/fast_agent/mcp/common.py:6-26",
          "note": "SEP = \"__\", namespaced name truncated to 64."
        }
      ]
    },
    "resources": {
      "status": "full",
      "notes": "resources/list, resources/templates/list and resources/read are all called. A resource reaches the model as an @server:uri mention a person typed, expanded into EmbeddedResource blocks before the turn — there is no tool the model can call to read one. Anything a remote server returns carrying a file:// URI is rewritten before it reaches the conversation.",
      "listChanged": {
        "status": "full",
        "notes": "Modern only, through the subscriptions/listen filter. On the handshake path the notification is received and dropped.",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/mcp_connection_manager.py:535-536"
          }
        ],
        "research": [
          "fast-agent-subscribes-only-on-the-modern-path"
        ]
      },
      "subscribe": {
        "status": "full",
        "notes": "Expressed as resource URIs in the subscriptions/listen filter, gated on the server advertising resources.subscribe. resources/subscribe is never called, so there is no subscription at all on a handshake-era connection. Changing the watched set closes and reopens the stream.",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/mcp_connection_manager.py:537-542,587-602"
          },
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "modelcontextprotocol/python-sdk",
            "date": "2026-08-25",
            "path": "mcp/client/subscriptions.py:1,201-233",
            "note": "mcp 2.0.0. subscriptions/listen is SEP-2575, 2026-07-28 only."
          }
        ],
        "research": [
          "fast-agent-subscribes-only-on-the-modern-path"
        ]
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "evalstate/fast-agent",
          "date": "2026-08-25",
          "commit": "1b58e686",
          "path": "src/fast_agent/mcp/client_connection.py:252-263,395-416"
        },
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "evalstate/fast-agent",
          "date": "2026-08-25",
          "commit": "1b58e686",
          "path": "src/fast_agent/ui/prompt/resource_mentions.py:250-278"
        }
      ],
      "research": [
        "fast-agent-resources-need-a-user-to-ask"
      ]
    },
    "prompts": {
      "status": "full",
      "notes": "prompts/list and prompts/get are both called, with a per-server prompt cache and a search across servers when a prompt is named without one. A fetched prompt is applied as persistent conversation messages. Triggered by /prompt or the agent API, never by the model.",
      "listChanged": {
        "status": "full",
        "notes": "Modern only, same as resources. Dropped on the handshake path.",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/mcp_connection_manager.py:534"
          }
        ],
        "research": [
          "fast-agent-subscribes-only-on-the-modern-path"
        ]
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "evalstate/fast-agent",
          "date": "2026-08-25",
          "commit": "1b58e686",
          "path": "src/fast_agent/mcp/mcp_aggregator.py:3132-3193,3414-3448"
        },
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "evalstate/fast-agent",
          "date": "2026-08-25",
          "commit": "1b58e686",
          "path": "src/fast_agent/agents/mcp_agent.py:1810-1811"
        }
      ],
      "research": [
        "fast-agent-resources-need-a-user-to-ask"
      ]
    },
    "completions": {
      "status": "partial",
      "notes": "completion/complete is called for one thing: filling a resource template argument in the interactive completer. Prompt-argument completion is not wired up, and a failure returns an empty completion rather than surfacing.",
      "evidence": [
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "evalstate/fast-agent",
          "date": "2026-08-25",
          "commit": "1b58e686",
          "path": "src/fast_agent/mcp/mcp_aggregator.py:4007-4035"
        },
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "evalstate/fast-agent",
          "date": "2026-08-25",
          "commit": "1b58e686",
          "path": "src/fast_agent/mcp/client_connection.py:278-284"
        }
      ]
    },
    "sampling": {
      "status": "full",
      "notes": "Declared and served by default: auto_sampling is on, so a server gets a sampling capability unless the config turns it off. The model is the server entry's sampling.model, else the agent's model, else the global default; with none of those the request fails with an internal error rather than falling back. A failure is returned as ErrorData, so a sampling problem does not break the connection.",
      "tools": {
        "status": "full",
        "notes": "Tools in the request are passed to the LLM, and a tool call comes back as CreateMessageResultWithTools with stopReason \"toolUse\". The server executes and follows up.",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/sampling.py:168-188,252-266"
          }
        ]
      },
      "context": {
        "status": "unsupported",
        "notes": "includeContext is not read anywhere; the sampling converter ignores it.",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/llm/sampling_converter.py"
          }
        ]
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "evalstate/fast-agent",
          "date": "2026-08-25",
          "commit": "1b58e686",
          "path": "src/fast_agent/mcp/client_callback_runtime.py:139-164"
        },
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "evalstate/fast-agent",
          "date": "2026-08-25",
          "commit": "1b58e686",
          "path": "src/fast_agent/config.py:248-252",
          "note": "auto_sampling defaults to true."
        },
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "evalstate/fast-agent",
          "date": "2026-08-25",
          "commit": "1b58e686",
          "path": "src/fast_agent/mcp/sampling.py:191-274"
        }
      ],
      "research": [
        "fast-agent-declares-capabilities-per-server"
      ]
    },
    "elicitation": {
      "status": "full",
      "notes": "Declared and served by default. Three modes — forms (the default), auto-cancel, and none — resolvable globally, per server, or per agent through a decorator. The forms handler renders a schema-driven prompt in the terminal.",
      "form": {
        "status": "full",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/elicitation_handlers.py:296-330"
          }
        ]
      },
      "url": {
        "status": "full",
        "notes": "ElicitRequestURLParams is handled as a distinct branch: the URL is shown inline and queued for attachment to the originating request's result, so a URL elicitation raised mid-tool-call is reported against that call. A -32042 URL_ELICITATION_REQUIRED error is decorated with the same display payload.",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/elicitation_handlers.py:191-215,312-313"
          },
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/client_connection.py:58,320-376"
          }
        ]
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "evalstate/fast-agent",
          "date": "2026-08-25",
          "commit": "1b58e686",
          "path": "src/fast_agent/mcp/elicitation_factory.py:97-146",
          "note": "The global default mode is forms, so a default install declares elicitation."
        },
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "modelcontextprotocol/python-sdk",
          "date": "2026-08-25",
          "path": "mcp/client/session.py:594-602",
          "note": "mcp 2.0.0 declares both the form and url sub-capabilities whenever any elicitation callback is passed; a client cannot declare one without the other."
        }
      ],
      "research": [
        "fast-agent-declares-capabilities-per-server"
      ]
    },
    "roots": {
      "status": "partial",
      "notes": "Declared only for a server whose config entry lists roots, and served correctly when it is: roots/list returns the configured file:// URIs, with an optional alias so the URI presented to the server differs from the local path. The roots are read once from config and never change.",
      "listChanged": {
        "status": "unsupported",
        "notes": "The SDK declares roots.listChanged: true whenever a roots callback exists, with no way to opt out. Nothing in fast-agent sends notifications/roots/list_changed. The declaration is inaccurate and not fast-agent's to fix.",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/client_callback_runtime.py:123-137"
          },
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "modelcontextprotocol/python-sdk",
            "date": "2026-08-25",
            "path": "mcp/client/session.py:603-608",
            "note": "mcp 2.0.0. The upstream TODO beside it asks the same question."
          }
        ],
        "research": [
          "fast-agent-never-sends-roots-list-changed"
        ]
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "evalstate/fast-agent",
          "date": "2026-08-25",
          "commit": "1b58e686",
          "path": "src/fast_agent/mcp/client_callback_runtime.py:123-137"
        },
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "evalstate/fast-agent",
          "date": "2026-08-25",
          "commit": "1b58e686",
          "path": "src/fast_agent/config.py:571-580",
          "note": "A root URI must start with file://, enforced in config."
        }
      ],
      "research": [
        "fast-agent-never-sends-roots-list-changed",
        "fast-agent-declares-capabilities-per-server"
      ]
    },
    "logging": {
      "status": "unsupported",
      "notes": "logging/setLevel is never called and no handler renders a notifications/message. On the handshake path a log notification reaches the generic server-notification callback, which is only ever assigned in a unit test.",
      "evidence": [
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "evalstate/fast-agent",
          "date": "2026-08-25",
          "commit": "1b58e686",
          "path": "src/fast_agent/mcp/client_callback_runtime.py:252-284"
        },
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "evalstate/fast-agent",
          "date": "2026-08-25",
          "commit": "1b58e686",
          "path": "src/fast_agent/mcp/mcp_aggregator.py:503",
          "note": "server_notification_callback is set to None here and assigned nowhere else in src/."
        }
      ],
      "research": [
        "fast-agent-subscribes-only-on-the-modern-path"
      ]
    },
    "instructions": {
      "status": "full",
      "notes": "The server's instructions string is read and injected into the system prompt through a {{serverInstructions}} resolver, re-resolved when servers are attached or detached. Suppressible per server with include_instructions: false, and the UI reports both whether a server sent instructions and whether they are enabled.",
      "evidence": [
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "evalstate/fast-agent",
          "date": "2026-08-25",
          "commit": "1b58e686",
          "path": "src/fast_agent/mcp/mcp_aggregator.py:2019-2068"
        },
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "evalstate/fast-agent",
          "date": "2026-08-25",
          "commit": "1b58e686",
          "path": "src/fast_agent/core/instruction_refresh.py:238-246"
        },
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "evalstate/fast-agent",
          "date": "2026-08-25",
          "commit": "1b58e686",
          "path": "src/fast_agent/config.py:662-663"
        }
      ]
    },
    "icons": {
      "status": "unsupported",
      "notes": "No icon handling anywhere in the MCP client.",
      "evidence": [
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "evalstate/fast-agent",
          "date": "2026-08-25",
          "commit": "1b58e686",
          "path": "src/fast_agent/mcp"
        }
      ]
    },
    "tasks": {
      "status": "unsupported",
      "notes": "No tasks/* call of any kind. The server's tasks capability is readable through server_supports_feature, which nothing calls with \"tasks\" — the enum member is the only trace.",
      "evidence": [
        {
          "tier": "read",
          "at": "2026-07-28",
          "source": "evalstate/fast-agent",
          "date": "2026-08-25",
          "commit": "1b58e686",
          "path": "src/fast_agent/mcp/mcp_aggregator.py:1875-1911"
        }
      ]
    },
    "extensions": {
      "io.modelcontextprotocol/skills": {
        "status": "full",
        "notes": "SEP-2640 draft d7490ecd, implemented against locally-declared wire models because the Python SDK carries none. skills/list, skills/get, and resources/directory/read when the server's extension settings say directoryRead: true. Skill resources are verified against SHA-256 digests before install, under six size and count limits fast-agent chose itself.",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/skills_extension.py:1-91"
          },
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/skills/mcp_registry.py:67-171"
          },
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/client_connection.py:286-303"
          }
        ],
        "research": [
          "fast-agent-ships-skills-over-mcp-ahead-of-the-sdk"
        ]
      }
    },
    "bonusFeatures": {
      "modelInitiatedResourceRead": {
        "status": "unsupported",
        "notes": "By design rather than omission. Resources are reachable to a person through @server:uri mentions with URI completion, and to application code through the agent API. The model gets no mechanism.",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/ui/prompt/resource_mentions.py:250-278"
          }
        ],
        "research": [
          "fast-agent-resources-need-a-user-to-ask"
        ]
      },
      "protocolEraForcing": {
        "status": "full",
        "notes": "protocol_mode: auto | modern | legacy, global or per server, also settable per connection from the CLI. modern subclasses the SDK client so a failed discover unwinds the transport instead of silently falling back. The negotiated era and how it was reached are shown in /mcp.",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/config.py:241,602-603"
          },
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/client_connection.py:62-64,67-92"
          }
        ],
        "research": [
          "fast-agent-leads-with-the-modern-discover-probe"
        ]
      },
      "transportDiagnostics": {
        "status": "full",
        "notes": "Every frame is attributed to a channel — stdio, GET, POST (JSON), POST (SSE), listen, resumption — and rendered as a bucketed timeline in /mcp. The channel for a POST is decided from the response content type and the request method, so a subscriptions/listen stream is separated from ordinary SSE traffic. Discovery responses are accounted separately so a probe rejection is not counted as a transport error.",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/transport_tracking.py"
          },
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/client_gateway.py:378-388,449-480"
          }
        ]
      },
      "remoteFileUriSanitization": {
        "status": "full",
        "notes": "A tool result, prompt result or resource read from a remote server that carries a file:// URI is rewritten before it reaches the conversation: a ResourceLink becomes a text block saying the attachment was blocked, and an embedded resource keeps its content under a sanitized URI.",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/mcp/client_connection.py:378-416"
          }
        ]
      },
      "providerManagedMcp": {
        "status": "full",
        "notes": "A server entry can set management: provider, which hands the server URL or connector id to the model provider (OpenAI Responses) instead of connecting to it. fast-agent then speaks no MCP to that server at all, and the settings that only make sense for a local connection are rejected in validation.",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/config.py:596-597,747-771"
          }
        ]
      }
    },
    "research": [
      "fast-agent-leads-with-the-modern-discover-probe",
      "fast-agent-declares-capabilities-per-server",
      "fast-agent-never-sends-roots-list-changed",
      "fast-agent-subscribes-only-on-the-modern-path",
      "fast-agent-ships-skills-over-mcp-ahead-of-the-sdk",
      "fast-agent-resources-need-a-user-to-ask"
    ],
    "byProtocolVersion": {
      "2025-11-25": {
        "resources": {
          "status": "full",
          "notes": "Same read path. The watching stops working.",
          "listChanged": {
            "status": "unsupported",
            "notes": "The notification arrives and is dropped: the handler forwards everything except progress and tools/list_changed to a callback that is never assigned outside a test.",
            "evidence": [
              {
                "tier": "read",
                "at": "2025-11-25",
                "source": "evalstate/fast-agent",
                "date": "2026-08-25",
                "commit": "1b58e686",
                "path": "src/fast_agent/mcp/client_callback_runtime.py:252-284"
              }
            ]
          },
          "subscribe": {
            "status": "unsupported",
            "notes": "resources/subscribe is never called. The subscription loop is gated on a DiscoverResult being present.",
            "evidence": [
              {
                "tier": "read",
                "at": "2025-11-25",
                "source": "evalstate/fast-agent",
                "date": "2026-08-25",
                "commit": "1b58e686",
                "path": "src/fast_agent/mcp/mcp_connection_manager.py:525-532"
              }
            ]
          },
          "research": [
            "fast-agent-subscribes-only-on-the-modern-path"
          ]
        },
        "prompts": {
          "status": "full",
          "listChanged": {
            "status": "unsupported",
            "notes": "Dropped with the rest.",
            "evidence": [
              {
                "tier": "read",
                "at": "2025-11-25",
                "source": "evalstate/fast-agent",
                "date": "2026-08-25",
                "commit": "1b58e686",
                "path": "src/fast_agent/mcp/client_callback_runtime.py:252-284"
              }
            ]
          }
        },
        "bonusFeatures": {
          "healthPing": {
            "status": "full",
            "notes": "A ping loop runs on the handshake path only, every 30 seconds by default, treating the connection as failed after three consecutive misses. ping was removed in 2026-07-28 and the SDK deprecates the method outside legacy mode, so a modern connection has no health signal of its own.",
            "evidence": [
              {
                "tier": "read",
                "at": "2025-11-25",
                "source": "evalstate/fast-agent",
                "date": "2026-08-25",
                "commit": "1b58e686",
                "path": "src/fast_agent/mcp/mcp_connection_manager.py:726-728"
              },
              {
                "tier": "read",
                "at": "2025-11-25",
                "source": "evalstate/fast-agent",
                "date": "2026-08-25",
                "commit": "1b58e686",
                "path": "src/fast_agent/config.py:614-618"
              },
              {
                "tier": "read",
                "at": "2026-07-28",
                "source": "modelcontextprotocol/python-sdk",
                "date": "2026-08-25",
                "path": "mcp/client/client.py:522",
                "note": "mcp 2.0.0 deprecates ping outside mode=legacy."
              }
            ]
          },
          "sessionRecovery": {
            "status": "full",
            "notes": "A -32600 \"Session terminated\" on a handshake-era connection is turned into a typed error and, with reconnect_on_disconnect left on, the operation is replayed against a fresh connection. The check explicitly excludes modern connections, which carry no session to lose.",
            "evidence": [
              {
                "tier": "read",
                "at": "2025-11-25",
                "source": "evalstate/fast-agent",
                "date": "2026-08-25",
                "commit": "1b58e686",
                "path": "src/fast_agent/mcp/client_connection.py:305-318"
              },
              {
                "tier": "read",
                "at": "2025-11-25",
                "source": "evalstate/fast-agent",
                "date": "2026-08-25",
                "commit": "1b58e686",
                "path": "src/fast_agent/config.py:665-671"
              }
            ]
          }
        }
      }
    },
    "metadata": {
      "vendor": "Shaun Smith (llmindset)",
      "openSource": true,
      "license": "Apache-2.0",
      "sourceUrl": "https://github.com/evalstate/fast-agent",
      "lastVerified": "2026-08-25",
      "source": {
        "repo": "https://github.com/evalstate/fast-agent.git",
        "ref": "main",
        "checkedCommit": "1b58e686482627e4fc841b40ee69c34056fec55d",
        "commitDate": "2026-08-23T21:04:17Z",
        "checkedAt": "2026-08-25",
        "paths": [
          "src/fast_agent/mcp/client_connection.py",
          "src/fast_agent/mcp/client_callback_runtime.py",
          "src/fast_agent/mcp/client_gateway.py",
          "src/fast_agent/mcp/mcp_connection_manager.py",
          "src/fast_agent/mcp/mcp_aggregator.py",
          "src/fast_agent/mcp/oauth_client.py",
          "src/fast_agent/mcp/sampling.py",
          "src/fast_agent/mcp/elicitation_factory.py",
          "src/fast_agent/mcp/elicitation_handlers.py",
          "src/fast_agent/mcp/skills_extension.py",
          "src/fast_agent/mcp/common.py",
          "src/fast_agent/skills/mcp_registry.py",
          "src/fast_agent/ui/prompt/resource_mentions.py",
          "src/fast_agent/agents/mcp_agent.py",
          "src/fast_agent/core/instruction_refresh.py",
          "src/fast_agent/config.py",
          "src/fast_agent/utils/transports.py",
          "pyproject.toml",
          "uv.lock"
        ]
      },
      "sdk": {
        "name": "mcp",
        "language": "python",
        "official": true,
        "declared": "==2.0.0",
        "resolved": "2.0.0",
        "patched": false,
        "notes": "The first Python-SDK read in the registry, and the first client on an SDK that speaks 2026-07-28. Both mcp and its split-out mcp-types are pinned to exactly 2.0.0 in pyproject.toml and resolve there in uv.lock; there is no [tool.uv] override and no vendored fork. src/fast_agent/patch/ is a Python port of codex apply_patch, not an SDK patch. The version range is entirely the SDK's — fast-agent names no revision of its own and picks an era instead, so pinsProtocolVersion would misstate what is happening: the SDK pins both ends of the range, and fast-agent chooses which end to try first.",
        "evidence": [
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "pyproject.toml:18-20"
          },
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "uv.lock:1918-1920,1943-1945"
          },
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "modelcontextprotocol/python-sdk",
            "date": "2026-08-25",
            "path": "mcp_types/version.py",
            "note": "mcp-types 2.0.0. KNOWN_PROTOCOL_VERSIONS spans 2024-11-05 to 2026-07-28; LATEST_HANDSHAKE_VERSION is 2025-11-25 and LATEST_MODERN_VERSION is 2026-07-28. Read from the PyPI wheel, which the project does not publish as a tagged source tree."
          },
          {
            "tier": "read",
            "at": "2026-07-28",
            "source": "evalstate/fast-agent",
            "date": "2026-08-25",
            "commit": "1b58e686",
            "path": "src/fast_agent/patch/engine.py:1-3",
            "note": "The patch package is an apply_patch port, not a dependency patch."
          }
        ],
        "research": [
          "fast-agent-leads-with-the-modern-discover-probe"
        ]
      }
    }
  },
  "openclaw": {
    "title": "OpenClaw",
    "clientInfoNames": [
      "openclaw-bundle-mcp",
      "openclaw-node-host"
    ],
    "url": "https://github.com/openclaw/openclaw",
    "description": "Multi-channel AI gateway that runs agents across chat surfaces and remote nodes. Two MCP client surfaces: the per-session agent bundle and the headless node host.",
    "category": "agent-framework",
    "platforms": [
      "windows",
      "macos",
      "linux"
    ],
    "protocolVersions": [
      "2024-11-05",
      "2025-03-26",
      "2025-06-18",
      "2025-11-25"
    ],
    "preferredProtocolVersion": "2025-11-25",
    "transports": {
      "stdio": {
        "status": "full",
        "notes": "SDK StdioClientTransport subclassed as OpenClawStdioClientTransport. Server stderr is attached to the debug log per line rather than discarded.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "openclaw/openclaw",
            "date": "2026-08-26",
            "commit": "a2d54319",
            "path": "src/agents/mcp-transport.ts:36-62"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "openclaw/openclaw",
            "date": "2026-08-26",
            "commit": "a2d54319",
            "path": "src/agents/mcp-transport-config.ts:240-256"
          }
        ]
      },
      "sse": {
        "status": "full",
        "notes": "The fallback for any non-stdio server, including one configured by URL with no transport named. See openclaw-defaults-a-url-server-to-sse.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "openclaw/openclaw",
            "date": "2026-08-26",
            "commit": "a2d54319",
            "path": "src/agents/mcp-transport-config.ts:283-286"
          }
        ],
        "research": [
          "openclaw-defaults-a-url-server-to-sse"
        ]
      },
      "streamableHttp": {
        "status": "full",
        "notes": "Built only when the config names it explicitly. Sends the mcp-protocol-version header from the transport's negotiated value. Recovers from an expired session on a 404 without replaying the failed call.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "openclaw/openclaw",
            "date": "2026-08-26",
            "commit": "a2d54319",
            "path": "src/agents/mcp-transport-config.ts:271-282"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "openclaw/openclaw",
            "date": "2026-08-26",
            "commit": "a2d54319",
            "path": "src/agents/mcp-http-transport.ts:128-129,186-187"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "openclaw/openclaw",
            "date": "2026-08-26",
            "commit": "a2d54319",
            "path": "src/agents/mcp-client-lifecycle.ts:19-30"
          }
        ],
        "research": [
          "openclaw-recovers-expired-http-sessions-without-patching-the-sdk"
        ]
      }
    },
    "authentication": {
      "oauth": {
        "status": "full",
        "notes": "Full SDK OAuth provider with a persisted per-identity store. Both registration paths are available: Dynamic Client Registration through saveClientInformation, and a Client ID Metadata Document through a per-server oauth.clientMetadataUrl. Credentials can be invalidated by scope (all, client, tokens, verifier, discovery).",
        "clientIdMetadataDocument": true,
        "dynamicRegistration": true,
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "openclaw/openclaw",
            "date": "2026-08-26",
            "commit": "a2d54319",
            "path": "src/agents/mcp-oauth-provider.ts:42-116"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "openclaw/openclaw",
            "date": "2026-08-26",
            "commit": "a2d54319",
            "path": "src/agents/mcp-oauth-provider.ts:103",
            "note": "clientMetadataUrl is plumbed to the SDK provider."
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "openclaw/openclaw",
            "date": "2026-08-26",
            "commit": "a2d54319",
            "path": "src/config/types.mcp.ts:55",
            "note": "Per-server oauth.clientMetadataUrl config field."
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "openclaw/openclaw",
            "date": "2026-08-26",
            "commit": "a2d54319",
            "path": "src/agents/mcp-oauth-provider.ts:171-186"
          }
        ]
      }
    },
    "tools": {
      "status": "full",
      "notes": "Every tool on every enabled server is materialized as a first-class agent tool with its full JSON schema, prefixed per server with collision-safe renaming. Descriptions are passed through a prompt-injection scrubber first. Two compaction surfaces can hide them behind a search interface instead.",
      "listChanged": {
        "status": "full",
        "notes": "Subscribed on both surfaces with autoRefresh false and no debounce: the notification invalidates the catalog and the next turn rebuilds it, rather than refetching immediately.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "openclaw/openclaw",
            "date": "2026-08-26",
            "commit": "a2d54319",
            "path": "src/agents/agent-bundle-mcp-runtime.ts:686-701"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "openclaw/openclaw",
            "date": "2026-08-26",
            "commit": "a2d54319",
            "path": "src/node-host/mcp.ts:279-286"
          }
        ]
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "openclaw/openclaw",
          "date": "2026-08-26",
          "commit": "a2d54319",
          "path": "src/agents/agent-bundle-mcp-materialize.ts:337-403"
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "openclaw/openclaw",
          "date": "2026-08-26",
          "commit": "a2d54319",
          "path": "src/agents/agent-bundle-mcp-runtime.ts:831",
          "note": "Descriptions pass through sanitizeMcpMetadataText."
        }
      ],
      "research": [
        "openclaw-scrubs-tool-descriptions-with-three-regexes"
      ]
    },
    "resources": {
      "status": "full",
      "notes": "Reachable by the model through generated per-server resources_list and resources_read tools, added only when the server declared resources and the operator's tool filter allows them. Names match neither Codex's nor opencode's convention.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "openclaw/openclaw",
          "date": "2026-08-26",
          "commit": "a2d54319",
          "path": "src/agents/agent-bundle-mcp-materialize.ts:337-374"
        }
      ],
      "research": [
        "openclaw-names-its-resource-tools-a-fourth-way"
      ]
    },
    "prompts": {
      "status": "full",
      "notes": "Same shape as resources: generated per-server prompts_list and prompts_get tools, gated the same way.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "openclaw/openclaw",
          "date": "2026-08-26",
          "commit": "a2d54319",
          "path": "src/agents/agent-bundle-mcp-materialize.ts:376-403"
        }
      ],
      "research": [
        "openclaw-names-its-resource-tools-a-fourth-way"
      ]
    },
    "completions": {
      "status": "unsupported",
      "notes": "No completion/complete call in either surface. Verified by searching the MCP client files rather than inferred.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "openclaw/openclaw",
          "date": "2026-08-26",
          "commit": "a2d54319",
          "path": "src/agents",
          "note": "No completion/complete call in src/agents or src/node-host."
        }
      ]
    },
    "sampling": {
      "status": "unsupported",
      "notes": "Not declared and not implemented. No CreateMessageRequestSchema handler exists on either surface.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "openclaw/openclaw",
          "date": "2026-08-26",
          "commit": "a2d54319",
          "path": "src/agents/agent-bundle-mcp-runtime.ts:219-231"
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "openclaw/openclaw",
          "date": "2026-08-26",
          "commit": "a2d54319",
          "path": "src/node-host/mcp.ts:276-288"
        }
      ],
      "research": [
        "openclaw-declares-nothing-unless-mcp-apps-is-on"
      ]
    },
    "elicitation": {
      "status": "unsupported",
      "notes": "Not declared and not implemented. No ElicitRequestSchema handler on either surface.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "openclaw/openclaw",
          "date": "2026-08-26",
          "commit": "a2d54319",
          "path": "src/agents/agent-bundle-mcp-runtime.ts:219-231"
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "openclaw/openclaw",
          "date": "2026-08-26",
          "commit": "a2d54319",
          "path": "src/node-host/mcp.ts:276-288"
        }
      ],
      "research": [
        "openclaw-declares-nothing-unless-mcp-apps-is-on"
      ]
    },
    "roots": {
      "status": "unsupported",
      "notes": "Not declared and not implemented. No ListRootsRequestSchema handler, so unlike goose, opencode and fast-agent this client does not reach the roots.listChanged declaration gap at all.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "openclaw/openclaw",
          "date": "2026-08-26",
          "commit": "a2d54319",
          "path": "src/agents/agent-bundle-mcp-runtime.ts:219-231"
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "openclaw/openclaw",
          "date": "2026-08-26",
          "commit": "a2d54319",
          "path": "src/node-host/mcp.ts:276-288"
        }
      ],
      "research": [
        "openclaw-declares-nothing-unless-mcp-apps-is-on"
      ]
    },
    "logging": {
      "status": "unsupported",
      "notes": "No logging/setLevel call and no logging notification handler. Server stderr on stdio is logged, which is not the same thing.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "openclaw/openclaw",
          "date": "2026-08-26",
          "commit": "a2d54319",
          "path": "src/agents/mcp-transport.ts:36-62"
        }
      ]
    },
    "instructions": {
      "status": "unsupported",
      "notes": "The server's instructions field from initialize is never read. Verified by searching both surfaces for it rather than assumed.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "openclaw/openclaw",
          "date": "2026-08-26",
          "commit": "a2d54319",
          "path": "src/agents",
          "note": "No read of the initialize result's instructions field in either surface."
        }
      ]
    },
    "tasks": {
      "status": "unsupported",
      "notes": "No tasks/* call anywhere in the MCP client files.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "openclaw/openclaw",
          "date": "2026-08-26",
          "commit": "a2d54319",
          "path": "src/agents",
          "note": "No tasks/* request in src/agents or src/node-host."
        }
      ]
    },
    "extensions": {
      "io.modelcontextprotocol/ui": {
        "status": "partial",
        "notes": "Declared with a mimeTypes list of text/html;profile=mcp-app, but only when mcp.apps.enabled is true in config, which defaults to false. A default install declares no extensions and no capabilities at all.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "openclaw/openclaw",
            "date": "2026-08-26",
            "commit": "a2d54319",
            "path": "src/agents/agent-bundle-mcp-runtime.ts:93-94"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "openclaw/openclaw",
            "date": "2026-08-26",
            "commit": "a2d54319",
            "path": "src/agents/agent-bundle-mcp-runtime.ts:219-231"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "openclaw/openclaw",
            "date": "2026-08-26",
            "commit": "a2d54319",
            "path": "src/agents/agent-bundle-mcp-runtime.ts:294",
            "note": "mcp.apps.enabled === true, default false."
          }
        ],
        "research": [
          "openclaw-declares-nothing-unless-mcp-apps-is-on"
        ]
      }
    },
    "research": [
      "openclaw-declares-nothing-unless-mcp-apps-is-on",
      "openclaw-recovers-expired-http-sessions-without-patching-the-sdk",
      "openclaw-defaults-a-url-server-to-sse",
      "openclaw-names-its-resource-tools-a-fourth-way",
      "openclaw-scrubs-tool-descriptions-with-three-regexes"
    ],
    "metadata": {
      "vendor": "OpenClaw Foundation",
      "openSource": true,
      "license": "MIT",
      "sourceUrl": "https://github.com/openclaw/openclaw",
      "lastVerified": "2026-08-26",
      "source": {
        "repo": "https://github.com/openclaw/openclaw.git",
        "ref": "main",
        "checkedCommit": "a2d54319bc31d8c4079d8960eb59beb568b8e16a",
        "commitDate": "2026-08-26T16:44:13Z",
        "checkedAt": "2026-08-26",
        "paths": [
          "src/agents/agent-bundle-mcp-runtime.ts",
          "src/agents/agent-bundle-mcp-materialize.ts",
          "src/agents/mcp-client-lifecycle.ts",
          "src/agents/mcp-transport.ts",
          "src/agents/mcp-transport-config.ts",
          "src/agents/mcp-http-transport.ts",
          "src/agents/mcp-stdio-transport.ts",
          "src/agents/mcp-oauth-provider.ts",
          "src/agents/mcp-metadata.ts",
          "src/node-host/mcp.ts",
          "package.json",
          "pnpm-lock.yaml"
        ]
      },
      "sdk": {
        "name": "@modelcontextprotocol/sdk",
        "language": "typescript",
        "official": true,
        "declared": "1.30.0",
        "resolved": "1.30.0",
        "patched": false,
        "pinsProtocolVersion": "2025-11-25",
        "notes": "Pinned to an exact version at four declaration sites (root, ui, extensions/browser, extensions/qa-lab) and they all agree, unlike Cline where two workspaces disagreed. Unpatched: patches/ is empty and pnpm-workspace.yaml has no patchedDependencies. No protocol version literal appears anywhere in the client code, so the revision is entirely the SDK's: 1.30.0 pins LATEST_PROTOCOL_VERSION at 2025-11-25. Where opencode patched the SDK for expired-session recovery, OpenClaw subclasses the transports instead and handles it in its own lifecycle code.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "openclaw/openclaw",
            "date": "2026-08-26",
            "commit": "a2d54319",
            "path": "package.json:2040"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "openclaw/openclaw",
            "date": "2026-08-26",
            "commit": "a2d54319",
            "path": "ui/package.json:22"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "openclaw/openclaw",
            "date": "2026-08-26",
            "commit": "a2d54319",
            "path": "extensions/browser/package.json:8"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "openclaw/openclaw",
            "date": "2026-08-26",
            "commit": "a2d54319",
            "path": "extensions/qa-lab/package.json:9"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "openclaw/openclaw",
            "date": "2026-08-26",
            "commit": "a2d54319",
            "path": "pnpm-lock.yaml:66,417,489,1008",
            "note": "All resolutions are 1.30.0."
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "openclaw/openclaw",
            "date": "2026-08-26",
            "commit": "a2d54319",
            "path": "patches/",
            "note": "Directory is empty; no patchedDependencies in pnpm-workspace.yaml or package.json."
          }
        ],
        "research": [
          "openclaw-recovers-expired-http-sessions-without-patching-the-sdk"
        ]
      }
    }
  },
  "hermes-agent": {
    "title": "Hermes Agent",
    "clientInfoNames": [
      "hermes-agent",
      "hermes-probe",
      "hermes"
    ],
    "url": "https://github.com/NousResearch/hermes-agent",
    "description": "Python agent CLI, desktop app and gateway from Nous Research. The second client here on the mcp Python SDK and the counterpart to fast-agent on it: same library, opposite protocol-era default. Hermes leads with the initialize handshake and probes server/discover only when a server rejects it. One MCP client serves every surface.",
    "category": "cli",
    "platforms": [
      "windows",
      "macos",
      "linux"
    ],
    "protocolVersions": [
      "2024-11-05",
      "2025-03-26",
      "2025-06-18",
      "2025-11-25",
      "2026-07-28"
    ],
    "preferredProtocolVersion": "2025-11-25",
    "transports": {
      "stdio": {
        "status": "full",
        "notes": "The SDK's stdio_client. Spawned process groups are registered with a shared parent-death supervisor and a spawn ledger, and on Windows Hermes first puts itself in a kill-on-close job object, so a hard kill of Hermes does not leave children running. Server stderr goes to a shared log file, orphans from earlier attempts are reaped before each spawn, and a session can be recycled on idle_timeout_seconds or max_lifetime_seconds. npx, uvx and pipx packages get an OSV malware check before spawn, which fails open on timeout. The handshake is bounded by connect_timeout inside the coroutine.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_transport.py:306-435"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool.py:38-70"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_health.py:40-60"
          }
        ]
      },
      "streamableHttp": {
        "status": "full",
        "notes": "The default for a server configured with a url. Hermes probes for both the current streamable_http_client and the deprecated streamablehttp_client alias. It builds its own httpx client, which adds a 10 MiB body cap, proxy settings from the environment and the OS, and optional mTLS client certificates. The MCP-Protocol-Version header is seeded from the handshake-era constant, not the newest revision.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool.py:143-190"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_transport.py:562-668"
          }
        ],
        "research": [
          "hermes-defaults-a-url-server-to-streamable-http",
          "hermes-seeds-the-protocol-header-from-the-handshake-version"
        ]
      },
      "sse": {
        "status": "full",
        "notes": "Selected by transport: sse, and also used as a fallback. When the first Streamable HTTP connect is rejected with 400, 405, 406 or 411, or with the SDK's -32603 \"Server returned an error response\", Hermes retries over SSE and keeps SSE for later reconnects. The fallback does not fire on a timeout, an auth error, a reconnect after a working session, or with strict_redirect_headers, which SSE refuses at connect.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_transport.py:532-560,623-668"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_errors.py:73-91"
          }
        ],
        "research": [
          "hermes-defaults-a-url-server-to-streamable-http"
        ]
      }
    },
    "authentication": {
      "oauth": {
        "status": "full",
        "notes": "Opt-in through auth: oauth on the server entry, on the SDK's OAuthClientProvider. By default the client_id is Hermes' Client ID Metadata Document URL when the server supports CIMD, else RFC 7591 dynamic registration with application_type native. Tokens persist per server, are reloaded when another process refreshes them, and are bound to the issuer. An RFC 8628 device flow runs only on request, through hermes mcp login --flow device or oauth.flow: device. The web dashboard can receive the browser callback in place of a loopback listener.",
        "pkce": true,
        "dynamicRegistration": true,
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_oauth.py:1-9,935-1025,1101-1157"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_oauth_manager.py:1-6,321-330"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_oauth_device.py:1-5,16-92"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_dashboard_oauth.py:1-3,38-190"
          }
        ]
      },
      "headers": {
        "status": "full",
        "notes": "Arbitrary headers per server entry, plus an optional identity_header carrying a static value or the active Hermes profile name. Authorization is always dropped on a cross-origin redirect, and strict_redirect_headers drops every configured header there.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_transport.py:117-150,600-622"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_errors.py:213-323"
          }
        ]
      }
    },
    "tools": {
      "status": "full",
      "notes": "Paginated: a shared helper follows nextCursor across up to 50 pages for tools, resources and prompts, holding the server's RPC lock, and reads SEP-2549 cache hints from the first page. tools/list is sent only when the server advertised tools. Registered names are mcp__<server>__<tool>, clamped to 64 characters with a hash suffix. Tool descriptions are checked against ten prompt-injection patterns, which log a warning and block nothing.",
      "listChanged": {
        "status": "full",
        "notes": "A message_handler on the session watches notifications/tools/list_changed and schedules a background refresh, kept strongly referenced so it is not garbage-collected mid-flight. The refresh re-paginates under the RPC lock and deregisters only the names that went away.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_health.py:60-70,99-170"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_transport.py:177-178"
          }
        ]
      },
      "result": {
        "status": "full",
        "notes": "Both fields reach the model in one JSON string unless the text mirrors the JSON. Over 2,000,000 serialized characters the structured value is replaced by a head-and-tail truncated string.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "olaservo/structured-content-research",
            "url": "https://github.com/olaservo/structured-content-research/blob/0c0395d/notes/hermes-agent-tool-result-handling.md",
            "date": "2026-11-08",
            "commit": "0c0395d",
            "path": "notes/hermes-agent-tool-result-handling.md",
            "note": "The read tier for tool result handling lives in that repo (AGENTS.md); this entry summarises its note, which read the Hermes Agent source at e0754412."
          }
        ],
        "content": {
          "status": "full",
          "notes": "Text blocks joined with newlines under a result key in a JSON string."
        },
        "structuredContent": {
          "status": "partial",
          "notes": "Appended as a structuredContent key unless a text block is an exact JSON copy of it, in which case the copy is dropped. With empty content it becomes the result value. Ignored on isError."
        },
        "_meta": {
          "status": "partial",
          "notes": "Application keys ride along as a _meta key; protocol-reserved keys are stripped."
        }
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "NousResearch/hermes-agent",
          "date": "2026-11-09",
          "commit": "9dcf7714",
          "path": "tools/mcp_tool.py:256-306,425-445"
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "NousResearch/hermes-agent",
          "date": "2026-11-09",
          "commit": "9dcf7714",
          "path": "tools/mcp_tool_transport.py:158-169,674-692"
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "NousResearch/hermes-agent",
          "date": "2026-11-09",
          "commit": "9dcf7714",
          "path": "tools/mcp_tool_schema.py:15-41,147-183"
        }
      ]
    },
    "resources": {
      "status": "full",
      "notes": "Reachable by the model, not only listed. Hermes materializes per-server mcp__<server>__list_resources and mcp__<server>__read_resource tools, registered only when the server's own capabilities advertised resources, and suppressible with tools.resources on the server entry. ResourceLink results are rewritten to point at the same server's read_resource tool. A server tool whose name normalises to the same name wins over the utility.",
      "listChanged": {
        "status": "unsupported",
        "notes": "notifications/resources/list_changed is matched and logged at debug level as ignored. The utility tools query the server on every call, so nothing cached goes stale. The August entry recorded this as full; the same ignore branch was already there at a24c12d1.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_health.py:118-119"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "a24c12d1",
            "path": "tools/mcp_tool.py:2752-2753"
          }
        ]
      },
      "subscribe": {
        "status": "unsupported",
        "notes": "Nothing calls resources/subscribe. Hermes learns about resource changes only from the list-changed notification.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/",
            "note": "No subscribe_resource, resources/subscribe or ResourceUpdatedNotification anywhere in tools/, hermes_cli/, agent/ or gateway/."
          }
        ]
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "NousResearch/hermes-agent",
          "date": "2026-11-09",
          "commit": "9dcf7714",
          "path": "tools/mcp_tool_registration.py:185-212,315-350"
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "NousResearch/hermes-agent",
          "date": "2026-11-09",
          "commit": "9dcf7714",
          "path": "tools/mcp_tool_schema.py:240-253,319-335"
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "NousResearch/hermes-agent",
          "date": "2026-11-09",
          "commit": "9dcf7714",
          "path": "tools/mcp_tool_handlers.py:785-810,839-844"
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "NousResearch/hermes-agent",
          "date": "2026-11-09",
          "commit": "9dcf7714",
          "path": "tools/mcp_tool_content.py:293-309"
        }
      ],
      "research": [
        "hermes-names-its-resource-tools-a-fifth-way"
      ]
    },
    "prompts": {
      "status": "full",
      "notes": "Same shape as resources: per-server mcp__<server>__list_prompts and mcp__<server>__get_prompt tools, gated on the server having advertised prompts and suppressible with tools.prompts.",
      "listChanged": {
        "status": "unsupported",
        "notes": "notifications/prompts/list_changed is matched and logged at debug level as ignored. The August entry recorded this as full; the same ignore branch was already there at a24c12d1.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_health.py:116-117"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "a24c12d1",
            "path": "tools/mcp_tool.py:2750-2751"
          }
        ]
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "NousResearch/hermes-agent",
          "date": "2026-11-09",
          "commit": "9dcf7714",
          "path": "tools/mcp_tool_handlers.py:813-835,845-850"
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "NousResearch/hermes-agent",
          "date": "2026-11-09",
          "commit": "9dcf7714",
          "path": "tools/mcp_tool_registration.py:185-212"
        }
      ],
      "research": [
        "hermes-names-its-resource-tools-a-fifth-way"
      ]
    },
    "completions": {
      "status": "unsupported",
      "notes": "No completion/complete call anywhere. Neither prompt arguments nor resource template variables get server-side completion.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "NousResearch/hermes-agent",
          "date": "2026-11-09",
          "commit": "9dcf7714",
          "path": "tools/",
          "note": "No completion/complete or CompleteRequest in the MCP client."
        }
      ]
    },
    "sampling": {
      "status": "full",
      "notes": "Declared and served by default: sampling.enabled defaults to true on the server entry. Requests are rate-limited, ten a minute by default, audited to the log with model and token counts, and a failure is returned as ErrorData. A docstring records sampling as deprecated upstream under SEP-2577 and freezes the handler.",
      "tools": {
        "status": "partial",
        "notes": "Opt-in per server through expose_client_tools, off by default. A comment says strict servers rejected the unknown sampling.tools sub-capability during initialization (#5468). Server-sent tools are forwarded to the model and CreateMessageResultWithTools is returned whatever the setting. At a24c12d1 the sub-capability was always declared.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_sampling.py:110-112,180-188,214-219"
          },
          {
            "tier": "declared",
            "status": "unsupported",
            "at": "2025-11-25",
            "source": "canimcp-probe",
            "date": "2026-11-08",
            "clientVersion": "0.23.0+689.ga9ff979",
            "config": "default",
            "artifact": "probe/runs/hermes-agent@0.23.0+689.ga9ff979/default/both-http/tools.result.mirror",
            "note": "initialize.capabilities on the wire was {\"sampling\":{},\"elicitation\":{\"form\":{},\"url\":{}}} (wire.jsonl). No tools key under sampling."
          }
        ]
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "NousResearch/hermes-agent",
          "date": "2026-11-09",
          "commit": "9dcf7714",
          "path": "tools/mcp_tool_server_run.py:268-270"
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "NousResearch/hermes-agent",
          "date": "2026-11-09",
          "commit": "9dcf7714",
          "path": "tools/mcp_tool_sampling.py:94-118,182-203"
        },
        {
          "tier": "declared",
          "status": "full",
          "at": "2025-11-25",
          "source": "canimcp-probe",
          "date": "2026-11-08",
          "clientVersion": "0.23.0+689.ga9ff979",
          "config": "default",
          "artifact": "probe/runs/hermes-agent@0.23.0+689.ga9ff979/default/both-http/tools.result.mirror",
          "note": "initialize.capabilities on the wire was {\"sampling\":{},\"elicitation\":{\"form\":{},\"url\":{}}} (wire.jsonl)."
        }
      ]
    },
    "elicitation": {
      "status": "partial",
      "notes": "Declared and served by default: elicitation.enabled defaults to true. Hermes passes only an elicitation callback, and mcp 2.3.0 turns any callback into a declaration of both form and url modes. Requests go through Hermes' approval system, and accept, decline and error counts are tracked per server.",
      "form": {
        "status": "partial",
        "notes": "The user sees the message and a summary of the requested fields and answers accept, decline or cancel. Accept returns empty content, so the server gets no field values back. A timeout or exception fails closed. The empty accept was already there at a24c12d1.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_sampling.py:290-333"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "a24c12d1",
            "path": "tools/mcp_tool.py:2363"
          },
          {
            "tier": "declared",
            "status": "full",
            "at": "2025-11-25",
            "source": "canimcp-probe",
            "date": "2026-11-08",
            "clientVersion": "0.23.0+689.ga9ff979",
            "config": "default",
            "artifact": "probe/runs/hermes-agent@0.23.0+689.ga9ff979/default/both-http/tools.result.mirror",
            "note": "initialize.capabilities on the wire was {\"sampling\":{},\"elicitation\":{\"form\":{},\"url\":{}}} (wire.jsonl)."
          }
        ]
      },
      "url": {
        "status": "unsupported",
        "notes": "URL-mode requests are declined with a log line saying URL-mode elicitation is not implemented. The url capability is declared anyway, because the SDK declares it whenever an elicitation callback is set. The August entry recorded this as full; the decline was already there at a24c12d1.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_sampling.py:310-313"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "a24c12d1",
            "path": "tools/mcp_tool.py:2263-2270"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "modelcontextprotocol/python-sdk",
            "url": "https://github.com/modelcontextprotocol/python-sdk/tree/v2.3.0",
            "date": "2026-11-09",
            "commit": "2118f14f",
            "path": "src/mcp/client/session.py:634-638"
          },
          {
            "tier": "declared",
            "status": "full",
            "at": "2025-11-25",
            "source": "canimcp-probe",
            "date": "2026-11-08",
            "clientVersion": "0.23.0+689.ga9ff979",
            "config": "default",
            "artifact": "probe/runs/hermes-agent@0.23.0+689.ga9ff979/default/both-http/tools.result.mirror",
            "note": "initialize.capabilities on the wire was {\"sampling\":{},\"elicitation\":{\"form\":{},\"url\":{}}} (wire.jsonl)."
          }
        ],
        "research": [
          "hermes-declares-url-elicitation-it-declines"
        ]
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "NousResearch/hermes-agent",
          "date": "2026-11-09",
          "commit": "9dcf7714",
          "path": "tools/mcp_tool_server_run.py:273-276"
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "NousResearch/hermes-agent",
          "date": "2026-11-09",
          "commit": "9dcf7714",
          "path": "tools/mcp_tool_sampling.py:264-288"
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "modelcontextprotocol/python-sdk",
          "url": "https://github.com/modelcontextprotocol/python-sdk/tree/v2.3.0",
          "date": "2026-11-09",
          "commit": "2118f14f",
          "path": "src/mcp/client/session.py:634-638"
        },
        {
          "tier": "declared",
          "status": "full",
          "at": "2025-11-25",
          "source": "canimcp-probe",
          "date": "2026-11-08",
          "clientVersion": "0.23.0+689.ga9ff979",
          "config": "default",
          "artifact": "probe/runs/hermes-agent@0.23.0+689.ga9ff979/default/both-http/tools.result.mirror",
          "note": "initialize.capabilities on the wire was {\"sampling\":{},\"elicitation\":{\"form\":{},\"url\":{}}} (wire.jsonl)."
        }
      ]
    },
    "roots": {
      "status": "unsupported",
      "notes": "No list_roots_callback is passed at either session construction site and no roots handler exists anywhere in the client, so nothing is declared and roots/list is never answered. Hermes is the second client read here that does not reach the SDK roots.listChanged problem at all, for the same reason as OpenClaw: it never opts in.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "NousResearch/hermes-agent",
          "date": "2026-11-09",
          "commit": "9dcf7714",
          "path": "tools/mcp_tool_transport.py:171-186",
          "note": "_session_kwargs carries the sampling and elicitation handlers, message_handler, logging_callback and client_info only."
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "modelcontextprotocol/python-sdk",
          "url": "https://github.com/modelcontextprotocol/python-sdk/tree/v2.3.0",
          "date": "2026-11-09",
          "commit": "2118f14f",
          "path": "src/mcp/client/session.py:639-648",
          "note": "ClientSession derives the roots capability from list_roots_callback; with none passed the capability is absent."
        },
        {
          "tier": "declared",
          "status": "unsupported",
          "at": "2025-11-25",
          "source": "canimcp-probe",
          "date": "2026-11-08",
          "clientVersion": "0.23.0+689.ga9ff979",
          "config": "default",
          "artifact": "probe/runs/hermes-agent@0.23.0+689.ga9ff979/default/both-http/tools.result.mirror",
          "note": "initialize.capabilities on the wire was {\"sampling\":{},\"elicitation\":{\"form\":{},\"url\":{}}} (wire.jsonl). No roots key."
        }
      ],
      "research": [
        "fast-agent-never-sends-roots-list-changed"
      ]
    },
    "logging": {
      "status": "partial",
      "notes": "Receives but does not steer. A logging_callback routes notifications/message into Hermes' own logging, tagged with the server name, mapping MCP levels onto Python ones and truncating a single payload at 2000 characters so a chatty or broken server cannot flood the log. The docstring records that without it the SDK's default callback discards them, so server-side warnings during a tool call were invisible, and credits the fix as a port of an opencode change. Nothing calls logging/setLevel, so the server's default verbosity is whatever it chooses.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "NousResearch/hermes-agent",
          "date": "2026-11-09",
          "commit": "9dcf7714",
          "path": "tools/mcp_tool_health.py:73-97"
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "NousResearch/hermes-agent",
          "date": "2026-11-09",
          "commit": "9dcf7714",
          "path": "tools/mcp_tool_transport.py:179-180"
        }
      ]
    },
    "instructions": {
      "status": "unsupported",
      "notes": "The instructions field of the negotiation result is never read. Only capabilities is consumed, to gate the resource and prompt utility tools.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "NousResearch/hermes-agent",
          "date": "2026-11-09",
          "commit": "9dcf7714",
          "path": "tools/mcp_tool_registration.py:192"
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "NousResearch/hermes-agent",
          "date": "2026-11-09",
          "commit": "9dcf7714",
          "path": "tools/mcp_tool_transport.py:168"
        }
      ]
    },
    "tasks": {
      "status": "unsupported",
      "notes": "No tasks methods referenced anywhere in the client.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "NousResearch/hermes-agent",
          "date": "2026-11-09",
          "commit": "9dcf7714",
          "path": "tools/",
          "note": "No tasks/* call in the MCP client."
        }
      ]
    },
    "bonusFeatures": {
      "modelInitiatedResourceRead": {
        "status": "full",
        "notes": "The model can read a resource with no user in the loop, through the per-server read_resource tool, provided the server advertised resources.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_handlers.py:799-807,842-844"
          }
        ],
        "research": [
          "hermes-names-its-resource-tools-a-fifth-way",
          "model-initiated-resource-read"
        ]
      },
      "toolDescriptionScrubbing": {
        "status": "partial",
        "notes": "Ten regexes check every MCP tool description for prompt-injection patterns and log a warning; the text reaches the model unchanged. What is removed is Unicode tag characters and bidi embedding, override and isolate controls. The August entry called the regex pass scrubbing; it was warn-only then too.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_schema.py:15-41,225-233"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/ansi_strip.py:86-97"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_registration.py:289-297"
          }
        ],
        "research": [
          "openclaw-scrubs-tool-descriptions-with-three-regexes"
        ]
      },
      "deferredToolLoading": {
        "status": "full",
        "notes": "MCP tools are removed from the model-visible tool array by default and replaced with a tool_search, tool_describe and tool_call bridge, with a catalog listing embedded in the bridge's description under a token budget that degrades through five fixed forms rather than truncating. Core Hermes tools are deferred only when named in a curated list.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/tool_search.py:1-7,40-89,150-162,204-221,344-380"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "model_tools.py:546-557"
          }
        ]
      },
      "resultSpillover": {
        "status": "full",
        "notes": "An MCP result past 50,000 characters, configurable through tool_budget.mcp_result_size_chars and tighter than the 100,000 generic default, is written to a spillover file and replaced in context by a block naming its size, path and a read_file recovery line. A single result is hard-capped at 2,000,000 characters with a head and tail split around an omission notice.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/budget_config.py:17-41,62-63"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_content.py:20-34"
          }
        ]
      },
      "sessionRecovery": {
        "status": "full",
        "notes": "Expired HTTP sessions are detected and the transport reconnected. The call is retried once only for tools annotated readOnlyHint: true; any other tool gets the transport healed and an outcome_uncertain error instead of a replay. A connect-failure cooldown keeps a dead server from being retried in a tight loop, and a parked server probes itself every 300 seconds.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_errors.py:504-532"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_handlers.py:233-258,342-385"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_server_run.py:188-240"
          }
        ],
        "research": [
          "openclaw-recovers-expired-http-sessions-without-patching-the-sdk"
        ]
      },
      "nonMcpEndpointDetection": {
        "status": "full",
        "notes": "A URL that answers HEAD or GET with a content type outside the MCP media types is POSTed a hand-written minimal initialize frame at 2025-03-26, naming itself hermes-probe, before Hermes raises NonMcpEndpointError. The check is skipped for SSE, OAuth servers and any server that has connected before.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_transport.py:27-29,439-490"
          }
        ]
      },
      "eventsExtension": {
        "status": "partial",
        "notes": "Opt-in per server with events: true. Implements webhook delivery from the experimental Triggers & Events extension: events/list, events/subscribe with a webhook URL and secret, and events/unsubscribe, exposed to the model as three utility tools. Subscribing always asks the user, and the gateway verifies Standard Webhooks signatures on delivery. Poll and push delivery are not implemented, and nothing is declared in the client capabilities.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_events.py:1-11,226-245,357-436"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_registration.py:196-197"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "gateway/platforms/webhook_mcp_events.py:1-60"
          }
        ]
      },
      "trustTiers": {
        "status": "full",
        "notes": "Each server entry takes trust: full, the default, or untrusted, and an unrecognised value is treated as untrusted. On an untrusted server every tool call needs approval unless the tool's annotations carry readOnlyHint: true, and an approval can be remembered per server and tool. The hint is cached with the schema, so lazily registered tools are gated the same way.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_registration.py:38-107"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_handlers.py:60-74,124-205"
          }
        ]
      },
      "declaredToolCosts": {
        "status": "full",
        "notes": "A server entry can declare per-tool costs, single figures or ranges, through tool_costs, plus a per-chat spend_limit. The approval prompt names the cost and the chat's running total, counted at the top of each range, and a call that would pass the limit needs an explicit yes even on a trust: full server. The figures come from client config, not from the server.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_costs.py:1-11,63-88,145-232"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_handlers.py:124-205"
          }
        ]
      },
      "lazyServerStart": {
        "status": "full",
        "notes": "With lazy: true on a server entry, Hermes registers the server's tools from an on-disk schema cache without starting the server, and connects on first use. Entries are keyed by server name and a fingerprint of the connection config, are written after each live registration, and expire on the SEP-2549 ttlMs from tools/list. Entries without a TTL never expire, and a missing or stale entry falls back to a normal connect.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_schema_cache.py:1-109"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_registration.py:402-429"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool_discovery.py:209-216,404-436"
          }
        ]
      }
    },
    "research": [
      "hermes-leads-with-the-legacy-handshake",
      "hermes-declares-url-elicitation-it-declines",
      "hermes-names-its-resource-tools-a-fifth-way",
      "hermes-seeds-the-protocol-header-from-the-handshake-version",
      "hermes-defaults-a-url-server-to-streamable-http",
      "hermes-runs-one-mcp-client-for-every-surface",
      "hermes-goes-on-the-wire-as-mcp"
    ],
    "metadata": {
      "vendor": "Nous Research",
      "openSource": true,
      "license": "MIT",
      "sourceUrl": "https://github.com/NousResearch/hermes-agent",
      "lastVerified": "2026-11-09",
      "source": {
        "repo": "https://github.com/NousResearch/hermes-agent.git",
        "ref": "main",
        "checkedCommit": "9dcf7714df7a0d49c335925d12d4b017274ee355",
        "commitDate": "2026-11-09T14:20:28Z",
        "checkedAt": "2026-11-09",
        "paths": [
          "tools/mcp_tool.py",
          "tools/mcp_tool_*.py",
          "tools/mcp_oauth.py",
          "tools/mcp_oauth_manager.py",
          "tools/mcp_oauth_device.py",
          "tools/mcp_oauth_provider.py",
          "tools/mcp_dashboard_oauth.py",
          "tools/mcp_schema_cache.py",
          "tools/tool_search.py",
          "tools/budget_config.py",
          "tools/lazy_deps.py",
          "tools/ansi_strip.py",
          "tools/computer_use/cua_backend_session.py",
          "hermes_platform/resolver/app.py",
          "gateway/platforms/webhook_mcp_events.py",
          "model_tools.py",
          "hermes_cli/mcp_config.py",
          "hermes_cli/main_install_repair.py",
          "pyproject.toml",
          "uv.lock"
        ]
      },
      "sdk": {
        "name": "mcp",
        "language": "python",
        "official": true,
        "declared": "==2.3.0",
        "resolved": "2.3.0",
        "patched": false,
        "notes": "mcp==2.3.0 exactly, resolving to 2.3.0 in uv.lock alongside mcp-types 2.3.0, with no [tool.uv] source override and no vendored fork. Unlike every other client read here, the SDK is not a base dependency. It is declared identically under the mcp and computer-use extras and the dev dependency group. The runtime lazy install the August read found is gone: tools/lazy_deps.py is now a retired shim, and install repair syncs the mcp extra when mcp_servers is configured and the SDK is missing. The import is deferred behind _ensure_mcp_sdk, so a session with no MCP servers configured never pays for it. Every version decision on the live path is the SDK's: Hermes names no revision of its own and picks an era instead. The revisions it names itself are 2025-03-26, in a fallback constant and the non-MCP-endpoint probe frame, and 2025-06-18, in the desktop-app liveness probe.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "pyproject.toml:422-433,443-448,563-570"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "uv.lock:3554-3592"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/lazy_deps.py:1-26"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "hermes_cli/main_install_repair.py:251-310"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "NousResearch/hermes-agent",
            "date": "2026-11-09",
            "commit": "9dcf7714",
            "path": "tools/mcp_tool.py:76-92,143-190"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "modelcontextprotocol/python-sdk",
            "url": "https://pypi.org/project/mcp-types/2.3.0/",
            "date": "2026-11-09",
            "path": "mcp_types/version.py:24-59",
            "note": "HANDSHAKE_PROTOCOL_VERSIONS ends at 2025-11-25; MODERN_PROTOCOL_VERSIONS holds 2026-07-28 alone. Same values as 2.0.0."
          }
        ],
        "research": [
          "hermes-leads-with-the-legacy-handshake"
        ]
      }
    }
  },
  "kilocode": {
    "title": "Kilo Code",
    "clientInfoNames": [
      "kilo"
    ],
    "url": "https://kilo.ai",
    "description": "Open-source coding agent for VS Code, JetBrains and the terminal. Now built on opencode, not Cline: the CLI is a fork of opencode's, and the VS Code and JetBrains extensions both spawn `kilo serve`, so one MCP client sits behind every surface. Ships a patched SDK 1.32.1 on main; the v2 branch has moved to the split SDK.",
    "category": "ide",
    "platforms": [
      "windows",
      "macos",
      "linux"
    ],
    "protocolVersions": [
      "2024-11-05",
      "2025-03-26",
      "2025-06-18",
      "2025-11-25"
    ],
    "preferredProtocolVersion": "2025-11-25",
    "transports": {
      "stdio": {
        "status": "full",
        "notes": "Docker and podman commands get --rm injected. The child environment is rebuilt without Kilo backend credentials, and stderr is piped and drained into the log.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "Kilo-Org/kilocode",
            "date": "2026-11-10",
            "commit": "278edf3a",
            "path": "packages/opencode/src/mcp/index.ts:69-81,446-471"
          }
        ]
      },
      "sse": {
        "status": "full",
        "notes": "Fallback when Streamable HTTP fails, against the same URL. Not tried after an auth failure. Same order as opencode.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "Kilo-Org/kilocode",
            "date": "2026-11-10",
            "commit": "278edf3a",
            "path": "packages/opencode/src/mcp/index.ts:369-438"
          }
        ]
      },
      "streamableHttp": {
        "status": "full",
        "notes": "Tried first for every remote server. Requests go through a fetch wrapper that normalises the optional GET stream probe.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "Kilo-Org/kilocode",
            "date": "2026-11-10",
            "commit": "278edf3a",
            "path": "packages/opencode/src/mcp/index.ts:349-386"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "Kilo-Org/kilocode",
            "date": "2026-11-10",
            "commit": "278edf3a",
            "path": "packages/opencode/src/kilocode/mcp/sse-probe.ts"
          }
        ]
      }
    },
    "authentication": {
      "oauth": {
        "status": "full",
        "notes": "CIMD is Kilo's addition: clientMetadataUrl is https://kilo.ai/docs/oauth/kilo/client.json, offered only when no clientId or clientSecret is configured and the redirect URI is the default. The SDK uses it when the authorization server supports URL-based client ids and falls back to DCR otherwise. A stored token that has expired is refreshed before connecting, bounded by the connect timeout, because some servers answer an expired token with 403 and the SDK only retries 401. The callback is a loopback server on 127.0.0.1.",
        "clientIdMetadataDocument": true,
        "dynamicRegistration": true,
        "grantTypes": [
          "authorization_code",
          "refresh_token"
        ],
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "Kilo-Org/kilocode",
            "date": "2026-11-10",
            "commit": "278edf3a",
            "path": "packages/opencode/src/mcp/oauth-provider.ts:56-83"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "Kilo-Org/kilocode",
            "date": "2026-11-10",
            "commit": "278edf3a",
            "path": "packages/opencode/src/kilocode/mcp/client-metadata.ts"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "@modelcontextprotocol/sdk",
            "url": "https://www.npmjs.com/package/@modelcontextprotocol/sdk/v/1.32.1",
            "date": "2026-11-10",
            "path": "dist/esm/client/auth.js:302-309"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "Kilo-Org/kilocode",
            "date": "2026-11-10",
            "commit": "278edf3a",
            "path": "packages/opencode/src/mcp/index.ts:360-366"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "Kilo-Org/kilocode",
            "date": "2026-11-10",
            "commit": "278edf3a",
            "path": "packages/opencode/src/kilocode/mcp/refresh.ts"
          }
        ],
        "research": [
          "kilocode-adds-cimd-and-pre-connect-token-refresh"
        ]
      },
      "header": {
        "status": "full",
        "notes": "A headers map on a remote server is passed as requestInit headers on both transports.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "Kilo-Org/kilocode",
            "date": "2026-11-10",
            "commit": "278edf3a",
            "path": "packages/opencode/src/mcp/index.ts:372-384"
          }
        ]
      }
    },
    "tools": {
      "status": "full",
      "notes": "tools/list is called only when the server declares tools. Paginated with a duplicate-cursor guard. A page whose outputSchema fails to compile is re-requested without outputSchema.",
      "listChanged": {
        "status": "full",
        "notes": "Re-lists the catalog and publishes ToolsChanged. Registered only when the server declared tools.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "Kilo-Org/kilocode",
            "date": "2026-11-10",
            "commit": "278edf3a",
            "path": "packages/opencode/src/mcp/index.ts:575-585"
          }
        ]
      },
      "result": {
        "status": "full",
        "notes": "The direct path is the default: Code Mode is opt-in here (KILO_EXPERIMENTAL_CODE_MODE or experimental.code_mode), where opencode made it the default route. On the direct path content wins and structuredContent fills in as one JSON text block only when content is empty.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "olaservo/structured-content-research",
            "url": "https://github.com/olaservo/structured-content-research/blob/0c0395d/notes/kilocode-tool-result-handling.md",
            "date": "2026-11-08",
            "commit": "0c0395d",
            "path": "notes/kilocode-tool-result-handling.md",
            "note": "The read tier for tool result handling lives in that repo (AGENTS.md); this entry summarises its note, which read the Kilo Code source at b6a49d0."
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "Kilo-Org/kilocode",
            "date": "2026-11-10",
            "commit": "278edf3a",
            "path": "packages/opencode/src/kilocode/tool/code-mode.ts",
            "note": "Code Mode gate checked at this commit."
          }
        ],
        "content": {
          "status": "full",
          "notes": "Text blocks reach the model joined and truncated at 2000 lines or 50 KB. Images become attachments. audio and resource_link blocks are dropped."
        },
        "structuredContent": {
          "status": "partial",
          "notes": "Reaches the model only when content is empty, as JSON.stringify of the object. With Code Mode on, scripts receive it as the return value."
        }
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "Kilo-Org/kilocode",
          "date": "2026-11-10",
          "commit": "278edf3a",
          "path": "packages/opencode/src/mcp/catalog.ts:18-35,145-168"
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "Kilo-Org/kilocode",
          "date": "2026-11-10",
          "commit": "278edf3a",
          "path": "packages/opencode/src/mcp/index.ts:505"
        }
      ]
    },
    "resources": {
      "status": "full",
      "notes": "Exposed as three built-in tools, list_mcp_resources, list_mcp_resource_templates and read_mcp_resource, registered only when a connected server declares resources. Same as opencode.",
      "listChanged": {
        "status": "unsupported",
        "notes": "Only logging and tools/list_changed handlers are registered.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "Kilo-Org/kilocode",
            "date": "2026-11-10",
            "commit": "278edf3a",
            "path": "packages/opencode/src/mcp/index.ts:571-585"
          }
        ]
      },
      "subscribe": {
        "status": "unsupported",
        "notes": "No resources/subscribe call and no resources/updated handler.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "Kilo-Org/kilocode",
            "date": "2026-11-10",
            "commit": "278edf3a",
            "path": "packages/opencode/src/mcp/index.ts:571-585"
          }
        ]
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "Kilo-Org/kilocode",
          "date": "2026-11-10",
          "commit": "278edf3a",
          "path": "packages/opencode/src/session/tools.ts:41-43,229"
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "Kilo-Org/kilocode",
          "date": "2026-11-10",
          "commit": "278edf3a",
          "path": "packages/opencode/src/mcp/catalog.ts:129-143"
        }
      ],
      "research": [
        "model-initiated-resource-read"
      ]
    },
    "prompts": {
      "status": "partial",
      "notes": "Every server prompt becomes a slash command. Only text content survives, and arguments are filled positionally as $1, $2. Same as opencode.",
      "listChanged": {
        "status": "unsupported",
        "notes": "No prompts/list_changed handler is registered."
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "Kilo-Org/kilocode",
          "date": "2026-11-10",
          "commit": "278edf3a",
          "path": "packages/opencode/src/command/index.ts:144-169"
        },
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "Kilo-Org/kilocode",
          "date": "2026-11-10",
          "commit": "278edf3a",
          "path": "packages/opencode/src/mcp/catalog.ts:121-127"
        }
      ]
    },
    "completions": {
      "status": "unsupported",
      "notes": "No completion/complete call.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "Kilo-Org/kilocode",
          "date": "2026-11-10",
          "commit": "278edf3a",
          "path": "packages/opencode/src/mcp"
        }
      ]
    },
    "sampling": {
      "status": "unsupported",
      "notes": "Commented out in the capability object, against opencode issue 11948. Kilo kept opencode's comments and links.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "Kilo-Org/kilocode",
          "date": "2026-11-10",
          "commit": "278edf3a",
          "path": "packages/opencode/src/mcp/index.ts:56-67"
        }
      ],
      "research": [
        "opencode-declares-only-roots"
      ]
    },
    "elicitation": {
      "status": "unsupported",
      "notes": "Commented out against opencode issue 23066.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "Kilo-Org/kilocode",
          "date": "2026-11-10",
          "commit": "278edf3a",
          "path": "packages/opencode/src/mcp/index.ts:56-67"
        }
      ],
      "research": [
        "opencode-declares-only-roots"
      ]
    },
    "roots": {
      "status": "full",
      "notes": "The only capability Kilo declares. list_roots returns one root, the file URL of the instance directory.",
      "listChanged": {
        "status": "unsupported",
        "notes": "Declared as a bare roots:{}. Nothing sends notifications/roots/list_changed."
      },
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "Kilo-Org/kilocode",
          "date": "2026-11-10",
          "commit": "278edf3a",
          "path": "packages/opencode/src/mcp/index.ts:56-67,108-114"
        }
      ]
    },
    "logging": {
      "status": "partial",
      "notes": "Receives notifications/message into the log. Never calls logging/setLevel.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "Kilo-Org/kilocode",
          "date": "2026-11-10",
          "commit": "278edf3a",
          "path": "packages/opencode/src/mcp/index.ts:571-573"
        }
      ]
    },
    "instructions": {
      "status": "full",
      "notes": "Server instructions are trimmed and carried per server.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "Kilo-Org/kilocode",
          "date": "2026-11-10",
          "commit": "278edf3a",
          "path": "packages/opencode/src/mcp/index.ts:513"
        }
      ]
    },
    "icons": {
      "status": "unsupported",
      "notes": "No icon handling in the client.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "Kilo-Org/kilocode",
          "date": "2026-11-10",
          "commit": "278edf3a",
          "path": "packages/opencode/src/mcp"
        }
      ]
    },
    "tasks": {
      "status": "unsupported",
      "notes": "Commented out against opencode issue 28567.",
      "evidence": [
        {
          "tier": "read",
          "at": "2025-11-25",
          "source": "Kilo-Org/kilocode",
          "date": "2026-11-10",
          "commit": "278edf3a",
          "path": "packages/opencode/src/mcp/index.ts:56-67"
        }
      ],
      "research": [
        "opencode-declares-only-roots"
      ]
    },
    "extensions": {
      "io.modelcontextprotocol/ui": {
        "status": "partial",
        "notes": "Behind KILO_EXPERIMENTAL_MCP_APPS. A tool with _meta.ui.resourceUri gets mcpApp metadata on its tool part, and two experimental HTTP endpoints read a resource and call a tool for a widget. The extension is not declared in the capability object, and no widget host is in the repo.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "Kilo-Org/kilocode",
            "date": "2026-11-10",
            "commit": "278edf3a",
            "path": "packages/opencode/src/kilocode/mcp/apps.ts"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "Kilo-Org/kilocode",
            "date": "2026-11-10",
            "commit": "278edf3a",
            "path": "packages/opencode/src/mcp/index.ts:56-67"
          }
        ]
      }
    },
    "bonusFeatures": {
      "modelInitiatedResourceRead": {
        "status": "full",
        "notes": "The same three tool names as opencode and Codex, each permission-gated.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "Kilo-Org/kilocode",
            "date": "2026-11-10",
            "commit": "278edf3a",
            "path": "packages/opencode/src/session/tools.ts:41-43"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "Kilo-Org/kilocode",
            "date": "2026-11-10",
            "commit": "278edf3a",
            "path": "packages/opencode/src/permission/index.ts:507"
          }
        ],
        "research": [
          "model-initiated-resource-read"
        ]
      },
      "patchedSdkSessionRecovery": {
        "status": "full",
        "notes": "opencode's session-recovery patch carried forward onto SDK 1.32.1: a 404 on a request carrying a session id re-initializes and retries once. The patch also adds offline_access scope selection and keeps output validators across paginated tools/list pages.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "Kilo-Org/kilocode",
            "date": "2026-11-10",
            "commit": "278edf3a",
            "path": "patches/@modelcontextprotocol%2Fsdk@1.32.1.patch"
          }
        ],
        "research": [
          "opencode-patches-its-sdk-for-session-recovery"
        ]
      }
    },
    "research": [
      "kilocode-runs-opencodes-mcp-client-behind-every-surface",
      "kilocode-adds-cimd-and-pre-connect-token-refresh"
    ],
    "metadata": {
      "vendor": "Kilo Code",
      "openSource": true,
      "license": "MIT",
      "sourceUrl": "https://github.com/Kilo-Org/kilocode",
      "lastVerified": "2026-11-10",
      "source": {
        "repo": "https://github.com/Kilo-Org/kilocode.git",
        "ref": "main",
        "checkedCommit": "278edf3a3eea1944ab1b14a5989f850df4a9056b",
        "commitDate": "2026-11-10T14:44:31Z",
        "checkedAt": "2026-11-10",
        "paths": [
          "packages/opencode/src/mcp/index.ts",
          "packages/opencode/src/mcp/catalog.ts",
          "packages/opencode/src/mcp/oauth-provider.ts",
          "packages/opencode/src/session/tools.ts",
          "packages/opencode/src/command/index.ts",
          "packages/opencode/src/kilocode/mcp/",
          "packages/opencode/src/kilocode/tool/code-mode.ts",
          "packages/opencode/src/effect/runtime-flags.ts",
          "packages/kilo-vscode/src/services/cli-backend/server-manager.ts",
          "packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloBackendCliManager.kt",
          "patches/@modelcontextprotocol%2Fsdk@1.32.1.patch"
        ]
      },
      "sdk": {
        "name": "@modelcontextprotocol/sdk",
        "language": "typescript",
        "official": true,
        "declared": "1.32.1",
        "resolved": "1.32.1",
        "patched": true,
        "pinsProtocolVersion": "2025-11-25",
        "notes": "Pinned exactly in packages/opencode and patched through bun's patchedDependencies. 1.32.1 sets LATEST_PROTOCOL_VERSION to 2025-11-25 and supports back to 2024-10-07, so the SDK decides the revision. Upstream opencode has since moved to @modelcontextprotocol/client 2.4.0; Kilo's v2 branch is on @modelcontextprotocol/client 2.3.1, also patched, and main has not followed.",
        "evidence": [
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "Kilo-Org/kilocode",
            "date": "2026-11-10",
            "commit": "278edf3a",
            "path": "packages/opencode/package.json:109"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "Kilo-Org/kilocode",
            "date": "2026-11-10",
            "commit": "278edf3a",
            "path": "bun.lock:623,1034,1919"
          },
          {
            "tier": "read",
            "at": "2025-11-25",
            "source": "@modelcontextprotocol/sdk",
            "url": "https://www.npmjs.com/package/@modelcontextprotocol/sdk/v/1.32.1",
            "date": "2026-11-10",
            "path": "dist/esm/types.js:2-4"
          }
        ],
        "research": [
          "kilocode-runs-opencodes-mcp-client-behind-every-surface"
        ]
      }
    }
  },
  "antigravity": {
    "title": "Google Antigravity",
    "clientInfoNames": [
      "Antigravity",
      "Antigravity-Client",
      "antigravity",
      "antigravity-client"
    ],
    "url": "https://antigravity.google",
    "description": "Google's agentic IDE and CLI, the successor to Gemini CLI for consumer accounts. Closed source, so nothing here is a read. The entry joins Apify's curated record, unchanged since November 2025, to Hugging Face MCP traffic, and the two disagree on protocol revision and elicitation.",
    "category": "ide",
    "platforms": [
      "windows",
      "macos",
      "linux"
    ],
    "protocolVersions": [
      "2024-11-05",
      "2025-03-26",
      "2025-06-18",
      "2025-11-25",
      "2026-07-28"
    ],
    "preferredProtocolVersion": "2026-07-28",
    "transports": {
      "stdio": {
        "status": "full",
        "evidence": [
          {
            "tier": "declared",
            "at": "2025-06-18",
            "source": "apify/mcp-client-capabilities",
            "url": "https://github.com/apify/mcp-client-capabilities/blob/2b28e97/src/mcp_client_capabilities/mcp-clients.json",
            "date": "2026-11-11",
            "commit": "2b28e97"
          }
        ]
      }
    },
    "tools": {
      "status": "full",
      "notes": "Hugging Face traffic includes tool calls from clients sending these names, so the agent does call MCP tools.",
      "evidence": [
        {
          "tier": "declared",
          "at": "2025-06-18",
          "source": "apify/mcp-client-capabilities",
          "url": "https://github.com/apify/mcp-client-capabilities/blob/2b28e97/src/mcp_client_capabilities/mcp-clients.json",
          "date": "2026-11-11",
          "commit": "2b28e97"
        }
      ]
    },
    "resources": {
      "status": "unsupported",
      "evidence": [
        {
          "tier": "declared",
          "at": "2025-06-18",
          "source": "apify/mcp-client-capabilities",
          "url": "https://github.com/apify/mcp-client-capabilities/blob/2b28e97/src/mcp_client_capabilities/mcp-clients.json",
          "date": "2026-11-11",
          "commit": "2b28e97",
          "note": "No resources key on the antigravity-client record."
        }
      ]
    },
    "prompts": {
      "status": "unsupported",
      "evidence": [
        {
          "tier": "declared",
          "at": "2025-06-18",
          "source": "apify/mcp-client-capabilities",
          "url": "https://github.com/apify/mcp-client-capabilities/blob/2b28e97/src/mcp_client_capabilities/mcp-clients.json",
          "date": "2026-11-11",
          "commit": "2b28e97",
          "note": "No prompts key on the antigravity-client record."
        }
      ]
    },
    "sampling": {
      "status": "unsupported",
      "evidence": [
        {
          "tier": "declared",
          "at": "2025-06-18",
          "source": "apify/mcp-client-capabilities",
          "url": "https://github.com/apify/mcp-client-capabilities/blob/2b28e97/src/mcp_client_capabilities/mcp-clients.json",
          "date": "2026-11-11",
          "commit": "2b28e97",
          "note": "No sampling key on the antigravity-client record."
        }
      ]
    },
    "elicitation": {
      "status": "untested",
      "notes": "The tiers disagree. Apify's record has no elicitation key at 2025-06-18. Hugging Face traffic sets both elicitation and URL elicitation, with no revision recorded. Neither tier exercised it, and the source cannot be read.",
      "evidence": [
        {
          "tier": "declared",
          "at": "2025-06-18",
          "source": "apify/mcp-client-capabilities",
          "url": "https://github.com/apify/mcp-client-capabilities/blob/2b28e97/src/mcp_client_capabilities/mcp-clients.json",
          "date": "2026-11-11",
          "commit": "2b28e97",
          "status": "unsupported",
          "note": "No elicitation key on the antigravity-client record."
        }
      ]
    },
    "roots": {
      "status": "full",
      "listChanged": {
        "status": "full"
      },
      "evidence": [
        {
          "tier": "declared",
          "at": "2025-06-18",
          "source": "apify/mcp-client-capabilities",
          "url": "https://github.com/apify/mcp-client-capabilities/blob/2b28e97/src/mcp_client_capabilities/mcp-clients.json",
          "date": "2026-11-11",
          "commit": "2b28e97",
          "note": "Records roots with listChanged: true."
        }
      ]
    },
    "research": [
      "gemini-cli-succeeded-by-closed-source-antigravity"
    ],
    "metadata": {
      "vendor": "Google",
      "openSource": false
    }
  }
}
