midnight-mcp 0.1.41 → 0.2.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/README.md +32 -1
- package/dist/bin.d.ts +1 -0
- package/dist/bin.js +10764 -0
- package/dist/index.d.ts +205 -3
- package/dist/index.js +10722 -15
- package/package.json +16 -6
- package/dist/config/compact-version.d.ts +0 -183
- package/dist/config/compact-version.js +0 -423
- package/dist/db/index.d.ts +0 -3
- package/dist/db/index.js +0 -2
- package/dist/db/vectorStore.d.ts +0 -69
- package/dist/db/vectorStore.js +0 -196
- package/dist/pipeline/embeddings.d.ts +0 -25
- package/dist/pipeline/embeddings.js +0 -103
- package/dist/pipeline/github.d.ts +0 -84
- package/dist/pipeline/github.js +0 -399
- package/dist/pipeline/index.d.ts +0 -11
- package/dist/pipeline/index.js +0 -6
- package/dist/pipeline/indexer.d.ts +0 -41
- package/dist/pipeline/indexer.js +0 -254
- package/dist/pipeline/parser.d.ts +0 -46
- package/dist/pipeline/parser.js +0 -436
- package/dist/pipeline/releases.d.ts +0 -112
- package/dist/pipeline/releases.js +0 -298
- package/dist/pipeline/repository.d.ts +0 -372
- package/dist/pipeline/repository.js +0 -520
- package/dist/prompts/index.d.ts +0 -3
- package/dist/prompts/index.js +0 -2
- package/dist/prompts/templates.d.ts +0 -26
- package/dist/prompts/templates.js +0 -443
- package/dist/resources/code.d.ts +0 -15
- package/dist/resources/code.js +0 -122
- package/dist/resources/content/code-content.d.ts +0 -6
- package/dist/resources/content/code-content.js +0 -802
- package/dist/resources/content/docs-content.d.ts +0 -14
- package/dist/resources/content/docs-content.js +0 -1202
- package/dist/resources/content/index.d.ts +0 -6
- package/dist/resources/content/index.js +0 -6
- package/dist/resources/docs.d.ts +0 -15
- package/dist/resources/docs.js +0 -98
- package/dist/resources/index.d.ts +0 -6
- package/dist/resources/index.js +0 -13
- package/dist/resources/schemas.d.ts +0 -16
- package/dist/resources/schemas.js +0 -407
- package/dist/scripts/index-repos.d.ts +0 -12
- package/dist/scripts/index-repos.js +0 -53
- package/dist/server.d.ts +0 -43
- package/dist/server.js +0 -696
- package/dist/services/index.d.ts +0 -6
- package/dist/services/index.js +0 -6
- package/dist/services/sampling.d.ts +0 -62
- package/dist/services/sampling.js +0 -277
- package/dist/tools/analyze.d.ts +0 -106
- package/dist/tools/analyze.js +0 -431
- package/dist/tools/generation.d.ts +0 -9
- package/dist/tools/generation.js +0 -285
- package/dist/tools/health.d.ts +0 -120
- package/dist/tools/health.js +0 -365
- package/dist/tools/index.d.ts +0 -14
- package/dist/tools/index.js +0 -22
- package/dist/tools/meta.d.ts +0 -61
- package/dist/tools/meta.js +0 -282
- package/dist/tools/repository/constants.d.ts +0 -19
- package/dist/tools/repository/constants.js +0 -324
- package/dist/tools/repository/handlers.d.ts +0 -373
- package/dist/tools/repository/handlers.js +0 -724
- package/dist/tools/repository/index.d.ts +0 -9
- package/dist/tools/repository/index.js +0 -13
- package/dist/tools/repository/schemas.d.ts +0 -153
- package/dist/tools/repository/schemas.js +0 -106
- package/dist/tools/repository/tools.d.ts +0 -7
- package/dist/tools/repository/tools.js +0 -484
- package/dist/tools/repository/validation.d.ts +0 -106
- package/dist/tools/repository/validation.js +0 -820
- package/dist/tools/repository.d.ts +0 -6
- package/dist/tools/repository.js +0 -7
- package/dist/tools/search.d.ts +0 -76
- package/dist/tools/search.js +0 -423
- package/dist/types/index.d.ts +0 -2
- package/dist/types/index.js +0 -2
- package/dist/types/mcp.d.ts +0 -187
- package/dist/types/mcp.js +0 -6
- package/dist/utils/cache.d.ts +0 -77
- package/dist/utils/cache.js +0 -172
- package/dist/utils/config.d.ts +0 -70
- package/dist/utils/config.js +0 -294
- package/dist/utils/errors.d.ts +0 -111
- package/dist/utils/errors.js +0 -165
- package/dist/utils/health.d.ts +0 -29
- package/dist/utils/health.js +0 -132
- package/dist/utils/hosted-api.d.ts +0 -67
- package/dist/utils/hosted-api.js +0 -119
- package/dist/utils/index.d.ts +0 -16
- package/dist/utils/index.js +0 -15
- package/dist/utils/logger.d.ts +0 -48
- package/dist/utils/logger.js +0 -124
- package/dist/utils/rate-limit.d.ts +0 -61
- package/dist/utils/rate-limit.js +0 -148
- package/dist/utils/validation.d.ts +0 -52
- package/dist/utils/validation.js +0 -255
package/dist/server.js
DELETED
|
@@ -1,696 +0,0 @@
|
|
|
1
|
-
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
-
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, ListResourceTemplatesRequestSchema, SubscribeRequestSchema, UnsubscribeRequestSchema, SetLevelRequestSchema, CompleteRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
4
|
-
import { logger, formatErrorResponse, setMCPLogCallback, trackToolCall, } from "./utils/index.js";
|
|
5
|
-
import { vectorStore } from "./db/index.js";
|
|
6
|
-
import { allTools } from "./tools/index.js";
|
|
7
|
-
import { allResources, getDocumentation, getCode, getSchema, } from "./resources/index.js";
|
|
8
|
-
import { promptDefinitions, generatePrompt } from "./prompts/index.js";
|
|
9
|
-
import { registerSamplingCallback } from "./services/index.js";
|
|
10
|
-
import { createRequire } from "module";
|
|
11
|
-
// Read version from package.json (single source of truth)
|
|
12
|
-
const require = createRequire(import.meta.url);
|
|
13
|
-
const packageJson = require("../package.json");
|
|
14
|
-
const CURRENT_VERSION = packageJson.version;
|
|
15
|
-
const SERVER_INFO = {
|
|
16
|
-
name: "midnight-mcp",
|
|
17
|
-
version: CURRENT_VERSION,
|
|
18
|
-
description: "MCP Server for Midnight Blockchain Development",
|
|
19
|
-
};
|
|
20
|
-
// Version check state
|
|
21
|
-
let versionCheckResult = {
|
|
22
|
-
isOutdated: false,
|
|
23
|
-
latestVersion: CURRENT_VERSION,
|
|
24
|
-
updateMessage: null,
|
|
25
|
-
};
|
|
26
|
-
/**
|
|
27
|
-
* Check for updates against npm registry (runs at startup)
|
|
28
|
-
*/
|
|
29
|
-
async function checkForUpdates() {
|
|
30
|
-
try {
|
|
31
|
-
const controller = new AbortController();
|
|
32
|
-
const timeoutId = setTimeout(() => controller.abort(), 5000); // 5s timeout
|
|
33
|
-
const response = await fetch("https://registry.npmjs.org/midnight-mcp/latest", { signal: controller.signal });
|
|
34
|
-
clearTimeout(timeoutId);
|
|
35
|
-
if (!response.ok)
|
|
36
|
-
return;
|
|
37
|
-
const data = (await response.json());
|
|
38
|
-
const latestVersion = data.version;
|
|
39
|
-
if (latestVersion !== CURRENT_VERSION) {
|
|
40
|
-
versionCheckResult = {
|
|
41
|
-
isOutdated: true,
|
|
42
|
-
latestVersion,
|
|
43
|
-
updateMessage: `⚠️ UPDATE AVAILABLE: v${latestVersion} (you have v${CURRENT_VERSION}). ` +
|
|
44
|
-
`Run: rm -rf ~/.npm/_npx && restart Claude Desktop. ` +
|
|
45
|
-
`Or update config to use: "midnight-mcp@latest"`,
|
|
46
|
-
};
|
|
47
|
-
logger.warn(`Outdated version detected: v${CURRENT_VERSION} -> v${latestVersion}`);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
catch {
|
|
51
|
-
// Silently ignore version check failures (offline, timeout, etc.)
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Get update warning if outdated (to include in responses)
|
|
56
|
-
*/
|
|
57
|
-
export function getUpdateWarning() {
|
|
58
|
-
return versionCheckResult.updateMessage;
|
|
59
|
-
}
|
|
60
|
-
// Resource subscriptions tracking
|
|
61
|
-
const resourceSubscriptions = new Set();
|
|
62
|
-
/**
|
|
63
|
-
* Clear all subscriptions (useful for server restart/testing)
|
|
64
|
-
*/
|
|
65
|
-
export function clearSubscriptions() {
|
|
66
|
-
resourceSubscriptions.clear();
|
|
67
|
-
logger.debug("Subscriptions cleared");
|
|
68
|
-
}
|
|
69
|
-
// Resource templates for parameterized resources (RFC 6570 URI Templates)
|
|
70
|
-
const resourceTemplates = [
|
|
71
|
-
{
|
|
72
|
-
uriTemplate: "midnight://code/{owner}/{repo}/{path}",
|
|
73
|
-
name: "Repository Code",
|
|
74
|
-
title: "📄 Repository Code Files",
|
|
75
|
-
description: "Access code files from any Midnight repository by specifying owner, repo, and file path",
|
|
76
|
-
mimeType: "text/plain",
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
uriTemplate: "midnight://docs/{section}/{topic}",
|
|
80
|
-
name: "Documentation",
|
|
81
|
-
title: "📚 Documentation Sections",
|
|
82
|
-
description: "Access documentation by section (guides, api, concepts) and topic",
|
|
83
|
-
mimeType: "text/markdown",
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
uriTemplate: "midnight://examples/{category}/{name}",
|
|
87
|
-
name: "Example Contracts",
|
|
88
|
-
title: "📝 Example Contracts",
|
|
89
|
-
description: "Access example contracts by category (counter, bboard, token, voting) and name",
|
|
90
|
-
mimeType: "text/x-compact",
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
uriTemplate: "midnight://schema/{type}",
|
|
94
|
-
name: "Schema Definitions",
|
|
95
|
-
title: "🔧 Schema Definitions",
|
|
96
|
-
description: "Access JSON schemas for contract AST, transactions, and proofs",
|
|
97
|
-
mimeType: "application/json",
|
|
98
|
-
},
|
|
99
|
-
];
|
|
100
|
-
/**
|
|
101
|
-
* Create and configure the MCP server
|
|
102
|
-
*/
|
|
103
|
-
// Current MCP logging level (controlled by client)
|
|
104
|
-
let mcpLogLevel = "info";
|
|
105
|
-
// Server instance for sending notifications
|
|
106
|
-
let serverInstance = null;
|
|
107
|
-
// Track if server is connected (can send notifications)
|
|
108
|
-
let isConnected = false;
|
|
109
|
-
/**
|
|
110
|
-
* Mark server as connected (safe to send notifications)
|
|
111
|
-
*/
|
|
112
|
-
export function setServerConnected(connected) {
|
|
113
|
-
isConnected = connected;
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Send a log message to the MCP client
|
|
117
|
-
* This allows clients to see server logs for debugging
|
|
118
|
-
*/
|
|
119
|
-
export function sendLogToClient(level, loggerName, data) {
|
|
120
|
-
// Only send if server exists AND is connected
|
|
121
|
-
if (!serverInstance || !isConnected)
|
|
122
|
-
return;
|
|
123
|
-
// Map levels to numeric values for comparison
|
|
124
|
-
const levelValues = {
|
|
125
|
-
debug: 0,
|
|
126
|
-
info: 1,
|
|
127
|
-
notice: 2,
|
|
128
|
-
warning: 3,
|
|
129
|
-
error: 4,
|
|
130
|
-
critical: 5,
|
|
131
|
-
alert: 6,
|
|
132
|
-
emergency: 7,
|
|
133
|
-
};
|
|
134
|
-
// Only send if level meets threshold
|
|
135
|
-
if (levelValues[level] < levelValues[mcpLogLevel])
|
|
136
|
-
return;
|
|
137
|
-
try {
|
|
138
|
-
serverInstance.notification({
|
|
139
|
-
method: "notifications/message",
|
|
140
|
-
params: {
|
|
141
|
-
level,
|
|
142
|
-
logger: loggerName,
|
|
143
|
-
data,
|
|
144
|
-
},
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
catch {
|
|
148
|
-
// Ignore notification errors
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Send a progress notification to the MCP client
|
|
153
|
-
* Used for long-running operations like compound tools
|
|
154
|
-
*/
|
|
155
|
-
export function sendProgressNotification(progressToken, progress, total, message) {
|
|
156
|
-
if (!serverInstance)
|
|
157
|
-
return;
|
|
158
|
-
try {
|
|
159
|
-
serverInstance.notification({
|
|
160
|
-
method: "notifications/progress",
|
|
161
|
-
params: {
|
|
162
|
-
progressToken,
|
|
163
|
-
progress,
|
|
164
|
-
...(total !== undefined && { total }),
|
|
165
|
-
...(message && { message }),
|
|
166
|
-
},
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
catch {
|
|
170
|
-
// Ignore notification errors
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
export function createServer() {
|
|
174
|
-
const server = new Server(SERVER_INFO, {
|
|
175
|
-
capabilities: {
|
|
176
|
-
tools: {
|
|
177
|
-
listChanged: true,
|
|
178
|
-
},
|
|
179
|
-
resources: {
|
|
180
|
-
subscribe: true,
|
|
181
|
-
listChanged: true,
|
|
182
|
-
},
|
|
183
|
-
prompts: {
|
|
184
|
-
listChanged: true,
|
|
185
|
-
},
|
|
186
|
-
logging: {},
|
|
187
|
-
completions: {},
|
|
188
|
-
},
|
|
189
|
-
});
|
|
190
|
-
// Store server instance for logging notifications
|
|
191
|
-
serverInstance = server;
|
|
192
|
-
// Wire up MCP logging - send logger output to client
|
|
193
|
-
setMCPLogCallback((level, loggerName, data) => {
|
|
194
|
-
sendLogToClient(level, loggerName, data);
|
|
195
|
-
});
|
|
196
|
-
// Register tool handlers
|
|
197
|
-
registerToolHandlers(server);
|
|
198
|
-
// Register resource handlers
|
|
199
|
-
registerResourceHandlers(server);
|
|
200
|
-
// Register prompt handlers
|
|
201
|
-
registerPromptHandlers(server);
|
|
202
|
-
// Register subscription handlers
|
|
203
|
-
registerSubscriptionHandlers(server);
|
|
204
|
-
// Register logging handler
|
|
205
|
-
registerLoggingHandler(server);
|
|
206
|
-
// Register completions handler
|
|
207
|
-
registerCompletionsHandler(server);
|
|
208
|
-
// Setup sampling callback if available
|
|
209
|
-
setupSampling(server);
|
|
210
|
-
return server;
|
|
211
|
-
}
|
|
212
|
-
/**
|
|
213
|
-
* Register logging handler for MCP logging capability
|
|
214
|
-
*/
|
|
215
|
-
function registerLoggingHandler(server) {
|
|
216
|
-
server.setRequestHandler(SetLevelRequestSchema, async (request) => {
|
|
217
|
-
const { level } = request.params;
|
|
218
|
-
mcpLogLevel = level;
|
|
219
|
-
logger.info(`MCP log level set to: ${level}`);
|
|
220
|
-
sendLogToClient("info", "midnight-mcp", {
|
|
221
|
-
message: `Log level changed to ${level}`,
|
|
222
|
-
});
|
|
223
|
-
return {};
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
// Completion suggestions for prompt arguments
|
|
227
|
-
const COMPLETION_VALUES = {
|
|
228
|
-
"midnight:create-contract": {
|
|
229
|
-
contractType: [
|
|
230
|
-
"token",
|
|
231
|
-
"voting",
|
|
232
|
-
"credential",
|
|
233
|
-
"auction",
|
|
234
|
-
"escrow",
|
|
235
|
-
"custom",
|
|
236
|
-
],
|
|
237
|
-
privacyLevel: ["full", "partial", "public"],
|
|
238
|
-
complexity: ["beginner", "intermediate", "advanced"],
|
|
239
|
-
},
|
|
240
|
-
"midnight:review-contract": {
|
|
241
|
-
focusAreas: [
|
|
242
|
-
"security",
|
|
243
|
-
"performance",
|
|
244
|
-
"privacy",
|
|
245
|
-
"readability",
|
|
246
|
-
"gas-optimization",
|
|
247
|
-
],
|
|
248
|
-
},
|
|
249
|
-
"midnight:explain-concept": {
|
|
250
|
-
concept: [
|
|
251
|
-
"zk-proofs",
|
|
252
|
-
"circuits",
|
|
253
|
-
"witnesses",
|
|
254
|
-
"ledger",
|
|
255
|
-
"state-management",
|
|
256
|
-
"privacy-model",
|
|
257
|
-
"token-transfers",
|
|
258
|
-
"merkle-trees",
|
|
259
|
-
],
|
|
260
|
-
level: ["beginner", "intermediate", "advanced"],
|
|
261
|
-
},
|
|
262
|
-
"midnight:compare-approaches": {
|
|
263
|
-
approaches: [
|
|
264
|
-
"token-standards",
|
|
265
|
-
"state-management",
|
|
266
|
-
"privacy-patterns",
|
|
267
|
-
"circuit-design",
|
|
268
|
-
],
|
|
269
|
-
},
|
|
270
|
-
"midnight:debug-contract": {
|
|
271
|
-
errorType: [
|
|
272
|
-
"compilation",
|
|
273
|
-
"runtime",
|
|
274
|
-
"logic",
|
|
275
|
-
"privacy-leak",
|
|
276
|
-
"state-corruption",
|
|
277
|
-
],
|
|
278
|
-
},
|
|
279
|
-
};
|
|
280
|
-
/**
|
|
281
|
-
* Register completions handler for argument autocompletion
|
|
282
|
-
*/
|
|
283
|
-
function registerCompletionsHandler(server) {
|
|
284
|
-
server.setRequestHandler(CompleteRequestSchema, async (request) => {
|
|
285
|
-
const { ref, argument } = request.params;
|
|
286
|
-
if (ref.type !== "ref/prompt") {
|
|
287
|
-
return { completion: { values: [], hasMore: false } };
|
|
288
|
-
}
|
|
289
|
-
const promptName = ref.name;
|
|
290
|
-
const argName = argument.name;
|
|
291
|
-
const currentValue = argument.value?.toLowerCase() || "";
|
|
292
|
-
// Get completion values for this prompt/argument
|
|
293
|
-
const promptCompletions = COMPLETION_VALUES[promptName];
|
|
294
|
-
if (!promptCompletions) {
|
|
295
|
-
return { completion: { values: [], hasMore: false } };
|
|
296
|
-
}
|
|
297
|
-
const argValues = promptCompletions[argName];
|
|
298
|
-
if (!argValues) {
|
|
299
|
-
return { completion: { values: [], hasMore: false } };
|
|
300
|
-
}
|
|
301
|
-
// Filter by current input
|
|
302
|
-
const filtered = argValues.filter((v) => v.toLowerCase().includes(currentValue));
|
|
303
|
-
return {
|
|
304
|
-
completion: {
|
|
305
|
-
values: filtered.slice(0, 20),
|
|
306
|
-
total: filtered.length,
|
|
307
|
-
hasMore: filtered.length > 20,
|
|
308
|
-
},
|
|
309
|
-
};
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
/**
|
|
313
|
-
* Register tool handlers
|
|
314
|
-
*/
|
|
315
|
-
function registerToolHandlers(server) {
|
|
316
|
-
// List available tools with annotations and output schemas
|
|
317
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
318
|
-
logger.debug("Listing tools");
|
|
319
|
-
return {
|
|
320
|
-
tools: allTools.map((tool) => ({
|
|
321
|
-
name: tool.name,
|
|
322
|
-
description: tool.description,
|
|
323
|
-
inputSchema: tool.inputSchema,
|
|
324
|
-
// Include output schema if defined
|
|
325
|
-
...(tool.outputSchema && { outputSchema: tool.outputSchema }),
|
|
326
|
-
// Include annotations if defined
|
|
327
|
-
...(tool.annotations && { annotations: tool.annotations }),
|
|
328
|
-
})),
|
|
329
|
-
};
|
|
330
|
-
});
|
|
331
|
-
// Handle tool calls
|
|
332
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
333
|
-
const { name, arguments: args } = request.params;
|
|
334
|
-
logger.info(`Tool called: ${name}`, { args });
|
|
335
|
-
const startTime = Date.now();
|
|
336
|
-
const tool = allTools.find((t) => t.name === name);
|
|
337
|
-
if (!tool) {
|
|
338
|
-
const availableTools = allTools
|
|
339
|
-
.map((t) => t.name)
|
|
340
|
-
.slice(0, 5)
|
|
341
|
-
.join(", ");
|
|
342
|
-
// Track failed tool call (unknown tool)
|
|
343
|
-
trackToolCall(name, false, Date.now() - startTime, CURRENT_VERSION);
|
|
344
|
-
return {
|
|
345
|
-
content: [
|
|
346
|
-
{
|
|
347
|
-
type: "text",
|
|
348
|
-
text: JSON.stringify({
|
|
349
|
-
error: `Unknown tool: ${name}`,
|
|
350
|
-
suggestion: `Available tools include: ${availableTools}...`,
|
|
351
|
-
hint: "Use ListTools to see all available tools",
|
|
352
|
-
}, null, 2),
|
|
353
|
-
},
|
|
354
|
-
],
|
|
355
|
-
isError: true,
|
|
356
|
-
};
|
|
357
|
-
}
|
|
358
|
-
try {
|
|
359
|
-
const result = await tool.handler(args);
|
|
360
|
-
const durationMs = Date.now() - startTime;
|
|
361
|
-
// Track successful tool call (fire-and-forget, won't block response)
|
|
362
|
-
trackToolCall(name, true, durationMs, CURRENT_VERSION);
|
|
363
|
-
// Include prominent update prompt in ALL responses when outdated
|
|
364
|
-
const updateWarning = getUpdateWarning();
|
|
365
|
-
if (updateWarning && versionCheckResult.isOutdated) {
|
|
366
|
-
// Prepend update notice with MANUAL instructions (auto-update not possible in sandbox)
|
|
367
|
-
const updatePrompt = {
|
|
368
|
-
"🚨 UPDATE AVAILABLE": {
|
|
369
|
-
message: `You are using v${CURRENT_VERSION} but v${versionCheckResult.latestVersion} is available.`,
|
|
370
|
-
userAction: {
|
|
371
|
-
instruction: "Tell the user to update manually. Auto-update is NOT possible because you run in a sandboxed environment without access to local files.",
|
|
372
|
-
steps: [
|
|
373
|
-
"1. Edit config file to use 'midnight-mcp@latest' instead of 'midnight-mcp'",
|
|
374
|
-
"2. Run: rm -rf ~/.npm/_npx (to clear npm cache)",
|
|
375
|
-
"3. Restart the editor completely (Cmd+Q on Mac, then reopen)",
|
|
376
|
-
],
|
|
377
|
-
configLocations: {
|
|
378
|
-
claudeDesktop: "~/Library/Application Support/Claude/claude_desktop_config.json",
|
|
379
|
-
cursor: ".cursor/mcp.json",
|
|
380
|
-
vscode: ".vscode/mcp.json",
|
|
381
|
-
windsurf: "~/.codeium/windsurf/mcp_config.json",
|
|
382
|
-
},
|
|
383
|
-
},
|
|
384
|
-
note: "If user already has @latest in config, they just need to clear cache (rm -rf ~/.npm/_npx) and restart.",
|
|
385
|
-
},
|
|
386
|
-
result,
|
|
387
|
-
};
|
|
388
|
-
return {
|
|
389
|
-
content: [
|
|
390
|
-
{
|
|
391
|
-
type: "text",
|
|
392
|
-
text: JSON.stringify(updatePrompt, null, 2),
|
|
393
|
-
},
|
|
394
|
-
],
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
return {
|
|
398
|
-
content: [
|
|
399
|
-
{
|
|
400
|
-
type: "text",
|
|
401
|
-
text: JSON.stringify(result, null, 2),
|
|
402
|
-
},
|
|
403
|
-
],
|
|
404
|
-
// Include structured content for machine-readable responses
|
|
405
|
-
// This allows clients to parse results without JSON.parse()
|
|
406
|
-
structuredContent: result,
|
|
407
|
-
};
|
|
408
|
-
}
|
|
409
|
-
catch (error) {
|
|
410
|
-
const durationMs = Date.now() - startTime;
|
|
411
|
-
logger.error(`Tool error: ${name}`, { error: String(error) });
|
|
412
|
-
// Track failed tool call
|
|
413
|
-
trackToolCall(name, false, durationMs, CURRENT_VERSION);
|
|
414
|
-
const errorResponse = formatErrorResponse(error, `tool:${name}`);
|
|
415
|
-
return {
|
|
416
|
-
content: [
|
|
417
|
-
{
|
|
418
|
-
type: "text",
|
|
419
|
-
text: JSON.stringify(errorResponse, null, 2),
|
|
420
|
-
},
|
|
421
|
-
],
|
|
422
|
-
isError: true,
|
|
423
|
-
};
|
|
424
|
-
}
|
|
425
|
-
});
|
|
426
|
-
}
|
|
427
|
-
/**
|
|
428
|
-
* Register resource handlers
|
|
429
|
-
*/
|
|
430
|
-
function registerResourceHandlers(server) {
|
|
431
|
-
// List available resources
|
|
432
|
-
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
433
|
-
logger.debug("Listing resources");
|
|
434
|
-
return {
|
|
435
|
-
resources: allResources.map((resource) => ({
|
|
436
|
-
uri: resource.uri,
|
|
437
|
-
name: resource.name,
|
|
438
|
-
description: resource.description,
|
|
439
|
-
mimeType: resource.mimeType,
|
|
440
|
-
})),
|
|
441
|
-
};
|
|
442
|
-
});
|
|
443
|
-
// List resource templates (RFC 6570 URI Templates)
|
|
444
|
-
server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => {
|
|
445
|
-
logger.debug("Listing resource templates");
|
|
446
|
-
return {
|
|
447
|
-
resourceTemplates: resourceTemplates.map((template) => ({
|
|
448
|
-
uriTemplate: template.uriTemplate,
|
|
449
|
-
name: template.name,
|
|
450
|
-
title: template.title,
|
|
451
|
-
description: template.description,
|
|
452
|
-
mimeType: template.mimeType,
|
|
453
|
-
})),
|
|
454
|
-
};
|
|
455
|
-
});
|
|
456
|
-
// Read resource content
|
|
457
|
-
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
458
|
-
const { uri } = request.params;
|
|
459
|
-
logger.info(`Resource requested: ${uri}`);
|
|
460
|
-
try {
|
|
461
|
-
let content = null;
|
|
462
|
-
let mimeType = "text/plain";
|
|
463
|
-
if (uri.startsWith("midnight://docs/")) {
|
|
464
|
-
content = await getDocumentation(uri);
|
|
465
|
-
mimeType = "text/markdown";
|
|
466
|
-
}
|
|
467
|
-
else if (uri.startsWith("midnight://code/")) {
|
|
468
|
-
content = await getCode(uri);
|
|
469
|
-
mimeType = "text/x-compact";
|
|
470
|
-
}
|
|
471
|
-
else if (uri.startsWith("midnight://schema/")) {
|
|
472
|
-
const schema = getSchema(uri);
|
|
473
|
-
content = schema ? JSON.stringify(schema, null, 2) : null;
|
|
474
|
-
mimeType = "application/json";
|
|
475
|
-
}
|
|
476
|
-
if (!content) {
|
|
477
|
-
const resourceTypes = [
|
|
478
|
-
"midnight://docs/",
|
|
479
|
-
"midnight://code/",
|
|
480
|
-
"midnight://schema/",
|
|
481
|
-
];
|
|
482
|
-
const validPrefix = resourceTypes.find((p) => uri.startsWith(p));
|
|
483
|
-
return {
|
|
484
|
-
contents: [
|
|
485
|
-
{
|
|
486
|
-
uri,
|
|
487
|
-
mimeType: "application/json",
|
|
488
|
-
text: JSON.stringify({
|
|
489
|
-
error: `Resource not found: ${uri}`,
|
|
490
|
-
suggestion: validPrefix
|
|
491
|
-
? `Check the resource path after '${validPrefix}'`
|
|
492
|
-
: `Valid resource prefixes: ${resourceTypes.join(", ")}`,
|
|
493
|
-
hint: "Use ListResources to see all available resources",
|
|
494
|
-
}, null, 2),
|
|
495
|
-
},
|
|
496
|
-
],
|
|
497
|
-
};
|
|
498
|
-
}
|
|
499
|
-
return {
|
|
500
|
-
contents: [
|
|
501
|
-
{
|
|
502
|
-
uri,
|
|
503
|
-
mimeType,
|
|
504
|
-
text: content,
|
|
505
|
-
},
|
|
506
|
-
],
|
|
507
|
-
};
|
|
508
|
-
}
|
|
509
|
-
catch (error) {
|
|
510
|
-
logger.error(`Resource error: ${uri}`, { error: String(error) });
|
|
511
|
-
const errorResponse = formatErrorResponse(error, `resource:${uri}`);
|
|
512
|
-
return {
|
|
513
|
-
contents: [
|
|
514
|
-
{
|
|
515
|
-
uri,
|
|
516
|
-
mimeType: "application/json",
|
|
517
|
-
text: JSON.stringify(errorResponse, null, 2),
|
|
518
|
-
},
|
|
519
|
-
],
|
|
520
|
-
};
|
|
521
|
-
}
|
|
522
|
-
});
|
|
523
|
-
}
|
|
524
|
-
/**
|
|
525
|
-
* Register prompt handlers
|
|
526
|
-
*/
|
|
527
|
-
function registerPromptHandlers(server) {
|
|
528
|
-
// List available prompts
|
|
529
|
-
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
530
|
-
logger.debug("Listing prompts");
|
|
531
|
-
return {
|
|
532
|
-
prompts: promptDefinitions.map((prompt) => ({
|
|
533
|
-
name: prompt.name,
|
|
534
|
-
description: prompt.description,
|
|
535
|
-
arguments: prompt.arguments,
|
|
536
|
-
})),
|
|
537
|
-
};
|
|
538
|
-
});
|
|
539
|
-
// Get prompt content
|
|
540
|
-
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
541
|
-
const { name, arguments: args } = request.params;
|
|
542
|
-
logger.info(`Prompt requested: ${name}`, { args });
|
|
543
|
-
const prompt = promptDefinitions.find((p) => p.name === name);
|
|
544
|
-
if (!prompt) {
|
|
545
|
-
return {
|
|
546
|
-
description: `Unknown prompt: ${name}`,
|
|
547
|
-
messages: [],
|
|
548
|
-
};
|
|
549
|
-
}
|
|
550
|
-
const messages = generatePrompt(name, args || {});
|
|
551
|
-
return {
|
|
552
|
-
description: prompt.description,
|
|
553
|
-
messages: messages.map((m) => ({
|
|
554
|
-
role: m.role,
|
|
555
|
-
content: m.content,
|
|
556
|
-
})),
|
|
557
|
-
};
|
|
558
|
-
});
|
|
559
|
-
}
|
|
560
|
-
/**
|
|
561
|
-
* Register resource subscription handlers
|
|
562
|
-
*/
|
|
563
|
-
function registerSubscriptionHandlers(server) {
|
|
564
|
-
// Handle subscribe requests
|
|
565
|
-
server.setRequestHandler(SubscribeRequestSchema, async (request) => {
|
|
566
|
-
const { uri } = request.params;
|
|
567
|
-
logger.info(`Subscribing to resource: ${uri}`);
|
|
568
|
-
// Validate that the URI is a valid resource
|
|
569
|
-
const validPrefixes = [
|
|
570
|
-
"midnight://docs/",
|
|
571
|
-
"midnight://code/",
|
|
572
|
-
"midnight://schema/",
|
|
573
|
-
];
|
|
574
|
-
const isValid = validPrefixes.some((prefix) => uri.startsWith(prefix));
|
|
575
|
-
if (!isValid) {
|
|
576
|
-
logger.warn(`Invalid subscription URI: ${uri}`);
|
|
577
|
-
throw new Error(`Invalid subscription URI: ${uri}. Valid prefixes: ${validPrefixes.join(", ")}`);
|
|
578
|
-
}
|
|
579
|
-
resourceSubscriptions.add(uri);
|
|
580
|
-
logger.debug(`Active subscriptions: ${resourceSubscriptions.size}`);
|
|
581
|
-
return {};
|
|
582
|
-
});
|
|
583
|
-
// Handle unsubscribe requests
|
|
584
|
-
server.setRequestHandler(UnsubscribeRequestSchema, async (request) => {
|
|
585
|
-
const { uri } = request.params;
|
|
586
|
-
logger.info(`Unsubscribing from resource: ${uri}`);
|
|
587
|
-
resourceSubscriptions.delete(uri);
|
|
588
|
-
logger.debug(`Active subscriptions: ${resourceSubscriptions.size}`);
|
|
589
|
-
return {};
|
|
590
|
-
});
|
|
591
|
-
}
|
|
592
|
-
/**
|
|
593
|
-
* Notify subscribers when a resource changes
|
|
594
|
-
* Call this when re-indexing or when docs are updated
|
|
595
|
-
*/
|
|
596
|
-
export function notifyResourceUpdate(server, uri) {
|
|
597
|
-
if (resourceSubscriptions.has(uri)) {
|
|
598
|
-
logger.info(`Notifying subscribers of update: ${uri}`);
|
|
599
|
-
// Send notification via the server
|
|
600
|
-
server.notification({
|
|
601
|
-
method: "notifications/resources/updated",
|
|
602
|
-
params: { uri },
|
|
603
|
-
});
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
/**
|
|
607
|
-
* Get the list of active subscriptions
|
|
608
|
-
*/
|
|
609
|
-
export function getActiveSubscriptions() {
|
|
610
|
-
return Array.from(resourceSubscriptions);
|
|
611
|
-
}
|
|
612
|
-
/**
|
|
613
|
-
* Setup sampling capability
|
|
614
|
-
* Registers a callback that allows the server to request LLM completions
|
|
615
|
-
*/
|
|
616
|
-
function setupSampling(server) {
|
|
617
|
-
// Create a sampling callback that uses the server's request method
|
|
618
|
-
const samplingCallback = async (request) => {
|
|
619
|
-
logger.debug("Requesting sampling from client", {
|
|
620
|
-
messageCount: request.messages.length,
|
|
621
|
-
maxTokens: request.maxTokens,
|
|
622
|
-
});
|
|
623
|
-
try {
|
|
624
|
-
// Request completion from the client
|
|
625
|
-
const response = await server.request({
|
|
626
|
-
method: "sampling/createMessage",
|
|
627
|
-
params: {
|
|
628
|
-
messages: request.messages,
|
|
629
|
-
systemPrompt: request.systemPrompt,
|
|
630
|
-
maxTokens: request.maxTokens || 2048,
|
|
631
|
-
temperature: request.temperature,
|
|
632
|
-
modelPreferences: request.modelPreferences,
|
|
633
|
-
},
|
|
634
|
-
},
|
|
635
|
-
// Use a schema that matches the expected response
|
|
636
|
-
{
|
|
637
|
-
parse: (data) => {
|
|
638
|
-
const response = data;
|
|
639
|
-
// Basic validation of expected response structure
|
|
640
|
-
if (!response || typeof response !== "object") {
|
|
641
|
-
throw new Error("Invalid sampling response: expected object");
|
|
642
|
-
}
|
|
643
|
-
if (!response.content || typeof response.content !== "object") {
|
|
644
|
-
throw new Error("Invalid sampling response: missing content");
|
|
645
|
-
}
|
|
646
|
-
return response;
|
|
647
|
-
},
|
|
648
|
-
_def: { typeName: "SamplingResponse" },
|
|
649
|
-
});
|
|
650
|
-
return response;
|
|
651
|
-
}
|
|
652
|
-
catch (error) {
|
|
653
|
-
logger.error("Sampling request failed", { error: String(error) });
|
|
654
|
-
throw error;
|
|
655
|
-
}
|
|
656
|
-
};
|
|
657
|
-
// Register the callback
|
|
658
|
-
registerSamplingCallback(samplingCallback);
|
|
659
|
-
logger.info("Sampling capability configured");
|
|
660
|
-
}
|
|
661
|
-
/**
|
|
662
|
-
* Initialize the server and vector store
|
|
663
|
-
*/
|
|
664
|
-
export async function initializeServer() {
|
|
665
|
-
logger.info("Initializing Midnight MCP Server...");
|
|
666
|
-
// Check for updates in background (non-blocking)
|
|
667
|
-
checkForUpdates().catch(() => {
|
|
668
|
-
// Ignore errors - version check is best-effort
|
|
669
|
-
});
|
|
670
|
-
// Initialize vector store
|
|
671
|
-
try {
|
|
672
|
-
await vectorStore.initialize();
|
|
673
|
-
logger.info("Vector store initialized");
|
|
674
|
-
}
|
|
675
|
-
catch (error) {
|
|
676
|
-
logger.warn("Vector store initialization failed, continuing without it", {
|
|
677
|
-
error: String(error),
|
|
678
|
-
});
|
|
679
|
-
}
|
|
680
|
-
// Create and return server
|
|
681
|
-
const server = createServer();
|
|
682
|
-
logger.info(`Server v${CURRENT_VERSION} created successfully`);
|
|
683
|
-
return server;
|
|
684
|
-
}
|
|
685
|
-
/**
|
|
686
|
-
* Start the server with stdio transport
|
|
687
|
-
*/
|
|
688
|
-
export async function startServer() {
|
|
689
|
-
const server = await initializeServer();
|
|
690
|
-
const transport = new StdioServerTransport();
|
|
691
|
-
await server.connect(transport);
|
|
692
|
-
// Now safe to send notifications
|
|
693
|
-
setServerConnected(true);
|
|
694
|
-
logger.info("Midnight MCP Server running on stdio");
|
|
695
|
-
}
|
|
696
|
-
//# sourceMappingURL=server.js.map
|
package/dist/services/index.d.ts
DELETED