Skip to main content

wire/answer/
mcp_health.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4// Copyright (c) 2026 2youg1 and the sprawling contributors
5
6//! Where each tool server one address reaches stands, and what it
7//! offers.
8
9use kernel::{Address, AxError, Payload, ServerLabel};
10use serde::{Deserialize, Serialize};
11
12/// One line per server the address's configuration names, in the order
13/// the configuration names them.
14///
15/// Order is the file's rather than best-first: somebody scanning this
16/// list twice finds the same server in the same place, and a list that
17/// reordered itself as servers came and went could not be scanned at
18/// all.
19#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
20#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
21pub struct McpHealthAnswer {
22    pub addr: Address,
23    pub servers: Vec<McpServerHealth>,
24}
25
26/// One server, as the handshake found it.
27#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
28#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
29pub struct McpServerHealth {
30    pub label: ServerLabel,
31    /// How this server is reached, in the word a person chose: `stdio`,
32    /// `http` or `sse`.
33    pub transport: String,
34    /// The command line or the url, whichever this transport is.
35    pub target: String,
36    pub state: McpState,
37}
38
39/// The three answers a handshake can come back with.
40///
41/// Exhaustive rather than a flag beside an optional reason: "it is
42/// answering", "it wants an account" and "it failed, and here is why"
43/// are three different things for a person to do next, and a shape that
44/// left the reason optional would let a failure travel without one.
45#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
46#[serde(rename_all = "snake_case")]
47#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
48pub enum McpState {
49    /// It answered, and here is everything it offers.
50    Connected {
51        /// The revision the far end agreed to, which is not always the
52        /// one that was asked for.
53        protocol_version: String,
54        /// What the server calls itself.
55        server: String,
56        tools: Vec<McpToolLine>,
57    },
58    /// It is up and it understood the request, and it wants an account
59    /// this city does not hold yet. Its own state rather than a
60    /// failure, because what a person does about it is sign in rather
61    /// than check the address.
62    Authenticating {
63        /// What to do about it, as the refusal stated it.
64        recovery: String,
65    },
66    /// It did not answer, and the whole refusal travels: the action that
67    /// failed, the subject it failed on, the stable code, and the
68    /// recovery a person can act on.
69    Failed { refusal: Box<AxError> },
70}
71
72/// One tool a server offers, under the name the model sees it by.
73#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
74#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
75pub struct McpToolLine {
76    /// The name the server knows it by, which is what a person reading
77    /// that server's own documentation will find.
78    pub remote: String,
79    /// The name this city knows it by: the server's label, then the
80    /// remote name. This is what appears in a run's history.
81    pub name: String,
82    pub disclosure: String,
83    /// The tool's input schema, exactly as the server published it. Not
84    /// summarised here: a schema is what a person checks a tool's
85    /// arguments against, and a summary would be a second, lossy
86    /// authority on what the server accepts.
87    pub input_schema: Payload,
88}