Skip to content

Commit 37ce0f5

Browse files
its-mashclaude
andauthored
feat: Add custom server configuration fields (env vars, args, headers) (#54)
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 0def66b commit 37ce0f5

21 files changed

Lines changed: 1700 additions & 18 deletions

File tree

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ futures = "0.3"
2525

2626
# Serialization
2727
serde = { version = "1.0", features = ["derive"] }
28-
serde_json = "1.0"
28+
serde_json = { version = "1.0", features = ["preserve_order"] }
2929

3030
# Error handling
3131
anyhow = "1.0"

apps/desktop/src-tauri/src/commands/logs.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Tauri commands for server log management
22
33
use crate::state::AppState;
4-
use mcpmux_core::{LogLevel, ServerLog};
4+
use mcpmux_core::{AppSettingsService, LogLevel, ServerLog};
55
use serde::Serialize;
66
use tauri::State;
77
use tracing::{info, warn};
@@ -107,3 +107,33 @@ pub async fn get_server_log_file(
107107

108108
Ok(path.to_string_lossy().to_string())
109109
}
110+
111+
/// Get log retention period in days (0 = keep forever)
112+
#[tauri::command]
113+
pub async fn get_log_retention_days(state: State<'_, AppState>) -> Result<u32, String> {
114+
let settings = AppSettingsService::new(state.settings_repository.clone());
115+
Ok(settings.get_log_retention_days().await)
116+
}
117+
118+
/// Set log retention period in days (0 = keep forever)
119+
#[tauri::command]
120+
pub async fn set_log_retention_days(days: u32, state: State<'_, AppState>) -> Result<(), String> {
121+
info!("[Logs] Setting log retention to {} days", days);
122+
123+
let settings = AppSettingsService::new(state.settings_repository.clone());
124+
settings
125+
.set_log_retention_days(days)
126+
.await
127+
.map_err(|e| format!("Failed to save log retention setting: {}", e))?;
128+
129+
// Run cleanup immediately with the new setting if retention is enabled
130+
if days > 0 {
131+
match state.server_log_manager.cleanup_logs_older_than(days).await {
132+
Ok(n) if n > 0 => info!("[Logs] Cleaned up {} old log file(s)", n),
133+
Ok(_) => {}
134+
Err(e) => warn!("[Logs] Cleanup after setting change failed: {}", e),
135+
}
136+
}
137+
138+
Ok(())
139+
}

apps/desktop/src-tauri/src/commands/server.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ pub async fn save_server_inputs(
133133
id: String,
134134
input_values: HashMap<String, String>,
135135
space_id: String,
136+
env_overrides: Option<HashMap<String, String>>,
137+
args_append: Option<Vec<String>>,
138+
extra_headers: Option<HashMap<String, String>>,
136139
) -> Result<InstalledServer, String> {
137140
let service_lock = app_service.read().await;
138141
let service = service_lock
@@ -142,7 +145,14 @@ pub async fn save_server_inputs(
142145
let space_uuid = uuid::Uuid::parse_str(&space_id).map_err(|e| e.to_string())?;
143146

144147
service
145-
.update_config(space_uuid, &id, input_values)
148+
.update_config(
149+
space_uuid,
150+
&id,
151+
input_values,
152+
env_overrides,
153+
args_append,
154+
extra_headers,
155+
)
146156
.await
147157
.map_err(|e| e.to_string())
148158
}

apps/desktop/src-tauri/src/lib.rs

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use mcpmux_core::branding;
66
use std::sync::Arc;
77
use tauri::{Emitter, Manager};
88
use tokio::sync::RwLock;
9-
use tracing::{error, info, warn};
9+
use tracing::{debug, error, info, warn};
1010

1111
mod commands;
1212
mod services;
@@ -519,6 +519,53 @@ pub fn run() {
519519
});
520520
}
521521

522+
// Start periodic log cleanup task
523+
{
524+
let log_manager = app_state.server_log_manager.clone();
525+
let settings_repo_for_cleanup = app_state.settings_repository.clone();
526+
527+
tauri::async_runtime::spawn(async move {
528+
use mcpmux_core::AppSettingsService;
529+
530+
let settings = AppSettingsService::new(settings_repo_for_cleanup);
531+
532+
// Run cleanup once at startup
533+
let retention_days = settings.get_log_retention_days().await;
534+
if retention_days > 0 {
535+
info!(
536+
"[LogCleanup] Running startup cleanup (retention: {} days)",
537+
retention_days
538+
);
539+
match log_manager.cleanup_logs_older_than(retention_days).await {
540+
Ok(n) if n > 0 => {
541+
info!("[LogCleanup] Startup cleanup removed {} file(s)", n)
542+
}
543+
Ok(_) => debug!("[LogCleanup] No old log files to clean up"),
544+
Err(e) => warn!("[LogCleanup] Startup cleanup failed: {}", e),
545+
}
546+
}
547+
548+
// Then run every 24 hours
549+
let mut interval =
550+
tokio::time::interval(std::time::Duration::from_secs(24 * 60 * 60));
551+
interval.tick().await; // skip the first immediate tick (already ran above)
552+
553+
loop {
554+
interval.tick().await;
555+
let days = settings.get_log_retention_days().await;
556+
if days > 0 {
557+
match log_manager.cleanup_logs_older_than(days).await {
558+
Ok(n) if n > 0 => {
559+
info!("[LogCleanup] Periodic cleanup removed {} file(s)", n)
560+
}
561+
Ok(_) => {}
562+
Err(e) => warn!("[LogCleanup] Periodic cleanup failed: {}", e),
563+
}
564+
}
565+
}
566+
});
567+
}
568+
522569
// Setup system tray
523570
tray::setup_tray(app.handle())?;
524571

@@ -749,6 +796,8 @@ pub fn run() {
749796
commands::get_server_logs,
750797
commands::clear_server_logs,
751798
commands::get_server_log_file,
799+
commands::get_log_retention_days,
800+
commands::set_log_retention_days,
752801
// App log commands
753802
get_logs_path,
754803
open_logs_folder,

apps/desktop/src/App.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,7 @@ function DashboardView() {
465465
<div className="relative">
466466
<pre className="bg-mcpmux-dark text-primary-100 p-4 rounded-lg text-sm overflow-x-auto font-mono">
467467
{`"mcpmux": {
468+
"type": "http",
468469
"url": "${gatewayStatus.url || 'http://localhost:3100'}/mcp"
469470
}`}
470471
</pre>
@@ -473,7 +474,7 @@ function DashboardView() {
473474
size="sm"
474475
className="absolute top-2 right-2"
475476
onClick={async () => {
476-
const config = `"mcpmux": {\n "url": "${gatewayStatus.url || 'http://localhost:3100'}/mcp"\n}`;
477+
const config = `"mcpmux": {\n "type": "http",\n "url": "${gatewayStatus.url || 'http://localhost:3100'}/mcp"\n}`;
477478
await navigator.clipboard.writeText(config);
478479
setExportSuccess('Config copied to clipboard!');
479480
setTimeout(() => setExportSuccess(null), 2000);

apps/desktop/src/components/ConfigEditorModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ export function ConfigEditorModal({ spaceId, spaceName, onClose, onSaved }: Conf
165165
<div className="flex items-center justify-between p-4 border-b border-[rgb(var(--border))]">
166166
<div>
167167
<h3 className="text-lg font-semibold flex items-center gap-2">
168-
Add Server Manually
168+
Add Custom Server
169169
</h3>
170170
<p className="text-sm text-[rgb(var(--muted))]">
171171
Edit the JSON configuration for space: {spaceName}

0 commit comments

Comments
 (0)