@crowley/rag-mcp 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,13 +10,29 @@ export function createArchitectureTools(projectName) {
10
10
  name: "record_adr",
11
11
  description: `Record an Architecture Decision Record (ADR). Use this to document important architectural decisions, technology choices, and design patterns for ${projectName}.`,
12
12
  schema: z.object({
13
- title: z.string().describe("Short title for the decision (e.g., 'Use WebSocket for real-time updates')"),
14
- context: z.string().describe("Why this decision was needed - the problem or requirement"),
13
+ title: z
14
+ .string()
15
+ .describe("Short title for the decision (e.g., 'Use WebSocket for real-time updates')"),
16
+ context: z
17
+ .string()
18
+ .describe("Why this decision was needed - the problem or requirement"),
15
19
  decision: z.string().describe("What was decided"),
16
- consequences: z.string().optional().describe("Positive and negative consequences of this decision"),
17
- alternatives: z.string().optional().describe("What alternatives were considered"),
18
- status: z.enum(["proposed", "accepted", "deprecated", "superseded"]).optional().describe("Status of the decision (default: accepted)"),
19
- tags: z.array(z.string()).optional().describe("Tags for categorization (e.g., ['api', 'security', 'database'])"),
20
+ consequences: z
21
+ .string()
22
+ .optional()
23
+ .describe("Positive and negative consequences of this decision"),
24
+ alternatives: z
25
+ .string()
26
+ .optional()
27
+ .describe("What alternatives were considered"),
28
+ status: z
29
+ .enum(["proposed", "accepted", "deprecated", "superseded"])
30
+ .optional()
31
+ .describe("Status of the decision (default: accepted)"),
32
+ tags: z
33
+ .array(z.string())
34
+ .optional()
35
+ .describe("Tags for categorization (e.g., ['api', 'security', 'database'])"),
20
36
  }),
21
37
  annotations: TOOL_ANNOTATIONS["record_adr"],
22
38
  handler: async (args, ctx) => {
@@ -54,9 +70,18 @@ ${alternatives ? `## Alternatives Considered\n${alternatives}` : ""}`;
54
70
  name: "get_adrs",
55
71
  description: `Get Architecture Decision Records for ${projectName}. Search by topic or list all ADRs.`,
56
72
  schema: z.object({
57
- query: z.string().optional().describe("Search query (optional - returns all if empty)"),
58
- status: z.enum(["proposed", "accepted", "deprecated", "superseded", "all"]).optional().describe("Filter by status"),
59
- limit: z.coerce.number().optional().describe("Max results (default: 10)"),
73
+ query: z
74
+ .string()
75
+ .optional()
76
+ .describe("Search query (optional - returns all if empty)"),
77
+ status: z
78
+ .enum(["proposed", "accepted", "deprecated", "superseded", "all"])
79
+ .optional()
80
+ .describe("Filter by status"),
81
+ limit: z.coerce
82
+ .number()
83
+ .optional()
84
+ .describe("Max results (default: 10)"),
60
85
  }),
61
86
  annotations: TOOL_ANNOTATIONS["get_adrs"],
62
87
  handler: async (args, ctx) => {
@@ -87,8 +112,7 @@ ${alternatives ? `## Alternatives Considered\n${alternatives}` : ""}`;
87
112
  const icon = statusIcons[adrStatus] || "\u26AA";
88
113
  result += `### ${i + 1}. ${icon} ${m.metadata?.adrTitle || m.relatedTo || "ADR"}\n`;
89
114
  result += `**Status:** ${adrStatus} | **ID:** \`${m.id}\`\n\n`;
90
- result +=
91
- truncate(m.content, 500) + "\n\n";
115
+ result += truncate(m.content, 500) + "\n\n";
92
116
  });
93
117
  return result;
94
118
  },
@@ -97,12 +121,27 @@ ${alternatives ? `## Alternatives Considered\n${alternatives}` : ""}`;
97
121
  name: "record_pattern",
98
122
  description: `Record an architectural pattern used in ${projectName}. Patterns define how specific types of code should be structured.`,
99
123
  schema: z.object({
100
- name: z.string().describe("Pattern name (e.g., 'Service Layer', 'Repository Pattern', 'API Endpoint')"),
101
- description: z.string().describe("What this pattern is for and when to use it"),
102
- structure: z.string().describe("How code following this pattern should be structured (file organization, naming, etc.)"),
103
- example: z.string().optional().describe("Example code or file reference demonstrating the pattern"),
104
- appliesTo: z.string().optional().describe("Where this pattern applies (e.g., 'backend/src/modules/*', 'all API endpoints')"),
105
- tags: z.array(z.string()).optional().describe("Tags (e.g., ['backend', 'api', 'module'])"),
124
+ name: z
125
+ .string()
126
+ .describe("Pattern name (e.g., 'Service Layer', 'Repository Pattern', 'API Endpoint')"),
127
+ description: z
128
+ .string()
129
+ .describe("What this pattern is for and when to use it"),
130
+ structure: z
131
+ .string()
132
+ .describe("How code following this pattern should be structured (file organization, naming, etc.)"),
133
+ example: z
134
+ .string()
135
+ .optional()
136
+ .describe("Example code or file reference demonstrating the pattern"),
137
+ appliesTo: z
138
+ .string()
139
+ .optional()
140
+ .describe("Where this pattern applies (e.g., 'backend/src/modules/*', 'all API endpoints')"),
141
+ tags: z
142
+ .array(z.string())
143
+ .optional()
144
+ .describe("Tags (e.g., ['backend', 'api', 'module'])"),
106
145
  }),
107
146
  annotations: TOOL_ANNOTATIONS["record_pattern"],
108
147
  handler: async (args, ctx) => {
@@ -136,9 +175,18 @@ ${appliesTo ? `## Applies To\n${appliesTo}` : ""}`;
136
175
  name: "get_patterns",
137
176
  description: `Get architectural patterns for ${projectName}. Use to understand how to structure new code.`,
138
177
  schema: z.object({
139
- query: z.string().optional().describe("Search for patterns by name or description"),
140
- appliesTo: z.string().optional().describe("Filter by what patterns apply to (e.g., 'api', 'module')"),
141
- limit: z.coerce.number().optional().describe("Max results (default: 10)"),
178
+ query: z
179
+ .string()
180
+ .optional()
181
+ .describe("Search for patterns by name or description"),
182
+ appliesTo: z
183
+ .string()
184
+ .optional()
185
+ .describe("Filter by what patterns apply to (e.g., 'api', 'module')"),
186
+ limit: z.coerce
187
+ .number()
188
+ .optional()
189
+ .describe("Max results (default: 10)"),
142
190
  }),
143
191
  annotations: TOOL_ANNOTATIONS["get_patterns"],
144
192
  handler: async (args, ctx) => {
@@ -180,8 +228,14 @@ ${appliesTo ? `## Applies To\n${appliesTo}` : ""}`;
180
228
  description: `Check if code or a feature follows established architectural patterns. Analyzes code against recorded patterns and ADRs.`,
181
229
  schema: z.object({
182
230
  code: z.string().optional().describe("Code snippet to check"),
183
- filePath: z.string().optional().describe("File path for context (helps determine which patterns apply)"),
184
- featureDescription: z.string().optional().describe("Description of what the code does (alternative to providing code)"),
231
+ filePath: z
232
+ .string()
233
+ .optional()
234
+ .describe("File path for context (helps determine which patterns apply)"),
235
+ featureDescription: z
236
+ .string()
237
+ .optional()
238
+ .describe("Description of what the code does (alternative to providing code)"),
185
239
  }),
186
240
  annotations: TOOL_ANNOTATIONS["check_architecture"],
187
241
  handler: async (args, ctx) => {
@@ -309,7 +363,17 @@ Provide a structured analysis:
309
363
  description: `Get architectural guidance for implementing a new feature. Suggests structure, patterns to follow, and relevant ADRs.`,
310
364
  schema: z.object({
311
365
  feature: z.string().describe("Feature to implement"),
312
- type: z.enum(["api", "module", "service", "component", "integration", "other"]).optional().describe("Type of feature"),
366
+ type: z
367
+ .enum([
368
+ "api",
369
+ "module",
370
+ "service",
371
+ "component",
372
+ "integration",
373
+ "other",
374
+ ])
375
+ .optional()
376
+ .describe("Type of feature"),
313
377
  }),
314
378
  annotations: TOOL_ANNOTATIONS["suggest_architecture"],
315
379
  handler: async (args, ctx) => {
@@ -391,14 +455,22 @@ Provide a structured analysis:
391
455
  schema: z.object({
392
456
  title: z.string().describe("Short description of the tech debt"),
393
457
  description: z.string().describe("Detailed description of the issue"),
394
- location: z.string().optional().describe("Where in the codebase (file paths, modules)"),
395
- impact: z.enum(["low", "medium", "high", "critical"]).describe("Impact level"),
458
+ location: z
459
+ .string()
460
+ .optional()
461
+ .describe("Where in the codebase (file paths, modules)"),
462
+ impact: z
463
+ .enum(["low", "medium", "high", "critical"])
464
+ .describe("Impact level"),
396
465
  suggestedFix: z.string().optional().describe("How to fix this debt"),
397
- relatedAdr: z.string().optional().describe("Related ADR ID if this violates a decision"),
466
+ relatedAdr: z
467
+ .string()
468
+ .optional()
469
+ .describe("Related ADR ID if this violates a decision"),
398
470
  }),
399
471
  annotations: TOOL_ANNOTATIONS["record_tech_debt"],
400
472
  handler: async (args, ctx) => {
401
- const { title, description, location, impact, suggestedFix, relatedAdr } = args;
473
+ const { title, description, location, impact, suggestedFix, relatedAdr, } = args;
402
474
  const debtContent = `# Tech Debt: ${title}
403
475
 
404
476
  ## Impact
@@ -436,8 +508,14 @@ ${relatedAdr ? `## Related ADR\n${relatedAdr}` : ""}`;
436
508
  name: "get_tech_debt",
437
509
  description: `List technical debt items for ${projectName}.`,
438
510
  schema: z.object({
439
- impact: z.enum(["low", "medium", "high", "critical", "all"]).optional().describe("Filter by impact"),
440
- limit: z.coerce.number().optional().describe("Max results (default: 10)"),
511
+ impact: z
512
+ .enum(["low", "medium", "high", "critical", "all"])
513
+ .optional()
514
+ .describe("Filter by impact"),
515
+ limit: z.coerce
516
+ .number()
517
+ .optional()
518
+ .describe("Max results (default: 10)"),
441
519
  }),
442
520
  annotations: TOOL_ANNOTATIONS["get_tech_debt"],
443
521
  handler: async (args, ctx) => {
@@ -492,8 +570,14 @@ ${relatedAdr ? `## Related ADR\n${relatedAdr}` : ""}`;
492
570
  name: "analyze_project_structure",
493
571
  description: `Analyze the current project structure and compare with established patterns. Identifies inconsistencies and suggests improvements.`,
494
572
  schema: z.object({
495
- path: z.string().optional().describe("Specific path to analyze (default: entire project)"),
496
- deep: z.boolean().optional().describe("Perform deep analysis including code patterns (default: false)"),
573
+ path: z
574
+ .string()
575
+ .optional()
576
+ .describe("Specific path to analyze (default: entire project)"),
577
+ deep: z
578
+ .boolean()
579
+ .optional()
580
+ .describe("Perform deep analysis including code patterns (default: false)"),
497
581
  }),
498
582
  annotations: TOOL_ANNOTATIONS["analyze_project_structure"],
499
583
  handler: async (args, ctx) => {
package/dist/tools/ask.js CHANGED
@@ -31,7 +31,10 @@ export function createAskTools(projectName) {
31
31
  description: "Get a detailed explanation of a code snippet.",
32
32
  schema: z.object({
33
33
  code: z.string().describe("Code snippet to explain"),
34
- filePath: z.string().optional().describe("Optional file path for context"),
34
+ filePath: z
35
+ .string()
36
+ .optional()
37
+ .describe("Optional file path for context"),
35
38
  }),
36
39
  annotations: TOOL_ANNOTATIONS["explain_code"],
37
40
  handler: async (args, ctx) => {
@@ -97,13 +100,22 @@ export function createAskTools(projectName) {
97
100
  description: `Analyze a conversation to extract learnings, decisions, and insights for ${projectName}.`,
98
101
  schema: z.object({
99
102
  conversation: z.string().describe("The conversation text to analyze"),
100
- context: z.string().optional().describe("Additional context about the conversation"),
101
- autoSave: z.boolean().optional().describe("Automatically save extracted learnings (default: false)"),
102
- minConfidence: z.coerce.number().optional().describe("Minimum confidence threshold for learnings (0-1, default: 0.7)"),
103
+ context: z
104
+ .string()
105
+ .optional()
106
+ .describe("Additional context about the conversation"),
107
+ autoSave: z
108
+ .boolean()
109
+ .optional()
110
+ .describe("Automatically save extracted learnings (default: false)"),
111
+ minConfidence: z.coerce
112
+ .number()
113
+ .optional()
114
+ .describe("Minimum confidence threshold for learnings (0-1, default: 0.7)"),
103
115
  }),
104
116
  annotations: TOOL_ANNOTATIONS["analyze_conversation"],
105
117
  handler: async (args, ctx) => {
106
- const { conversation, context, autoSave = false, minConfidence = 0.7 } = args;
118
+ const { conversation, context, autoSave = false, minConfidence = 0.7, } = args;
107
119
  const response = await ctx.api.post("/api/analyze-conversation", {
108
120
  projectName: ctx.projectName,
109
121
  conversation,
@@ -153,7 +165,10 @@ export function createAskTools(projectName) {
153
165
  content: z.string().describe("Content to analyze and remember"),
154
166
  context: z.string().optional().describe("Additional context"),
155
167
  relatedTo: z.string().optional().describe("Related feature or topic"),
156
- tags: z.array(z.string()).optional().describe("Tags for categorization"),
168
+ tags: z
169
+ .array(z.string())
170
+ .optional()
171
+ .describe("Tags for categorization"),
157
172
  }),
158
173
  annotations: TOOL_ANNOTATIONS["auto_remember"],
159
174
  handler: async (args, ctx) => {
@@ -180,9 +195,9 @@ export function createAskTools(projectName) {
180
195
  type: memoryType,
181
196
  content,
182
197
  relatedTo,
183
- tags: tags || (analysis.learnings?.[0]?.tags),
198
+ tags: tags || analysis.learnings?.[0]?.tags,
184
199
  metadata: {
185
- source: 'auto_pattern',
200
+ source: "auto_pattern",
186
201
  confidence,
187
202
  },
188
203
  });
@@ -9,7 +9,10 @@ export function createCacheTools(projectName) {
9
9
  name: "get_cache_stats",
10
10
  description: `Get cache statistics for ${projectName}. Shows hit rates, cache levels, and memory usage.`,
11
11
  schema: z.object({
12
- sessionId: z.string().optional().describe("Optional session ID for session-specific stats"),
12
+ sessionId: z
13
+ .string()
14
+ .optional()
15
+ .describe("Optional session ID for session-specific stats"),
13
16
  }),
14
17
  annotations: TOOL_ANNOTATIONS["get_cache_stats"],
15
18
  handler: async (args, ctx) => {
@@ -50,8 +53,14 @@ export function createCacheTools(projectName) {
50
53
  description: `Warm the embedding cache for ${projectName}. Pre-loads frequently used embeddings for faster responses.`,
51
54
  schema: z.object({
52
55
  sessionId: z.string().describe("Session ID to warm cache for"),
53
- previousSessionId: z.string().optional().describe("Previous session to copy cache from (for session resumption)"),
54
- recentQueries: z.array(z.string()).optional().describe("Recent queries to pre-warm in cache"),
56
+ previousSessionId: z
57
+ .string()
58
+ .optional()
59
+ .describe("Previous session to copy cache from (for session resumption)"),
60
+ recentQueries: z
61
+ .array(z.string())
62
+ .optional()
63
+ .describe("Recent queries to pre-warm in cache"),
55
64
  }),
56
65
  annotations: TOOL_ANNOTATIONS["warm_cache"],
57
66
  handler: async (args, ctx) => {
@@ -14,13 +14,21 @@ export function createClusteringTools(projectName) {
14
14
  name: "cluster_code",
15
15
  description: `Cluster code in the ${projectName} codebase by similarity. Groups related files around seed points.`,
16
16
  schema: z.object({
17
- seedIds: z.array(z.string()).describe("Seed point IDs to cluster around"),
18
- limit: z.coerce.number().optional().describe("Max results per cluster (default: 5)"),
19
- threshold: z.coerce.number().optional().describe("Minimum similarity threshold (0-1, default: 0.7)"),
17
+ seedIds: z
18
+ .array(z.string())
19
+ .describe("Seed point IDs to cluster around"),
20
+ limit: z.coerce
21
+ .number()
22
+ .optional()
23
+ .describe("Max results per cluster (default: 5)"),
24
+ threshold: z.coerce
25
+ .number()
26
+ .optional()
27
+ .describe("Minimum similarity threshold (0-1, default: 0.7)"),
20
28
  }),
21
29
  annotations: TOOL_ANNOTATIONS["cluster_code"],
22
30
  handler: async (args, ctx) => {
23
- const { seedIds, limit = 5, threshold = 0.7 } = args;
31
+ const { seedIds, limit = 5, threshold = 0.7, } = args;
24
32
  const response = await ctx.api.post("/api/clusters", {
25
33
  collection: `${ctx.collectionPrefix}codebase`,
26
34
  seedIds,
@@ -51,15 +59,26 @@ export function createClusteringTools(projectName) {
51
59
  name: "find_duplicates",
52
60
  description: `Find duplicate or near-duplicate code in ${projectName}. Groups similar files by content.`,
53
61
  schema: z.object({
54
- collection: z.string().optional().describe("Collection to search (default: codebase)"),
55
- limit: z.coerce.number().optional().describe("Max duplicate groups to return (default: 10)"),
56
- threshold: z.coerce.number().optional().describe("Minimum similarity threshold (0-1, default: 0.9)"),
62
+ collection: z
63
+ .string()
64
+ .optional()
65
+ .describe("Collection to search (default: codebase)"),
66
+ limit: z.coerce
67
+ .number()
68
+ .optional()
69
+ .describe("Max duplicate groups to return (default: 10)"),
70
+ threshold: z.coerce
71
+ .number()
72
+ .optional()
73
+ .describe("Minimum similarity threshold (0-1, default: 0.9)"),
57
74
  }),
58
75
  annotations: TOOL_ANNOTATIONS["find_duplicates"],
59
76
  handler: async (args, ctx) => {
60
- const { collection, limit = 10, threshold = 0.9 } = args;
77
+ const { collection, limit = 10, threshold = 0.9, } = args;
61
78
  const fullCollection = collection
62
- ? (collection.startsWith(ctx.collectionPrefix) ? collection : `${ctx.collectionPrefix}${collection}`)
79
+ ? collection.startsWith(ctx.collectionPrefix)
80
+ ? collection
81
+ : `${ctx.collectionPrefix}${collection}`
63
82
  : `${ctx.collectionPrefix}codebase`;
64
83
  const response = await ctx.api.post("/api/duplicates", {
65
84
  collection: fullCollection,
@@ -95,13 +114,21 @@ export function createClusteringTools(projectName) {
95
114
  name: "recommend_similar",
96
115
  description: `Recommend similar code based on positive and negative examples in ${projectName}.`,
97
116
  schema: z.object({
98
- positiveIds: z.array(z.string()).describe("IDs of vectors to find similar code to"),
99
- negativeIds: z.array(z.string()).optional().describe("IDs of vectors to avoid (dissimilar)"),
100
- limit: z.coerce.number().optional().describe("Max results (default: 5)"),
117
+ positiveIds: z
118
+ .array(z.string())
119
+ .describe("IDs of vectors to find similar code to"),
120
+ negativeIds: z
121
+ .array(z.string())
122
+ .optional()
123
+ .describe("IDs of vectors to avoid (dissimilar)"),
124
+ limit: z.coerce
125
+ .number()
126
+ .optional()
127
+ .describe("Max results (default: 5)"),
101
128
  }),
102
129
  annotations: TOOL_ANNOTATIONS["recommend_similar"],
103
130
  handler: async (args, ctx) => {
104
- const { positiveIds, negativeIds, limit = 5 } = args;
131
+ const { positiveIds, negativeIds, limit = 5, } = args;
105
132
  const response = await ctx.api.post("/api/recommend", {
106
133
  collection: `${ctx.collectionPrefix}codebase`,
107
134
  positiveIds,
@@ -127,13 +154,22 @@ export function createClusteringTools(projectName) {
127
154
  description: `Extract learnings and insights from text for ${projectName}. Identifies decisions, patterns, and concepts.`,
128
155
  schema: z.object({
129
156
  text: z.string().describe("Text to extract learnings from"),
130
- context: z.string().optional().describe("Additional context about the text"),
131
- autoSave: z.boolean().optional().describe("Automatically save extracted learnings (default: false)"),
132
- minConfidence: z.coerce.number().optional().describe("Minimum confidence threshold (0-1, default: 0.7)"),
157
+ context: z
158
+ .string()
159
+ .optional()
160
+ .describe("Additional context about the text"),
161
+ autoSave: z
162
+ .boolean()
163
+ .optional()
164
+ .describe("Automatically save extracted learnings (default: false)"),
165
+ minConfidence: z.coerce
166
+ .number()
167
+ .optional()
168
+ .describe("Minimum confidence threshold (0-1, default: 0.7)"),
133
169
  }),
134
170
  annotations: TOOL_ANNOTATIONS["extract_learnings"],
135
171
  handler: async (args, ctx) => {
136
- const { text, context, autoSave = false, minConfidence = 0.7 } = args;
172
+ const { text, context, autoSave = false, minConfidence = 0.7, } = args;
137
173
  const response = await ctx.api.post("/api/memory/extract", {
138
174
  projectName: ctx.projectName,
139
175
  text,
@@ -15,12 +15,18 @@ export function createConfluenceTools(projectName) {
15
15
  description: `Search indexed Confluence documentation for ${projectName}. Returns relevant pages with content snippets.`,
16
16
  schema: z.object({
17
17
  query: z.string().describe("Search query for Confluence content"),
18
- limit: z.coerce.number().optional().describe("Max results (default: 5)"),
19
- spaceKey: z.string().optional().describe("Filter by Confluence space key"),
18
+ limit: z.coerce
19
+ .number()
20
+ .optional()
21
+ .describe("Max results (default: 5)"),
22
+ spaceKey: z
23
+ .string()
24
+ .optional()
25
+ .describe("Filter by Confluence space key"),
20
26
  }),
21
27
  annotations: TOOL_ANNOTATIONS["search_confluence"],
22
28
  handler: async (args, ctx) => {
23
- const { query, limit = 5, spaceKey } = args;
29
+ const { query, limit = 5, spaceKey, } = args;
24
30
  const response = await ctx.api.post("/api/search", {
25
31
  collection: `${ctx.collectionPrefix}confluence`,
26
32
  query,
@@ -44,14 +50,26 @@ export function createConfluenceTools(projectName) {
44
50
  name: "index_confluence",
45
51
  description: `Index Confluence spaces/pages for ${projectName}. Requires Confluence credentials in RAG API.`,
46
52
  schema: z.object({
47
- spaceKeys: z.array(z.string()).optional().describe("Specific space keys to index (indexes all accessible if empty)"),
48
- labels: z.array(z.string()).optional().describe("Filter pages by labels"),
49
- maxPages: z.coerce.number().optional().describe("Maximum pages to index (default: 500)"),
50
- force: z.boolean().optional().describe("Force re-index even if already indexed"),
53
+ spaceKeys: z
54
+ .array(z.string())
55
+ .optional()
56
+ .describe("Specific space keys to index (indexes all accessible if empty)"),
57
+ labels: z
58
+ .array(z.string())
59
+ .optional()
60
+ .describe("Filter pages by labels"),
61
+ maxPages: z.coerce
62
+ .number()
63
+ .optional()
64
+ .describe("Maximum pages to index (default: 500)"),
65
+ force: z
66
+ .boolean()
67
+ .optional()
68
+ .describe("Force re-index even if already indexed"),
51
69
  }),
52
70
  annotations: TOOL_ANNOTATIONS["index_confluence"],
53
71
  handler: async (args, ctx) => {
54
- const { spaceKeys, labels, maxPages = 500, force = false } = args;
72
+ const { spaceKeys, labels, maxPages = 500, force = false, } = args;
55
73
  const response = await ctx.api.post("/api/index/confluence", {
56
74
  projectName: ctx.projectName,
57
75
  spaceKeys,