@crowley/rag-mcp 1.0.4 → 1.0.6
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/dist/annotations.d.ts +16 -0
- package/dist/annotations.js +158 -0
- package/dist/context-enrichment.d.ts +2 -2
- package/dist/context-enrichment.js +37 -14
- package/dist/formatters.d.ts +2 -0
- package/dist/formatters.js +12 -0
- package/dist/index.js +64 -47
- package/dist/schemas.d.ts +97 -0
- package/dist/schemas.js +128 -0
- package/dist/tool-middleware.d.ts +40 -0
- package/dist/tool-middleware.js +216 -0
- package/dist/tool-registry.js +2 -1
- package/dist/tools/advanced.d.ts +2 -2
- package/dist/tools/advanced.js +200 -275
- package/dist/tools/agents.d.ts +2 -2
- package/dist/tools/agents.js +59 -78
- package/dist/tools/analytics.d.ts +2 -2
- package/dist/tools/analytics.js +170 -210
- package/dist/tools/architecture.d.ts +2 -2
- package/dist/tools/architecture.js +506 -661
- package/dist/tools/ask.d.ts +2 -2
- package/dist/tools/ask.js +164 -219
- package/dist/tools/cache.d.ts +2 -2
- package/dist/tools/cache.js +63 -82
- package/dist/tools/clustering.d.ts +2 -2
- package/dist/tools/clustering.js +154 -215
- package/dist/tools/confluence.d.ts +2 -2
- package/dist/tools/confluence.js +80 -116
- package/dist/tools/database.d.ts +2 -2
- package/dist/tools/database.js +303 -380
- package/dist/tools/feedback.d.ts +2 -2
- package/dist/tools/feedback.js +143 -184
- package/dist/tools/guidelines.d.ts +2 -2
- package/dist/tools/guidelines.js +123 -135
- package/dist/tools/indexing.d.ts +2 -2
- package/dist/tools/indexing.js +104 -100
- package/dist/tools/memory.d.ts +2 -2
- package/dist/tools/memory.js +299 -485
- package/dist/tools/pm.d.ts +2 -2
- package/dist/tools/pm.js +367 -615
- package/dist/tools/review.d.ts +2 -2
- package/dist/tools/review.js +142 -189
- package/dist/tools/search.d.ts +2 -2
- package/dist/tools/search.js +230 -305
- package/dist/tools/session.d.ts +2 -2
- package/dist/tools/session.js +288 -345
- package/dist/tools/suggestions.d.ts +2 -2
- package/dist/tools/suggestions.js +444 -255
- package/dist/types.d.ts +19 -2
- package/package.json +4 -2
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool annotations map for all MCP tools.
|
|
3
|
+
*
|
|
4
|
+
* Annotations help clients understand tool behaviour:
|
|
5
|
+
* readOnlyHint – tool does NOT modify its environment
|
|
6
|
+
* destructiveHint – tool may delete or irreversibly change data
|
|
7
|
+
* idempotentHint – repeated calls with same args have no extra effect
|
|
8
|
+
* openWorldHint – tool interacts with external entities (RAG API)
|
|
9
|
+
*/
|
|
10
|
+
export interface ToolAnnotations {
|
|
11
|
+
readOnlyHint?: boolean;
|
|
12
|
+
destructiveHint?: boolean;
|
|
13
|
+
idempotentHint?: boolean;
|
|
14
|
+
openWorldHint?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare const TOOL_ANNOTATIONS: Record<string, ToolAnnotations>;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool annotations map for all MCP tools.
|
|
3
|
+
*
|
|
4
|
+
* Annotations help clients understand tool behaviour:
|
|
5
|
+
* readOnlyHint – tool does NOT modify its environment
|
|
6
|
+
* destructiveHint – tool may delete or irreversibly change data
|
|
7
|
+
* idempotentHint – repeated calls with same args have no extra effect
|
|
8
|
+
* openWorldHint – tool interacts with external entities (RAG API)
|
|
9
|
+
*/
|
|
10
|
+
// ── Shorthand presets ───────────────────────────────────────
|
|
11
|
+
/** Read-only, idempotent – the vast majority of tools */
|
|
12
|
+
const RO = {
|
|
13
|
+
readOnlyHint: true,
|
|
14
|
+
destructiveHint: false,
|
|
15
|
+
idempotentHint: true,
|
|
16
|
+
openWorldHint: true,
|
|
17
|
+
};
|
|
18
|
+
/** Mutating but non-destructive (create / append) */
|
|
19
|
+
const MUT = {
|
|
20
|
+
readOnlyHint: false,
|
|
21
|
+
destructiveHint: false,
|
|
22
|
+
idempotentHint: false,
|
|
23
|
+
openWorldHint: true,
|
|
24
|
+
};
|
|
25
|
+
/** Idempotent upsert (record_*, setup_project, validate, promote) */
|
|
26
|
+
const UPSERT = {
|
|
27
|
+
readOnlyHint: false,
|
|
28
|
+
destructiveHint: false,
|
|
29
|
+
idempotentHint: true,
|
|
30
|
+
openWorldHint: true,
|
|
31
|
+
};
|
|
32
|
+
/** Destructive – may delete or irreversibly change data */
|
|
33
|
+
const DESTRUCT = {
|
|
34
|
+
readOnlyHint: false,
|
|
35
|
+
destructiveHint: true,
|
|
36
|
+
idempotentHint: false,
|
|
37
|
+
openWorldHint: true,
|
|
38
|
+
};
|
|
39
|
+
// ── Per-tool annotations ────────────────────────────────────
|
|
40
|
+
export const TOOL_ANNOTATIONS = {
|
|
41
|
+
// ── search (8) ──────────────────────────────────────────
|
|
42
|
+
search_codebase: RO,
|
|
43
|
+
search_similar: RO,
|
|
44
|
+
grouped_search: RO,
|
|
45
|
+
hybrid_search: RO,
|
|
46
|
+
search_docs: RO,
|
|
47
|
+
get_project_stats: RO,
|
|
48
|
+
find_symbol: RO,
|
|
49
|
+
search_graph: RO,
|
|
50
|
+
// ── ask (5) ─────────────────────────────────────────────
|
|
51
|
+
ask_codebase: RO,
|
|
52
|
+
explain_code: RO,
|
|
53
|
+
find_feature: RO,
|
|
54
|
+
analyze_conversation: RO,
|
|
55
|
+
auto_remember: MUT, // creates memory from conversation
|
|
56
|
+
// ── indexing (4) ────────────────────────────────────────
|
|
57
|
+
index_codebase: MUT,
|
|
58
|
+
get_index_status: RO,
|
|
59
|
+
reindex_zero_downtime: MUT,
|
|
60
|
+
list_aliases: RO,
|
|
61
|
+
// ── memory (11) ────────────────────────────────────────
|
|
62
|
+
remember: MUT,
|
|
63
|
+
recall: RO,
|
|
64
|
+
list_memories: RO,
|
|
65
|
+
forget: DESTRUCT,
|
|
66
|
+
update_todo: MUT,
|
|
67
|
+
batch_remember: MUT,
|
|
68
|
+
validate_memory: UPSERT, // idempotent status update
|
|
69
|
+
review_memories: RO,
|
|
70
|
+
promote_memory: UPSERT, // idempotent promotion
|
|
71
|
+
run_quality_gates: MUT, // may update memory status
|
|
72
|
+
memory_maintenance: DESTRUCT, // prunes old memories
|
|
73
|
+
// ── architecture (9) ───────────────────────────────────
|
|
74
|
+
record_adr: UPSERT,
|
|
75
|
+
get_adrs: RO,
|
|
76
|
+
record_pattern: UPSERT,
|
|
77
|
+
get_patterns: RO,
|
|
78
|
+
check_architecture: RO,
|
|
79
|
+
suggest_architecture: RO,
|
|
80
|
+
record_tech_debt: UPSERT,
|
|
81
|
+
get_tech_debt: RO,
|
|
82
|
+
analyze_project_structure: RO,
|
|
83
|
+
// ── database (8) ───────────────────────────────────────
|
|
84
|
+
record_table: UPSERT,
|
|
85
|
+
get_table_info: RO,
|
|
86
|
+
record_db_rule: UPSERT,
|
|
87
|
+
get_db_rules: RO,
|
|
88
|
+
record_enum: UPSERT,
|
|
89
|
+
get_enums: RO,
|
|
90
|
+
check_db_schema: RO,
|
|
91
|
+
suggest_db_schema: RO,
|
|
92
|
+
// ── confluence (4) ─────────────────────────────────────
|
|
93
|
+
search_confluence: RO,
|
|
94
|
+
index_confluence: MUT,
|
|
95
|
+
get_confluence_status: RO,
|
|
96
|
+
list_confluence_spaces: RO,
|
|
97
|
+
// ── pm (7) ─────────────────────────────────────────────
|
|
98
|
+
search_requirements: RO,
|
|
99
|
+
analyze_requirements: RO,
|
|
100
|
+
estimate_feature: RO,
|
|
101
|
+
get_feature_status: RO,
|
|
102
|
+
list_requirements: RO,
|
|
103
|
+
ask_pm: RO,
|
|
104
|
+
generate_spec: RO,
|
|
105
|
+
// ── review (3) ─────────────────────────────────────────
|
|
106
|
+
review_code: RO, // generates review, no side-effects
|
|
107
|
+
generate_tests: RO, // generates test suggestions
|
|
108
|
+
analyze_tests: RO,
|
|
109
|
+
// ── analytics (8) ──────────────────────────────────────
|
|
110
|
+
get_tool_analytics: RO,
|
|
111
|
+
get_knowledge_gaps: RO,
|
|
112
|
+
get_analytics: RO,
|
|
113
|
+
backup_collection: MUT, // creates a backup snapshot
|
|
114
|
+
list_backups: RO,
|
|
115
|
+
enable_quantization: DESTRUCT, // irreversible vector re-encoding
|
|
116
|
+
get_platform_stats: RO,
|
|
117
|
+
get_prediction_stats: RO,
|
|
118
|
+
// ── clustering (4) ─────────────────────────────────────
|
|
119
|
+
cluster_code: RO, // computes clusters, no persistence
|
|
120
|
+
find_duplicates: RO,
|
|
121
|
+
recommend_similar: RO,
|
|
122
|
+
extract_learnings: RO,
|
|
123
|
+
// ── session (7) ────────────────────────────────────────
|
|
124
|
+
summarize_context: RO,
|
|
125
|
+
summarize_changes: RO,
|
|
126
|
+
analyze_usage_patterns: RO,
|
|
127
|
+
get_developer_profile: RO,
|
|
128
|
+
start_session: MUT,
|
|
129
|
+
get_session_context: RO,
|
|
130
|
+
end_session: MUT,
|
|
131
|
+
// ── feedback (4) ───────────────────────────────────────
|
|
132
|
+
feedback_search: MUT, // stores search feedback
|
|
133
|
+
feedback_memory: MUT, // stores memory feedback
|
|
134
|
+
suggest_better_query: RO,
|
|
135
|
+
get_quality_metrics: RO,
|
|
136
|
+
// ── suggestions (7) ────────────────────────────────────
|
|
137
|
+
context_briefing: RO,
|
|
138
|
+
get_contextual_suggestions: RO,
|
|
139
|
+
suggest_related_code: RO,
|
|
140
|
+
suggest_implementation: RO,
|
|
141
|
+
suggest_tests: RO,
|
|
142
|
+
get_code_context: RO,
|
|
143
|
+
setup_project: UPSERT, // writes config (idempotent)
|
|
144
|
+
// ── cache (2) ──────────────────────────────────────────
|
|
145
|
+
get_cache_stats: RO,
|
|
146
|
+
warm_cache: MUT,
|
|
147
|
+
// ── guidelines (1) ─────────────────────────────────────
|
|
148
|
+
get_rag_guidelines: RO,
|
|
149
|
+
// ── advanced (5) ───────────────────────────────────────
|
|
150
|
+
merge_memories: DESTRUCT, // merges → deletes originals
|
|
151
|
+
get_completion_context: RO,
|
|
152
|
+
get_import_suggestions: RO,
|
|
153
|
+
get_type_context: RO,
|
|
154
|
+
get_behavior_patterns: RO,
|
|
155
|
+
// ── agents (2) ─────────────────────────────────────────
|
|
156
|
+
run_agent: MUT, // side-effects depend on agent type
|
|
157
|
+
get_agent_types: RO,
|
|
158
|
+
};
|
|
@@ -26,9 +26,9 @@ export declare class ContextEnricher {
|
|
|
26
26
|
*/
|
|
27
27
|
before(name: string, args: Record<string, unknown>, ctx: ToolContext): Promise<string | null>;
|
|
28
28
|
/**
|
|
29
|
-
* After hook: fire-and-forget session activity tracking.
|
|
29
|
+
* After hook: fire-and-forget session activity tracking + implicit feedback.
|
|
30
30
|
*/
|
|
31
|
-
after(name: string,
|
|
31
|
+
after(name: string, args: Record<string, unknown>, result: string, ctx: ToolContext): void;
|
|
32
32
|
/**
|
|
33
33
|
* Extract a semantic query string from tool arguments.
|
|
34
34
|
*/
|
|
@@ -18,6 +18,7 @@ export const DEFAULT_ENRICHABLE_TOOLS = new Set([
|
|
|
18
18
|
"suggest_implementation",
|
|
19
19
|
"suggest_related_code",
|
|
20
20
|
"check_architecture",
|
|
21
|
+
"context_briefing",
|
|
21
22
|
"run_agent",
|
|
22
23
|
]);
|
|
23
24
|
export const DEFAULT_SKIP_TOOLS = new Set([
|
|
@@ -79,21 +80,43 @@ export class ContextEnricher {
|
|
|
79
80
|
}
|
|
80
81
|
}
|
|
81
82
|
/**
|
|
82
|
-
* After hook: fire-and-forget session activity tracking.
|
|
83
|
+
* After hook: fire-and-forget session activity tracking + implicit feedback.
|
|
83
84
|
*/
|
|
84
|
-
after(name,
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
85
|
+
after(name, args, result, ctx) {
|
|
86
|
+
// Session activity tracking
|
|
87
|
+
if (ctx.activeSessionId) {
|
|
88
|
+
ctx.api
|
|
89
|
+
.post(`/api/session/${ctx.activeSessionId}/activity`, {
|
|
90
|
+
projectName: ctx.projectName,
|
|
91
|
+
type: "tool",
|
|
92
|
+
value: name,
|
|
93
|
+
})
|
|
94
|
+
.catch(() => { });
|
|
95
|
+
}
|
|
96
|
+
// Implicit positive feedback for enrichable search tools
|
|
97
|
+
if (this.config.enrichableTools.has(name)) {
|
|
98
|
+
const query = this.extractQuery(args);
|
|
99
|
+
if (query &&
|
|
100
|
+
result &&
|
|
101
|
+
!result.includes("No results") &&
|
|
102
|
+
!result.includes("not found") &&
|
|
103
|
+
!result.includes("No relevant context found")) {
|
|
104
|
+
// Count approximate results for weighted feedback
|
|
105
|
+
const numbered = result.match(/^\d+\./gm);
|
|
106
|
+
const bullets = result.match(/^[-*] /gm);
|
|
107
|
+
const resultCount = numbered?.length ?? bullets?.length ?? 1;
|
|
108
|
+
ctx.api
|
|
109
|
+
.post("/api/feedback/search", {
|
|
110
|
+
projectName: ctx.projectName,
|
|
111
|
+
query,
|
|
112
|
+
feedbackType: "helpful",
|
|
113
|
+
toolName: name,
|
|
114
|
+
resultCount,
|
|
115
|
+
sessionId: ctx.activeSessionId,
|
|
116
|
+
})
|
|
117
|
+
.catch(() => { });
|
|
118
|
+
}
|
|
119
|
+
}
|
|
97
120
|
}
|
|
98
121
|
/**
|
|
99
122
|
* Extract a semantic query string from tool arguments.
|
package/dist/formatters.d.ts
CHANGED
|
@@ -39,6 +39,8 @@ export declare function formatNavigationResults(results: Array<{
|
|
|
39
39
|
score: number;
|
|
40
40
|
graphExpanded?: boolean;
|
|
41
41
|
}>): string;
|
|
42
|
+
/** Format pagination footer for list tools */
|
|
43
|
+
export declare function paginationFooter(count: number, limit: number, offset: number): string;
|
|
42
44
|
/** Format a simple list of files with scores */
|
|
43
45
|
export declare function formatFileList(files: Array<{
|
|
44
46
|
file: string;
|
package/dist/formatters.js
CHANGED
|
@@ -80,6 +80,18 @@ export function formatNavigationResults(results) {
|
|
|
80
80
|
return out;
|
|
81
81
|
}).join('\n\n');
|
|
82
82
|
}
|
|
83
|
+
/** Format pagination footer for list tools */
|
|
84
|
+
export function paginationFooter(count, limit, offset) {
|
|
85
|
+
const hasMore = count >= limit;
|
|
86
|
+
if (!hasMore && offset === 0)
|
|
87
|
+
return "";
|
|
88
|
+
let footer = `\n---\n_Showing ${offset + 1}–${offset + count}`;
|
|
89
|
+
if (hasMore) {
|
|
90
|
+
footer += ` | More results available (offset: ${offset + limit})`;
|
|
91
|
+
}
|
|
92
|
+
footer += "_\n";
|
|
93
|
+
return footer;
|
|
94
|
+
}
|
|
83
95
|
/** Format a simple list of files with scores */
|
|
84
96
|
export function formatFileList(files, emptyMessage = "No files found.") {
|
|
85
97
|
if (!files || files.length === 0)
|
package/dist/index.js
CHANGED
|
@@ -10,12 +10,11 @@
|
|
|
10
10
|
* - PROJECT_PATH: Path to project codebase for indexing
|
|
11
11
|
* - RAG_API_URL: URL of the shared RAG API (default: http://localhost:3100)
|
|
12
12
|
*/
|
|
13
|
-
import {
|
|
13
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
14
14
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
15
|
-
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
16
15
|
import { createApiClient } from "./api-client.js";
|
|
17
|
-
import { ToolRegistry } from "./tool-registry.js";
|
|
18
16
|
import { ContextEnricher } from "./context-enrichment.js";
|
|
17
|
+
import { wrapHandler } from "./tool-middleware.js";
|
|
19
18
|
// Tool modules
|
|
20
19
|
import { createSearchTools } from "./tools/search.js";
|
|
21
20
|
import { createAskTools } from "./tools/ask.js";
|
|
@@ -51,59 +50,77 @@ const ctx = {
|
|
|
51
50
|
collectionPrefix: COLLECTION_PREFIX,
|
|
52
51
|
enrichmentEnabled: true,
|
|
53
52
|
};
|
|
54
|
-
//
|
|
55
|
-
const registry = new ToolRegistry();
|
|
56
|
-
registry.register(createSearchTools(PROJECT_NAME));
|
|
57
|
-
registry.register(createAskTools(PROJECT_NAME));
|
|
58
|
-
registry.register(createIndexingTools(PROJECT_NAME));
|
|
59
|
-
registry.register(createMemoryTools(PROJECT_NAME));
|
|
60
|
-
registry.register(createArchitectureTools(PROJECT_NAME));
|
|
61
|
-
registry.register(createDatabaseTools(PROJECT_NAME));
|
|
62
|
-
registry.register(createConfluenceTools(PROJECT_NAME));
|
|
63
|
-
registry.register(createPmTools(PROJECT_NAME));
|
|
64
|
-
registry.register(createReviewTools(PROJECT_NAME));
|
|
65
|
-
registry.register(createAnalyticsTools(PROJECT_NAME));
|
|
66
|
-
registry.register(createClusteringTools(PROJECT_NAME));
|
|
67
|
-
registry.register(createSessionTools(PROJECT_NAME, ctx));
|
|
68
|
-
registry.register(createFeedbackTools(PROJECT_NAME));
|
|
69
|
-
registry.register(createSuggestionTools(PROJECT_NAME));
|
|
70
|
-
registry.register(createCacheTools(PROJECT_NAME));
|
|
71
|
-
registry.register(createGuidelinesTools(PROJECT_NAME));
|
|
72
|
-
registry.register(createAdvancedTools(PROJECT_NAME));
|
|
73
|
-
registry.register(createAgentTools(PROJECT_NAME));
|
|
74
|
-
// Initialize context enrichment middleware
|
|
53
|
+
// Context enrichment middleware
|
|
75
54
|
const enricher = new ContextEnricher({
|
|
76
55
|
maxAutoRecall: 3,
|
|
77
56
|
minRelevance: 0.6,
|
|
78
57
|
timeoutMs: 2000,
|
|
79
58
|
});
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
59
|
+
// Collect all tool specs from modules
|
|
60
|
+
const allSpecs = [
|
|
61
|
+
...createSearchTools(PROJECT_NAME),
|
|
62
|
+
...createAskTools(PROJECT_NAME),
|
|
63
|
+
...createIndexingTools(PROJECT_NAME),
|
|
64
|
+
...createMemoryTools(PROJECT_NAME),
|
|
65
|
+
...createArchitectureTools(PROJECT_NAME),
|
|
66
|
+
...createDatabaseTools(PROJECT_NAME),
|
|
67
|
+
...createConfluenceTools(PROJECT_NAME),
|
|
68
|
+
...createPmTools(PROJECT_NAME),
|
|
69
|
+
...createReviewTools(PROJECT_NAME),
|
|
70
|
+
...createAnalyticsTools(PROJECT_NAME),
|
|
71
|
+
...createClusteringTools(PROJECT_NAME),
|
|
72
|
+
...createSessionTools(PROJECT_NAME, ctx),
|
|
73
|
+
...createFeedbackTools(PROJECT_NAME),
|
|
74
|
+
...createSuggestionTools(PROJECT_NAME),
|
|
75
|
+
...createCacheTools(PROJECT_NAME),
|
|
76
|
+
...createGuidelinesTools(PROJECT_NAME),
|
|
77
|
+
...createAdvancedTools(PROJECT_NAME),
|
|
78
|
+
...createAgentTools(PROJECT_NAME),
|
|
79
|
+
];
|
|
80
|
+
// MCP Server (modern McpServer API with native Zod validation)
|
|
81
|
+
const server = new McpServer({ name: `${PROJECT_NAME}-rag`, version: "1.0.5" }, { capabilities: { tools: {} } });
|
|
82
|
+
// Register all tools with McpServer using wrapHandler middleware
|
|
83
|
+
for (const spec of allSpecs) {
|
|
84
|
+
const wrapped = wrapHandler(spec.name, spec.handler, { enricher, ctx });
|
|
85
|
+
server.registerTool(spec.name, {
|
|
86
|
+
description: spec.description,
|
|
87
|
+
inputSchema: spec.schema,
|
|
88
|
+
...(spec.outputSchema ? { outputSchema: spec.outputSchema } : {}),
|
|
89
|
+
annotations: spec.annotations,
|
|
90
|
+
}, async (args) => {
|
|
91
|
+
const result = await wrapped(args, ctx);
|
|
92
|
+
if (typeof result === "string") {
|
|
93
|
+
return { content: [{ type: "text", text: result }] };
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
content: [{ type: "text", text: result.text }],
|
|
97
|
+
structuredContent: result.structured,
|
|
98
|
+
};
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
// Graceful shutdown: close active session on exit
|
|
102
|
+
async function cleanup() {
|
|
103
|
+
if (ctx.activeSessionId) {
|
|
104
|
+
try {
|
|
105
|
+
await api.post(`/api/session/${ctx.activeSessionId}/end`, {
|
|
106
|
+
projectName: PROJECT_NAME,
|
|
107
|
+
summary: "Session ended by MCP server shutdown",
|
|
108
|
+
autoSaveLearnings: true,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
// Best-effort, don't block shutdown
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
process.exit(0);
|
|
116
|
+
}
|
|
117
|
+
process.on("SIGINT", cleanup);
|
|
118
|
+
process.on("SIGTERM", cleanup);
|
|
102
119
|
// Start server
|
|
103
120
|
async function main() {
|
|
104
121
|
const transport = new StdioServerTransport();
|
|
105
122
|
await server.connect(transport);
|
|
106
123
|
console.error(`${PROJECT_NAME} RAG MCP server running (collection prefix: ${COLLECTION_PREFIX})`);
|
|
107
|
-
console.error(`Registered ${
|
|
124
|
+
console.error(`Registered ${allSpecs.length} tools from 18 modules`);
|
|
108
125
|
}
|
|
109
126
|
main().catch(console.error);
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common Zod schemas shared across tool modules.
|
|
3
|
+
*
|
|
4
|
+
* Import individual shapes into each tool module when migrating
|
|
5
|
+
* from raw JSON Schema objects to Zod-based inputSchema definitions.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import type { ToolInputSchema } from "./types.js";
|
|
9
|
+
/**
|
|
10
|
+
* Convert a Zod object schema to the MCP ToolInputSchema format.
|
|
11
|
+
* Used during Phase 2 migration while ToolRegistry still expects raw JSON Schema.
|
|
12
|
+
* Phase 3 passes Zod schemas directly to McpServer.registerTool().
|
|
13
|
+
*/
|
|
14
|
+
export declare function zodToInputSchema(schema: z.ZodObject<z.ZodRawShape>): ToolInputSchema;
|
|
15
|
+
export declare const QueryStr: z.ZodString;
|
|
16
|
+
export declare const Limit: z.ZodDefault<z.ZodNumber>;
|
|
17
|
+
export declare const Offset: z.ZodDefault<z.ZodNumber>;
|
|
18
|
+
export declare const FilePath: z.ZodString;
|
|
19
|
+
export declare const FilePaths: z.ZodArray<z.ZodString, "many">;
|
|
20
|
+
export declare const Content: z.ZodString;
|
|
21
|
+
export declare const CollectionSuffix: z.ZodString;
|
|
22
|
+
export declare const MemoryType: z.ZodEnum<["decision", "insight", "pattern", "adr", "tech_debt", "todo", "architecture", "convention", "bug_fix", "optimization"]>;
|
|
23
|
+
export declare const ResponseFormat: z.ZodDefault<z.ZodEnum<["json", "markdown"]>>;
|
|
24
|
+
export declare const Importance: z.ZodDefault<z.ZodEnum<["low", "medium", "high", "critical"]>>;
|
|
25
|
+
export declare const Priority: z.ZodEnum<["low", "medium", "high", "critical"]>;
|
|
26
|
+
export declare const Severity: z.ZodEnum<["low", "medium", "high", "critical"]>;
|
|
27
|
+
export declare const PaginationParams: z.ZodObject<{
|
|
28
|
+
limit: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
|
|
29
|
+
offset: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
|
|
30
|
+
}, "strip", z.ZodTypeAny, {
|
|
31
|
+
limit?: number | undefined;
|
|
32
|
+
offset?: number | undefined;
|
|
33
|
+
}, {
|
|
34
|
+
limit?: number | undefined;
|
|
35
|
+
offset?: number | undefined;
|
|
36
|
+
}>;
|
|
37
|
+
export declare const SearchFilters: z.ZodOptional<z.ZodObject<{
|
|
38
|
+
file_type: z.ZodOptional<z.ZodString>;
|
|
39
|
+
directory: z.ZodOptional<z.ZodString>;
|
|
40
|
+
}, "strip", z.ZodTypeAny, {
|
|
41
|
+
file_type?: string | undefined;
|
|
42
|
+
directory?: string | undefined;
|
|
43
|
+
}, {
|
|
44
|
+
file_type?: string | undefined;
|
|
45
|
+
directory?: string | undefined;
|
|
46
|
+
}>>;
|
|
47
|
+
export declare const Tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
48
|
+
export declare const Confidence: z.ZodOptional<z.ZodNumber>;
|
|
49
|
+
/** Base shape for search tools: query + optional limit + optional filters */
|
|
50
|
+
export declare const SearchInput: z.ZodObject<{
|
|
51
|
+
query: z.ZodString;
|
|
52
|
+
limit: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
|
|
53
|
+
filters: z.ZodOptional<z.ZodObject<{
|
|
54
|
+
file_type: z.ZodOptional<z.ZodString>;
|
|
55
|
+
directory: z.ZodOptional<z.ZodString>;
|
|
56
|
+
}, "strip", z.ZodTypeAny, {
|
|
57
|
+
file_type?: string | undefined;
|
|
58
|
+
directory?: string | undefined;
|
|
59
|
+
}, {
|
|
60
|
+
file_type?: string | undefined;
|
|
61
|
+
directory?: string | undefined;
|
|
62
|
+
}>>;
|
|
63
|
+
}, "strip", z.ZodTypeAny, {
|
|
64
|
+
query: string;
|
|
65
|
+
limit?: number | undefined;
|
|
66
|
+
filters?: {
|
|
67
|
+
file_type?: string | undefined;
|
|
68
|
+
directory?: string | undefined;
|
|
69
|
+
} | undefined;
|
|
70
|
+
}, {
|
|
71
|
+
query: string;
|
|
72
|
+
limit?: number | undefined;
|
|
73
|
+
filters?: {
|
|
74
|
+
file_type?: string | undefined;
|
|
75
|
+
directory?: string | undefined;
|
|
76
|
+
} | undefined;
|
|
77
|
+
}>;
|
|
78
|
+
/** Base shape for memory record tools */
|
|
79
|
+
export declare const MemoryRecordInput: z.ZodObject<{
|
|
80
|
+
content: z.ZodString;
|
|
81
|
+
type: z.ZodEnum<["decision", "insight", "pattern", "adr", "tech_debt", "todo", "architecture", "convention", "bug_fix", "optimization"]>;
|
|
82
|
+
tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
83
|
+
importance: z.ZodOptional<z.ZodDefault<z.ZodEnum<["low", "medium", "high", "critical"]>>>;
|
|
84
|
+
context: z.ZodOptional<z.ZodString>;
|
|
85
|
+
}, "strip", z.ZodTypeAny, {
|
|
86
|
+
type: "decision" | "insight" | "todo" | "adr" | "pattern" | "tech_debt" | "architecture" | "convention" | "bug_fix" | "optimization";
|
|
87
|
+
content: string;
|
|
88
|
+
context?: string | undefined;
|
|
89
|
+
tags?: string[] | undefined;
|
|
90
|
+
importance?: "low" | "medium" | "high" | "critical" | undefined;
|
|
91
|
+
}, {
|
|
92
|
+
type: "decision" | "insight" | "todo" | "adr" | "pattern" | "tech_debt" | "architecture" | "convention" | "bug_fix" | "optimization";
|
|
93
|
+
content: string;
|
|
94
|
+
context?: string | undefined;
|
|
95
|
+
tags?: string[] | undefined;
|
|
96
|
+
importance?: "low" | "medium" | "high" | "critical" | undefined;
|
|
97
|
+
}>;
|
package/dist/schemas.js
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common Zod schemas shared across tool modules.
|
|
3
|
+
*
|
|
4
|
+
* Import individual shapes into each tool module when migrating
|
|
5
|
+
* from raw JSON Schema objects to Zod-based inputSchema definitions.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
9
|
+
// ── JSON Schema conversion ──────────────────────────────────
|
|
10
|
+
/**
|
|
11
|
+
* Convert a Zod object schema to the MCP ToolInputSchema format.
|
|
12
|
+
* Used during Phase 2 migration while ToolRegistry still expects raw JSON Schema.
|
|
13
|
+
* Phase 3 passes Zod schemas directly to McpServer.registerTool().
|
|
14
|
+
*/
|
|
15
|
+
export function zodToInputSchema(schema) {
|
|
16
|
+
const jsonSchema = zodToJsonSchema(schema, { target: "openApi3" });
|
|
17
|
+
return {
|
|
18
|
+
type: "object",
|
|
19
|
+
properties: (jsonSchema.properties ?? {}),
|
|
20
|
+
...(Array.isArray(jsonSchema.required) && jsonSchema.required.length > 0
|
|
21
|
+
? { required: jsonSchema.required }
|
|
22
|
+
: {}),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
// ── Primitives ──────────────────────────────────────────────
|
|
26
|
+
export const QueryStr = z
|
|
27
|
+
.string()
|
|
28
|
+
.min(1)
|
|
29
|
+
.describe("Search query or question");
|
|
30
|
+
export const Limit = z
|
|
31
|
+
.number()
|
|
32
|
+
.int()
|
|
33
|
+
.min(1)
|
|
34
|
+
.max(100)
|
|
35
|
+
.default(20)
|
|
36
|
+
.describe("Maximum results to return");
|
|
37
|
+
export const Offset = z
|
|
38
|
+
.number()
|
|
39
|
+
.int()
|
|
40
|
+
.min(0)
|
|
41
|
+
.default(0)
|
|
42
|
+
.describe("Pagination offset");
|
|
43
|
+
export const FilePath = z
|
|
44
|
+
.string()
|
|
45
|
+
.min(1)
|
|
46
|
+
.describe("File path relative to project root");
|
|
47
|
+
export const FilePaths = z
|
|
48
|
+
.array(FilePath)
|
|
49
|
+
.min(1)
|
|
50
|
+
.describe("List of file paths");
|
|
51
|
+
export const Content = z
|
|
52
|
+
.string()
|
|
53
|
+
.min(1)
|
|
54
|
+
.describe("Text content");
|
|
55
|
+
export const CollectionSuffix = z
|
|
56
|
+
.string()
|
|
57
|
+
.min(1)
|
|
58
|
+
.describe("Collection suffix (e.g. 'codebase', 'docs')");
|
|
59
|
+
// ── Enums ───────────────────────────────────────────────────
|
|
60
|
+
export const MemoryType = z.enum([
|
|
61
|
+
"decision",
|
|
62
|
+
"insight",
|
|
63
|
+
"pattern",
|
|
64
|
+
"adr",
|
|
65
|
+
"tech_debt",
|
|
66
|
+
"todo",
|
|
67
|
+
"architecture",
|
|
68
|
+
"convention",
|
|
69
|
+
"bug_fix",
|
|
70
|
+
"optimization",
|
|
71
|
+
]);
|
|
72
|
+
export const ResponseFormat = z
|
|
73
|
+
.enum(["json", "markdown"])
|
|
74
|
+
.default("markdown")
|
|
75
|
+
.describe("Output format");
|
|
76
|
+
export const Importance = z
|
|
77
|
+
.enum(["low", "medium", "high", "critical"])
|
|
78
|
+
.default("medium")
|
|
79
|
+
.describe("Importance level");
|
|
80
|
+
export const Priority = z
|
|
81
|
+
.enum(["low", "medium", "high", "critical"])
|
|
82
|
+
.describe("Priority level");
|
|
83
|
+
export const Severity = z
|
|
84
|
+
.enum(["low", "medium", "high", "critical"])
|
|
85
|
+
.describe("Severity level");
|
|
86
|
+
// ── Reusable object shapes ──────────────────────────────────
|
|
87
|
+
export const PaginationParams = z.object({
|
|
88
|
+
limit: Limit.optional(),
|
|
89
|
+
offset: Offset.optional(),
|
|
90
|
+
});
|
|
91
|
+
export const SearchFilters = z
|
|
92
|
+
.object({
|
|
93
|
+
file_type: z
|
|
94
|
+
.string()
|
|
95
|
+
.optional()
|
|
96
|
+
.describe("Filter by file extension (e.g. 'ts', 'py')"),
|
|
97
|
+
directory: z
|
|
98
|
+
.string()
|
|
99
|
+
.optional()
|
|
100
|
+
.describe("Filter by directory prefix"),
|
|
101
|
+
})
|
|
102
|
+
.optional()
|
|
103
|
+
.describe("Search filters");
|
|
104
|
+
export const Tags = z
|
|
105
|
+
.array(z.string())
|
|
106
|
+
.optional()
|
|
107
|
+
.describe("Tags for categorization");
|
|
108
|
+
export const Confidence = z
|
|
109
|
+
.number()
|
|
110
|
+
.min(0)
|
|
111
|
+
.max(1)
|
|
112
|
+
.optional()
|
|
113
|
+
.describe("Confidence score (0-1)");
|
|
114
|
+
// ── Composite input shapes ──────────────────────────────────
|
|
115
|
+
/** Base shape for search tools: query + optional limit + optional filters */
|
|
116
|
+
export const SearchInput = z.object({
|
|
117
|
+
query: QueryStr,
|
|
118
|
+
limit: Limit.optional(),
|
|
119
|
+
filters: SearchFilters,
|
|
120
|
+
});
|
|
121
|
+
/** Base shape for memory record tools */
|
|
122
|
+
export const MemoryRecordInput = z.object({
|
|
123
|
+
content: Content.describe("Content to remember"),
|
|
124
|
+
type: MemoryType,
|
|
125
|
+
tags: Tags,
|
|
126
|
+
importance: Importance.optional(),
|
|
127
|
+
context: z.string().optional().describe("Additional context"),
|
|
128
|
+
});
|