@identikey/coding-mcp 2.0.1
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.
- package/LICENSE +21 -0
- package/README.md +134 -0
- package/build/common/apiClient.d.ts +14 -0
- package/build/common/apiClient.d.ts.map +1 -0
- package/build/common/apiClient.js +68 -0
- package/build/common/personaClient.d.ts +48 -0
- package/build/common/personaClient.d.ts.map +1 -0
- package/build/common/personaClient.js +101 -0
- package/build/common/promptBuilder.d.ts +10 -0
- package/build/common/promptBuilder.d.ts.map +1 -0
- package/build/common/promptBuilder.js +14 -0
- package/build/common/providerConfig.d.ts +23 -0
- package/build/common/providerConfig.d.ts.map +1 -0
- package/build/common/providerConfig.js +43 -0
- package/build/common/tokenFormatter.d.ts +12 -0
- package/build/common/tokenFormatter.d.ts.map +1 -0
- package/build/common/tokenFormatter.js +24 -0
- package/build/core/CommandDispatcher.d.ts +81 -0
- package/build/core/CommandDispatcher.d.ts.map +1 -0
- package/build/core/CommandDispatcher.js +242 -0
- package/build/core/ToolCommand.d.ts +188 -0
- package/build/core/ToolCommand.d.ts.map +1 -0
- package/build/core/ToolCommand.js +63 -0
- package/build/core/ToolRegistry.d.ts +80 -0
- package/build/core/ToolRegistry.d.ts.map +1 -0
- package/build/core/ToolRegistry.js +279 -0
- package/build/index.d.ts +8 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +329 -0
- package/build/infra/eventBus.d.ts +120 -0
- package/build/infra/eventBus.d.ts.map +1 -0
- package/build/infra/eventBus.js +138 -0
- package/build/personas/ada/index.d.ts +15 -0
- package/build/personas/ada/index.d.ts.map +1 -0
- package/build/personas/ada/index.js +121 -0
- package/build/personas/atlas/index.d.ts +13 -0
- package/build/personas/atlas/index.d.ts.map +1 -0
- package/build/personas/atlas/index.js +65 -0
- package/build/personas/charles/index.d.ts +18 -0
- package/build/personas/charles/index.d.ts.map +1 -0
- package/build/personas/charles/index.js +190 -0
- package/build/personas/hermes/index.d.ts +13 -0
- package/build/personas/hermes/index.d.ts.map +1 -0
- package/build/personas/hermes/index.js +61 -0
- package/build/personas/iris/index.d.ts +13 -0
- package/build/personas/iris/index.d.ts.map +1 -0
- package/build/personas/iris/index.js +61 -0
- package/build/personas/router.d.ts +18 -0
- package/build/personas/router.d.ts.map +1 -0
- package/build/personas/router.js +302 -0
- package/build/personas/sentinel/index.d.ts +13 -0
- package/build/personas/sentinel/index.d.ts.map +1 -0
- package/build/personas/sentinel/index.js +62 -0
- package/build/personas/types.d.ts +91 -0
- package/build/personas/types.d.ts.map +1 -0
- package/build/personas/types.js +60 -0
- package/build/personas/xavier/index.d.ts +14 -0
- package/build/personas/xavier/index.d.ts.map +1 -0
- package/build/personas/xavier/index.js +80 -0
- package/build/prompts/architectPrompts.d.ts +5 -0
- package/build/prompts/architectPrompts.d.ts.map +1 -0
- package/build/prompts/architectPrompts.js +58 -0
- package/build/prompts/codeadvicePrompts.d.ts +5 -0
- package/build/prompts/codeadvicePrompts.d.ts.map +1 -0
- package/build/prompts/codeadvicePrompts.js +13 -0
- package/build/prompts/researcherPrompts.d.ts +2 -0
- package/build/prompts/researcherPrompts.d.ts.map +1 -0
- package/build/prompts/researcherPrompts.js +39 -0
- package/build/tools/architect.d.ts +32 -0
- package/build/tools/architect.d.ts.map +1 -0
- package/build/tools/architect.js +75 -0
- package/build/tools/ask.d.ts +39 -0
- package/build/tools/ask.d.ts.map +1 -0
- package/build/tools/ask.js +139 -0
- package/build/tools/codeReview.d.ts +22 -0
- package/build/tools/codeReview.d.ts.map +1 -0
- package/build/tools/codeReview.js +35 -0
- package/build/tools/codeadvice.d.ts +29 -0
- package/build/tools/codeadvice.d.ts.map +1 -0
- package/build/tools/codeadvice.js +56 -0
- package/build/tools/discover.d.ts +24 -0
- package/build/tools/discover.d.ts.map +1 -0
- package/build/tools/discover.js +220 -0
- package/build/tools/persona.d.ts +48 -0
- package/build/tools/persona.d.ts.map +1 -0
- package/build/tools/persona.js +108 -0
- package/build/tools/researcher.d.ts +61 -0
- package/build/tools/researcher.d.ts.map +1 -0
- package/build/tools/researcher.js +346 -0
- package/build/tools/screenshot.d.ts +28 -0
- package/build/tools/screenshot.d.ts.map +1 -0
- package/build/tools/screenshot.js +46 -0
- package/package.json +56 -0
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Registry - Central hub for managing MCP tool commands
|
|
3
|
+
* Implements the Command pattern with EventBus integration
|
|
4
|
+
*/
|
|
5
|
+
import { ToolLifecycle, ToolNotFoundError, DuplicateToolError, ToolError } from './ToolCommand.js';
|
|
6
|
+
import { eventBus } from '../infra/eventBus.js';
|
|
7
|
+
export class ToolRegistry {
|
|
8
|
+
tools = new Map();
|
|
9
|
+
healthCache = new Map();
|
|
10
|
+
eventBus;
|
|
11
|
+
constructor(eventBusInstance) {
|
|
12
|
+
this.eventBus = eventBusInstance || eventBus;
|
|
13
|
+
// Listen for system events
|
|
14
|
+
this.eventBus.on('system:shutdown', this.handleShutdown.bind(this), 'ToolRegistry');
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Register a new tool command
|
|
18
|
+
*/
|
|
19
|
+
async register(tool, source = 'unknown') {
|
|
20
|
+
if (this.tools.has(tool.name)) {
|
|
21
|
+
throw new DuplicateToolError(tool.name);
|
|
22
|
+
}
|
|
23
|
+
// Create registration record
|
|
24
|
+
const registration = {
|
|
25
|
+
tool,
|
|
26
|
+
registeredAt: Date.now(),
|
|
27
|
+
source,
|
|
28
|
+
enabled: true
|
|
29
|
+
};
|
|
30
|
+
// Emit lifecycle event
|
|
31
|
+
this.eventBus.emit('tool:lifecycle', {
|
|
32
|
+
name: tool.name,
|
|
33
|
+
state: ToolLifecycle.LOADING,
|
|
34
|
+
metadata: { source, version: tool.version }
|
|
35
|
+
});
|
|
36
|
+
try {
|
|
37
|
+
// Call onLoad hook if present
|
|
38
|
+
if (tool.onLoad) {
|
|
39
|
+
await tool.onLoad();
|
|
40
|
+
}
|
|
41
|
+
// Register the tool
|
|
42
|
+
this.tools.set(tool.name, registration);
|
|
43
|
+
// Update lifecycle state
|
|
44
|
+
this.eventBus.emit('tool:lifecycle', {
|
|
45
|
+
name: tool.name,
|
|
46
|
+
state: ToolLifecycle.READY
|
|
47
|
+
});
|
|
48
|
+
// Emit registration event
|
|
49
|
+
this.eventBus.emit('tool:registered', {
|
|
50
|
+
name: tool.name,
|
|
51
|
+
version: tool.version,
|
|
52
|
+
source
|
|
53
|
+
});
|
|
54
|
+
console.log(`✅ Tool '${tool.name}' registered from ${source}`);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
// Handle registration failure
|
|
58
|
+
this.eventBus.emit('tool:lifecycle', {
|
|
59
|
+
name: tool.name,
|
|
60
|
+
state: ToolLifecycle.ERROR,
|
|
61
|
+
metadata: { error: error instanceof Error ? error.message : String(error) }
|
|
62
|
+
});
|
|
63
|
+
this.eventBus.emit('tool:error', {
|
|
64
|
+
name: tool.name,
|
|
65
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
66
|
+
});
|
|
67
|
+
throw new ToolError(`Failed to register tool '${tool.name}': ${error instanceof Error ? error.message : String(error)}`, 'EXECUTION_ERROR', tool.name, error instanceof Error ? error : undefined);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Unregister a tool command
|
|
72
|
+
*/
|
|
73
|
+
async unregister(name, reason) {
|
|
74
|
+
const registration = this.tools.get(name);
|
|
75
|
+
if (!registration) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
// Emit lifecycle event
|
|
79
|
+
this.eventBus.emit('tool:lifecycle', {
|
|
80
|
+
name,
|
|
81
|
+
state: ToolLifecycle.UNLOADING,
|
|
82
|
+
metadata: { reason }
|
|
83
|
+
});
|
|
84
|
+
try {
|
|
85
|
+
// Call onUnload hook if present
|
|
86
|
+
if (registration.tool.onUnload) {
|
|
87
|
+
await registration.tool.onUnload();
|
|
88
|
+
}
|
|
89
|
+
// Remove from registry
|
|
90
|
+
this.tools.delete(name);
|
|
91
|
+
this.healthCache.delete(name);
|
|
92
|
+
// Update lifecycle state
|
|
93
|
+
this.eventBus.emit('tool:lifecycle', {
|
|
94
|
+
name,
|
|
95
|
+
state: ToolLifecycle.DISPOSED
|
|
96
|
+
});
|
|
97
|
+
// Emit unregistration event
|
|
98
|
+
this.eventBus.emit('tool:unregistered', {
|
|
99
|
+
name,
|
|
100
|
+
reason
|
|
101
|
+
});
|
|
102
|
+
console.log(`❌ Tool '${name}' unregistered${reason ? `: ${reason}` : ''}`);
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
// Handle unload failure
|
|
107
|
+
this.eventBus.emit('tool:error', {
|
|
108
|
+
name,
|
|
109
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
110
|
+
});
|
|
111
|
+
// Force removal even if unload fails
|
|
112
|
+
this.tools.delete(name);
|
|
113
|
+
this.healthCache.delete(name);
|
|
114
|
+
console.warn(`⚠️ Tool '${name}' forcibly removed due to unload error:`, error);
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Get a registered tool by name
|
|
120
|
+
*/
|
|
121
|
+
get(name) {
|
|
122
|
+
const registration = this.tools.get(name);
|
|
123
|
+
return registration?.enabled ? registration.tool : undefined;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Get tool registration info
|
|
127
|
+
*/
|
|
128
|
+
getRegistration(name) {
|
|
129
|
+
return this.tools.get(name);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Check if a tool is registered
|
|
133
|
+
*/
|
|
134
|
+
has(name) {
|
|
135
|
+
return this.tools.has(name);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* List all registered tools
|
|
139
|
+
*/
|
|
140
|
+
list() {
|
|
141
|
+
return Array.from(this.tools.values())
|
|
142
|
+
.filter(reg => reg.enabled)
|
|
143
|
+
.map(reg => reg.tool);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* List all tool registrations (including disabled)
|
|
147
|
+
*/
|
|
148
|
+
listRegistrations() {
|
|
149
|
+
return Array.from(this.tools.values());
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Get tool names only
|
|
153
|
+
*/
|
|
154
|
+
getToolNames() {
|
|
155
|
+
return Array.from(this.tools.keys());
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Get registry statistics
|
|
159
|
+
*/
|
|
160
|
+
getStats() {
|
|
161
|
+
const registrations = Array.from(this.tools.values());
|
|
162
|
+
const categories = {};
|
|
163
|
+
const sources = {};
|
|
164
|
+
registrations.forEach(reg => {
|
|
165
|
+
// Count categories
|
|
166
|
+
const category = reg.tool.metadata?.category || 'uncategorized';
|
|
167
|
+
categories[category] = (categories[category] || 0) + 1;
|
|
168
|
+
// Count sources
|
|
169
|
+
sources[reg.source] = (sources[reg.source] || 0) + 1;
|
|
170
|
+
});
|
|
171
|
+
return {
|
|
172
|
+
totalTools: registrations.length,
|
|
173
|
+
enabledTools: registrations.filter(r => r.enabled).length,
|
|
174
|
+
disabledTools: registrations.filter(r => !r.enabled).length,
|
|
175
|
+
categories,
|
|
176
|
+
sources
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Enable/disable a tool
|
|
181
|
+
*/
|
|
182
|
+
setEnabled(name, enabled) {
|
|
183
|
+
const registration = this.tools.get(name);
|
|
184
|
+
if (!registration) {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
registration.enabled = enabled;
|
|
188
|
+
this.eventBus.emit('tool:lifecycle', {
|
|
189
|
+
name,
|
|
190
|
+
state: enabled ? ToolLifecycle.READY : ToolLifecycle.DISPOSED,
|
|
191
|
+
metadata: { enabled }
|
|
192
|
+
});
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Check tool health
|
|
197
|
+
*/
|
|
198
|
+
async checkHealth(name, useCache = true) {
|
|
199
|
+
const registration = this.tools.get(name);
|
|
200
|
+
if (!registration) {
|
|
201
|
+
throw new ToolNotFoundError(name);
|
|
202
|
+
}
|
|
203
|
+
// Check cache first
|
|
204
|
+
if (useCache) {
|
|
205
|
+
const cached = this.healthCache.get(name);
|
|
206
|
+
if (cached && (Date.now() - cached.lastChecked) < 30000) { // 30 second cache
|
|
207
|
+
return cached;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
let healthStatus = {
|
|
211
|
+
healthy: true,
|
|
212
|
+
lastChecked: Date.now()
|
|
213
|
+
};
|
|
214
|
+
try {
|
|
215
|
+
// Use tool's health check if available
|
|
216
|
+
if (registration.tool.healthCheck) {
|
|
217
|
+
healthStatus = await registration.tool.healthCheck();
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
healthStatus = {
|
|
222
|
+
healthy: false,
|
|
223
|
+
message: error instanceof Error ? error.message : String(error),
|
|
224
|
+
lastChecked: Date.now()
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
// Cache result
|
|
228
|
+
this.healthCache.set(name, healthStatus);
|
|
229
|
+
// Emit health event
|
|
230
|
+
this.eventBus.emit('tool:health', {
|
|
231
|
+
name,
|
|
232
|
+
status: healthStatus
|
|
233
|
+
});
|
|
234
|
+
return healthStatus;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Check health of all tools
|
|
238
|
+
*/
|
|
239
|
+
async checkAllHealth() {
|
|
240
|
+
const results = {};
|
|
241
|
+
const names = this.getToolNames();
|
|
242
|
+
await Promise.allSettled(names.map(async (name) => {
|
|
243
|
+
try {
|
|
244
|
+
results[name] = await this.checkHealth(name, false);
|
|
245
|
+
}
|
|
246
|
+
catch (error) {
|
|
247
|
+
results[name] = {
|
|
248
|
+
healthy: false,
|
|
249
|
+
message: error instanceof Error ? error.message : String(error),
|
|
250
|
+
lastChecked: Date.now()
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
}));
|
|
254
|
+
return results;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Clear all tools (for testing or shutdown)
|
|
258
|
+
*/
|
|
259
|
+
async clear() {
|
|
260
|
+
const names = Array.from(this.tools.keys());
|
|
261
|
+
await Promise.allSettled(names.map(name => this.unregister(name, 'registry cleared')));
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Handle system shutdown
|
|
265
|
+
*/
|
|
266
|
+
async handleShutdown() {
|
|
267
|
+
console.log('🔄 ToolRegistry: Shutting down, unregistering all tools...');
|
|
268
|
+
await this.clear();
|
|
269
|
+
console.log('✅ ToolRegistry: Shutdown complete');
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Create a new registry instance (for testing)
|
|
273
|
+
*/
|
|
274
|
+
static create(eventBusInstance) {
|
|
275
|
+
return new ToolRegistry(eventBusInstance);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
// Singleton instance
|
|
279
|
+
export const toolRegistry = new ToolRegistry();
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import "./personas/charles/index.js";
|
|
2
|
+
import "./personas/ada/index.js";
|
|
3
|
+
import "./personas/xavier/index.js";
|
|
4
|
+
import "./personas/atlas/index.js";
|
|
5
|
+
import "./personas/hermes/index.js";
|
|
6
|
+
import "./personas/sentinel/index.js";
|
|
7
|
+
import "./personas/iris/index.js";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAgEA,OAAO,6BAA6B,CAAC;AACrC,OAAO,yBAAyB,CAAC;AACjC,OAAO,4BAA4B,CAAC;AACpC,OAAO,2BAA2B,CAAC;AACnC,OAAO,4BAA4B,CAAC;AACpC,OAAO,8BAA8B,CAAC;AACtC,OAAO,0BAA0B,CAAC"}
|
package/build/index.js
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
4
|
+
import { screenshotToolName, screenshotToolDescription, ScreenshotToolSchema, runScreenshotTool, } from "./tools/screenshot.js";
|
|
5
|
+
import { architectToolName, architectToolDescription, ArchitectToolSchema, runArchitectTool, } from "./tools/architect.js";
|
|
6
|
+
import { codeReviewToolName, codeReviewToolDescription, CodeReviewToolSchema, runCodeReviewTool, } from "./tools/codeReview.js";
|
|
7
|
+
import { codeAdviceToolName, codeAdviceToolDescription, CodeAdviceToolSchema, runCodeAdviceTool, } from "./tools/codeadvice.js";
|
|
8
|
+
import { researcherToolName, researcherToolDescription, ResearcherToolSchema, runResearcherTool, } from "./tools/researcher.js";
|
|
9
|
+
import { personaToolName, personaToolDescription, PersonaToolSchema, runPersonaTool, } from "./tools/persona.js";
|
|
10
|
+
import { askToolName, askToolDescription, AskToolSchema, runAskTool, } from "./tools/ask.js";
|
|
11
|
+
import { discoverToolName, discoverToolDescription, DiscoverToolSchema, runDiscoverTool, } from "./tools/discover.js";
|
|
12
|
+
// Import personas to auto-register
|
|
13
|
+
import "./personas/charles/index.js";
|
|
14
|
+
import "./personas/ada/index.js";
|
|
15
|
+
import "./personas/xavier/index.js";
|
|
16
|
+
import "./personas/atlas/index.js";
|
|
17
|
+
import "./personas/hermes/index.js";
|
|
18
|
+
import "./personas/sentinel/index.js";
|
|
19
|
+
import "./personas/iris/index.js";
|
|
20
|
+
/**
|
|
21
|
+
* MCP server providing Cursor Tools:
|
|
22
|
+
* 1) Screenshot
|
|
23
|
+
* 2) Architect
|
|
24
|
+
* 3) CodeReview
|
|
25
|
+
* 4) CodeAdvice
|
|
26
|
+
* 5) Researcher
|
|
27
|
+
* 6) Persona (Direct access)
|
|
28
|
+
* 7) Ask (Smart routing)
|
|
29
|
+
* 8) Discover (List personas)
|
|
30
|
+
*/
|
|
31
|
+
// 1. Create an MCP server instance
|
|
32
|
+
const server = new Server({
|
|
33
|
+
name: "cursor-tools",
|
|
34
|
+
version: "2.0.1",
|
|
35
|
+
}, {
|
|
36
|
+
capabilities: {
|
|
37
|
+
tools: {},
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
// 2. Define the list of tools
|
|
41
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
42
|
+
return {
|
|
43
|
+
tools: [
|
|
44
|
+
{
|
|
45
|
+
name: screenshotToolName,
|
|
46
|
+
description: screenshotToolDescription,
|
|
47
|
+
inputSchema: {
|
|
48
|
+
type: "object",
|
|
49
|
+
properties: {
|
|
50
|
+
url: {
|
|
51
|
+
type: "string",
|
|
52
|
+
description: "Full URL to screenshot",
|
|
53
|
+
},
|
|
54
|
+
relativePath: {
|
|
55
|
+
type: "string",
|
|
56
|
+
description: "Relative path appended to http://localhost:3000",
|
|
57
|
+
},
|
|
58
|
+
fullPathToScreenshot: {
|
|
59
|
+
type: "string",
|
|
60
|
+
description: "Path to where the screenshot file should be saved. This should be a cwd-style full path to the file (not relative to the current working directory) including the file name and extension.",
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
required: [],
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: architectToolName,
|
|
68
|
+
description: architectToolDescription,
|
|
69
|
+
inputSchema: {
|
|
70
|
+
type: "object",
|
|
71
|
+
properties: {
|
|
72
|
+
task: {
|
|
73
|
+
type: "string",
|
|
74
|
+
description: "Description of the task",
|
|
75
|
+
},
|
|
76
|
+
code: {
|
|
77
|
+
type: "string",
|
|
78
|
+
description: "Concatenated code from one or more files",
|
|
79
|
+
},
|
|
80
|
+
reasoning_effort: {
|
|
81
|
+
type: "string",
|
|
82
|
+
enum: ["low", "medium", "high"],
|
|
83
|
+
description: "How hard the model should think (default: high)",
|
|
84
|
+
},
|
|
85
|
+
persona: {
|
|
86
|
+
type: "string",
|
|
87
|
+
description: "Persona to apply (e.g., 'charles' for British architect)",
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
required: ["task", "code"],
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: codeReviewToolName,
|
|
95
|
+
description: codeReviewToolDescription,
|
|
96
|
+
inputSchema: {
|
|
97
|
+
type: "object",
|
|
98
|
+
properties: {
|
|
99
|
+
folderPath: {
|
|
100
|
+
type: "string",
|
|
101
|
+
description: "Path to the full root directory of the repository to diff against main",
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
required: ["folderPath"],
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: codeAdviceToolName,
|
|
109
|
+
description: codeAdviceToolDescription,
|
|
110
|
+
inputSchema: {
|
|
111
|
+
type: "object",
|
|
112
|
+
properties: {
|
|
113
|
+
task: {
|
|
114
|
+
type: "string",
|
|
115
|
+
description: "Description of the problem or advice needed",
|
|
116
|
+
},
|
|
117
|
+
code: {
|
|
118
|
+
type: "string",
|
|
119
|
+
description: "Relevant code snippet",
|
|
120
|
+
},
|
|
121
|
+
reasoning_effort: {
|
|
122
|
+
type: "string",
|
|
123
|
+
enum: ["low", "medium", "high"],
|
|
124
|
+
description: "How hard the model should think (low/medium/high)",
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
required: ["task", "code"],
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: researcherToolName,
|
|
132
|
+
description: researcherToolDescription,
|
|
133
|
+
inputSchema: {
|
|
134
|
+
type: "object",
|
|
135
|
+
properties: {
|
|
136
|
+
query: {
|
|
137
|
+
type: "string",
|
|
138
|
+
description: "Research query to investigate",
|
|
139
|
+
},
|
|
140
|
+
search_engines: {
|
|
141
|
+
type: "array",
|
|
142
|
+
items: {
|
|
143
|
+
type: "string",
|
|
144
|
+
enum: [
|
|
145
|
+
"google",
|
|
146
|
+
"xai",
|
|
147
|
+
"arxiv",
|
|
148
|
+
"wikipedia",
|
|
149
|
+
"github",
|
|
150
|
+
"stackexchange",
|
|
151
|
+
"pubmed",
|
|
152
|
+
"semantic_scholar",
|
|
153
|
+
],
|
|
154
|
+
},
|
|
155
|
+
description: "Search engines to use (default: google, xai)",
|
|
156
|
+
},
|
|
157
|
+
max_results_per_engine: {
|
|
158
|
+
type: "number",
|
|
159
|
+
description: "Maximum results per search engine (1-20, default: 5)",
|
|
160
|
+
},
|
|
161
|
+
deep_search: {
|
|
162
|
+
type: "boolean",
|
|
163
|
+
description: "Whether to perform deep search by following links",
|
|
164
|
+
},
|
|
165
|
+
include_academic: {
|
|
166
|
+
type: "boolean",
|
|
167
|
+
description: "Whether to prioritize academic sources",
|
|
168
|
+
},
|
|
169
|
+
citation_style: {
|
|
170
|
+
type: "string",
|
|
171
|
+
enum: ["apa", "mla", "chicago", "ieee", "inline"],
|
|
172
|
+
description: "Citation style to use (default: inline)",
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
required: ["query"],
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
name: personaToolName,
|
|
180
|
+
description: personaToolDescription,
|
|
181
|
+
inputSchema: {
|
|
182
|
+
type: "object",
|
|
183
|
+
properties: {
|
|
184
|
+
persona_id: {
|
|
185
|
+
type: "string",
|
|
186
|
+
description: "ID of the persona (e.g., 'charles')",
|
|
187
|
+
},
|
|
188
|
+
query: {
|
|
189
|
+
type: "string",
|
|
190
|
+
description: "Question or request for the persona",
|
|
191
|
+
},
|
|
192
|
+
context: {
|
|
193
|
+
type: "string",
|
|
194
|
+
description: "Additional context or code to analyze",
|
|
195
|
+
},
|
|
196
|
+
analysis_type: {
|
|
197
|
+
type: "string",
|
|
198
|
+
enum: ["comprehensive", "advice", "research", "review"],
|
|
199
|
+
description: "Type of analysis (default: advice)",
|
|
200
|
+
},
|
|
201
|
+
reasoning_effort: {
|
|
202
|
+
type: "string",
|
|
203
|
+
enum: ["low", "medium", "high"],
|
|
204
|
+
description: "Reasoning effort level",
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
required: ["persona_id", "query"],
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
name: askToolName,
|
|
212
|
+
description: askToolDescription,
|
|
213
|
+
inputSchema: {
|
|
214
|
+
type: "object",
|
|
215
|
+
properties: {
|
|
216
|
+
persona_id: {
|
|
217
|
+
type: "string",
|
|
218
|
+
description: "Persona to use: 'auto' (default) routes to best expert, or a specific id like 'charles', 'ada', 'xavier'",
|
|
219
|
+
},
|
|
220
|
+
query: {
|
|
221
|
+
type: "string",
|
|
222
|
+
description: "Your question or request",
|
|
223
|
+
},
|
|
224
|
+
context: {
|
|
225
|
+
type: "string",
|
|
226
|
+
description: "Additional code or context for analysis",
|
|
227
|
+
},
|
|
228
|
+
hint: {
|
|
229
|
+
type: "string",
|
|
230
|
+
description: "Optional hint for routing (e.g., 'architecture', 'security')",
|
|
231
|
+
},
|
|
232
|
+
explain_routing: {
|
|
233
|
+
type: "boolean",
|
|
234
|
+
description: "Show which persona was selected and why",
|
|
235
|
+
},
|
|
236
|
+
reasoning_effort: {
|
|
237
|
+
type: "string",
|
|
238
|
+
enum: ["low", "medium", "high"],
|
|
239
|
+
description: "How thoroughly to think about the answer",
|
|
240
|
+
},
|
|
241
|
+
provider: {
|
|
242
|
+
type: "string",
|
|
243
|
+
enum: ["xai", "openai"],
|
|
244
|
+
description: "Optional provider override; defaults to persona preference or heuristic",
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
required: ["query"],
|
|
248
|
+
},
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
name: discoverToolName,
|
|
252
|
+
description: discoverToolDescription,
|
|
253
|
+
inputSchema: {
|
|
254
|
+
type: "object",
|
|
255
|
+
properties: {
|
|
256
|
+
category: {
|
|
257
|
+
type: "string",
|
|
258
|
+
enum: [
|
|
259
|
+
"architecture",
|
|
260
|
+
"algorithms",
|
|
261
|
+
"security",
|
|
262
|
+
"frontend",
|
|
263
|
+
"backend",
|
|
264
|
+
"data",
|
|
265
|
+
"all",
|
|
266
|
+
],
|
|
267
|
+
description: "Filter personas by category",
|
|
268
|
+
},
|
|
269
|
+
verbose: {
|
|
270
|
+
type: "boolean",
|
|
271
|
+
description: "Show detailed information including example queries",
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
required: [],
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
],
|
|
278
|
+
};
|
|
279
|
+
});
|
|
280
|
+
// 3. Implement the tool call logic
|
|
281
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
282
|
+
const { name, arguments: args } = request.params;
|
|
283
|
+
switch (name) {
|
|
284
|
+
case screenshotToolName: {
|
|
285
|
+
const validated = ScreenshotToolSchema.parse(args);
|
|
286
|
+
return await runScreenshotTool(validated);
|
|
287
|
+
}
|
|
288
|
+
case architectToolName: {
|
|
289
|
+
const validated = ArchitectToolSchema.parse(args);
|
|
290
|
+
return await runArchitectTool(validated);
|
|
291
|
+
}
|
|
292
|
+
case codeReviewToolName: {
|
|
293
|
+
const validated = CodeReviewToolSchema.parse(args);
|
|
294
|
+
return await runCodeReviewTool(validated);
|
|
295
|
+
}
|
|
296
|
+
case codeAdviceToolName: {
|
|
297
|
+
const validated = CodeAdviceToolSchema.parse(args);
|
|
298
|
+
return await runCodeAdviceTool(validated);
|
|
299
|
+
}
|
|
300
|
+
case researcherToolName: {
|
|
301
|
+
const validated = ResearcherToolSchema.parse(args);
|
|
302
|
+
return await runResearcherTool(validated);
|
|
303
|
+
}
|
|
304
|
+
case personaToolName: {
|
|
305
|
+
const validated = PersonaToolSchema.parse(args);
|
|
306
|
+
return await runPersonaTool(validated);
|
|
307
|
+
}
|
|
308
|
+
case askToolName: {
|
|
309
|
+
const validated = AskToolSchema.parse(args);
|
|
310
|
+
return await runAskTool(validated);
|
|
311
|
+
}
|
|
312
|
+
case discoverToolName: {
|
|
313
|
+
const validated = DiscoverToolSchema.parse(args);
|
|
314
|
+
return await runDiscoverTool(validated);
|
|
315
|
+
}
|
|
316
|
+
default:
|
|
317
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
// 4. Start the MCP server with a stdio transport
|
|
321
|
+
async function main() {
|
|
322
|
+
const transport = new StdioServerTransport();
|
|
323
|
+
await server.connect(transport);
|
|
324
|
+
console.error("Cursor Tools MCP Server running on stdio");
|
|
325
|
+
}
|
|
326
|
+
main().catch((error) => {
|
|
327
|
+
console.error("Fatal error:", error);
|
|
328
|
+
process.exit(1);
|
|
329
|
+
});
|