Codex MCP installation (#345)
This commit is contained in:
@@ -33,6 +33,7 @@ openssl-sys = { workspace = true }
|
||||
rmcp = { version = "0.2.1", features = ["server", "transport-io"] }
|
||||
schemars = "0.8"
|
||||
regex = "1.11.1"
|
||||
toml = "0.8"
|
||||
sentry = { version = "0.41.0", features = ["anyhow", "backtrace", "panic", "debug-images"] }
|
||||
sentry-tracing = { version = "0.41.0", features = ["backtrace"] }
|
||||
reqwest = { version = "0.12", features = ["json"] }
|
||||
|
||||
56
crates/server/src/mcp/agent_config.rs
Normal file
56
crates/server/src/mcp/agent_config.rs
Normal file
@@ -0,0 +1,56 @@
|
||||
//! Utilities for reading and writing external agent config files (not the server's own config).
|
||||
//!
|
||||
//! These helpers abstract over JSON vs TOML formats used by different agents.
|
||||
|
||||
use executors::executors::BaseCodingAgent;
|
||||
use serde_json::Value;
|
||||
use tokio::fs;
|
||||
|
||||
/// Determine if the agent's config file is TOML-based.
|
||||
fn is_toml_config(agent: &BaseCodingAgent) -> bool {
|
||||
matches!(agent, BaseCodingAgent::Codex)
|
||||
}
|
||||
|
||||
/// Read an agent's external config file (JSON or TOML) and normalize it to serde_json::Value.
|
||||
pub async fn read_agent_config(
|
||||
config_path: &std::path::Path,
|
||||
agent: &BaseCodingAgent,
|
||||
) -> Result<Value, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let file_content = fs::read_to_string(config_path).await.unwrap_or_else(|_| {
|
||||
if is_toml_config(agent) {
|
||||
"".to_string()
|
||||
} else {
|
||||
"{}".to_string()
|
||||
}
|
||||
});
|
||||
|
||||
if is_toml_config(agent) {
|
||||
// Parse TOML then convert to JSON Value
|
||||
if file_content.trim().is_empty() {
|
||||
return Ok(serde_json::json!({}));
|
||||
}
|
||||
let toml_val: toml::Value = toml::from_str(&file_content)?;
|
||||
let json_string = serde_json::to_string(&toml_val)?;
|
||||
Ok(serde_json::from_str(&json_string)?)
|
||||
} else {
|
||||
Ok(serde_json::from_str(&file_content)?)
|
||||
}
|
||||
}
|
||||
|
||||
/// Write an agent's external config (as serde_json::Value) back to disk in the agent's format (JSON or TOML).
|
||||
pub async fn write_agent_config(
|
||||
config_path: &std::path::Path,
|
||||
agent: &BaseCodingAgent,
|
||||
config: &Value,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
if is_toml_config(agent) {
|
||||
// Convert JSON Value back to TOML
|
||||
let toml_value: toml::Value = serde_json::from_str(&serde_json::to_string(config)?)?;
|
||||
let toml_content = toml::to_string_pretty(&toml_value)?;
|
||||
fs::write(config_path, toml_content).await?;
|
||||
} else {
|
||||
let json_content = serde_json::to_string_pretty(config)?;
|
||||
fs::write(config_path, json_content).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
pub mod agent_config;
|
||||
pub mod task_server;
|
||||
|
||||
@@ -17,7 +17,11 @@ use tokio::fs;
|
||||
use ts_rs::TS;
|
||||
use utils::{assets::config_path, response::ApiResponse};
|
||||
|
||||
use crate::{error::ApiError, DeploymentImpl};
|
||||
use crate::{
|
||||
error::ApiError,
|
||||
mcp::agent_config::{read_agent_config, write_agent_config},
|
||||
DeploymentImpl,
|
||||
};
|
||||
|
||||
pub fn router() -> Router<DeploymentImpl> {
|
||||
Router::new()
|
||||
@@ -210,11 +214,8 @@ async fn update_mcp_servers_in_config(
|
||||
fs::create_dir_all(parent).await?;
|
||||
}
|
||||
|
||||
// Read existing config file or create empty object if it doesn't exist
|
||||
let file_content = fs::read_to_string(config_path)
|
||||
.await
|
||||
.unwrap_or_else(|_| "{}".to_string());
|
||||
let mut config: Value = serde_json::from_str(&file_content)?;
|
||||
// Read existing config (JSON or TOML depending on agent)
|
||||
let mut config = read_agent_config(config_path, agent).await?;
|
||||
|
||||
let mcp_path = agent.mcp_attribute_path().unwrap();
|
||||
|
||||
@@ -224,9 +225,8 @@ async fn update_mcp_servers_in_config(
|
||||
// Set the MCP servers using the correct attribute path
|
||||
set_mcp_servers_in_config_path(agent, &mut config, &mcp_path, &new_servers)?;
|
||||
|
||||
// Write the updated config back to file
|
||||
let updated_content = serde_json::to_string_pretty(&config)?;
|
||||
fs::write(config_path, updated_content).await?;
|
||||
// Write the updated config back to file (JSON or TOML depending on agent)
|
||||
write_agent_config(config_path, agent, &config).await?;
|
||||
|
||||
let new_count = new_servers.len();
|
||||
let message = match (old_servers, new_count) {
|
||||
@@ -246,10 +246,8 @@ async fn read_mcp_servers_from_config(
|
||||
config_path: &std::path::Path,
|
||||
agent: &BaseCodingAgent,
|
||||
) -> Result<HashMap<String, Value>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let file_content = fs::read_to_string(config_path)
|
||||
.await
|
||||
.unwrap_or_else(|_| "{}".to_string());
|
||||
let raw_config: Value = serde_json::from_str(&file_content)?;
|
||||
// Read config in appropriate format (JSON or TOML) and normalize to serde_json::Value
|
||||
let raw_config = read_agent_config(config_path, agent).await?;
|
||||
let mcp_path = agent.mcp_attribute_path().unwrap();
|
||||
let servers = get_mcp_servers_from_config_path(agent, &raw_config, &mcp_path);
|
||||
Ok(servers)
|
||||
|
||||
Reference in New Issue
Block a user