midnight-mcp 0.1.9 → 0.1.10
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 +6 -3
- package/dist/tools/analyze.js +2 -0
- package/dist/tools/generation.js +3 -0
- package/dist/tools/health.js +2 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.js +3 -0
- package/dist/tools/meta.d.ts +61 -0
- package/dist/tools/meta.js +281 -0
- package/dist/tools/repository/handlers.d.ts +73 -15
- package/dist/tools/repository/handlers.js +184 -10
- package/dist/tools/repository/schemas.d.ts +25 -0
- package/dist/tools/repository/schemas.js +18 -0
- package/dist/tools/repository/tools.js +121 -1
- package/dist/tools/search.js +1 -0
- package/dist/types/mcp.d.ts +20 -0
- package/dist/utils/errors.d.ts +66 -0
- package/dist/utils/errors.js +70 -0
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -73,7 +73,7 @@ Restart your editor after adding the config. **No API keys required.**
|
|
|
73
73
|
|
|
74
74
|
## Features
|
|
75
75
|
|
|
76
|
-
**
|
|
76
|
+
**23 Tools** — Search, analyze, version tracking, AI generation, compound operations
|
|
77
77
|
|
|
78
78
|
| Category | Tools |
|
|
79
79
|
| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -81,8 +81,11 @@ Restart your editor after adding the config. **No API keys required.**
|
|
|
81
81
|
| Analysis | `midnight-analyze-contract`, `midnight-explain-circuit` |
|
|
82
82
|
| Repository | `midnight-get-file`, `midnight-list-examples`, `midnight-get-latest-updates` |
|
|
83
83
|
| Versioning | `midnight-get-version-info`, `midnight-check-breaking-changes`, `midnight-get-migration-guide`, `midnight-get-file-at-version`, `midnight-compare-syntax`, `midnight-get-latest-syntax` |
|
|
84
|
-
| AI Generation | `midnight-generate-contract`, `midnight-review-contract`, `midnight-document-contract`
|
|
85
|
-
|
|
|
84
|
+
| AI Generation | `midnight-generate-contract`, `midnight-review-contract`, `midnight-document-contract` _(requires sampling)_ |
|
|
85
|
+
| Compound | `midnight-upgrade-check`, `midnight-get-repo-context` _(saves 50-70% tokens)_ |
|
|
86
|
+
| Discovery | `midnight-list-tool-categories`, `midnight-list-category-tools`, `midnight-health-check`, `midnight-get-status` |
|
|
87
|
+
|
|
88
|
+
> **Tip:** Use compound tools (`midnight-upgrade-check`, `midnight-get-repo-context`) for efficient multi-step operations in a single call.
|
|
86
89
|
|
|
87
90
|
**9 Embedded Resources** — Quick references available offline: Compact syntax, SDK API, OpenZeppelin contracts, tokenomics, wallet integration, common errors
|
|
88
91
|
|
package/dist/tools/analyze.js
CHANGED
|
@@ -397,6 +397,7 @@ export const analyzeTools = [
|
|
|
397
397
|
readOnlyHint: true,
|
|
398
398
|
idempotentHint: true,
|
|
399
399
|
title: "Analyze Compact Contract",
|
|
400
|
+
category: "analyze",
|
|
400
401
|
},
|
|
401
402
|
handler: analyzeContract,
|
|
402
403
|
},
|
|
@@ -418,6 +419,7 @@ export const analyzeTools = [
|
|
|
418
419
|
readOnlyHint: true,
|
|
419
420
|
idempotentHint: true,
|
|
420
421
|
title: "Explain Circuit",
|
|
422
|
+
category: "analyze",
|
|
421
423
|
},
|
|
422
424
|
handler: explainCircuit,
|
|
423
425
|
},
|
package/dist/tools/generation.js
CHANGED
|
@@ -182,6 +182,7 @@ EXAMPLE USAGE:
|
|
|
182
182
|
idempotentHint: false,
|
|
183
183
|
openWorldHint: true,
|
|
184
184
|
longRunningHint: true,
|
|
185
|
+
category: "generation",
|
|
185
186
|
},
|
|
186
187
|
handler: handleGenerateContract,
|
|
187
188
|
},
|
|
@@ -223,6 +224,7 @@ OUTPUT INCLUDES:
|
|
|
223
224
|
idempotentHint: true,
|
|
224
225
|
openWorldHint: true,
|
|
225
226
|
longRunningHint: true,
|
|
227
|
+
category: "generation",
|
|
226
228
|
},
|
|
227
229
|
handler: handleReviewContract,
|
|
228
230
|
},
|
|
@@ -268,6 +270,7 @@ MARKDOWN INCLUDES:
|
|
|
268
270
|
idempotentHint: true,
|
|
269
271
|
openWorldHint: true,
|
|
270
272
|
longRunningHint: true,
|
|
273
|
+
category: "generation",
|
|
271
274
|
},
|
|
272
275
|
handler: handleDocumentContract,
|
|
273
276
|
},
|
package/dist/tools/health.js
CHANGED
|
@@ -140,6 +140,7 @@ export const healthTools = [
|
|
|
140
140
|
readOnlyHint: true,
|
|
141
141
|
idempotentHint: true,
|
|
142
142
|
title: "Health Check",
|
|
143
|
+
category: "health",
|
|
143
144
|
},
|
|
144
145
|
handler: healthCheck,
|
|
145
146
|
},
|
|
@@ -155,6 +156,7 @@ export const healthTools = [
|
|
|
155
156
|
readOnlyHint: true,
|
|
156
157
|
idempotentHint: true,
|
|
157
158
|
title: "Get Server Status",
|
|
159
|
+
category: "health",
|
|
158
160
|
},
|
|
159
161
|
handler: getStatus,
|
|
160
162
|
},
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export type { GetFileInput, ListExamplesInput, GetLatestUpdatesInput, } from "./
|
|
|
7
7
|
export { healthTools, healthCheck, getStatus } from "./health.js";
|
|
8
8
|
export type { HealthCheckInput, GetStatusInput } from "./health.js";
|
|
9
9
|
export { generationTools, generationHandlers } from "./generation.js";
|
|
10
|
+
export { metaTools, listToolCategories, listCategoryTools } from "./meta.js";
|
|
10
11
|
export type { ExtendedToolDefinition, ToolAnnotations, OutputSchema, } from "../types/index.js";
|
|
11
12
|
import type { ExtendedToolDefinition } from "../types/index.js";
|
|
12
13
|
export declare const allTools: ExtendedToolDefinition[];
|
package/dist/tools/index.js
CHANGED
|
@@ -3,13 +3,16 @@ export { analyzeTools, analyzeContract, explainCircuit } from "./analyze.js";
|
|
|
3
3
|
export { repositoryTools, getFile, listExamples, getLatestUpdates, } from "./repository.js";
|
|
4
4
|
export { healthTools, healthCheck, getStatus } from "./health.js";
|
|
5
5
|
export { generationTools, generationHandlers } from "./generation.js";
|
|
6
|
+
export { metaTools, listToolCategories, listCategoryTools } from "./meta.js";
|
|
6
7
|
// Combined tool list for MCP server
|
|
7
8
|
import { searchTools } from "./search.js";
|
|
8
9
|
import { analyzeTools } from "./analyze.js";
|
|
9
10
|
import { repositoryTools } from "./repository.js";
|
|
10
11
|
import { healthTools } from "./health.js";
|
|
11
12
|
import { generationTools } from "./generation.js";
|
|
13
|
+
import { metaTools } from "./meta.js";
|
|
12
14
|
export const allTools = [
|
|
15
|
+
...metaTools, // Discovery tools first for visibility
|
|
13
16
|
...searchTools,
|
|
14
17
|
...analyzeTools,
|
|
15
18
|
...repositoryTools,
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meta-tools for progressive disclosure and tool discovery
|
|
3
|
+
* These tools help AI agents efficiently discover and use available capabilities
|
|
4
|
+
*/
|
|
5
|
+
import type { ExtendedToolDefinition, OutputSchema, ToolCategory } from "../types/index.js";
|
|
6
|
+
interface ListCategoriesInput {
|
|
7
|
+
includeToolCounts?: boolean;
|
|
8
|
+
}
|
|
9
|
+
interface ListCategoryToolsInput {
|
|
10
|
+
category: ToolCategory;
|
|
11
|
+
includeSchemas?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* List available tool categories
|
|
15
|
+
* Use this first to understand what's available before drilling into specific tools
|
|
16
|
+
*/
|
|
17
|
+
export declare function listToolCategories(_input: ListCategoriesInput): Promise<{
|
|
18
|
+
categories: {
|
|
19
|
+
name: string;
|
|
20
|
+
description: string;
|
|
21
|
+
toolCount: number;
|
|
22
|
+
useCases: string[];
|
|
23
|
+
}[];
|
|
24
|
+
totalTools: number;
|
|
25
|
+
recommendation: string;
|
|
26
|
+
tip: string;
|
|
27
|
+
}>;
|
|
28
|
+
/**
|
|
29
|
+
* List tools within a specific category
|
|
30
|
+
* Progressive disclosure: drill into a category to see its tools
|
|
31
|
+
*/
|
|
32
|
+
export declare function listCategoryTools(input: ListCategoryToolsInput): Promise<{
|
|
33
|
+
error: string;
|
|
34
|
+
availableCategories: string[];
|
|
35
|
+
suggestion: string;
|
|
36
|
+
category?: undefined;
|
|
37
|
+
description?: undefined;
|
|
38
|
+
tools?: undefined;
|
|
39
|
+
} | {
|
|
40
|
+
category: ToolCategory;
|
|
41
|
+
description: string;
|
|
42
|
+
tools: {
|
|
43
|
+
inputSchema?: {
|
|
44
|
+
type: "object";
|
|
45
|
+
properties: Record<string, unknown>;
|
|
46
|
+
required?: string[];
|
|
47
|
+
} | undefined;
|
|
48
|
+
outputSchema?: OutputSchema | undefined;
|
|
49
|
+
name: string;
|
|
50
|
+
description: string;
|
|
51
|
+
title: string;
|
|
52
|
+
isCompound: boolean;
|
|
53
|
+
requiresSampling: boolean | undefined;
|
|
54
|
+
}[];
|
|
55
|
+
suggestion: string;
|
|
56
|
+
error?: undefined;
|
|
57
|
+
availableCategories?: undefined;
|
|
58
|
+
}>;
|
|
59
|
+
export declare const metaTools: ExtendedToolDefinition[];
|
|
60
|
+
export {};
|
|
61
|
+
//# sourceMappingURL=meta.d.ts.map
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meta-tools for progressive disclosure and tool discovery
|
|
3
|
+
* These tools help AI agents efficiently discover and use available capabilities
|
|
4
|
+
*/
|
|
5
|
+
// Import all tool arrays to build the index
|
|
6
|
+
import { searchTools } from "./search.js";
|
|
7
|
+
import { analyzeTools } from "./analyze.js";
|
|
8
|
+
import { repositoryTools } from "./repository.js";
|
|
9
|
+
import { healthTools } from "./health.js";
|
|
10
|
+
import { generationTools } from "./generation.js";
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// Tool Category Descriptions
|
|
13
|
+
// ============================================================================
|
|
14
|
+
const CATEGORY_INFO = {
|
|
15
|
+
search: {
|
|
16
|
+
description: "Semantic search across Midnight codebase - find code by meaning, not keywords",
|
|
17
|
+
useCases: [
|
|
18
|
+
"Find example implementations",
|
|
19
|
+
"Search for patterns",
|
|
20
|
+
"Discover relevant code",
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
analyze: {
|
|
24
|
+
description: "Static analysis of Compact contracts - security, structure, patterns",
|
|
25
|
+
useCases: [
|
|
26
|
+
"Security audit",
|
|
27
|
+
"Code review",
|
|
28
|
+
"Understand contract structure",
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
repository: {
|
|
32
|
+
description: "Access repository files, examples, and recent updates",
|
|
33
|
+
useCases: [
|
|
34
|
+
"Get specific files",
|
|
35
|
+
"List examples",
|
|
36
|
+
"Track repository changes",
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
versioning: {
|
|
40
|
+
description: "Version management, breaking changes, and migration assistance",
|
|
41
|
+
useCases: [
|
|
42
|
+
"Check for updates",
|
|
43
|
+
"Plan upgrades",
|
|
44
|
+
"Compare versions",
|
|
45
|
+
"Get migration guides",
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
generation: {
|
|
49
|
+
description: "AI-powered code generation, review, and documentation (requires sampling)",
|
|
50
|
+
useCases: ["Generate contracts", "Review code", "Generate documentation"],
|
|
51
|
+
},
|
|
52
|
+
health: {
|
|
53
|
+
description: "Server health checks and status monitoring",
|
|
54
|
+
useCases: ["Check API status", "Monitor rate limits", "Debug connectivity"],
|
|
55
|
+
},
|
|
56
|
+
compound: {
|
|
57
|
+
description: "Multi-step operations in a single call - saves tokens and reduces latency",
|
|
58
|
+
useCases: [
|
|
59
|
+
"Full upgrade analysis",
|
|
60
|
+
"Get complete repo context",
|
|
61
|
+
"One-shot operations",
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
const listCategoriesOutputSchema = {
|
|
66
|
+
type: "object",
|
|
67
|
+
properties: {
|
|
68
|
+
categories: {
|
|
69
|
+
type: "array",
|
|
70
|
+
description: "Available tool categories",
|
|
71
|
+
items: {
|
|
72
|
+
type: "object",
|
|
73
|
+
properties: {
|
|
74
|
+
name: { type: "string", description: "Category identifier" },
|
|
75
|
+
description: {
|
|
76
|
+
type: "string",
|
|
77
|
+
description: "What the category does",
|
|
78
|
+
},
|
|
79
|
+
toolCount: { type: "number", description: "Number of tools" },
|
|
80
|
+
useCases: {
|
|
81
|
+
type: "array",
|
|
82
|
+
description: "When to use this category",
|
|
83
|
+
items: { type: "string" },
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
totalTools: { type: "number", description: "Total tool count" },
|
|
89
|
+
recommendation: {
|
|
90
|
+
type: "string",
|
|
91
|
+
description: "Suggested starting point",
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
required: ["categories", "totalTools"],
|
|
95
|
+
description: "Tool categories for progressive discovery",
|
|
96
|
+
};
|
|
97
|
+
const listCategoryToolsOutputSchema = {
|
|
98
|
+
type: "object",
|
|
99
|
+
properties: {
|
|
100
|
+
category: { type: "string", description: "Category name" },
|
|
101
|
+
tools: {
|
|
102
|
+
type: "array",
|
|
103
|
+
description: "Tools in this category",
|
|
104
|
+
items: {
|
|
105
|
+
type: "object",
|
|
106
|
+
properties: {
|
|
107
|
+
name: { type: "string", description: "Tool name" },
|
|
108
|
+
description: { type: "string", description: "What the tool does" },
|
|
109
|
+
title: { type: "string", description: "Human-readable title" },
|
|
110
|
+
isCompound: {
|
|
111
|
+
type: "boolean",
|
|
112
|
+
description: "Whether this is a compound tool",
|
|
113
|
+
},
|
|
114
|
+
requiresSampling: {
|
|
115
|
+
type: "boolean",
|
|
116
|
+
description: "Requires client sampling capability",
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
suggestion: { type: "string", description: "Usage suggestion" },
|
|
122
|
+
},
|
|
123
|
+
required: ["category", "tools"],
|
|
124
|
+
description: "Tools within a specific category",
|
|
125
|
+
};
|
|
126
|
+
// ============================================================================
|
|
127
|
+
// Handler Functions
|
|
128
|
+
// ============================================================================
|
|
129
|
+
// Build tool index by category
|
|
130
|
+
function getToolsByCategory() {
|
|
131
|
+
const allTools = [
|
|
132
|
+
...searchTools,
|
|
133
|
+
...analyzeTools,
|
|
134
|
+
...repositoryTools,
|
|
135
|
+
...healthTools,
|
|
136
|
+
...generationTools,
|
|
137
|
+
];
|
|
138
|
+
const byCategory = new Map();
|
|
139
|
+
for (const tool of allTools) {
|
|
140
|
+
const category = tool.annotations?.category || "repository";
|
|
141
|
+
if (!byCategory.has(category)) {
|
|
142
|
+
byCategory.set(category, []);
|
|
143
|
+
}
|
|
144
|
+
byCategory.get(category).push(tool);
|
|
145
|
+
}
|
|
146
|
+
return byCategory;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* List available tool categories
|
|
150
|
+
* Use this first to understand what's available before drilling into specific tools
|
|
151
|
+
*/
|
|
152
|
+
export async function listToolCategories(_input) {
|
|
153
|
+
const toolsByCategory = getToolsByCategory();
|
|
154
|
+
const categories = Object.entries(CATEGORY_INFO).map(([name, info]) => ({
|
|
155
|
+
name,
|
|
156
|
+
description: info.description,
|
|
157
|
+
toolCount: toolsByCategory.get(name)?.length || 0,
|
|
158
|
+
useCases: info.useCases,
|
|
159
|
+
}));
|
|
160
|
+
// Filter out empty categories
|
|
161
|
+
const nonEmptyCategories = categories.filter((c) => c.toolCount > 0);
|
|
162
|
+
const totalTools = nonEmptyCategories.reduce((sum, c) => sum + c.toolCount, 0);
|
|
163
|
+
return {
|
|
164
|
+
categories: nonEmptyCategories,
|
|
165
|
+
totalTools,
|
|
166
|
+
recommendation: "Start with 'compound' category for efficient multi-step operations, or 'search' to find relevant code.",
|
|
167
|
+
tip: "Use midnight-list-category-tools to see tools within a specific category.",
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* List tools within a specific category
|
|
172
|
+
* Progressive disclosure: drill into a category to see its tools
|
|
173
|
+
*/
|
|
174
|
+
export async function listCategoryTools(input) {
|
|
175
|
+
const toolsByCategory = getToolsByCategory();
|
|
176
|
+
const tools = toolsByCategory.get(input.category) || [];
|
|
177
|
+
if (tools.length === 0) {
|
|
178
|
+
return {
|
|
179
|
+
error: `Unknown or empty category: ${input.category}`,
|
|
180
|
+
availableCategories: Object.keys(CATEGORY_INFO),
|
|
181
|
+
suggestion: "Use midnight-list-tool-categories to see available categories.",
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
const categoryInfo = CATEGORY_INFO[input.category];
|
|
185
|
+
return {
|
|
186
|
+
category: input.category,
|
|
187
|
+
description: categoryInfo.description,
|
|
188
|
+
tools: tools.map((t) => ({
|
|
189
|
+
name: t.name,
|
|
190
|
+
description: t.description.split("\n")[0], // First line only
|
|
191
|
+
title: t.annotations?.title || t.name,
|
|
192
|
+
isCompound: t.annotations?.category === "compound",
|
|
193
|
+
requiresSampling: t.annotations?.longRunningHint &&
|
|
194
|
+
t.annotations?.category === "generation",
|
|
195
|
+
...(input.includeSchemas && {
|
|
196
|
+
inputSchema: t.inputSchema,
|
|
197
|
+
outputSchema: t.outputSchema,
|
|
198
|
+
}),
|
|
199
|
+
})),
|
|
200
|
+
suggestion: generateCategorySuggestion(input.category),
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
function generateCategorySuggestion(category) {
|
|
204
|
+
switch (category) {
|
|
205
|
+
case "compound":
|
|
206
|
+
return "🚀 Compound tools save 50-70% tokens. Use midnight-upgrade-check or midnight-get-repo-context for efficient operations.";
|
|
207
|
+
case "search":
|
|
208
|
+
return "💡 Search tools use semantic matching - describe what you want in natural language.";
|
|
209
|
+
case "generation":
|
|
210
|
+
return "⚠️ Generation tools require sampling capability. They use the client's LLM for AI-powered operations.";
|
|
211
|
+
case "versioning":
|
|
212
|
+
return "📦 For version checks, prefer midnight-upgrade-check (compound) over individual version tools.";
|
|
213
|
+
case "analyze":
|
|
214
|
+
return "🔍 Analyze tools work on Compact code. Provide the contract source code directly.";
|
|
215
|
+
default:
|
|
216
|
+
return `Use these tools for ${CATEGORY_INFO[category]?.useCases[0] || "related operations"}.`;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// ============================================================================
|
|
220
|
+
// Tool Definitions
|
|
221
|
+
// ============================================================================
|
|
222
|
+
export const metaTools = [
|
|
223
|
+
{
|
|
224
|
+
name: "midnight-list-tool-categories",
|
|
225
|
+
description: "📋 DISCOVERY TOOL: List available tool categories for progressive exploration. Use this FIRST to understand what capabilities are available, then drill into specific categories with midnight-list-category-tools. Reduces cognitive load by organizing 21 tools into 7 logical groups.",
|
|
226
|
+
inputSchema: {
|
|
227
|
+
type: "object",
|
|
228
|
+
properties: {
|
|
229
|
+
includeToolCounts: {
|
|
230
|
+
type: "boolean",
|
|
231
|
+
description: "Include number of tools per category (default: true)",
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
required: [],
|
|
235
|
+
},
|
|
236
|
+
outputSchema: listCategoriesOutputSchema,
|
|
237
|
+
annotations: {
|
|
238
|
+
readOnlyHint: true,
|
|
239
|
+
idempotentHint: true,
|
|
240
|
+
title: "📋 List Tool Categories",
|
|
241
|
+
category: "health",
|
|
242
|
+
},
|
|
243
|
+
handler: listToolCategories,
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
name: "midnight-list-category-tools",
|
|
247
|
+
description: "📋 DISCOVERY TOOL: List tools within a specific category. Use after midnight-list-tool-categories to see detailed tool information for a category of interest. Supports progressive disclosure pattern.",
|
|
248
|
+
inputSchema: {
|
|
249
|
+
type: "object",
|
|
250
|
+
properties: {
|
|
251
|
+
category: {
|
|
252
|
+
type: "string",
|
|
253
|
+
enum: [
|
|
254
|
+
"search",
|
|
255
|
+
"analyze",
|
|
256
|
+
"repository",
|
|
257
|
+
"versioning",
|
|
258
|
+
"generation",
|
|
259
|
+
"health",
|
|
260
|
+
"compound",
|
|
261
|
+
],
|
|
262
|
+
description: "Category to list tools for",
|
|
263
|
+
},
|
|
264
|
+
includeSchemas: {
|
|
265
|
+
type: "boolean",
|
|
266
|
+
description: "Include input/output schemas (default: false)",
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
required: ["category"],
|
|
270
|
+
},
|
|
271
|
+
outputSchema: listCategoryToolsOutputSchema,
|
|
272
|
+
annotations: {
|
|
273
|
+
readOnlyHint: true,
|
|
274
|
+
idempotentHint: true,
|
|
275
|
+
title: "📋 List Category Tools",
|
|
276
|
+
category: "health",
|
|
277
|
+
},
|
|
278
|
+
handler: listCategoryTools,
|
|
279
|
+
},
|
|
280
|
+
];
|
|
281
|
+
//# sourceMappingURL=meta.js.map
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Repository handler functions
|
|
3
3
|
* Business logic for repository-related MCP tools
|
|
4
4
|
*/
|
|
5
|
-
import type { GetFileInput, ListExamplesInput, GetLatestUpdatesInput, GetVersionInfoInput, CheckBreakingChangesInput, GetMigrationGuideInput, GetFileAtVersionInput, CompareSyntaxInput, GetLatestSyntaxInput } from "./schemas.js";
|
|
5
|
+
import type { GetFileInput, ListExamplesInput, GetLatestUpdatesInput, GetVersionInfoInput, CheckBreakingChangesInput, GetMigrationGuideInput, GetFileAtVersionInput, CompareSyntaxInput, GetLatestSyntaxInput, UpgradeCheckInput, FullRepoContextInput } from "./schemas.js";
|
|
6
6
|
/**
|
|
7
7
|
* Resolve repository name alias to owner/repo
|
|
8
8
|
*/
|
|
@@ -15,22 +15,21 @@ export declare function resolveRepo(repoName?: string): {
|
|
|
15
15
|
*/
|
|
16
16
|
export declare function getFile(input: GetFileInput): Promise<{
|
|
17
17
|
error: string;
|
|
18
|
+
code: "UNKNOWN_REPOSITORY";
|
|
18
19
|
suggestion: string;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
url?: undefined;
|
|
20
|
+
correction: {
|
|
21
|
+
invalidValue: string;
|
|
22
|
+
validValues: string[];
|
|
23
|
+
parameterName: string;
|
|
24
|
+
};
|
|
25
25
|
} | {
|
|
26
26
|
error: string;
|
|
27
|
-
|
|
27
|
+
code: "RESOURCE_NOT_FOUND";
|
|
28
28
|
suggestion: string;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
url?: undefined;
|
|
29
|
+
correction: {
|
|
30
|
+
suggestions?: string[] | undefined;
|
|
31
|
+
invalidPath: string;
|
|
32
|
+
};
|
|
34
33
|
} | {
|
|
35
34
|
content: string;
|
|
36
35
|
path: string;
|
|
@@ -38,8 +37,6 @@ export declare function getFile(input: GetFileInput): Promise<{
|
|
|
38
37
|
sha: string;
|
|
39
38
|
size: number;
|
|
40
39
|
url: string;
|
|
41
|
-
error?: undefined;
|
|
42
|
-
suggestion?: undefined;
|
|
43
40
|
}>;
|
|
44
41
|
/**
|
|
45
42
|
* List available example contracts and DApps
|
|
@@ -177,4 +174,65 @@ export declare function getLatestSyntax(input: GetLatestSyntaxInput): Promise<{
|
|
|
177
174
|
warning?: undefined;
|
|
178
175
|
examplePaths?: undefined;
|
|
179
176
|
}>;
|
|
177
|
+
/**
|
|
178
|
+
* Compound tool: Full upgrade check
|
|
179
|
+
* Combines: getVersionInfo + checkBreakingChanges + getMigrationGuide
|
|
180
|
+
* Reduces 3 tool calls to 1, saving ~60% tokens
|
|
181
|
+
*/
|
|
182
|
+
export declare function upgradeCheck(input: UpgradeCheckInput): Promise<{
|
|
183
|
+
repository: string;
|
|
184
|
+
currentVersion: string;
|
|
185
|
+
version: {
|
|
186
|
+
latest: string;
|
|
187
|
+
latestStable: string;
|
|
188
|
+
publishedAt: string | null;
|
|
189
|
+
isOutdated: boolean;
|
|
190
|
+
versionsBehind: number;
|
|
191
|
+
};
|
|
192
|
+
breakingChanges: {
|
|
193
|
+
count: number;
|
|
194
|
+
hasBreakingChanges: boolean;
|
|
195
|
+
items: string[];
|
|
196
|
+
};
|
|
197
|
+
migration: {
|
|
198
|
+
steps: string[];
|
|
199
|
+
deprecations: string[];
|
|
200
|
+
newFeatures: string[];
|
|
201
|
+
} | null;
|
|
202
|
+
urgency: "none" | "low" | "medium" | "high" | "critical";
|
|
203
|
+
recommendation: string;
|
|
204
|
+
}>;
|
|
205
|
+
/**
|
|
206
|
+
* Compound tool: Full repository context
|
|
207
|
+
* Combines: getVersionInfo + getLatestSyntax + listExamples (filtered)
|
|
208
|
+
* Provides everything needed to start working with a repo
|
|
209
|
+
*/
|
|
210
|
+
export declare function getFullRepoContext(input: FullRepoContextInput): Promise<{
|
|
211
|
+
repository: string;
|
|
212
|
+
quickStart: {
|
|
213
|
+
version: string;
|
|
214
|
+
installCommand: string;
|
|
215
|
+
docsUrl: string;
|
|
216
|
+
};
|
|
217
|
+
version: {
|
|
218
|
+
current: string;
|
|
219
|
+
stable: string | null;
|
|
220
|
+
publishedAt: string | null;
|
|
221
|
+
recentReleases: {
|
|
222
|
+
tag: string;
|
|
223
|
+
date: string;
|
|
224
|
+
}[];
|
|
225
|
+
};
|
|
226
|
+
syntax: {
|
|
227
|
+
version: string;
|
|
228
|
+
files: string[];
|
|
229
|
+
primaryReference: string | null;
|
|
230
|
+
} | null;
|
|
231
|
+
examples: {
|
|
232
|
+
name: string;
|
|
233
|
+
description: string;
|
|
234
|
+
complexity: string;
|
|
235
|
+
}[];
|
|
236
|
+
note: string;
|
|
237
|
+
}>;
|
|
180
238
|
//# sourceMappingURL=handlers.d.ts.map
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { githubClient } from "../../pipeline/index.js";
|
|
6
6
|
import { releaseTracker } from "../../pipeline/releases.js";
|
|
7
|
-
import { logger, DEFAULT_REPOSITORIES } from "../../utils/index.js";
|
|
7
|
+
import { logger, DEFAULT_REPOSITORIES, SelfCorrectionHints, } from "../../utils/index.js";
|
|
8
8
|
import { REPO_ALIASES, EXAMPLES } from "./constants.js";
|
|
9
9
|
/**
|
|
10
10
|
* Resolve repository name alias to owner/repo
|
|
@@ -36,18 +36,11 @@ export async function getFile(input) {
|
|
|
36
36
|
logger.debug("Getting file", { repo: input.repo, path: input.path });
|
|
37
37
|
const repoInfo = resolveRepo(input.repo);
|
|
38
38
|
if (!repoInfo) {
|
|
39
|
-
return
|
|
40
|
-
error: `Unknown repository: ${input.repo}`,
|
|
41
|
-
suggestion: `Valid repositories: ${Object.keys(REPO_ALIASES).join(", ")}`,
|
|
42
|
-
};
|
|
39
|
+
return SelfCorrectionHints.UNKNOWN_REPO(input.repo, Object.keys(REPO_ALIASES));
|
|
43
40
|
}
|
|
44
41
|
const file = await githubClient.getFileContent(repoInfo.owner, repoInfo.repo, input.path, input.ref);
|
|
45
42
|
if (!file) {
|
|
46
|
-
return {
|
|
47
|
-
error: `File not found: ${input.path}`,
|
|
48
|
-
repository: `${repoInfo.owner}/${repoInfo.repo}`,
|
|
49
|
-
suggestion: "Check the file path and try again. Use midnight:list-examples to see available example files.",
|
|
50
|
-
};
|
|
43
|
+
return SelfCorrectionHints.FILE_NOT_FOUND(input.path, `${repoInfo.owner}/${repoInfo.repo}`);
|
|
51
44
|
}
|
|
52
45
|
return {
|
|
53
46
|
content: file.content,
|
|
@@ -335,4 +328,185 @@ export async function getLatestSyntax(input) {
|
|
|
335
328
|
note: `This is the authoritative syntax reference at version ${reference.version}. Use this to ensure contracts are compilable.`,
|
|
336
329
|
};
|
|
337
330
|
}
|
|
331
|
+
// ============================================================================
|
|
332
|
+
// COMPOUND TOOLS - Reduce multiple API calls to single operations
|
|
333
|
+
// These tools combine related operations to minimize round-trips and token usage
|
|
334
|
+
// ============================================================================
|
|
335
|
+
/**
|
|
336
|
+
* Compound tool: Full upgrade check
|
|
337
|
+
* Combines: getVersionInfo + checkBreakingChanges + getMigrationGuide
|
|
338
|
+
* Reduces 3 tool calls to 1, saving ~60% tokens
|
|
339
|
+
*/
|
|
340
|
+
export async function upgradeCheck(input) {
|
|
341
|
+
const repoName = input?.repo || "compact";
|
|
342
|
+
const currentVersion = input.currentVersion;
|
|
343
|
+
logger.debug("Running compound upgrade check", {
|
|
344
|
+
repo: repoName,
|
|
345
|
+
currentVersion,
|
|
346
|
+
});
|
|
347
|
+
const resolved = resolveRepo(repoName);
|
|
348
|
+
if (!resolved) {
|
|
349
|
+
throw new Error(`Unknown repository: ${repoName}. Available: ${Object.keys(REPO_ALIASES).join(", ")}`);
|
|
350
|
+
}
|
|
351
|
+
// Fetch all data in parallel
|
|
352
|
+
const [versionInfo, outdatedInfo, breakingChanges] = await Promise.all([
|
|
353
|
+
releaseTracker.getVersionInfo(resolved.owner, resolved.repo),
|
|
354
|
+
releaseTracker.isOutdated(resolved.owner, resolved.repo, currentVersion),
|
|
355
|
+
releaseTracker.getBreakingChangesSince(resolved.owner, resolved.repo, currentVersion),
|
|
356
|
+
]);
|
|
357
|
+
const latestVersion = versionInfo.latestStableRelease?.tag || versionInfo.latestRelease?.tag;
|
|
358
|
+
// Only fetch migration guide if there are breaking changes
|
|
359
|
+
let migrationGuide = null;
|
|
360
|
+
if (breakingChanges.length > 0 && latestVersion) {
|
|
361
|
+
migrationGuide = await releaseTracker.getMigrationGuide(resolved.owner, resolved.repo, currentVersion, latestVersion);
|
|
362
|
+
}
|
|
363
|
+
// Compute upgrade urgency
|
|
364
|
+
const urgency = computeUpgradeUrgency(outdatedInfo, breakingChanges.length);
|
|
365
|
+
return {
|
|
366
|
+
repository: `${resolved.owner}/${resolved.repo}`,
|
|
367
|
+
currentVersion,
|
|
368
|
+
// Version summary
|
|
369
|
+
version: {
|
|
370
|
+
latest: latestVersion || "No releases",
|
|
371
|
+
latestStable: versionInfo.latestStableRelease?.tag || "No stable releases",
|
|
372
|
+
publishedAt: versionInfo.latestRelease?.publishedAt || null,
|
|
373
|
+
isOutdated: outdatedInfo.isOutdated,
|
|
374
|
+
versionsBehind: outdatedInfo.versionsBehind,
|
|
375
|
+
},
|
|
376
|
+
// Breaking changes summary
|
|
377
|
+
breakingChanges: {
|
|
378
|
+
count: breakingChanges.length,
|
|
379
|
+
hasBreakingChanges: breakingChanges.length > 0,
|
|
380
|
+
items: breakingChanges.slice(0, 10), // Limit to avoid token bloat
|
|
381
|
+
},
|
|
382
|
+
// Migration guide (only if needed)
|
|
383
|
+
migration: migrationGuide
|
|
384
|
+
? {
|
|
385
|
+
steps: migrationGuide.migrationSteps,
|
|
386
|
+
deprecations: migrationGuide.deprecations,
|
|
387
|
+
newFeatures: migrationGuide.newFeatures.slice(0, 5),
|
|
388
|
+
}
|
|
389
|
+
: null,
|
|
390
|
+
// Actionable recommendation
|
|
391
|
+
urgency,
|
|
392
|
+
recommendation: generateUpgradeRecommendation(urgency, breakingChanges.length, outdatedInfo),
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Compound tool: Full repository context
|
|
397
|
+
* Combines: getVersionInfo + getLatestSyntax + listExamples (filtered)
|
|
398
|
+
* Provides everything needed to start working with a repo
|
|
399
|
+
*/
|
|
400
|
+
export async function getFullRepoContext(input) {
|
|
401
|
+
const repoName = input?.repo || "compact";
|
|
402
|
+
logger.debug("Getting full repo context", { repo: repoName });
|
|
403
|
+
const resolved = resolveRepo(repoName);
|
|
404
|
+
if (!resolved) {
|
|
405
|
+
throw new Error(`Unknown repository: ${repoName}. Available: ${Object.keys(REPO_ALIASES).join(", ")}`);
|
|
406
|
+
}
|
|
407
|
+
// Fetch version info
|
|
408
|
+
const versionInfo = await releaseTracker.getVersionInfo(resolved.owner, resolved.repo);
|
|
409
|
+
const version = versionInfo.latestStableRelease?.tag ||
|
|
410
|
+
versionInfo.latestRelease?.tag ||
|
|
411
|
+
"main";
|
|
412
|
+
// Conditionally fetch syntax reference
|
|
413
|
+
let syntaxRef = null;
|
|
414
|
+
if (input.includeSyntax !== false) {
|
|
415
|
+
syntaxRef = await releaseTracker.getLatestSyntaxReference(resolved.owner, resolved.repo);
|
|
416
|
+
}
|
|
417
|
+
// Get relevant examples for this repo
|
|
418
|
+
let examples = [];
|
|
419
|
+
if (input.includeExamples !== false) {
|
|
420
|
+
// Filter examples relevant to this repo type
|
|
421
|
+
const repoType = getRepoType(repoName);
|
|
422
|
+
examples = EXAMPLES.filter((ex) => repoType === "all" || ex.category === repoType || repoType === "compact")
|
|
423
|
+
.slice(0, 5)
|
|
424
|
+
.map((ex) => ({
|
|
425
|
+
name: ex.name,
|
|
426
|
+
description: ex.description,
|
|
427
|
+
complexity: ex.complexity,
|
|
428
|
+
}));
|
|
429
|
+
}
|
|
430
|
+
return {
|
|
431
|
+
repository: `${resolved.owner}/${resolved.repo}`,
|
|
432
|
+
// Quick start info
|
|
433
|
+
quickStart: {
|
|
434
|
+
version,
|
|
435
|
+
installCommand: getInstallCommand(repoName, version),
|
|
436
|
+
docsUrl: `https://github.com/${resolved.owner}/${resolved.repo}`,
|
|
437
|
+
},
|
|
438
|
+
// Version context
|
|
439
|
+
version: {
|
|
440
|
+
current: version,
|
|
441
|
+
stable: versionInfo.latestStableRelease?.tag || null,
|
|
442
|
+
publishedAt: versionInfo.latestRelease?.publishedAt || null,
|
|
443
|
+
recentReleases: versionInfo.recentReleases.slice(0, 3).map((r) => ({
|
|
444
|
+
tag: r.tag,
|
|
445
|
+
date: r.publishedAt.split("T")[0],
|
|
446
|
+
})),
|
|
447
|
+
},
|
|
448
|
+
// Syntax reference (condensed)
|
|
449
|
+
syntax: syntaxRef
|
|
450
|
+
? {
|
|
451
|
+
version: syntaxRef.version,
|
|
452
|
+
files: syntaxRef.syntaxFiles.map((f) => f.path),
|
|
453
|
+
// Include first file content as primary reference
|
|
454
|
+
primaryReference: syntaxRef.syntaxFiles[0]?.content?.slice(0, 2000) || null,
|
|
455
|
+
}
|
|
456
|
+
: null,
|
|
457
|
+
// Relevant examples
|
|
458
|
+
examples,
|
|
459
|
+
note: `Use this context to write ${repoName} code at version ${version}. For detailed syntax, use midnight-get-latest-syntax.`,
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
// Helper functions for compound tools
|
|
463
|
+
function computeUpgradeUrgency(outdatedInfo, breakingCount) {
|
|
464
|
+
if (!outdatedInfo.isOutdated)
|
|
465
|
+
return "none";
|
|
466
|
+
if (breakingCount === 0 && outdatedInfo.versionsBehind <= 2)
|
|
467
|
+
return "low";
|
|
468
|
+
if (breakingCount <= 2 && outdatedInfo.versionsBehind <= 5)
|
|
469
|
+
return "medium";
|
|
470
|
+
if (breakingCount <= 5)
|
|
471
|
+
return "high";
|
|
472
|
+
return "critical";
|
|
473
|
+
}
|
|
474
|
+
function generateUpgradeRecommendation(urgency, breakingCount, outdatedInfo) {
|
|
475
|
+
switch (urgency) {
|
|
476
|
+
case "none":
|
|
477
|
+
return "✅ You're on the latest version. No action needed.";
|
|
478
|
+
case "low":
|
|
479
|
+
return `📦 Minor update available (${outdatedInfo.versionsBehind} versions behind). Safe to upgrade at your convenience.`;
|
|
480
|
+
case "medium":
|
|
481
|
+
return `⚠️ Update recommended. ${breakingCount} breaking change(s) to review. Plan upgrade within 2 weeks.`;
|
|
482
|
+
case "high":
|
|
483
|
+
return `🔶 Important update. ${breakingCount} breaking changes require attention. Schedule upgrade soon.`;
|
|
484
|
+
case "critical":
|
|
485
|
+
return `🚨 Critical update needed! ${breakingCount} breaking changes and ${outdatedInfo.versionsBehind} versions behind. Upgrade immediately.`;
|
|
486
|
+
default:
|
|
487
|
+
return "Check the breaking changes and plan your upgrade.";
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
function getRepoType(repoName) {
|
|
491
|
+
const name = repoName.toLowerCase();
|
|
492
|
+
if (name.includes("counter"))
|
|
493
|
+
return "counter";
|
|
494
|
+
if (name.includes("bboard"))
|
|
495
|
+
return "bboard";
|
|
496
|
+
if (name.includes("token") || name.includes("dex"))
|
|
497
|
+
return "token";
|
|
498
|
+
if (name.includes("voting"))
|
|
499
|
+
return "voting";
|
|
500
|
+
return "all";
|
|
501
|
+
}
|
|
502
|
+
function getInstallCommand(repoName, version) {
|
|
503
|
+
const name = repoName.toLowerCase();
|
|
504
|
+
if (name === "compact" || name.includes("compact")) {
|
|
505
|
+
return `npx @aspect-sh/pnpm dlx @midnight-ntwrk/create-midnight-app@${version}`;
|
|
506
|
+
}
|
|
507
|
+
if (name === "midnight-js" || name.includes("js")) {
|
|
508
|
+
return `npm install @midnight-ntwrk/midnight-js@${version}`;
|
|
509
|
+
}
|
|
510
|
+
return `git clone https://github.com/midnight-ntwrk/${repoName}.git && cd ${repoName} && git checkout ${version}`;
|
|
511
|
+
}
|
|
338
512
|
//# sourceMappingURL=handlers.js.map
|
|
@@ -99,6 +99,29 @@ export declare const GetLatestSyntaxInputSchema: z.ZodObject<{
|
|
|
99
99
|
}, {
|
|
100
100
|
repo?: string | undefined;
|
|
101
101
|
}>;
|
|
102
|
+
export declare const UpgradeCheckInputSchema: z.ZodObject<{
|
|
103
|
+
repo: z.ZodDefault<z.ZodString>;
|
|
104
|
+
currentVersion: z.ZodString;
|
|
105
|
+
}, "strip", z.ZodTypeAny, {
|
|
106
|
+
repo: string;
|
|
107
|
+
currentVersion: string;
|
|
108
|
+
}, {
|
|
109
|
+
currentVersion: string;
|
|
110
|
+
repo?: string | undefined;
|
|
111
|
+
}>;
|
|
112
|
+
export declare const FullRepoContextInputSchema: z.ZodObject<{
|
|
113
|
+
repo: z.ZodString;
|
|
114
|
+
includeExamples: z.ZodDefault<z.ZodBoolean>;
|
|
115
|
+
includeSyntax: z.ZodDefault<z.ZodBoolean>;
|
|
116
|
+
}, "strip", z.ZodTypeAny, {
|
|
117
|
+
repo: string;
|
|
118
|
+
includeExamples: boolean;
|
|
119
|
+
includeSyntax: boolean;
|
|
120
|
+
}, {
|
|
121
|
+
repo: string;
|
|
122
|
+
includeExamples?: boolean | undefined;
|
|
123
|
+
includeSyntax?: boolean | undefined;
|
|
124
|
+
}>;
|
|
102
125
|
export type GetFileInput = z.infer<typeof GetFileInputSchema>;
|
|
103
126
|
export type ListExamplesInput = z.infer<typeof ListExamplesInputSchema>;
|
|
104
127
|
export type GetLatestUpdatesInput = z.infer<typeof GetLatestUpdatesInputSchema>;
|
|
@@ -108,4 +131,6 @@ export type GetMigrationGuideInput = z.infer<typeof GetMigrationGuideInputSchema
|
|
|
108
131
|
export type GetFileAtVersionInput = z.infer<typeof GetFileAtVersionInputSchema>;
|
|
109
132
|
export type CompareSyntaxInput = z.infer<typeof CompareSyntaxInputSchema>;
|
|
110
133
|
export type GetLatestSyntaxInput = z.infer<typeof GetLatestSyntaxInputSchema>;
|
|
134
|
+
export type UpgradeCheckInput = z.infer<typeof UpgradeCheckInputSchema>;
|
|
135
|
+
export type FullRepoContextInput = z.infer<typeof FullRepoContextInputSchema>;
|
|
111
136
|
//# sourceMappingURL=schemas.d.ts.map
|
|
@@ -70,4 +70,22 @@ export const GetLatestSyntaxInputSchema = z.object({
|
|
|
70
70
|
.default("compact")
|
|
71
71
|
.describe("Repository name (default: 'compact')"),
|
|
72
72
|
});
|
|
73
|
+
// Compound tool schemas - reduce multiple API calls to one
|
|
74
|
+
export const UpgradeCheckInputSchema = z.object({
|
|
75
|
+
repo: z
|
|
76
|
+
.string()
|
|
77
|
+
.default("compact")
|
|
78
|
+
.describe("Repository name (default: 'compact')"),
|
|
79
|
+
currentVersion: z
|
|
80
|
+
.string()
|
|
81
|
+
.describe("Your current version (e.g., 'v0.14.0', '0.13.5')"),
|
|
82
|
+
});
|
|
83
|
+
export const FullRepoContextInputSchema = z.object({
|
|
84
|
+
repo: z.string().describe("Repository name (e.g., 'compact', 'midnight-js')"),
|
|
85
|
+
includeExamples: z
|
|
86
|
+
.boolean()
|
|
87
|
+
.default(true)
|
|
88
|
+
.describe("Include example code snippets"),
|
|
89
|
+
includeSyntax: z.boolean().default(true).describe("Include syntax reference"),
|
|
90
|
+
});
|
|
73
91
|
//# sourceMappingURL=schemas.js.map
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Repository tool definitions
|
|
3
3
|
* MCP tool registration for repository-related operations
|
|
4
4
|
*/
|
|
5
|
-
import { getFile, listExamples, getLatestUpdates, getVersionInfo, checkBreakingChanges, getMigrationGuide, getFileAtVersion, compareSyntax, getLatestSyntax, } from "./handlers.js";
|
|
5
|
+
import { getFile, listExamples, getLatestUpdates, getVersionInfo, checkBreakingChanges, getMigrationGuide, getFileAtVersion, compareSyntax, getLatestSyntax, upgradeCheck, getFullRepoContext, } from "./handlers.js";
|
|
6
6
|
// Tool definitions for MCP
|
|
7
7
|
export const repositoryTools = [
|
|
8
8
|
{
|
|
@@ -30,6 +30,7 @@ export const repositoryTools = [
|
|
|
30
30
|
readOnlyHint: true,
|
|
31
31
|
openWorldHint: true,
|
|
32
32
|
title: "Get Repository File",
|
|
33
|
+
category: "repository",
|
|
33
34
|
},
|
|
34
35
|
handler: getFile,
|
|
35
36
|
},
|
|
@@ -51,6 +52,7 @@ export const repositoryTools = [
|
|
|
51
52
|
readOnlyHint: true,
|
|
52
53
|
idempotentHint: true,
|
|
53
54
|
title: "List Example Contracts",
|
|
55
|
+
category: "repository",
|
|
54
56
|
},
|
|
55
57
|
handler: listExamples,
|
|
56
58
|
},
|
|
@@ -76,6 +78,7 @@ export const repositoryTools = [
|
|
|
76
78
|
readOnlyHint: true,
|
|
77
79
|
openWorldHint: true,
|
|
78
80
|
title: "Get Latest Updates",
|
|
81
|
+
category: "repository",
|
|
79
82
|
},
|
|
80
83
|
handler: getLatestUpdates,
|
|
81
84
|
},
|
|
@@ -96,6 +99,7 @@ export const repositoryTools = [
|
|
|
96
99
|
readOnlyHint: true,
|
|
97
100
|
openWorldHint: true,
|
|
98
101
|
title: "Get Version Info",
|
|
102
|
+
category: "versioning",
|
|
99
103
|
},
|
|
100
104
|
handler: getVersionInfo,
|
|
101
105
|
},
|
|
@@ -120,6 +124,7 @@ export const repositoryTools = [
|
|
|
120
124
|
readOnlyHint: true,
|
|
121
125
|
openWorldHint: true,
|
|
122
126
|
title: "Check Breaking Changes",
|
|
127
|
+
category: "versioning",
|
|
123
128
|
},
|
|
124
129
|
handler: checkBreakingChanges,
|
|
125
130
|
},
|
|
@@ -148,6 +153,7 @@ export const repositoryTools = [
|
|
|
148
153
|
readOnlyHint: true,
|
|
149
154
|
openWorldHint: true,
|
|
150
155
|
title: "Get Migration Guide",
|
|
156
|
+
category: "versioning",
|
|
151
157
|
},
|
|
152
158
|
handler: getMigrationGuide,
|
|
153
159
|
},
|
|
@@ -177,6 +183,7 @@ export const repositoryTools = [
|
|
|
177
183
|
idempotentHint: true,
|
|
178
184
|
openWorldHint: true,
|
|
179
185
|
title: "Get File at Version",
|
|
186
|
+
category: "versioning",
|
|
180
187
|
},
|
|
181
188
|
handler: getFileAtVersion,
|
|
182
189
|
},
|
|
@@ -210,6 +217,7 @@ export const repositoryTools = [
|
|
|
210
217
|
idempotentHint: true,
|
|
211
218
|
openWorldHint: true,
|
|
212
219
|
title: "Compare Syntax Between Versions",
|
|
220
|
+
category: "versioning",
|
|
213
221
|
},
|
|
214
222
|
handler: compareSyntax,
|
|
215
223
|
},
|
|
@@ -230,8 +238,120 @@ export const repositoryTools = [
|
|
|
230
238
|
readOnlyHint: true,
|
|
231
239
|
openWorldHint: true,
|
|
232
240
|
title: "Get Latest Syntax Reference",
|
|
241
|
+
category: "versioning",
|
|
233
242
|
},
|
|
234
243
|
handler: getLatestSyntax,
|
|
235
244
|
},
|
|
245
|
+
// ============================================================================
|
|
246
|
+
// COMPOUND TOOLS - Multi-step operations in a single call
|
|
247
|
+
// These reduce token usage by 50-70% compared to calling individual tools
|
|
248
|
+
// ============================================================================
|
|
249
|
+
{
|
|
250
|
+
name: "midnight-upgrade-check",
|
|
251
|
+
description: "🚀 COMPOUND TOOL: Complete upgrade analysis in ONE call. Combines version check + breaking changes + migration guide. Use this instead of calling midnight-get-version-info, midnight-check-breaking-changes, and midnight-get-migration-guide separately. Saves ~60% tokens.",
|
|
252
|
+
inputSchema: {
|
|
253
|
+
type: "object",
|
|
254
|
+
properties: {
|
|
255
|
+
repo: {
|
|
256
|
+
type: "string",
|
|
257
|
+
description: "Repository name (default: 'compact')",
|
|
258
|
+
},
|
|
259
|
+
currentVersion: {
|
|
260
|
+
type: "string",
|
|
261
|
+
description: "Your current version (e.g., 'v0.14.0', '0.13.5')",
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
required: ["currentVersion"],
|
|
265
|
+
},
|
|
266
|
+
outputSchema: {
|
|
267
|
+
type: "object",
|
|
268
|
+
properties: {
|
|
269
|
+
repository: { type: "string", description: "Full repository path" },
|
|
270
|
+
currentVersion: {
|
|
271
|
+
type: "string",
|
|
272
|
+
description: "Version being checked",
|
|
273
|
+
},
|
|
274
|
+
version: {
|
|
275
|
+
type: "object",
|
|
276
|
+
description: "Version summary",
|
|
277
|
+
properties: {
|
|
278
|
+
latest: { type: "string" },
|
|
279
|
+
latestStable: { type: "string" },
|
|
280
|
+
isOutdated: { type: "boolean" },
|
|
281
|
+
versionsBehind: { type: "number" },
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
breakingChanges: {
|
|
285
|
+
type: "object",
|
|
286
|
+
description: "Breaking changes summary",
|
|
287
|
+
properties: {
|
|
288
|
+
count: { type: "number" },
|
|
289
|
+
hasBreakingChanges: { type: "boolean" },
|
|
290
|
+
items: { type: "array" },
|
|
291
|
+
},
|
|
292
|
+
},
|
|
293
|
+
migration: { type: "object", description: "Migration guide if needed" },
|
|
294
|
+
urgency: {
|
|
295
|
+
type: "string",
|
|
296
|
+
description: "none|low|medium|high|critical",
|
|
297
|
+
},
|
|
298
|
+
recommendation: {
|
|
299
|
+
type: "string",
|
|
300
|
+
description: "Actionable recommendation",
|
|
301
|
+
},
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
annotations: {
|
|
305
|
+
readOnlyHint: true,
|
|
306
|
+
openWorldHint: true,
|
|
307
|
+
longRunningHint: true,
|
|
308
|
+
title: "⚡ Upgrade Check (Compound)",
|
|
309
|
+
category: "compound",
|
|
310
|
+
},
|
|
311
|
+
handler: upgradeCheck,
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
name: "midnight-get-repo-context",
|
|
315
|
+
description: "🚀 COMPOUND TOOL: Get everything needed to start working with a repository in ONE call. Combines version info + syntax reference + relevant examples. Use this at the start of a coding session instead of multiple individual calls. Saves ~50% tokens.",
|
|
316
|
+
inputSchema: {
|
|
317
|
+
type: "object",
|
|
318
|
+
properties: {
|
|
319
|
+
repo: {
|
|
320
|
+
type: "string",
|
|
321
|
+
description: "Repository name (e.g., 'compact', 'midnight-js')",
|
|
322
|
+
},
|
|
323
|
+
includeExamples: {
|
|
324
|
+
type: "boolean",
|
|
325
|
+
description: "Include example code snippets (default: true)",
|
|
326
|
+
},
|
|
327
|
+
includeSyntax: {
|
|
328
|
+
type: "boolean",
|
|
329
|
+
description: "Include syntax reference (default: true)",
|
|
330
|
+
},
|
|
331
|
+
},
|
|
332
|
+
required: ["repo"],
|
|
333
|
+
},
|
|
334
|
+
outputSchema: {
|
|
335
|
+
type: "object",
|
|
336
|
+
properties: {
|
|
337
|
+
repository: { type: "string", description: "Full repository path" },
|
|
338
|
+
quickStart: {
|
|
339
|
+
type: "object",
|
|
340
|
+
description: "Version and install command",
|
|
341
|
+
},
|
|
342
|
+
version: { type: "object", description: "Version details" },
|
|
343
|
+
syntax: { type: "object", description: "Syntax reference summary" },
|
|
344
|
+
examples: { type: "array", description: "Relevant examples" },
|
|
345
|
+
},
|
|
346
|
+
},
|
|
347
|
+
annotations: {
|
|
348
|
+
readOnlyHint: true,
|
|
349
|
+
openWorldHint: true,
|
|
350
|
+
longRunningHint: true,
|
|
351
|
+
title: "⚡ Get Repo Context (Compound)",
|
|
352
|
+
category: "compound",
|
|
353
|
+
},
|
|
354
|
+
handler: getFullRepoContext,
|
|
355
|
+
},
|
|
236
356
|
];
|
|
237
357
|
//# sourceMappingURL=tools.js.map
|
package/dist/tools/search.js
CHANGED
package/dist/types/mcp.d.ts
CHANGED
|
@@ -31,7 +31,27 @@ export interface ToolAnnotations {
|
|
|
31
31
|
* Human-readable title for display in UIs
|
|
32
32
|
*/
|
|
33
33
|
title?: string;
|
|
34
|
+
/**
|
|
35
|
+
* If true, this tool performs destructive or irreversible actions
|
|
36
|
+
* Clients should require human confirmation before execution
|
|
37
|
+
*/
|
|
38
|
+
destructiveHint?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* If true, this tool requires explicit human confirmation
|
|
41
|
+
* before execution (e.g., financial transactions, deletions)
|
|
42
|
+
*/
|
|
43
|
+
requiresConfirmation?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Tool category for progressive disclosure
|
|
46
|
+
* Allows clients to group/filter tools by domain
|
|
47
|
+
*/
|
|
48
|
+
category?: ToolCategory;
|
|
34
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Tool categories for progressive disclosure
|
|
52
|
+
* Clients can initially show categories, then expand to individual tools
|
|
53
|
+
*/
|
|
54
|
+
export type ToolCategory = "search" | "analyze" | "repository" | "versioning" | "generation" | "health" | "compound";
|
|
35
55
|
/**
|
|
36
56
|
* JSON Schema for structured tool outputs
|
|
37
57
|
* Enables better LLM parsing and IDE integration
|
package/dist/utils/errors.d.ts
CHANGED
|
@@ -25,6 +25,72 @@ export declare const ErrorCodes: {
|
|
|
25
25
|
readonly PARSE_ERROR: "PARSE_ERROR";
|
|
26
26
|
readonly CHROMADB_UNAVAILABLE: "CHROMADB_UNAVAILABLE";
|
|
27
27
|
readonly OPENAI_UNAVAILABLE: "OPENAI_UNAVAILABLE";
|
|
28
|
+
readonly MISSING_PARAM: "MISSING_PARAMETER";
|
|
29
|
+
readonly INVALID_VERSION: "INVALID_VERSION";
|
|
30
|
+
readonly SAMPLING_UNAVAILABLE: "SAMPLING_UNAVAILABLE";
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* LLM-friendly error hints that help the model self-correct
|
|
34
|
+
* These are designed to give the AI enough context to retry with corrected input
|
|
35
|
+
*/
|
|
36
|
+
export declare const SelfCorrectionHints: {
|
|
37
|
+
UNKNOWN_REPO: (repo: string, validRepos: string[]) => {
|
|
38
|
+
error: string;
|
|
39
|
+
code: "UNKNOWN_REPOSITORY";
|
|
40
|
+
suggestion: string;
|
|
41
|
+
correction: {
|
|
42
|
+
invalidValue: string;
|
|
43
|
+
validValues: string[];
|
|
44
|
+
parameterName: string;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
INVALID_VERSION: (version: string, example: string) => {
|
|
48
|
+
error: string;
|
|
49
|
+
code: "INVALID_VERSION";
|
|
50
|
+
suggestion: string;
|
|
51
|
+
correction: {
|
|
52
|
+
invalidValue: string;
|
|
53
|
+
expectedFormat: string;
|
|
54
|
+
example: string;
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
MISSING_REQUIRED_PARAM: (paramName: string, toolName: string) => {
|
|
58
|
+
error: string;
|
|
59
|
+
code: "MISSING_PARAMETER";
|
|
60
|
+
suggestion: string;
|
|
61
|
+
correction: {
|
|
62
|
+
missingParameter: string;
|
|
63
|
+
tool: string;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
FILE_NOT_FOUND: (path: string, repo: string, similarPaths?: string[]) => {
|
|
67
|
+
error: string;
|
|
68
|
+
code: "RESOURCE_NOT_FOUND";
|
|
69
|
+
suggestion: string;
|
|
70
|
+
correction: {
|
|
71
|
+
suggestions?: string[] | undefined;
|
|
72
|
+
invalidPath: string;
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
SAMPLING_NOT_AVAILABLE: (toolName: string) => {
|
|
76
|
+
error: string;
|
|
77
|
+
code: "SAMPLING_UNAVAILABLE";
|
|
78
|
+
suggestion: string;
|
|
79
|
+
alternatives: {
|
|
80
|
+
"midnight-generate-contract": string;
|
|
81
|
+
"midnight-review-contract": string;
|
|
82
|
+
"midnight-document-contract": string;
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
RATE_LIMIT: (retryAfter?: number) => {
|
|
86
|
+
error: string;
|
|
87
|
+
code: "RATE_LIMIT_EXCEEDED";
|
|
88
|
+
suggestion: string;
|
|
89
|
+
correction: {
|
|
90
|
+
retryAfterSeconds?: number | undefined;
|
|
91
|
+
action: string;
|
|
92
|
+
};
|
|
93
|
+
};
|
|
28
94
|
};
|
|
29
95
|
/**
|
|
30
96
|
* Create user-friendly error from various error types
|
package/dist/utils/errors.js
CHANGED
|
@@ -33,6 +33,76 @@ export const ErrorCodes = {
|
|
|
33
33
|
PARSE_ERROR: "PARSE_ERROR",
|
|
34
34
|
CHROMADB_UNAVAILABLE: "CHROMADB_UNAVAILABLE",
|
|
35
35
|
OPENAI_UNAVAILABLE: "OPENAI_UNAVAILABLE",
|
|
36
|
+
MISSING_PARAM: "MISSING_PARAMETER",
|
|
37
|
+
INVALID_VERSION: "INVALID_VERSION",
|
|
38
|
+
SAMPLING_UNAVAILABLE: "SAMPLING_UNAVAILABLE",
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* LLM-friendly error hints that help the model self-correct
|
|
42
|
+
* These are designed to give the AI enough context to retry with corrected input
|
|
43
|
+
*/
|
|
44
|
+
export const SelfCorrectionHints = {
|
|
45
|
+
UNKNOWN_REPO: (repo, validRepos) => ({
|
|
46
|
+
error: `Unknown repository: '${repo}'`,
|
|
47
|
+
code: ErrorCodes.UNKNOWN_REPO,
|
|
48
|
+
suggestion: `Try one of these instead: ${validRepos.slice(0, 8).join(", ")}`,
|
|
49
|
+
correction: {
|
|
50
|
+
invalidValue: repo,
|
|
51
|
+
validValues: validRepos,
|
|
52
|
+
parameterName: "repo",
|
|
53
|
+
},
|
|
54
|
+
}),
|
|
55
|
+
INVALID_VERSION: (version, example) => ({
|
|
56
|
+
error: `Invalid version format: '${version}'`,
|
|
57
|
+
code: ErrorCodes.INVALID_VERSION,
|
|
58
|
+
suggestion: `Version should be like '${example}'. Check available versions with midnight-get-version-info first.`,
|
|
59
|
+
correction: {
|
|
60
|
+
invalidValue: version,
|
|
61
|
+
expectedFormat: "v1.0.0 or 0.14.0",
|
|
62
|
+
example,
|
|
63
|
+
},
|
|
64
|
+
}),
|
|
65
|
+
MISSING_REQUIRED_PARAM: (paramName, toolName) => ({
|
|
66
|
+
error: `Missing required parameter: '${paramName}'`,
|
|
67
|
+
code: ErrorCodes.MISSING_PARAM,
|
|
68
|
+
suggestion: `The '${paramName}' parameter is required for ${toolName}. Please provide it.`,
|
|
69
|
+
correction: {
|
|
70
|
+
missingParameter: paramName,
|
|
71
|
+
tool: toolName,
|
|
72
|
+
},
|
|
73
|
+
}),
|
|
74
|
+
FILE_NOT_FOUND: (path, repo, similarPaths) => ({
|
|
75
|
+
error: `File not found: '${path}' in ${repo}`,
|
|
76
|
+
code: ErrorCodes.NOT_FOUND,
|
|
77
|
+
suggestion: similarPaths?.length
|
|
78
|
+
? `Did you mean: ${similarPaths.join(", ")}?`
|
|
79
|
+
: `Check the file path. Use midnight-get-file with a different path or list directory contents first.`,
|
|
80
|
+
correction: {
|
|
81
|
+
invalidPath: path,
|
|
82
|
+
...(similarPaths && { suggestions: similarPaths }),
|
|
83
|
+
},
|
|
84
|
+
}),
|
|
85
|
+
SAMPLING_NOT_AVAILABLE: (toolName) => ({
|
|
86
|
+
error: `Sampling capability not available`,
|
|
87
|
+
code: ErrorCodes.SAMPLING_UNAVAILABLE,
|
|
88
|
+
suggestion: `${toolName} requires a client that supports sampling (e.g., Claude Desktop). Use a non-AI alternative or switch clients.`,
|
|
89
|
+
alternatives: {
|
|
90
|
+
"midnight-generate-contract": "Use midnight-search-compact to find similar contracts as templates",
|
|
91
|
+
"midnight-review-contract": "Use midnight-analyze-contract for static analysis",
|
|
92
|
+
"midnight-document-contract": "Manual documentation or inline comments",
|
|
93
|
+
},
|
|
94
|
+
}),
|
|
95
|
+
RATE_LIMIT: (retryAfter) => ({
|
|
96
|
+
error: "GitHub API rate limit exceeded",
|
|
97
|
+
code: ErrorCodes.RATE_LIMIT,
|
|
98
|
+
suggestion: retryAfter
|
|
99
|
+
? `Wait ${retryAfter} seconds before retrying. Or add GITHUB_TOKEN for higher limits.`
|
|
100
|
+
: "Add GITHUB_TOKEN to increase from 60 to 5000 requests/hour.",
|
|
101
|
+
correction: {
|
|
102
|
+
action: "wait_and_retry",
|
|
103
|
+
...(retryAfter && { retryAfterSeconds: retryAfter }),
|
|
104
|
+
},
|
|
105
|
+
}),
|
|
36
106
|
};
|
|
37
107
|
/**
|
|
38
108
|
* Create user-friendly error from various error types
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { config, isHostedMode, isLocalMode } from "./config.js";
|
|
|
2
2
|
export type { Config, RepositoryConfig } from "./config.js";
|
|
3
3
|
export { DEFAULT_REPOSITORIES } from "./config.js";
|
|
4
4
|
export { logger } from "./logger.js";
|
|
5
|
-
export { MCPError, ErrorCodes, createUserError, formatErrorResponse, withErrorHandling, } from "./errors.js";
|
|
5
|
+
export { MCPError, ErrorCodes, createUserError, formatErrorResponse, withErrorHandling, SelfCorrectionHints, } from "./errors.js";
|
|
6
6
|
export { validateQuery, validateRepository, validatePath, validateRef, validateNumber, validateToolArgs, sanitizeString, } from "./validation.js";
|
|
7
7
|
export type { ValidationResult } from "./validation.js";
|
|
8
8
|
export { getHealthStatus, getQuickHealthStatus } from "./health.js";
|
package/dist/utils/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { config, isHostedMode, isLocalMode } from "./config.js";
|
|
2
2
|
export { DEFAULT_REPOSITORIES } from "./config.js";
|
|
3
3
|
export { logger } from "./logger.js";
|
|
4
|
-
export { MCPError, ErrorCodes, createUserError, formatErrorResponse, withErrorHandling, } from "./errors.js";
|
|
4
|
+
export { MCPError, ErrorCodes, createUserError, formatErrorResponse, withErrorHandling, SelfCorrectionHints, } from "./errors.js";
|
|
5
5
|
// Validation utilities
|
|
6
6
|
export { validateQuery, validateRepository, validatePath, validateRef, validateNumber, validateToolArgs, sanitizeString, } from "./validation.js";
|
|
7
7
|
// Health check utilities
|