Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

Non-object outputSchema and structuredContent are sent to clients that negotiated 2025-06-18 / 2025-11-25, where an object is required

未关闭
#1,337 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 3 天内回复

@Cassian433 已经在做这个了。

开始于 2026年10月11日。

  • #1340 来自 @Cassian433 —— 未关闭

评估

难度
3/5
预计耗时
1-2 天
新手友好度
28/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
活跃
技术栈
rust
领域
api

调研方向

Start with strip_output in crates/rmcp/src/handler/server/common.rs, which always keeps non-object output schemas, and with the version gating for result_type in crates/rmcp/src/handler/server.rs. Check that Json<Vec<T>> advertises an array outputSchema and returns a non-object structuredContent for a session negotiated to 2025-06-18. Done means that session omits both for non-object roots while 2026-07-28 keeps them. The issue lists three options, so confirm with maintainers which one to build first.

由索引模型根据 Issue 内容生成。

描述

bug P1 ready for work T-handler T-model

Summary

A tool that returns Json<Vec<T>> (or any non-object type) makes the server advertise a non-object outputSchema, and return a non-object structuredContent, to every client, including clients that negotiated protocol 2025-06-18 or 2025-11-25. In those versions both must be objects, so such a client sees a schema that is invalid for the version it asked for.

This is not a request to undo SEP-2106 (#874); allowing arrays and primitives is right for 2026-07-28. The gap is that the choice does not depend on the negotiated version, although other 2026-07-28 behaviour in handler/server.rs is gated on it.

What the spec versions say

  • 2025-06-18, schema.ts: outputSchema?: { type: "object"; properties?: ...; required?: string[] }
  • 2025-11-25, schema.ts: outputSchema?: { $schema?: string; type: "object"; ... }, and structuredContent?: { [key: string]: unknown }
  • 2026-07-28 (SEP-2106): any JSON Schema 2020-12 schema, any JSON value.

crates/rmcp/src/handler/server/common.rs (strip_output) says output schemas "are not restricted to type: "object" (per SEP-2106)" unconditionally.

Reproduction

rmcp 3.5.1, features = ["server", "macros", "transport-io"].

use rmcp::handler::server::router::tool::ToolRouter;
use rmcp::model::{Implementation, ServerCapabilities, ServerConfig};
use rmcp::{tool, tool_handler, tool_router, Json, ServerHandler, ServiceExt};

#[derive(Clone)]
struct Server { tool_router: ToolRouter<Self> }

#[tool_router]
impl Server {
    #[tool(description = "Returns a list of names")]
    async fn names(&self) -> Json<Vec<String>> {
        Json(vec!["a".to_string(), "b".to_string()])
    }
}

#[tool_handler]
impl ServerHandler for Server {
    fn get_info(&self) -> ServerConfig {
        ServerConfig::new(ServerCapabilities::builder().enable_tools().build())
            .with_server_info(Implementation::new("repro", "0.1.0"))
    }
}

#[tokio::main(flavor = "current_thread")]
async fn main() {
    let server = Server { tool_router: Server::tool_router() };
    server.serve(rmcp::transport::stdio()).await.unwrap().waiting().await.unwrap();
}

A client that asks for 2025-06-18:

{ printf '%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"1"}}}' \
  '{"jsonrpc":"2.0","method":"notifications/initialized"}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
  '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"names","arguments":{}}}'; sleep 1; } | ./target/debug/repro

Output (trimmed):

{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2025-06-18", ...}}
{"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"names", ...,
  "outputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","items":{"type":"string"},"type":"array"}}]}}
{"jsonrpc":"2.0","id":3,"result":{"content":[{"type":"text","text":"[\"a\",\"b\"]"}],"structuredContent":["a","b"],"isError":false}}

The server answers protocolVersion: 2025-06-18 and then advertises outputSchema.type: "array" and returns structuredContent: ["a","b"]. The same happens when the client asks for 2025-11-25. When I asked for 2026-07-28 in initialize, the server answered 2025-11-25 and still advertised the array schema.

Why it matters

A client that validates tools/list against the schema of the negotiated version will reject the tool, and some validate the whole list at once, so one tool with a list result can make every tool unavailable. We hit this shipping an MCP server (metamug/plunger#97); the report there was that the output schema was not an object. I have not checked which specific clients reject it, only that the advertised schema is invalid for the version that was negotiated.

The workaround is to wrap every list in a struct (as suggested in #532), which works everywhere, but it is easy to miss because Json<Vec<T>> compiles and works with clients that are lenient or new.

Suggested behaviour

Any of these would help, in rough order of preference:

  1. For a session that negotiated a version before 2026-07-28, omit outputSchema when its root type is not "object" (the call still works; the result is also in content), and do the same for structuredContent. This follows the version gating already used for result_type.
  2. Offer a wrapper (for example Json<Wrapped<T>>, or an attribute on #[tool]) that produces { "result": T } and an object schema in all versions, so authors have a supported way to be compatible without writing a struct for every list.
  3. At minimum, document on Json<T> and on schema_for_output that a non-object T is only valid for peers on 2026-07-28 and later.

Related: #532 (the same symptom, closed before SEP-2106), #874 (SEP-2106).

主要语言
Rust
星标
4k
派生
654
平均合并
3 天 4 小时
30 天内合并 PR
37

环境准备

在 Codespaces 中打开

在浏览器里用你自己的 GitHub 账号启动这个项目的开发容器。

  • 没有 Dockerfile 或 Docker Compose 文件
  • 没有 Pull Request 模板
  • 阅读贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

modelcontextprotocol/rust-sdk 的其他 Issue

查看 modelcontextprotocol/rust-sdk 的全部 Issue

相似的 Issue

更多 Rust Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。