Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

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

Đang mở
#1,337 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 3 ngày

@Cassian433 đang làm issue này rồi.

Từ ngày 11/10/2026.

  • #1340 của @Cassian433 — đang mở

Đánh giá

Độ khó
3/5
Thời gian dự kiến
1-2 ngày
Mức phù hợp với người mới
28/100
Loại issue
Lỗi
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
rust
Lĩnh vực
api

Hướng nghiên cứu

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.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

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).

Ngôn ngữ chính
Rust
Star
4k
Fork
654
Merge trung bình
3 ngày 4 giờ
Pull request đã merge (30 ngày)
37

Chuẩn bị môi trường

Mở trong Codespaces

Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của modelcontextprotocol/rust-sdk

Tất cả issue của modelcontextprotocol/rust-sdk

Issue tương tự

Thêm issue về Rust

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.