Skip to main content

agentshield/adapter/mcp/
mod.rs

1pub(crate) mod binding;
2pub(crate) mod dependencies;
3pub(crate) mod filter;
4pub(crate) mod loader;
5pub(crate) mod provenance;
6pub(crate) mod tools;
7
8#[cfg(test)]
9mod tests;
10
11use std::path::Path;
12
13use crate::analysis::AnalysisBundle;
14use crate::config::ScanPathFilter;
15use crate::error::Result;
16use crate::ir::*;
17
18pub use dependencies::parse_dependencies;
19pub use filter::{is_test_file, is_test_file_in};
20pub use provenance::parse_provenance;
21pub use tools::extract_mcp_tools_from_source;
22
23pub(crate) use loader::{
24    collect_source_files_with_filter, has_recursive_python_import, load_mcp_analysis,
25    load_mcp_target,
26};
27
28#[cfg(test)]
29use binding::bind_mcp_tool_operations;
30#[cfg(test)]
31use tools::{McpToolHandler, extract_mcp_tool_declarations_from_source, parse_mcp_tool_handler};
32
33/// MCP Server adapter.
34///
35/// Detects MCP servers by looking for:
36/// - package.json with dependencies
37/// - Python files importing FastMCP or mcp.server
38/// - mcp.json / mcp-config.json manifest
39pub struct McpAdapter;
40
41impl super::Adapter for McpAdapter {
42    fn framework(&self) -> Framework {
43        Framework::Mcp
44    }
45
46    fn detect(&self, root: &Path) -> bool {
47        super::mcp_metadata::metadata_root_for_scan(root).is_some()
48    }
49
50    fn load(&self, root: &Path, ignore_tests: bool) -> Result<Vec<ScanTarget>> {
51        let filter = ScanPathFilter::for_ignore_tests(ignore_tests);
52        self.load_with_filter(root, &filter)
53    }
54
55    fn load_with_filter(&self, root: &Path, filter: &ScanPathFilter) -> Result<Vec<ScanTarget>> {
56        load_mcp_target(root, filter).map(|(target, _)| vec![target])
57    }
58}
59
60impl super::AnalysisAdapter for McpAdapter {
61    fn framework(&self) -> Framework {
62        Framework::Mcp
63    }
64
65    fn detect(&self, root: &Path) -> bool {
66        super::mcp_metadata::metadata_root_for_scan(root).is_some()
67    }
68
69    fn load_analysis_with_filter(
70        &self,
71        root: &Path,
72        filter: &ScanPathFilter,
73    ) -> Result<Vec<AnalysisBundle>> {
74        load_mcp_analysis(root, filter)
75    }
76}
77
78pub(crate) struct McpAnalysisAdapter;
79
80impl super::AnalysisAdapter for McpAnalysisAdapter {
81    fn framework(&self) -> Framework {
82        Framework::Mcp
83    }
84
85    fn detect(&self, root: &Path) -> bool {
86        super::mcp_metadata::metadata_root_for_scan(root).is_some()
87    }
88
89    fn load_analysis_with_filter(
90        &self,
91        root: &Path,
92        filter: &ScanPathFilter,
93    ) -> Result<Vec<AnalysisBundle>> {
94        load_mcp_analysis(root, filter)
95    }
96}