Skip to content

Commit 33268aa

Browse files
committed
feat: add server/discover model types
Add the SEP-2575 server/discover request and result model, wire it into the JSON-RPC request/result unions, and cover basic serde routing. Fixes #869
1 parent 67a3085 commit 33268aa

8 files changed

Lines changed: 281 additions & 55 deletions

crates/rmcp/src/handler/server.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ impl<H: ServerHandler> Service<RoleServer> for H {
2727
// `context` is moved into the dispatch below, so read the negotiated version first.
2828
let protocol_version = context.protocol_version();
2929
let result = match request {
30+
ClientRequest::DiscoverRequest(_request) => {
31+
Err(McpError::method_not_found::<DiscoverRequestMethod>())
32+
}
3033
ClientRequest::InitializeRequest(request) => self
3134
.initialize(request.params, context)
3235
.await

crates/rmcp/src/model.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,55 @@ impl CustomRequest {
808808
}
809809
}
810810

811+
const_string!(DiscoverRequestMethod = "server/discover");
812+
813+
/// Sent from the client to discover server identity, capabilities, and supported protocol versions.
814+
pub type DiscoverRequest = Request<DiscoverRequestMethod, EmptyObject>;
815+
816+
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
817+
#[serde(rename_all = "camelCase")]
818+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
819+
#[non_exhaustive]
820+
pub struct DiscoverResult {
821+
pub supported_versions: Vec<ProtocolVersion>,
822+
pub capabilities: ServerCapabilities,
823+
pub server_info: Implementation,
824+
#[serde(skip_serializing_if = "Option::is_none")]
825+
pub instructions: Option<String>,
826+
#[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
827+
pub meta: Option<Meta>,
828+
}
829+
830+
impl DiscoverResult {
831+
pub fn new(
832+
supported_versions: impl Into<Vec<ProtocolVersion>>,
833+
capabilities: ServerCapabilities,
834+
) -> Self {
835+
Self {
836+
supported_versions: supported_versions.into(),
837+
capabilities,
838+
server_info: Implementation::from_build_env(),
839+
instructions: None,
840+
meta: None,
841+
}
842+
}
843+
844+
pub fn with_server_info(mut self, server_info: Implementation) -> Self {
845+
self.server_info = server_info;
846+
self
847+
}
848+
849+
pub fn with_instructions(mut self, instructions: impl Into<String>) -> Self {
850+
self.instructions = Some(instructions.into());
851+
self
852+
}
853+
854+
pub fn with_meta(mut self, meta: Meta) -> Self {
855+
self.meta = Some(meta);
856+
self
857+
}
858+
}
859+
811860
const_string!(InitializeResultMethod = "initialize");
812861
/// # Initialization
813862
/// This request is sent from the client to the server when it first connects, asking it to begin initialization.
@@ -3572,6 +3621,7 @@ macro_rules! ts_union {
35723621

35733622
ts_union!(
35743623
export type ClientRequest =
3624+
| DiscoverRequest
35753625
| PingRequest
35763626
| InitializeRequest
35773627
| CompleteRequest
@@ -3595,6 +3645,7 @@ ts_union!(
35953645
impl ClientRequest {
35963646
pub fn method(&self) -> &str {
35973647
match &self {
3648+
ClientRequest::DiscoverRequest(r) => r.method.as_str(),
35983649
ClientRequest::PingRequest(r) => r.method.as_str(),
35993650
ClientRequest::InitializeRequest(r) => r.method.as_str(),
36003651
ClientRequest::CompleteRequest(r) => r.method.as_str(),
@@ -3669,6 +3720,7 @@ ts_union!(
36693720

36703721
ts_union!(
36713722
export type ServerResult =
3723+
| DiscoverResult
36723724
| InitializeResult
36733725
| CompleteResult
36743726
| GetPromptResult

crates/rmcp/src/model/meta.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ macro_rules! variant_extension {
138138

139139
variant_extension! {
140140
ClientRequest {
141+
DiscoverRequest
141142
PingRequest
142143
InitializeRequest
143144
CompleteRequest

crates/rmcp/tests/test_deserialization.rs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,50 @@
1-
use rmcp::model::{JsonRpcResponse, ServerJsonRpcMessage, ServerResult};
1+
use rmcp::model::{
2+
ClientJsonRpcMessage, ClientRequest, JsonRpcResponse, ServerJsonRpcMessage, ServerResult,
3+
};
4+
use serde_json::json;
5+
6+
#[test]
7+
fn test_discover_request() {
8+
let message: ClientJsonRpcMessage = serde_json::from_value(json!({
9+
"jsonrpc": "2.0",
10+
"id": 1,
11+
"method": "server/discover",
12+
"params": {}
13+
}))
14+
.unwrap();
15+
16+
assert!(matches!(
17+
message,
18+
ClientJsonRpcMessage::Request(r)
19+
if matches!(r.request, ClientRequest::DiscoverRequest(_))
20+
));
21+
}
22+
23+
#[test]
24+
fn test_discover_result() {
25+
let message: ServerJsonRpcMessage = serde_json::from_value(json!({
26+
"jsonrpc": "2.0",
27+
"id": 1,
28+
"result": {
29+
"supportedVersions": ["2026-07-28", "2025-11-25"],
30+
"capabilities": {},
31+
"serverInfo": {
32+
"name": "test-server",
33+
"version": "1.0.0"
34+
}
35+
}
36+
}))
37+
.unwrap();
38+
39+
assert!(matches!(
40+
message,
41+
ServerJsonRpcMessage::Response(JsonRpcResponse {
42+
result: ServerResult::DiscoverResult(_),
43+
..
44+
})
45+
));
46+
}
47+
248
#[test]
349
fn test_tool_list_result() {
450
let json = std::fs::read("tests/test_deserialization/tool_list_result.json").unwrap();

crates/rmcp/tests/test_message_schema/client_json_rpc_message_schema.json

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,11 @@
530530
"CustomResult": {
531531
"description": "A catch-all response either side can use for custom requests."
532532
},
533+
"DiscoverRequestMethod": {
534+
"type": "string",
535+
"format": "const",
536+
"const": "server/discover"
537+
},
533538
"ElicitResult": {
534539
"description": "The result returned by a client in response to an elicitation request.\n\nContains the user's decision (accept/decline/cancel) and optionally their input data\nif they chose to accept the request.",
535540
"type": "object",
@@ -1038,10 +1043,10 @@
10381043
},
10391044
"anyOf": [
10401045
{
1041-
"$ref": "#/definitions/RequestNoParam"
1046+
"$ref": "#/definitions/Request"
10421047
},
10431048
{
1044-
"$ref": "#/definitions/Request"
1049+
"$ref": "#/definitions/RequestNoParam"
10451050
},
10461051
{
10471052
"$ref": "#/definitions/Request2"
@@ -1052,6 +1057,9 @@
10521057
{
10531058
"$ref": "#/definitions/Request4"
10541059
},
1060+
{
1061+
"$ref": "#/definitions/Request5"
1062+
},
10551063
{
10561064
"$ref": "#/definitions/RequestOptionalParam"
10571065
},
@@ -1061,9 +1069,6 @@
10611069
{
10621070
"$ref": "#/definitions/RequestOptionalParam3"
10631071
},
1064-
{
1065-
"$ref": "#/definitions/Request5"
1066-
},
10671072
{
10681073
"$ref": "#/definitions/Request6"
10691074
},
@@ -1073,20 +1078,23 @@
10731078
{
10741079
"$ref": "#/definitions/Request8"
10751080
},
1081+
{
1082+
"$ref": "#/definitions/Request9"
1083+
},
10761084
{
10771085
"$ref": "#/definitions/RequestOptionalParam4"
10781086
},
10791087
{
1080-
"$ref": "#/definitions/Request9"
1088+
"$ref": "#/definitions/Request10"
10811089
},
10821090
{
10831091
"$ref": "#/definitions/RequestOptionalParam5"
10841092
},
10851093
{
1086-
"$ref": "#/definitions/Request10"
1094+
"$ref": "#/definitions/Request11"
10871095
},
10881096
{
1089-
"$ref": "#/definitions/Request11"
1097+
"$ref": "#/definitions/Request12"
10901098
},
10911099
{
10921100
"$ref": "#/definitions/CustomRequest"
@@ -1426,10 +1434,10 @@
14261434
"type": "object",
14271435
"properties": {
14281436
"method": {
1429-
"$ref": "#/definitions/InitializeResultMethod"
1437+
"$ref": "#/definitions/DiscoverRequestMethod"
14301438
},
14311439
"params": {
1432-
"$ref": "#/definitions/InitializeRequestParams"
1440+
"$ref": "#/definitions/EmptyObject"
14331441
}
14341442
},
14351443
"required": [
@@ -1438,6 +1446,22 @@
14381446
]
14391447
},
14401448
"Request10": {
1449+
"description": "Represents a JSON-RPC request with method, parameters, and extensions.\n\nThis is the core structure for all MCP requests, containing:\n- `method`: The name of the method being called\n- `params`: The parameters for the method\n- `extensions`: Additional context data (similar to HTTP headers)",
1450+
"type": "object",
1451+
"properties": {
1452+
"method": {
1453+
"$ref": "#/definitions/GetTaskMethod"
1454+
},
1455+
"params": {
1456+
"$ref": "#/definitions/GetTaskParams"
1457+
}
1458+
},
1459+
"required": [
1460+
"method",
1461+
"params"
1462+
]
1463+
},
1464+
"Request11": {
14411465
"description": "Represents a JSON-RPC request with method, parameters, and extensions.\n\nThis is the core structure for all MCP requests, containing:\n- `method`: The name of the method being called\n- `params`: The parameters for the method\n- `extensions`: Additional context data (similar to HTTP headers)",
14421466
"type": "object",
14431467
"properties": {
@@ -1453,7 +1477,7 @@
14531477
"params"
14541478
]
14551479
},
1456-
"Request11": {
1480+
"Request12": {
14571481
"description": "Represents a JSON-RPC request with method, parameters, and extensions.\n\nThis is the core structure for all MCP requests, containing:\n- `method`: The name of the method being called\n- `params`: The parameters for the method\n- `extensions`: Additional context data (similar to HTTP headers)",
14581482
"type": "object",
14591483
"properties": {
@@ -1474,10 +1498,10 @@
14741498
"type": "object",
14751499
"properties": {
14761500
"method": {
1477-
"$ref": "#/definitions/CompleteRequestMethod"
1501+
"$ref": "#/definitions/InitializeResultMethod"
14781502
},
14791503
"params": {
1480-
"$ref": "#/definitions/CompleteRequestParams"
1504+
"$ref": "#/definitions/InitializeRequestParams"
14811505
}
14821506
},
14831507
"required": [
@@ -1490,10 +1514,10 @@
14901514
"type": "object",
14911515
"properties": {
14921516
"method": {
1493-
"$ref": "#/definitions/SetLevelRequestMethod"
1517+
"$ref": "#/definitions/CompleteRequestMethod"
14941518
},
14951519
"params": {
1496-
"$ref": "#/definitions/SetLevelRequestParams"
1520+
"$ref": "#/definitions/CompleteRequestParams"
14971521
}
14981522
},
14991523
"required": [
@@ -1506,10 +1530,10 @@
15061530
"type": "object",
15071531
"properties": {
15081532
"method": {
1509-
"$ref": "#/definitions/GetPromptRequestMethod"
1533+
"$ref": "#/definitions/SetLevelRequestMethod"
15101534
},
15111535
"params": {
1512-
"$ref": "#/definitions/GetPromptRequestParams"
1536+
"$ref": "#/definitions/SetLevelRequestParams"
15131537
}
15141538
},
15151539
"required": [
@@ -1522,10 +1546,10 @@
15221546
"type": "object",
15231547
"properties": {
15241548
"method": {
1525-
"$ref": "#/definitions/ReadResourceRequestMethod"
1549+
"$ref": "#/definitions/GetPromptRequestMethod"
15261550
},
15271551
"params": {
1528-
"$ref": "#/definitions/ReadResourceRequestParams"
1552+
"$ref": "#/definitions/GetPromptRequestParams"
15291553
}
15301554
},
15311555
"required": [
@@ -1538,10 +1562,10 @@
15381562
"type": "object",
15391563
"properties": {
15401564
"method": {
1541-
"$ref": "#/definitions/SubscribeRequestMethod"
1565+
"$ref": "#/definitions/ReadResourceRequestMethod"
15421566
},
15431567
"params": {
1544-
"$ref": "#/definitions/SubscribeRequestParams"
1568+
"$ref": "#/definitions/ReadResourceRequestParams"
15451569
}
15461570
},
15471571
"required": [
@@ -1554,10 +1578,10 @@
15541578
"type": "object",
15551579
"properties": {
15561580
"method": {
1557-
"$ref": "#/definitions/UnsubscribeRequestMethod"
1581+
"$ref": "#/definitions/SubscribeRequestMethod"
15581582
},
15591583
"params": {
1560-
"$ref": "#/definitions/UnsubscribeRequestParams"
1584+
"$ref": "#/definitions/SubscribeRequestParams"
15611585
}
15621586
},
15631587
"required": [
@@ -1570,10 +1594,10 @@
15701594
"type": "object",
15711595
"properties": {
15721596
"method": {
1573-
"$ref": "#/definitions/CallToolRequestMethod"
1597+
"$ref": "#/definitions/UnsubscribeRequestMethod"
15741598
},
15751599
"params": {
1576-
"$ref": "#/definitions/CallToolRequestParams"
1600+
"$ref": "#/definitions/UnsubscribeRequestParams"
15771601
}
15781602
},
15791603
"required": [
@@ -1586,10 +1610,10 @@
15861610
"type": "object",
15871611
"properties": {
15881612
"method": {
1589-
"$ref": "#/definitions/GetTaskMethod"
1613+
"$ref": "#/definitions/CallToolRequestMethod"
15901614
},
15911615
"params": {
1592-
"$ref": "#/definitions/GetTaskParams"
1616+
"$ref": "#/definitions/CallToolRequestParams"
15931617
}
15941618
},
15951619
"required": [

0 commit comments

Comments
 (0)