Files
codex/prs/bolinfest/study/PR-1621-study.md
2025-09-02 15:17:45 -07:00

6.9 KiB
Raw Blame History

DOs

  • Boldly update MCP schema version: set to 2025-06-18 and regenerate types.

    // codex-rs/mcp-types/src/lib.rs
    pub const MCP_SCHEMA_VERSION: &str = "2025-06-18";
    
    # codex-rs/mcp-types/generate_mcp_types.py
    SCHEMA_VERSION = "2025-06-18"
    
    # codex-rs/mcp-types/README.md
    https://modelcontextprotocol.io/specification/2025-06-18/basic
    
  • Prefer ContentBlock everywhere tool results or prompt content appear.

    use mcp_types::{CallToolResult, ContentBlock, TextContent};
    
    let result = CallToolResult {
        content: vec![ContentBlock::TextContent(TextContent {
            r#type: "text".into(),
            text: "Done".into(),
            annotations: None,
            _meta: None,
        })],
        is_error: None,
        structured_content: None,
    };
    
  • Return structuredContent for machine-readable tool output.

    use serde_json::json;
    
    let result = CallToolResult {
        content: vec![ContentBlock::TextContent(TextContent {
            r#type: "text".into(),
            text: "Indexed 3 files".into(),
            annotations: None,
            _meta: None,
        })],
        is_error: None,
        structured_content: Some(json!({ "indexed_count": 3 })),
    };
    
  • Handle new ResourceLink in UIs and clients.

    use mcp_types::ContentBlock;
    
    match block {
        ContentBlock::TextContent(t) => println!("{}", t.text),
        ContentBlock::ImageContent(_) => println!("<image>"),
        ContentBlock::AudioContent(_) => println!("<audio>"),
        ContentBlock::EmbeddedResource(r) => println!("embedded: {}", r.resource_uri()),
        ContentBlock::ResourceLink(link) => println!("link: {}", link.uri),
    }
    
  • Add title to Implementation and Tool for better UX.

    use mcp_types::Implementation;
    
    let client_info = Implementation {
        name: "codex-mcp-client".into(),
        title: Some("Codex".into()),
        version: env!("CARGO_PKG_VERSION").into(),
    };
    
    use mcp_types::{Tool, ToolInputSchema};
    
    let tool = Tool {
        name: "codex".into(),
        title: Some("Codex".into()),
        description: Some("Run a Codex session.".into()),
        input_schema: ToolInputSchema { r#type: "object".into(), properties: None, required: None },
        output_schema: None,
        annotations: None,
        _meta: None,
    };
    
  • Implement elicitation support: advertise capability and handle requests/results.

    use mcp_types::{ClientCapabilities, ElicitRequestParams, ElicitResult, ElicitRequestParamsRequestedSchema};
    
    let capabilities = ClientCapabilities {
        elicitation: Some(serde_json::json!({})),
        experimental: None, roots: None, sampling: None
    };
    
    let req = ElicitRequestParams {
        message: "Please confirm deletion".into(),
        requested_schema: ElicitRequestParamsRequestedSchema {
            r#type: "object".into(),
            properties: serde_json::json!({
                "confirm": { "type": "boolean", "title": "Confirm" }
            }),
            required: Some(vec!["confirm".into()]),
        },
    };
    
    let res = ElicitResult { action: "accept".into(), content: Some(serde_json::json!({"confirm": true})) };
    
  • Use ResourceTemplateReference when completing arguments (replaces ResourceReference).

    use mcp_types::{CompleteRequestParamsRef, ResourceTemplateReference};
    
    let r = CompleteRequestParamsRef::ResourceTemplateReference(ResourceTemplateReference {
        r#type: "ref/resource".into(),
        uri: "file:///repo/{path}".into(),
    });
    
  • Replace JSON-RPC batch handling with single-message handling.

    use mcp_types::JSONRPCMessage;
    
    match msg {
        JSONRPCMessage::Request(r) => process_request(r),
        JSONRPCMessage::Notification(n) => process_notification(n),
        JSONRPCMessage::Response(r) => process_response(r),
        JSONRPCMessage::Error(e) => process_error(e),
    }
    
  • Box error payloads where needed and deref at callsites.

    // callee
    fn parse_container_exec_arguments(...) -> Result<ExecParams, Box<ResponseInputItem>> {
        // ...
        Err(Box::new(output))
    }
    
    // caller
    let params = match parse_container_exec_arguments(arguments, sess, &call_id) {
        Ok(p) => p,
        Err(output) => return *output,
    };
    
  • Map enum property safely with r#enum when generating/using schemas.

    use mcp_types::EnumSchema;
    
    let schema = EnumSchema {
        r#enum: vec!["one".into(), "two".into()],
        enum_names: None,
        description: Some("Choose a value".into()),
        title: Some("Value".into()),
        r#type: "string".into(),
    };
    
  • Update tests to include new fields and versions.

    use mcp_types::{InitializeRequestParams, Implementation, MCP_SCHEMA_VERSION};
    
    let params = InitializeRequestParams {
        capabilities: Default::default(),
        client_info: Implementation { name: "acme-client".into(), title: Some("Acme".into()), version: "1.2.3".into() },
        protocol_version: MCP_SCHEMA_VERSION.into(),
    };
    
  • Keep tool error reporting inside CallToolResult with is_error = true.

    let err = CallToolResult {
        content: vec![ContentBlock::TextContent(TextContent {
            r#type: "text".into(),
            text: format!("Failed to start Codex session: {e}"),
            annotations: None,
            _meta: None,
        })],
        is_error: Some(true),
        structured_content: None,
    };
    

DONTs

  • Dont use removed types: CallToolResultContent, PromptMessageContent, ResourceReference, JSONRPCBatchRequest/JSONRPCBatchResponse.

    // BAD (removed):
    // let x: CallToolResultContent = CallToolResultContent::TextContent(...);
    // let y: JSONRPCMessage = JSONRPCMessage::BatchRequest(vec![]);
    
  • Dont forget structuredContent when returning machine-readable results.

    // BAD: drops structure, harder for clients to consume
    CallToolResult { content: vec![...], is_error: None, structured_content: None }
    
  • Dont ignore ResourceLink in renderers; links will be lost to users.

    // BAD: missing match arm for ContentBlock::ResourceLink(...)
    
  • Dont send protocol-level JSONRPCError for tool-level failures; set is_error instead.

    // BAD:
    // JSONRPCMessage::Error(JSONRPCError { ... "tool failed" ... })
    
  • Dont omit title in Implementation/Tool when a human-friendly label exists.

    // BAD:
    Implementation { name: "codex-mcp-client".into(), title: None, version: "…".into() }
    
  • Dont return unboxed error values when the function signature expects Box.

    // BAD:
    // fn parse(... ) -> Result<_, Box<ResponseInputItem>> { Err(output) } // not boxed
    
  • Dont keep JSON-RPC batch handling code; its no longer part of the schema.

    // BAD:
    // fn process_batch_request(...) { … }
    // fn process_batch_response(...) { … }
    
  • Dont leave stray typos or debug text in comments.

    - // Run the Codex session and stream events Fck to the client.
    + // Run the Codex session and stream events to the client.