ctxman 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/.ctxman/custom-profiles.example.json +20 -0
  2. package/.ctxman/llm-profiles.json +131 -0
  3. package/.ctxman/logs/ctxman-2026-07-02.log +156 -0
  4. package/.ctxman/self-knowledge/documents.lance/_transactions/0-b3dd1558-f95b-44b9-a154-18e8c330ae7a.txn +0 -0
  5. package/.ctxman/self-knowledge/documents.lance/_transactions/1-44bff6d4-e552-4010-a769-e09ad822698d.txn +0 -0
  6. package/.ctxman/self-knowledge/documents.lance/_transactions/10-37260794-5947-4ecb-b4c8-d732f58f40f1.txn +0 -0
  7. package/.ctxman/self-knowledge/documents.lance/_transactions/11-0d52a883-5518-463c-9b6d-986c3af89dfd.txn +0 -0
  8. package/.ctxman/self-knowledge/documents.lance/_transactions/12-ae354646-52f2-49c9-90fb-2e6ed8932663.txn +0 -0
  9. package/.ctxman/self-knowledge/documents.lance/_transactions/13-5d7d5e57-27da-498b-b734-091b9d38da13.txn +0 -0
  10. package/.ctxman/self-knowledge/documents.lance/_transactions/14-558ce928-810b-4252-a364-fdd1ee6f8a25.txn +0 -0
  11. package/.ctxman/self-knowledge/documents.lance/_transactions/15-27e3a58f-8b64-43b8-a9f4-e3369446968b.txn +0 -0
  12. package/.ctxman/self-knowledge/documents.lance/_transactions/16-a110c390-e5c8-4464-b976-bc7f5195fa15.txn +0 -0
  13. package/.ctxman/self-knowledge/documents.lance/_transactions/17-97513225-53de-4216-b61a-6337bd0cc4ad.txn +0 -0
  14. package/.ctxman/self-knowledge/documents.lance/_transactions/18-5ba450f0-c527-459c-bf4f-6d79b5e4285f.txn +0 -0
  15. package/.ctxman/self-knowledge/documents.lance/_transactions/19-600d3a63-5225-49e9-b8b7-30e037b564ab.txn +0 -0
  16. package/.ctxman/self-knowledge/documents.lance/_transactions/2-48a61b4e-92cf-4342-8376-914c1b99a9f9.txn +0 -0
  17. package/.ctxman/self-knowledge/documents.lance/_transactions/20-121dd912-5410-410e-84ff-82c7a23604a0.txn +0 -0
  18. package/.ctxman/self-knowledge/documents.lance/_transactions/3-bc6844ab-7ea3-4bb3-9ee1-538ce5664a9c.txn +0 -0
  19. package/.ctxman/self-knowledge/documents.lance/_transactions/4-d5e1754f-dbb5-454e-a9be-2a7da8d7bcf9.txn +0 -0
  20. package/.ctxman/self-knowledge/documents.lance/_transactions/5-4fae93df-0568-4b6f-8acf-8bef4bba6047.txn +0 -0
  21. package/.ctxman/self-knowledge/documents.lance/_transactions/6-4b1b8b87-068e-49a3-ba2b-d8dae628b252.txn +0 -0
  22. package/.ctxman/self-knowledge/documents.lance/_transactions/7-63d040fb-d2fa-4c0f-bed0-53411918a7b0.txn +0 -0
  23. package/.ctxman/self-knowledge/documents.lance/_transactions/8-c5628cf6-264c-420f-aab8-bc96a9083591.txn +0 -0
  24. package/.ctxman/self-knowledge/documents.lance/_transactions/9-c94570aa-5e53-4fcb-971f-cecc1d1d5492.txn +0 -0
  25. package/.ctxman/self-knowledge/documents.lance/_versions/1.manifest +0 -0
  26. package/.ctxman/self-knowledge/documents.lance/_versions/10.manifest +0 -0
  27. package/.ctxman/self-knowledge/documents.lance/_versions/11.manifest +0 -0
  28. package/.ctxman/self-knowledge/documents.lance/_versions/12.manifest +0 -0
  29. package/.ctxman/self-knowledge/documents.lance/_versions/13.manifest +0 -0
  30. package/.ctxman/self-knowledge/documents.lance/_versions/14.manifest +0 -0
  31. package/.ctxman/self-knowledge/documents.lance/_versions/15.manifest +0 -0
  32. package/.ctxman/self-knowledge/documents.lance/_versions/16.manifest +0 -0
  33. package/.ctxman/self-knowledge/documents.lance/_versions/17.manifest +0 -0
  34. package/.ctxman/self-knowledge/documents.lance/_versions/18.manifest +0 -0
  35. package/.ctxman/self-knowledge/documents.lance/_versions/19.manifest +0 -0
  36. package/.ctxman/self-knowledge/documents.lance/_versions/2.manifest +0 -0
  37. package/.ctxman/self-knowledge/documents.lance/_versions/20.manifest +0 -0
  38. package/.ctxman/self-knowledge/documents.lance/_versions/21.manifest +0 -0
  39. package/.ctxman/self-knowledge/documents.lance/_versions/3.manifest +0 -0
  40. package/.ctxman/self-knowledge/documents.lance/_versions/4.manifest +0 -0
  41. package/.ctxman/self-knowledge/documents.lance/_versions/5.manifest +0 -0
  42. package/.ctxman/self-knowledge/documents.lance/_versions/6.manifest +0 -0
  43. package/.ctxman/self-knowledge/documents.lance/_versions/7.manifest +0 -0
  44. package/.ctxman/self-knowledge/documents.lance/_versions/8.manifest +0 -0
  45. package/.ctxman/self-knowledge/documents.lance/_versions/9.manifest +0 -0
  46. package/.ctxman/self-knowledge/documents.lance/data/000010010011011101000010de8621405d9d5cb06540dbf02c.lance +0 -0
  47. package/.ctxman/self-knowledge/documents.lance/data/0000101001011100011000003fb62a4aa8978974075c144f1c.lance +0 -0
  48. package/.ctxman/self-knowledge/documents.lance/data/000011010000100111001011c6cc824d628f3bb1f4e04cd5d0.lance +0 -0
  49. package/.ctxman/self-knowledge/documents.lance/data/001000001000011001011100d8f74349ada090b332cd1df669.lance +0 -0
  50. package/.ctxman/self-knowledge/documents.lance/data/01000001111010001000010045ab44467bb1e7e4d8ae06bd58.lance +0 -0
  51. package/.ctxman/self-knowledge/documents.lance/data/01000101101110111110011131ef904241a89e1ffb6ddaf8e3.lance +0 -0
  52. package/.ctxman/self-knowledge/documents.lance/data/010010110000010000011010fbfcc145c6a8a827b28057a07e.lance +0 -0
  53. package/.ctxman/self-knowledge/documents.lance/data/1000011000101010001110003fb4f045c3835982efa1405324.lance +0 -0
  54. package/.ctxman/self-knowledge/documents.lance/data/100111011101110111101011f4396b410fa06af3b028d204e6.lance +0 -0
  55. package/.ctxman/self-knowledge/documents.lance/data/100111100111101000001100596b174e00995d6cc2969cc8dc.lance +0 -0
  56. package/.ctxman/self-knowledge/documents.lance/data/1010001100011000110010102ea16b484d887c7c9725feffd6.lance +0 -0
  57. package/.ctxman/self-knowledge/documents.lance/data/101101100010101111110111c5230944d9b3af7301b6392dda.lance +0 -0
  58. package/.ctxman/self-knowledge/documents.lance/data/1011011100100111111110105892bf41b5a530fedd7cf516f1.lance +0 -0
  59. package/.ctxman/self-knowledge/documents.lance/data/10111110000010001011110164e8774742bade87b483c10f36.lance +0 -0
  60. package/.ctxman/self-knowledge/documents.lance/data/1100000100010110001110103ffaca40a2a42c85067ebaf9ae.lance +0 -0
  61. package/.ctxman/self-knowledge/documents.lance/data/110000010001110110101110664bde4c76a78dfc14b05e83b8.lance +0 -0
  62. package/.ctxman/self-knowledge/documents.lance/data/11001100111000010100110050645c4281b1f35b2022234f7f.lance +0 -0
  63. package/.ctxman/self-knowledge/documents.lance/data/1101111011001100110111017214924a368f5719eab2246619.lance +0 -0
  64. package/.ctxman/self-knowledge/documents.lance/data/1110000111001010001000002150c24dcab653d39d07032e63.lance +0 -0
  65. package/.ctxman/self-knowledge/documents.lance/data/1110100000000100000011014d20534967a18b5c87721659ff.lance +0 -0
  66. package/.ctxman/self-knowledge/documents.lance/data/11110101111010000101011135a0114ef2b35dc6f1297a3381.lance +0 -0
  67. package/.ctxman/wizard-profiles/code-review/.contextignore +41 -0
  68. package/.ctxman/wizard-profiles/code-review/.contextinclude +30 -0
  69. package/.ctxman/wizard-profiles/code-review/.methodignore +26 -0
  70. package/.ctxman/wizard-profiles/code-review/.methodinclude +47 -0
  71. package/.ctxman/wizard-profiles/code-review/profile.json +26 -0
  72. package/.ctxman/wizard-profiles/documentation/.contextignore +21 -0
  73. package/.ctxman/wizard-profiles/documentation/.contextinclude +24 -0
  74. package/.ctxman/wizard-profiles/documentation/.methodignore +19 -0
  75. package/.ctxman/wizard-profiles/documentation/.methodinclude +44 -0
  76. package/.ctxman/wizard-profiles/documentation/profile.json +27 -0
  77. package/.ctxman/wizard-profiles/full/.contextignore +23 -0
  78. package/.ctxman/wizard-profiles/full/.contextinclude +38 -0
  79. package/.ctxman/wizard-profiles/full/.methodignore +5 -0
  80. package/.ctxman/wizard-profiles/full/.methodinclude +5 -0
  81. package/.ctxman/wizard-profiles/full/profile.json +28 -0
  82. package/.ctxman/wizard-profiles/llm-explain/.contextignore +25 -0
  83. package/.ctxman/wizard-profiles/llm-explain/.contextinclude +33 -0
  84. package/.ctxman/wizard-profiles/llm-explain/.methodignore +19 -0
  85. package/.ctxman/wizard-profiles/llm-explain/.methodinclude +48 -0
  86. package/.ctxman/wizard-profiles/llm-explain/profile.json +27 -0
  87. package/.ctxman/wizard-profiles/minimal/.contextignore +27 -0
  88. package/.ctxman/wizard-profiles/minimal/.contextinclude +14 -0
  89. package/.ctxman/wizard-profiles/minimal/.methodignore +22 -0
  90. package/.ctxman/wizard-profiles/minimal/.methodinclude +18 -0
  91. package/.ctxman/wizard-profiles/minimal/profile.json +26 -0
  92. package/.ctxman/wizard-profiles/security-audit/.contextignore +36 -0
  93. package/.ctxman/wizard-profiles/security-audit/.contextinclude +37 -0
  94. package/.ctxman/wizard-profiles/security-audit/.methodignore +29 -0
  95. package/.ctxman/wizard-profiles/security-audit/.methodinclude +60 -0
  96. package/.ctxman/wizard-profiles/security-audit/profile.json +34 -0
  97. package/README.md +1167 -0
  98. package/bin/cli.js +650 -0
  99. package/bin/cm-ask.js +95 -0
  100. package/bin/cm-gitingest.js +134 -0
  101. package/bin/cm-update.js +175 -0
  102. package/bin/mcp-server.js +31 -0
  103. package/ctxman.js +236 -0
  104. package/examples/README.md +298 -0
  105. package/examples/custom-llm-profiles.example.json +19 -0
  106. package/examples/wizard-profiles/code-review/.contextignore +41 -0
  107. package/examples/wizard-profiles/code-review/.contextinclude +30 -0
  108. package/examples/wizard-profiles/code-review/.methodignore +26 -0
  109. package/examples/wizard-profiles/code-review/.methodinclude +47 -0
  110. package/examples/wizard-profiles/code-review/profile.json +26 -0
  111. package/examples/wizard-profiles/documentation/.contextignore +21 -0
  112. package/examples/wizard-profiles/documentation/.contextinclude +24 -0
  113. package/examples/wizard-profiles/documentation/.methodignore +19 -0
  114. package/examples/wizard-profiles/documentation/.methodinclude +44 -0
  115. package/examples/wizard-profiles/documentation/profile.json +27 -0
  116. package/examples/wizard-profiles/full/.contextignore +23 -0
  117. package/examples/wizard-profiles/full/.contextinclude +38 -0
  118. package/examples/wizard-profiles/full/.methodignore +5 -0
  119. package/examples/wizard-profiles/full/.methodinclude +5 -0
  120. package/examples/wizard-profiles/full/profile.json +28 -0
  121. package/examples/wizard-profiles/llm-explain/.contextignore +25 -0
  122. package/examples/wizard-profiles/llm-explain/.contextinclude +33 -0
  123. package/examples/wizard-profiles/llm-explain/.methodignore +19 -0
  124. package/examples/wizard-profiles/llm-explain/.methodinclude +48 -0
  125. package/examples/wizard-profiles/llm-explain/profile.json +27 -0
  126. package/examples/wizard-profiles/minimal/.contextignore +27 -0
  127. package/examples/wizard-profiles/minimal/.contextinclude +14 -0
  128. package/examples/wizard-profiles/minimal/.methodignore +22 -0
  129. package/examples/wizard-profiles/minimal/.methodinclude +18 -0
  130. package/examples/wizard-profiles/minimal/profile.json +26 -0
  131. package/examples/wizard-profiles/security-audit/.contextignore +36 -0
  132. package/examples/wizard-profiles/security-audit/.contextinclude +37 -0
  133. package/examples/wizard-profiles/security-audit/.methodignore +29 -0
  134. package/examples/wizard-profiles/security-audit/.methodinclude +60 -0
  135. package/examples/wizard-profiles/security-audit/profile.json +34 -0
  136. package/index.js +68 -0
  137. package/lib/agents/pr-failure-agent.js +201 -0
  138. package/lib/analyzers/go-method-analyzer.js +126 -0
  139. package/lib/analyzers/method-analyzer.js +457 -0
  140. package/lib/analyzers/token-calculator.js +577 -0
  141. package/lib/api/mcp/prompts.js +319 -0
  142. package/lib/api/mcp/resources.js +269 -0
  143. package/lib/api/mcp/server.js +339 -0
  144. package/lib/api/mcp/transports/HttpSseTransport.js +63 -0
  145. package/lib/api/rest/server.js +405 -0
  146. package/lib/cache/CacheManager.js +388 -0
  147. package/lib/core/Analyzer.js +180 -0
  148. package/lib/core/ContextBuilder.js +325 -0
  149. package/lib/core/Reporter.js +270 -0
  150. package/lib/core/Scanner.js +129 -0
  151. package/lib/formatters/format-registry.js +419 -0
  152. package/lib/formatters/gitingest-formatter.js +746 -0
  153. package/lib/formatters/toon-formatter-v1.3.js +731 -0
  154. package/lib/formatters/toon-formatter.js +291 -0
  155. package/lib/integrations/git/BlameTracker.js +142 -0
  156. package/lib/integrations/git/DiffAnalyzer.js +260 -0
  157. package/lib/integrations/git/GitClient.js +336 -0
  158. package/lib/parsers/gitignore-parser.js +127 -0
  159. package/lib/parsers/method-filter-parser.js +50 -0
  160. package/lib/plugins/ExporterPlugin.js +102 -0
  161. package/lib/plugins/LanguagePlugin.js +100 -0
  162. package/lib/plugins/PluginManager.js +302 -0
  163. package/lib/rag/DataSourcePlugin.js +31 -0
  164. package/lib/rag/EmbeddingProvider.js +75 -0
  165. package/lib/rag/Indexer.js +83 -0
  166. package/lib/rag/VectorStoreFactory.js +24 -0
  167. package/lib/rag/sources/FileDataSource.js +70 -0
  168. package/lib/rag/stores/BaseVectorStore.js +43 -0
  169. package/lib/rag/stores/ChromaDBStore.js +85 -0
  170. package/lib/rag/stores/LanceDBStore.js +109 -0
  171. package/lib/rag/stores/PineconeStore.js +74 -0
  172. package/lib/ui/dashboard.js +109 -0
  173. package/lib/ui/index.js +15 -0
  174. package/lib/ui/progress-bar.js +110 -0
  175. package/lib/ui/select-input.js +51 -0
  176. package/lib/ui/wizard.js +359 -0
  177. package/lib/utils/clipboard-utils.js +66 -0
  178. package/lib/utils/config-utils.js +94 -0
  179. package/lib/utils/error-handler.js +145 -0
  180. package/lib/utils/file-utils.js +89 -0
  181. package/lib/utils/format-converter.js +325 -0
  182. package/lib/utils/git-utils.js +337 -0
  183. package/lib/utils/llm-detector.js +409 -0
  184. package/lib/utils/logger.js +278 -0
  185. package/lib/utils/token-utils.js +200 -0
  186. package/lib/utils/tokenizer-adapter.js +454 -0
  187. package/lib/utils/updater.js +565 -0
  188. package/lib/watch/FileWatcher.js +208 -0
  189. package/lib/watch/IncrementalAnalyzer.js +206 -0
  190. package/package.json +118 -0
@@ -0,0 +1,339 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+
3
+ import {
4
+ CallToolRequestSchema,
5
+ ListToolsRequestSchema,
6
+ ListResourcesRequestSchema,
7
+ ReadResourceRequestSchema,
8
+ ListResourceTemplatesRequestSchema,
9
+ ListPromptsRequestSchema,
10
+ GetPromptRequestSchema,
11
+ } from "@modelcontextprotocol/sdk/types.js";
12
+ import { z } from "zod";
13
+ import { Analyzer } from "../../core/Analyzer.js";
14
+ import { ContextBuilder } from "../../core/ContextBuilder.js";
15
+ import { Scanner } from "../../core/Scanner.js";
16
+ import { GitClient } from "../../integrations/git/GitClient.js";
17
+ import { ResourceProvider } from "./resources.js";
18
+ import { PromptProvider } from "./prompts.js";
19
+ import path from "path";
20
+ import fs from "fs";
21
+
22
+ class MCPServer {
23
+ constructor() {
24
+ this.server = new Server(
25
+ {
26
+ name: "ctxman",
27
+ version: "3.1.0",
28
+ },
29
+ {
30
+ capabilities: {
31
+ tools: {},
32
+ resources: {
33
+ subscribe: true,
34
+ listChanged: true
35
+ },
36
+ prompts: {
37
+ listChanged: true
38
+ },
39
+ },
40
+ }
41
+ );
42
+
43
+ this.analyzer = new Analyzer();
44
+ this.contextBuilder = new ContextBuilder();
45
+ this.resourceProvider = new ResourceProvider();
46
+ this.promptProvider = new PromptProvider(this.analyzer, this.contextBuilder);
47
+ this.setupHandlers();
48
+ this.setupErrorHandling();
49
+ }
50
+
51
+ setupHandlers() {
52
+ this.server.setRequestHandler(ListToolsRequestSchema, async () => {
53
+ return {
54
+ tools: [
55
+ {
56
+ name: "analyze_codebase",
57
+ description: "Analyze the codebase and return statistics and token counts",
58
+ inputSchema: {
59
+ type: "object",
60
+ properties: {
61
+ path: {
62
+ type: "string",
63
+ description: "Absolute path to the project root",
64
+ },
65
+ },
66
+ required: ["path"],
67
+ },
68
+ },
69
+ {
70
+ name: "generate_context",
71
+ description: "Generate optimized context for LLMs from the codebase",
72
+ inputSchema: {
73
+ type: "object",
74
+ properties: {
75
+ path: {
76
+ type: "string",
77
+ description: "Absolute path to the project root",
78
+ },
79
+ template: {
80
+ type: "string",
81
+ description: "Context template (bug-fix, feature, etc.)",
82
+ enum: ["bug-fix", "feature", "review", "refactor"],
83
+ },
84
+ maxTokens: {
85
+ type: "number",
86
+ description: "Maximum tokens for the context",
87
+ },
88
+ },
89
+ required: ["path"],
90
+ },
91
+ },
92
+ {
93
+ name: "git_diff",
94
+ description: "Analyze git changes and return diff context",
95
+ inputSchema: {
96
+ type: "object",
97
+ properties: {
98
+ path: { type: "string", description: "Project root" },
99
+ branch: { type: "string", description: "Branch to compare against (default: main)" }
100
+ },
101
+ required: ["path"]
102
+ }
103
+ },
104
+ {
105
+ name: "search_code",
106
+ description: "Search for code using regex or semantic search",
107
+ inputSchema: {
108
+ type: "object",
109
+ properties: {
110
+ path: { type: "string", description: "Project root" },
111
+ query: { type: "string", description: "Search query" },
112
+ type: { type: "string", enum: ["regex", "semantic"], default: "regex" }
113
+ },
114
+ required: ["path", "query"]
115
+ }
116
+ },
117
+ {
118
+ name: "list_methods",
119
+ description: "List all methods/functions in a given file or project",
120
+ inputSchema: {
121
+ type: "object",
122
+ properties: {
123
+ path: {
124
+ type: "string",
125
+ description: "Absolute path to the project root or a specific file"
126
+ },
127
+ file: {
128
+ type: "string",
129
+ description: "Optional: Relative path to a specific file within the project"
130
+ }
131
+ },
132
+ required: ["path"]
133
+ }
134
+ },
135
+ ],
136
+ };
137
+ });
138
+
139
+ // Resource handlers
140
+ this.server.setRequestHandler(ListResourcesRequestSchema, async (request) => {
141
+ const { cursor } = request.params || {};
142
+ return await this.resourceProvider.listResources(cursor);
143
+ });
144
+
145
+ this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
146
+ const { uri } = request.params;
147
+ return await this.resourceProvider.readResource(uri);
148
+ });
149
+
150
+ this.server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => {
151
+ return {
152
+ resourceTemplates: this.resourceProvider.getResourceTemplates()
153
+ };
154
+ });
155
+
156
+ // Prompt handlers
157
+ this.server.setRequestHandler(ListPromptsRequestSchema, async (request) => {
158
+ const { cursor } = request.params || {};
159
+ return this.promptProvider.listPrompts(cursor);
160
+ });
161
+
162
+ this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
163
+ const { name, arguments: args } = request.params;
164
+ return await this.promptProvider.getPrompt(name, args);
165
+ });
166
+
167
+ this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
168
+ const { name, arguments: args } = request.params;
169
+
170
+ try {
171
+ switch (name) {
172
+ case "analyze_codebase": {
173
+ const projectPath = args.path;
174
+
175
+ // Update resource provider project path
176
+ this.resourceProvider.projectPath = projectPath;
177
+
178
+ const scanner = new Scanner(projectPath);
179
+ const files = scanner.scan();
180
+ const analysis = await this.analyzer.analyze(files);
181
+
182
+ // Cache analysis result as a resource
183
+ const analysisId = Date.now().toString();
184
+ this.resourceProvider.cacheAnalysis(analysisId, analysis);
185
+
186
+ return {
187
+ content: [
188
+ {
189
+ type: "text",
190
+ text: JSON.stringify(analysis, null, 2),
191
+ },
192
+ ],
193
+ };
194
+ }
195
+ case "generate_context": {
196
+ const projectPath = args.path;
197
+
198
+ // Update resource provider project path
199
+ this.resourceProvider.projectPath = projectPath;
200
+
201
+ const scanner = new Scanner(projectPath);
202
+ const files = scanner.scan();
203
+ const analysis = await this.analyzer.analyze(files);
204
+
205
+ // Configure ContextBuilder based on args
206
+ const builderOptions = {
207
+ targetTokens: args.maxTokens,
208
+ useCase: args.template || "custom"
209
+ };
210
+ const contextBuilder = new ContextBuilder(builderOptions);
211
+ const context = contextBuilder.build(analysis);
212
+
213
+ // Cache context as a resource
214
+ const templateName = args.template || "custom";
215
+ const contextText = JSON.stringify(context, null, 2);
216
+ this.resourceProvider.cacheContext(templateName, contextText);
217
+
218
+ return {
219
+ content: [
220
+ {
221
+ type: "text",
222
+ text: contextText,
223
+ }
224
+ ]
225
+ }
226
+ }
227
+ case "git_diff": {
228
+ const projectPath = args.path;
229
+ const gitClient = new GitClient(projectPath);
230
+ const branch = args.branch || "main";
231
+
232
+ let diff;
233
+ try {
234
+ diff = gitClient.exec(`diff ${branch}`);
235
+ } catch (e) {
236
+ diff = `Error executing git diff: ${e.message}`;
237
+ }
238
+
239
+ return {
240
+ content: [{ type: "text", text: diff || "No changes detected." }]
241
+ };
242
+ }
243
+ case "search_code": {
244
+ const { path: projectPath, query, type } = args;
245
+ const scanner = new Scanner(projectPath);
246
+ const files = scanner.scan();
247
+ const results = [];
248
+
249
+ for (const file of files) {
250
+ try {
251
+ const content = fs.readFileSync(file.path, "utf-8");
252
+ const lines = content.split("\n");
253
+
254
+ lines.forEach((line, index) => {
255
+ let match = false;
256
+ if (type === "regex") {
257
+ try {
258
+ if (new RegExp(query).test(line)) match = true;
259
+ } catch (e) { /* ignore invalid regex */ }
260
+ } else {
261
+ if (line.includes(query)) match = true;
262
+ }
263
+
264
+ if (match) {
265
+ results.push({
266
+ file: file.relativePath,
267
+ line: index + 1,
268
+ content: line.trim()
269
+ });
270
+ }
271
+ });
272
+ } catch (e) {
273
+ // Skip read errors
274
+ }
275
+ }
276
+
277
+ return {
278
+ content: [{ type: "text", text: JSON.stringify(results, null, 2) }]
279
+ };
280
+ }
281
+ case "list_methods": {
282
+ const projectPath = args.path;
283
+ const scanner = new Scanner(projectPath);
284
+ const files = scanner.scan();
285
+
286
+ // Use Analyzer with methodLevel: true
287
+ const methodAnalyzer = new Analyzer({ methodLevel: true });
288
+ const analysis = await methodAnalyzer.analyze(files);
289
+
290
+ const methods = [];
291
+ if (analysis.files) {
292
+ for (const file of analysis.files) {
293
+ if (file.methods && file.methods.length > 0) {
294
+ methods.push({
295
+ file: file.relativePath,
296
+ methods: file.methods
297
+ });
298
+ }
299
+ }
300
+ }
301
+
302
+ return {
303
+ content: [{ type: "text", text: JSON.stringify(methods, null, 2) }]
304
+ };
305
+ }
306
+ default:
307
+ throw new Error(`Unknown tool: ${name}`);
308
+ }
309
+ } catch (error) {
310
+ return {
311
+ content: [
312
+ {
313
+ type: "text",
314
+ text: `Error: ${error.message}`,
315
+ },
316
+ ],
317
+ isError: true,
318
+ };
319
+ }
320
+ });
321
+ }
322
+
323
+ setupErrorHandling() {
324
+ this.server.onerror = (error) => {
325
+ console.error("[MCP Error]", error);
326
+ };
327
+ }
328
+
329
+ async start(transport) {
330
+ if (!transport) {
331
+ const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
332
+ transport = new StdioServerTransport();
333
+ }
334
+ await this.server.connect(transport);
335
+ console.error("Ctxman MCP Server running");
336
+ }
337
+ }
338
+
339
+ export default MCPServer;
@@ -0,0 +1,63 @@
1
+ import express from "express";
2
+ import cors from "cors";
3
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
4
+ import { randomUUID } from "crypto";
5
+
6
+ export class HttpSseTransport {
7
+ constructor(options = {}) {
8
+ this.port = options.port || 3000;
9
+ this.endpoint = options.endpoint || "/mcp";
10
+ this.app = express();
11
+
12
+ this.app.use(cors());
13
+ this.app.use(express.json());
14
+
15
+ // Authentication Middleware
16
+ if (options.auth && options.auth.apiKey) {
17
+ this.app.use((req, res, next) => {
18
+ const apiKey = req.headers["x-api-key"] || req.query.apiKey;
19
+ if (!apiKey || apiKey !== options.auth.apiKey) {
20
+ return res.status(401).json({ error: "Unauthorized" });
21
+ }
22
+ next();
23
+ });
24
+ }
25
+
26
+ // Initialize StreamableHTTPServerTransport
27
+ this.transport = new StreamableHTTPServerTransport({
28
+ sessionIdGenerator: () => randomUUID(),
29
+ enableJsonResponse: false, // Prefer SSE
30
+ ...options.transportOptions
31
+ });
32
+
33
+ this.setupRoutes();
34
+ }
35
+
36
+ setupRoutes() {
37
+ // Handle all requests to the endpoint via the transport
38
+ this.app.all(this.endpoint, async (req, res) => {
39
+ await this.transport.handleRequest(req, res);
40
+ });
41
+
42
+ // Support for separate messages endpoint if needed, but StreamableHTTPServerTransport handles it
43
+ this.app.post(`${this.endpoint}/messages`, async (req, res) => {
44
+ await this.transport.handleRequest(req, res);
45
+ });
46
+ }
47
+
48
+ async start() {
49
+ return new Promise((resolve) => {
50
+ this.server = this.app.listen(this.port, () => {
51
+ console.error(`MCP HTTP/SSE Server running on port ${this.port} at ${this.endpoint}`);
52
+ resolve(this.transport);
53
+ });
54
+ });
55
+ }
56
+
57
+ async close() {
58
+ if (this.server) {
59
+ this.server.close();
60
+ }
61
+ await this.transport.close();
62
+ }
63
+ }