-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
epic:mcp-managementMCP server viewing, editing, copyingMCP server viewing, editing, copyingepic:rust-migrationRust + Iced migration infrastructureRust + Iced migration infrastructurephase:4Phase 4 — Advanced featuresPhase 4 — Advanced featurespriority:highMust-have for MVPMust-have for MVPtype:migrationDirect port of existing Swift functionalityDirect port of existing Swift functionality
Description
Context
Form data types and validation logic for the MCP server add/edit form. Validates server name, transport-specific fields, and detects sensitive environment variables.
Ported from: Fig/Sources/Models/MCPServerFormData.swift
What to implement
File path
fig-core/src/models/mcp_form_data.rs
Rust definitions
use std::collections::HashMap;
use crate::models::mcp_server::MCPServer;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MCPServerType {
Stdio,
Http,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MCPServerScope {
Global,
Project,
}
#[derive(Debug, Clone, PartialEq)]
pub struct KeyValuePair {
pub id: uuid::Uuid,
pub key: String,
pub value: String,
}
impl KeyValuePair {
pub fn new(key: String, value: String) -> Self {
Self { id: uuid::Uuid::new_v4(), key, value }
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct MCPValidationError {
pub field: String,
pub message: String,
}
#[derive(Debug, Clone, PartialEq)]
pub struct MCPServerFormData {
pub name: String,
pub server_type: MCPServerType,
pub scope: MCPServerScope,
// Stdio fields
pub command: String,
pub args: Vec<String>,
pub env_vars: Vec<KeyValuePair>,
// HTTP fields
pub url: String,
pub headers: Vec<KeyValuePair>,
// Editing state
pub original_name: Option<String>, // None when adding, Some when editing
}
impl MCPServerFormData {
pub fn new_for_adding(scope: MCPServerScope) -> Self { ... }
pub fn from_server(name: &str, server: &MCPServer, scope: MCPServerScope) -> Self { ... }
/// Validate the form data. Returns empty vec if valid.
pub fn validate(&self, existing_names: &[String]) -> Vec<MCPValidationError> {
let mut errors = Vec::new();
// Name: required, alphanumeric + hyphens + underscores
if self.name.trim().is_empty() {
errors.push(MCPValidationError { field: "name".into(), message: "Server name is required".into() });
} else if !self.name.chars().all(|c| c.is_alphanumeric() || c == '-' || c == '_') {
errors.push(MCPValidationError { field: "name".into(), message: "Name must contain only letters, numbers, hyphens, and underscores".into() });
}
// Duplicate name check (skip if editing same name)
if self.original_name.as_deref() != Some(&self.name) && existing_names.contains(&self.name) {
errors.push(MCPValidationError { field: "name".into(), message: "A server with this name already exists".into() });
}
match self.server_type {
MCPServerType::Stdio => {
if self.command.trim().is_empty() {
errors.push(MCPValidationError { field: "command".into(), message: "Command is required for stdio servers".into() });
}
}
MCPServerType::Http => {
if self.url.trim().is_empty() {
errors.push(MCPValidationError { field: "url".into(), message: "URL is required for HTTP servers".into() });
} else if !self.url.starts_with("http://") && !self.url.starts_with("https://") {
errors.push(MCPValidationError { field: "url".into(), message: "URL must start with http:// or https://".into() });
}
}
}
errors
}
/// Convert form data to MCPServer model.
pub fn to_mcp_server(&self) -> MCPServer { ... }
/// Detect sensitive environment variables.
pub fn sensitive_env_warnings(&self) -> Vec<String> { ... }
}Sensitive patterns to detect in env var keys: token, key, secret, password, credential, auth.
Acceptance criteria
- Validation catches empty names, invalid characters, duplicate names
- Validation catches missing command (stdio) or invalid URL (HTTP)
-
to_mcp_server()correctly converts for both transport types -
from_server()populates form from existing server - Sensitive env var detection works
Test requirements
test_validate_empty_nametest_validate_invalid_name_charstest_validate_duplicate_nametest_validate_stdio_missing_commandtest_validate_http_invalid_urltest_validate_http_missing_urltest_to_mcp_server_stdiotest_to_mcp_server_httptest_from_server_round_triptest_sensitive_env_warningstest_editing_same_name_no_duplicate_error
Dependencies
Requires: #89
Blocks
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
epic:mcp-managementMCP server viewing, editing, copyingMCP server viewing, editing, copyingepic:rust-migrationRust + Iced migration infrastructureRust + Iced migration infrastructurephase:4Phase 4 — Advanced featuresPhase 4 — Advanced featurespriority:highMust-have for MVPMust-have for MVPtype:migrationDirect port of existing Swift functionalityDirect port of existing Swift functionality