objectiveai_sdk/agent/mcp.rs
1//! MCP server configuration for agents.
2
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6/// An MCP server that the agent can connect to.
7#[derive(
8 Debug,
9 Clone,
10 Serialize,
11 Deserialize,
12 PartialEq,
13 Eq,
14 PartialOrd,
15 Ord,
16 JsonSchema,
17 arbitrary::Arbitrary,
18)]
19#[schemars(rename = "agent.McpServer")]
20pub struct McpServer {
21 /// The URL of the MCP server.
22 pub url: String,
23 /// Whether this MCP server uses authorization.
24 #[serde(default)]
25 pub authorization: bool,
26}
27
28impl McpServer {
29 /// Validates the MCP server configuration.
30 ///
31 /// The URL must start with `http://localhost` or `https://`.
32 pub fn validate(&self) -> Result<(), String> {
33 // if !self.url.starts_with("http://localhost") && !self.url.starts_with("https://") {
34 // return Err(format!(
35 // "`mcp.url` must start with \"http://localhost\" or \"https://\", got: \"{}\"",
36 // self.url
37 // ));
38 // }
39 Ok(())
40 }
41}
42
43/// A list of MCP servers.
44pub type McpServers = Vec<McpServer>;
45
46pub mod mcp_servers {
47 //! Functions for working with [`McpServers`](super::McpServers).
48
49 /// Validates all MCP servers in the list.
50 ///
51 /// Checks that no duplicate servers exist.
52 pub fn validate(this: &super::McpServers) -> Result<(), String> {
53 for server in this {
54 server.validate()?;
55 }
56 for (i, a) in this.iter().enumerate() {
57 for b in &this[i + 1..] {
58 if a == b {
59 return Err(format!(
60 "`mcp_servers` contains duplicate entry: \"{}\"",
61 a.url
62 ));
63 }
64 }
65 }
66 Ok(())
67 }
68
69 /// Sorts the MCP servers for deterministic ordering.
70 ///
71 /// Empty lists become `None`.
72 pub fn prepare(mut this: super::McpServers) -> Option<super::McpServers> {
73 if this.is_empty() {
74 None
75 } else {
76 this.sort();
77 Some(this)
78 }
79 }
80}