# /mcp/read-resource/{channel}

> Kind 3: One resource of the caller’s servers, read. The ask carries the params as JSON; the server sends exactly one message, a result or an error, and closes the connection.

Canonical: https://provider.diverge.network/2.3.0/proxy/mcp/read-resource/
Specification revision: 2.3.0

The ask is kind `3` on [`/requests`](/2.3.0/proxy/requests/). Its
payload is the JSON of the params defined below, running to the end
of the message. The server answers on `/mcp/read-resource/{channel}` by
sending exactly one message and closing the connection. The message
is the response frame defined below: its first byte is `0`, followed
by the result as JSON, or `1`, followed by the error as JSON.
A path that the proxy or the server closes cleanly with no message
before the close states that the ask was not served. An abrupt end of the path, and a `/requests` connection
that ends before the server opens the path, leave the exchange
unanswered, and the proxy asks it again, as
[MCP Exchanges](/2.3.0/proxy/mcp/) provides.

The params are defined by `diverge-provider-sdk/src/shared/mcp/read_resource/request/request.rs`:

```rust
//! Asking for a resource to be read.

use rmcp::model::{ReadResourceRequestParams};
use serde_json::Error;

use crate::decode::Decode;
use crate::encode::{Encode, Writer};

/// The URI of a resource.
///
/// The URI is the server's to interpret. A relay that resolved one
/// would be deciding what a resource is.
///
/// # It is a wrapper, and a thin one
///
/// [`rmcp`] already defines the shape and this crate has no business
/// redefining it — an MCP request has one form and it is MCP's. What
/// the wrapper adds is the two impls beneath it, so that a channel
/// request carrying one writes `request.encode(out)` like every other
/// payload in this crate rather than reaching for `serde_json` itself.
#[derive(Debug, Clone, PartialEq)]
pub struct Request(
    /// The parameters, as [`rmcp`] defines them.
    pub ReadResourceRequestParams,
);

/// Its JSON, and nothing in front of it. The tag that says which
/// request this is belongs to whichever frame carries it.
impl Encode for Request {
    /// The ordinary JSON failure.
    type Error = Error;

    fn encode(&self, out: &mut Writer<'_>) -> Result<(), Error> {
        serde_json::to_writer(out, &self.0)
    }
}

impl Decode<'_> for Request {
    /// The ordinary JSON failure. There is nothing else here to get
    /// wrong — no tag to be unknown, and no empty case, since no bytes
    /// at all is a JSON document that ended too early and is reported
    /// as one.
    type Error = Error;

    fn decode(bytes: &[u8]) -> Result<Self, Error> {
        serde_json::from_slice(bytes).map(Request)
    }
}
```

The answer is defined by `diverge-provider-sdk/src/shared/mcp/read_resource/response/frame.rs`:

```rust
//! What reading a resource produced.

use rmcp::ErrorData;
use rmcp::model::ReadResourceResult;

use super::super::super::FrameError;
use crate::decode::Decode;
use crate::encode::{Encode, Writer};

/// The resource's contents, or the reason there are none.
///
/// A payload leads with one byte saying which — `0` for
/// [`Result`](Self::Result), `1` for [`Error`](Self::Error) — and the
/// rest is that variant's own JSON.
///
/// # One frame, then the finish
///
/// A read is answered once. There is no head, no body, and nothing
/// to reassemble.
///
/// # The error is [`rmcp`]'s, not this crate's
///
/// Everywhere else in this protocol a failure travels as
/// [`shared::error::Error`](crate::shared::error::Error), which is one
/// opaque JSON value, because everywhere else the failure is the
/// PROVIDER's own and it is nobody's business what it says.
///
/// This one is not the provider's. It is an MCP server's, relayed, and
/// its JSON-RPC code is content rather than detail: `-32601` is "no
/// such tool" and `-32602` is "the arguments were wrong", and an agent
/// told only that something failed cannot tell those apart or act
/// differently on them.
///
/// So the code goes through, along with the message and whatever data
/// came with it. A relay that flattened them would be deciding that an
/// MCP error means less than MCP says it does.
#[derive(Debug, Clone, PartialEq)]
pub enum Frame {
    /// The contents. Tag `0`.
    Result(ReadResourceResult),
    /// The server refused or could not answer. Tag `1`.
    ///
    /// See the type's own documentation for why this is
    /// [`ErrorData`] rather than the error every other endpoint uses.
    Error(ErrorData),
}

/// Tag for [`Frame::Result`].
const RESULT: u8 = 0;

/// Tag for [`Frame::Error`].
const ERROR: u8 = 1;

impl Encode for Frame {
    /// The ordinary JSON failure. Both variants are serialized and the
    /// tag cannot fail.
    type Error = serde_json::Error;

    // Spelled out rather than `Self::Error`: this enum has a variant
    // called `Error`, so the associated type is ambiguous by that name.
    fn encode(&self, out: &mut Writer<'_>) -> Result<(), serde_json::Error> {
        match self {
            Frame::Result(value) => {
                out.extend_from_slice(&[RESULT]);
                serde_json::to_writer(out, value)
            }
            Frame::Error(error) => {
                out.extend_from_slice(&[ERROR]);
                serde_json::to_writer(out, error)
            }
        }
    }
}

impl Decode<'_> for Frame {
    /// Three ways to fail, and only one of them is JSON.
    type Error = FrameError;

    // Spelled out for the same reason as `encode` above.
    fn decode(bytes: &[u8]) -> Result<Self, FrameError> {
        let (tag, rest) = bytes.split_first().ok_or(FrameError::Empty)?;
        match *tag {
            RESULT => serde_json::from_slice(rest)
                .map(Frame::Result)
                .map_err(FrameError::Body),
            ERROR => serde_json::from_slice(rest)
                .map(Frame::Error)
                .map_err(FrameError::Body),
            tag => Err(FrameError::UnknownTag(tag)),
        }
    }
}
```
