Skip to main content

agent_config/agents/cline/
mcp.rs

1//! Cline MCP surface. Global VS Code extension config at
2//! `Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json`,
3//! keyed by server name under `mcpServers`.
4
5use std::path::PathBuf;
6
7use crate::agents::planning as agent_planning;
8use crate::error::AgentConfigError;
9use crate::integration::{InstallReport, McpSurface, UninstallReport};
10use crate::paths;
11use crate::plan::{InstallPlan, UninstallPlan};
12use crate::scope::{Scope, ScopeKind};
13use crate::spec::{HookSpec, McpSpec};
14use crate::status::StatusReport;
15use crate::util::{mcp_json_object, ownership};
16
17use super::ClineAgent;
18
19impl ClineAgent {
20    pub(super) fn mcp_path(scope: &Scope) -> Result<PathBuf, AgentConfigError> {
21        match scope {
22            Scope::Global => paths::cline_mcp_global_file(),
23            Scope::Local(_) => Err(AgentConfigError::UnsupportedScope {
24                id: "cline",
25                scope: ScopeKind::Local,
26            }),
27        }
28    }
29}
30
31impl McpSurface for ClineAgent {
32    fn id(&self) -> &'static str {
33        "cline"
34    }
35
36    fn supported_mcp_scopes(&self) -> &'static [ScopeKind] {
37        &[ScopeKind::Global]
38    }
39
40    fn mcp_status(
41        &self,
42        scope: &Scope,
43        name: &str,
44        expected_owner: &str,
45    ) -> Result<StatusReport, AgentConfigError> {
46        McpSpec::validate_name(name)?;
47        let cfg = Self::mcp_path(scope)?;
48        let ledger = ownership::mcp_ledger_for(&cfg);
49        let presence = mcp_json_object::config_presence(&cfg, name)?;
50        let recorded = ownership::owner_of(&ledger, name)?;
51        Ok(StatusReport::for_mcp(
52            name,
53            cfg,
54            ledger,
55            presence,
56            expected_owner,
57            recorded,
58        ))
59    }
60
61    fn plan_install_mcp(
62        &self,
63        scope: &Scope,
64        spec: &McpSpec,
65    ) -> Result<InstallPlan, AgentConfigError> {
66        agent_planning::mcp_json_object_install(
67            McpSurface::id(self),
68            scope,
69            spec,
70            Self::mcp_path(scope),
71        )
72    }
73
74    fn plan_uninstall_mcp(
75        &self,
76        scope: &Scope,
77        name: &str,
78        owner_tag: &str,
79    ) -> Result<UninstallPlan, AgentConfigError> {
80        agent_planning::mcp_json_object_uninstall(
81            McpSurface::id(self),
82            scope,
83            name,
84            owner_tag,
85            Self::mcp_path(scope),
86        )
87    }
88
89    fn install_mcp(
90        &self,
91        scope: &Scope,
92        spec: &McpSpec,
93    ) -> Result<InstallReport, AgentConfigError> {
94        spec.validate()?;
95        let cfg = Self::mcp_path(scope)?;
96        spec.validate_local_secret_policy(scope)?;
97        scope.ensure_contained(&cfg)?;
98        let ledger = ownership::mcp_ledger_for(&cfg);
99        mcp_json_object::install(&cfg, &ledger, spec)
100    }
101
102    fn uninstall_mcp(
103        &self,
104        scope: &Scope,
105        name: &str,
106        owner_tag: &str,
107    ) -> Result<UninstallReport, AgentConfigError> {
108        McpSpec::validate_name(name)?;
109        HookSpec::validate_tag(owner_tag)?;
110        let cfg = Self::mcp_path(scope)?;
111        scope.ensure_contained(&cfg)?;
112        let ledger = ownership::mcp_ledger_for(&cfg);
113        mcp_json_object::uninstall(&cfg, &ledger, name, owner_tag, "mcp server")
114    }
115}