trusty_analyzer_mcp/
lib.rs1use serde::{Deserialize, Serialize};
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct ToolDefinition {
24 pub name: &'static str,
26 pub description: &'static str,
28 pub input_schema: serde_json::Value,
30 pub http_route: &'static str,
32 pub http_method: &'static str,
34}
35
36pub fn tool_definitions() -> Vec<ToolDefinition> {
45 vec![
46 ToolDefinition {
47 name: "cluster_concepts",
48 description:
49 "Cluster doc-comment themes from a set of source contents. Returns ConceptCluster entities labelled by nearest vocab word.",
50 input_schema: serde_json::json!({
51 "type": "object",
52 "properties": {
53 "contents": {
54 "type": "array",
55 "items": { "type": "string" },
56 "description": "Raw chunk source contents."
57 },
58 "file": {
59 "type": "string",
60 "description": "Anchor filename for emitted entity ids."
61 }
62 },
63 "required": ["contents"]
64 }),
65 http_route: "/analyze/concept-cluster",
66 http_method: "POST",
67 },
68 ToolDefinition {
69 name: "ner_extract",
70 description:
71 "Extract NaturalLanguagePhrase entities from doc-comment text via the optional ONNX NER model. Returns an empty list when the model is not installed.",
72 input_schema: serde_json::json!({
73 "type": "object",
74 "properties": {
75 "text": { "type": "string", "description": "Source text or pre-extracted doc text." },
76 "file": { "type": "string" },
77 "extract_doc_comments_first": {
78 "type": "boolean",
79 "description": "When true, pull /// and //! lines from `text` before running NER."
80 }
81 },
82 "required": ["text"]
83 }),
84 http_route: "/analyze/ner",
85 http_method: "POST",
86 },
87 ToolDefinition {
88 name: "ingest_scip",
89 description:
90 "Ingest SCIP-derived entity references and edges. Returns the materialised RawEntity list and edge tuples.",
91 input_schema: serde_json::json!({
92 "type": "object",
93 "properties": {
94 "refs": { "type": "array", "description": "ScipEntityRef objects." },
95 "edges": { "type": "array", "description": "ScipEdge objects." }
96 }
97 }),
98 http_route: "/analyze/scip-ingest",
99 http_method: "POST",
100 },
101 ToolDefinition {
102 name: "complexity_hotspots",
103 description: "Return the top-N chunks by cyclomatic complexity for an index.",
104 input_schema: serde_json::json!({
105 "type": "object",
106 "properties": {
107 "index_id": { "type": "string" },
108 "top_n": { "type": "integer", "default": 20 }
109 },
110 "required": ["index_id"]
111 }),
112 http_route: "/analyze/{index_id}/complexity_hotspots",
113 http_method: "GET",
114 },
115 ToolDefinition {
116 name: "find_smells",
117 description: "List chunks with one or more code-smell findings.",
118 input_schema: serde_json::json!({
119 "type": "object",
120 "properties": { "index_id": { "type": "string" } },
121 "required": ["index_id"]
122 }),
123 http_route: "/analyze/{index_id}/smells",
124 http_method: "GET",
125 },
126 ToolDefinition {
127 name: "analyze_quality",
128 description: "Aggregate quality stats for an index (avg cyclomatic, %A grade, smell count).",
129 input_schema: serde_json::json!({
130 "type": "object",
131 "properties": { "index_id": { "type": "string" } },
132 "required": ["index_id"]
133 }),
134 http_route: "/analyze/{index_id}/quality",
135 http_method: "GET",
136 },
137 ]
138}
139
140pub fn placeholder() -> &'static str {
143 "trusty-analyzer-mcp: transport layer pending; tool definitions available via tool_definitions()"
144}
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149
150 #[test]
151 fn tool_definitions_includes_new_analysis_tools() {
152 let defs = tool_definitions();
153 let names: Vec<&str> = defs.iter().map(|d| d.name).collect();
154 assert!(names.contains(&"cluster_concepts"));
155 assert!(names.contains(&"ner_extract"));
156 assert!(names.contains(&"ingest_scip"));
157 }
158
159 #[test]
160 fn tool_definitions_serialise() {
161 let defs = tool_definitions();
162 let json = serde_json::to_string(&defs).expect("serialise");
163 assert!(json.contains("cluster_concepts"));
164 }
165
166 #[test]
167 fn tool_definitions_have_non_empty_descriptions() {
168 for def in tool_definitions() {
169 assert!(
170 !def.description.is_empty(),
171 "{} missing description",
172 def.name
173 );
174 assert!(
175 !def.http_route.is_empty(),
176 "{} missing http_route",
177 def.name
178 );
179 }
180 }
181}