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