cmp-standards 2.4.0 → 2.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.
- package/README.md +633 -611
- package/dist/db/drizzle-client.d.ts +3 -3
- package/dist/db/drizzle-client.d.ts.map +1 -1
- package/dist/db/drizzle-client.js +57 -58
- package/dist/db/drizzle-client.js.map +1 -1
- package/dist/db/turso-client.js +11 -11
- package/dist/eslint/rules/no-async-useeffect.js +6 -6
- package/dist/hooks/cloud-pre-tool-use.js +20 -20
- package/dist/hooks/cloud-session-start.d.ts +15 -3
- package/dist/hooks/cloud-session-start.d.ts.map +1 -1
- package/dist/hooks/cloud-session-start.js +135 -8
- package/dist/hooks/cloud-session-start.js.map +1 -1
- package/dist/hooks/session-start.d.ts +2 -1
- package/dist/hooks/session-start.d.ts.map +1 -1
- package/dist/hooks/session-start.js +99 -74
- package/dist/hooks/session-start.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.js +2 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/schema/plans.d.ts +194 -0
- package/dist/schema/plans.d.ts.map +1 -0
- package/dist/schema/plans.js +180 -0
- package/dist/schema/plans.js.map +1 -0
- package/dist/services/ContextGenerator.d.ts +16 -0
- package/dist/services/ContextGenerator.d.ts.map +1 -0
- package/dist/services/ContextGenerator.js +62 -0
- package/dist/services/ContextGenerator.js.map +1 -0
- package/dist/services/PlanManager.d.ts +99 -0
- package/dist/services/PlanManager.d.ts.map +1 -0
- package/dist/services/PlanManager.js +372 -0
- package/dist/services/PlanManager.js.map +1 -0
- package/dist/services/ProjectScaffold.js +76 -76
- package/dist/services/context-injector.d.ts +105 -0
- package/dist/services/context-injector.d.ts.map +1 -0
- package/dist/services/context-injector.js +357 -0
- package/dist/services/context-injector.js.map +1 -0
- package/dist/services/index.d.ts +15 -15
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +18 -20
- package/dist/services/index.js.map +1 -1
- package/dist/services/memory-router.d.ts +98 -0
- package/dist/services/memory-router.d.ts.map +1 -0
- package/dist/services/memory-router.js +373 -0
- package/dist/services/memory-router.js.map +1 -0
- package/dist/services/pattern-tracker.d.ts +93 -0
- package/dist/services/pattern-tracker.d.ts.map +1 -0
- package/dist/services/pattern-tracker.js +347 -0
- package/dist/services/pattern-tracker.js.map +1 -0
- package/dist/services/semantic-search.d.ts +33 -35
- package/dist/services/semantic-search.d.ts.map +1 -1
- package/dist/services/semantic-search.js +207 -165
- package/dist/services/semantic-search.js.map +1 -1
- package/package.json +100 -100
- package/standards/README.md +50 -50
- package/standards/experts/expert-routing.md +215 -215
- package/standards/general/code-quality.md +86 -86
- package/standards/general/memory-usage.md +205 -205
- package/standards/general/sync-workflow.md +235 -235
- package/standards/general/workflow.md +82 -82
- package/standards/hooks/mandatory-tracking.md +446 -446
- package/standards/infrastructure/cloud-database.md +287 -287
- package/standards/mcp/server-design.md +243 -243
- package/standards/mcp/tool-patterns.md +354 -354
- package/standards/skills/skill-structure.md +286 -286
- package/standards/skills/workflow-design.md +323 -323
- package/standards/tools/tool-design.md +297 -297
- package/templates/agents/architecture-expert.md +61 -61
- package/templates/agents/database-expert.md +62 -62
- package/templates/agents/documentation-expert.md +57 -57
- package/templates/agents/memory-expert.md +88 -88
- package/templates/agents/performance-expert.md +61 -61
- package/templates/agents/security-expert.md +59 -59
- package/templates/agents/ux-expert.md +63 -63
- package/templates/agents/worker.md +75 -75
- package/templates/ai-skills/SKILL_TEMPLATE.md +55 -55
- package/templates/claude-settings.json +72 -72
- package/templates/commands/experts.md +138 -138
- package/templates/hooks/README.md +158 -158
- package/templates/hooks/project.config.json.template +77 -77
- package/templates/hooks/settings.local.json.template +57 -57
- package/templates/memory-config.json +56 -56
- package/templates/memory-config.schema.json +212 -212
- package/templates/settings.json +58 -58
- package/templates/skills/continue.md +205 -205
- package/templates/workflows/business-improvement.md +264 -264
- package/templates/workflows/expert-review.md +153 -153
- package/templates/workflows/internal-app.md +245 -245
- package/templates/workflows/sync-docs.md +187 -187
|
@@ -1,354 +1,354 @@
|
|
|
1
|
-
# Patrones de Diseño para MCP Tools
|
|
2
|
-
|
|
3
|
-
## Patrón: CRUD Básico
|
|
4
|
-
|
|
5
|
-
Para entidades que necesitan operaciones estándar:
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
// tools/entity.ts
|
|
9
|
-
export const entityTools = [
|
|
10
|
-
{
|
|
11
|
-
name: 'entity_create',
|
|
12
|
-
description: 'Create a new entity',
|
|
13
|
-
inputSchema: {
|
|
14
|
-
type: 'object',
|
|
15
|
-
properties: {
|
|
16
|
-
title: { type: 'string' },
|
|
17
|
-
data: { type: 'object' }
|
|
18
|
-
},
|
|
19
|
-
required: ['title']
|
|
20
|
-
}
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
name: 'entity_get',
|
|
24
|
-
description: 'Get entity by ID',
|
|
25
|
-
inputSchema: {
|
|
26
|
-
type: 'object',
|
|
27
|
-
properties: {
|
|
28
|
-
id: { type: 'string' }
|
|
29
|
-
},
|
|
30
|
-
required: ['id']
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
name: 'entity_list',
|
|
35
|
-
description: 'List entities with optional filters',
|
|
36
|
-
inputSchema: {
|
|
37
|
-
type: 'object',
|
|
38
|
-
properties: {
|
|
39
|
-
limit: { type: 'number', default: 10 },
|
|
40
|
-
filter: { type: 'object' }
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
name: 'entity_update',
|
|
46
|
-
description: 'Update entity by ID',
|
|
47
|
-
inputSchema: {
|
|
48
|
-
type: 'object',
|
|
49
|
-
properties: {
|
|
50
|
-
id: { type: 'string' },
|
|
51
|
-
updates: { type: 'object' }
|
|
52
|
-
},
|
|
53
|
-
required: ['id', 'updates']
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
name: 'entity_delete',
|
|
58
|
-
description: 'Delete entity by ID',
|
|
59
|
-
inputSchema: {
|
|
60
|
-
type: 'object',
|
|
61
|
-
properties: {
|
|
62
|
-
id: { type: 'string' }
|
|
63
|
-
},
|
|
64
|
-
required: ['id']
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
]
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
## Patrón: Search Tool
|
|
71
|
-
|
|
72
|
-
Para búsquedas con múltiples criterios:
|
|
73
|
-
|
|
74
|
-
```typescript
|
|
75
|
-
{
|
|
76
|
-
name: 'memory_search',
|
|
77
|
-
description: 'Search memories by content, domain, tags, or date range',
|
|
78
|
-
inputSchema: {
|
|
79
|
-
type: 'object',
|
|
80
|
-
properties: {
|
|
81
|
-
query: {
|
|
82
|
-
type: 'string',
|
|
83
|
-
description: 'Text to search in title and body'
|
|
84
|
-
},
|
|
85
|
-
domain: {
|
|
86
|
-
type: 'string',
|
|
87
|
-
description: 'Filter by domain (e.g., "architecture", "performance")'
|
|
88
|
-
},
|
|
89
|
-
tags: {
|
|
90
|
-
type: 'array',
|
|
91
|
-
items: { type: 'string' },
|
|
92
|
-
description: 'Filter by tags (AND logic)'
|
|
93
|
-
},
|
|
94
|
-
dateFrom: {
|
|
95
|
-
type: 'string',
|
|
96
|
-
description: 'ISO date string for start range'
|
|
97
|
-
},
|
|
98
|
-
dateTo: {
|
|
99
|
-
type: 'string',
|
|
100
|
-
description: 'ISO date string for end range'
|
|
101
|
-
},
|
|
102
|
-
limit: {
|
|
103
|
-
type: 'number',
|
|
104
|
-
default: 10,
|
|
105
|
-
description: 'Max results to return'
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
**Handler Pattern:**
|
|
113
|
-
|
|
114
|
-
```typescript
|
|
115
|
-
async function handleSearch(args: SearchArgs) {
|
|
116
|
-
const conditions: SQL[] = []
|
|
117
|
-
|
|
118
|
-
if (args.query) {
|
|
119
|
-
conditions.push(
|
|
120
|
-
or(
|
|
121
|
-
like(memories.title, `%${args.query}%`),
|
|
122
|
-
like(memories.body, `%${args.query}%`)
|
|
123
|
-
)
|
|
124
|
-
)
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (args.domain) {
|
|
128
|
-
conditions.push(eq(memories.domain, args.domain))
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Build query with all conditions
|
|
132
|
-
const results = await db.query.memories.findMany({
|
|
133
|
-
where: and(...conditions),
|
|
134
|
-
limit: args.limit ?? 10,
|
|
135
|
-
orderBy: desc(memories.createdAt)
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
return results
|
|
139
|
-
}
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
## Patrón: Batch Operations
|
|
143
|
-
|
|
144
|
-
Para operaciones sobre múltiples items:
|
|
145
|
-
|
|
146
|
-
```typescript
|
|
147
|
-
{
|
|
148
|
-
name: 'tasks_batch_update',
|
|
149
|
-
description: 'Update status of multiple tasks at once',
|
|
150
|
-
inputSchema: {
|
|
151
|
-
type: 'object',
|
|
152
|
-
properties: {
|
|
153
|
-
ids: {
|
|
154
|
-
type: 'array',
|
|
155
|
-
items: { type: 'string' },
|
|
156
|
-
description: 'Task IDs to update'
|
|
157
|
-
},
|
|
158
|
-
status: {
|
|
159
|
-
type: 'string',
|
|
160
|
-
enum: ['pending', 'in_progress', 'completed']
|
|
161
|
-
}
|
|
162
|
-
},
|
|
163
|
-
required: ['ids', 'status']
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
**Handler con Promise.all:**
|
|
169
|
-
|
|
170
|
-
```typescript
|
|
171
|
-
async function handleBatchUpdate(args: BatchUpdateArgs) {
|
|
172
|
-
const results = await Promise.allSettled(
|
|
173
|
-
args.ids.map(id =>
|
|
174
|
-
db.update(tasks)
|
|
175
|
-
.set({ status: args.status, updatedAt: new Date() })
|
|
176
|
-
.where(eq(tasks.id, id))
|
|
177
|
-
)
|
|
178
|
-
)
|
|
179
|
-
|
|
180
|
-
const succeeded = results.filter(r => r.status === 'fulfilled').length
|
|
181
|
-
const failed = results.filter(r => r.status === 'rejected').length
|
|
182
|
-
|
|
183
|
-
return {
|
|
184
|
-
total: args.ids.length,
|
|
185
|
-
succeeded,
|
|
186
|
-
failed
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
## Patrón: Aggregation Tool
|
|
192
|
-
|
|
193
|
-
Para datos agregados/estadísticas:
|
|
194
|
-
|
|
195
|
-
```typescript
|
|
196
|
-
{
|
|
197
|
-
name: 'analytics_summary',
|
|
198
|
-
description: 'Get aggregated analytics for a time period',
|
|
199
|
-
inputSchema: {
|
|
200
|
-
type: 'object',
|
|
201
|
-
properties: {
|
|
202
|
-
period: {
|
|
203
|
-
type: 'string',
|
|
204
|
-
enum: ['day', 'week', 'month'],
|
|
205
|
-
default: 'week'
|
|
206
|
-
},
|
|
207
|
-
metrics: {
|
|
208
|
-
type: 'array',
|
|
209
|
-
items: {
|
|
210
|
-
type: 'string',
|
|
211
|
-
enum: ['memories_created', 'patterns_detected', 'tasks_completed']
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
## Patrón: Composite Tool
|
|
220
|
-
|
|
221
|
-
Cuando una operación necesita múltiples pasos:
|
|
222
|
-
|
|
223
|
-
```typescript
|
|
224
|
-
{
|
|
225
|
-
name: 'session_init',
|
|
226
|
-
description: 'Initialize a new work session with context loading',
|
|
227
|
-
inputSchema: {
|
|
228
|
-
type: 'object',
|
|
229
|
-
properties: {
|
|
230
|
-
projectPath: { type: 'string' },
|
|
231
|
-
loadMemories: { type: 'boolean', default: true },
|
|
232
|
-
checkPatterns: { type: 'boolean', default: true }
|
|
233
|
-
},
|
|
234
|
-
required: ['projectPath']
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
**Handler:**
|
|
240
|
-
|
|
241
|
-
```typescript
|
|
242
|
-
async function handleSessionInit(args: SessionInitArgs) {
|
|
243
|
-
const results: Record<string, unknown> = {}
|
|
244
|
-
|
|
245
|
-
// Step 1: Load project config
|
|
246
|
-
results.config = await loadProjectConfig(args.projectPath)
|
|
247
|
-
|
|
248
|
-
// Step 2: Parallel operations
|
|
249
|
-
const [memories, patterns] = await Promise.all([
|
|
250
|
-
args.loadMemories ? loadRecentMemories() : [],
|
|
251
|
-
args.checkPatterns ? detectPatterns() : []
|
|
252
|
-
])
|
|
253
|
-
|
|
254
|
-
results.memories = memories
|
|
255
|
-
results.patterns = patterns
|
|
256
|
-
|
|
257
|
-
// Step 3: Generate context summary
|
|
258
|
-
results.summary = generateContextSummary(results)
|
|
259
|
-
|
|
260
|
-
return results
|
|
261
|
-
}
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
## Patrón: Validation Tool
|
|
265
|
-
|
|
266
|
-
Para validar datos antes de operaciones costosas:
|
|
267
|
-
|
|
268
|
-
```typescript
|
|
269
|
-
{
|
|
270
|
-
name: 'schema_validate',
|
|
271
|
-
description: 'Validate data against a schema before processing',
|
|
272
|
-
inputSchema: {
|
|
273
|
-
type: 'object',
|
|
274
|
-
properties: {
|
|
275
|
-
schemaName: { type: 'string' },
|
|
276
|
-
data: { type: 'object' }
|
|
277
|
-
},
|
|
278
|
-
required: ['schemaName', 'data']
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
## Anti-Patterns
|
|
284
|
-
|
|
285
|
-
### NO: Tools Demasiado Genéricas
|
|
286
|
-
|
|
287
|
-
```typescript
|
|
288
|
-
// MAL - demasiado genérica
|
|
289
|
-
{
|
|
290
|
-
name: 'do_database_operation',
|
|
291
|
-
inputSchema: {
|
|
292
|
-
properties: {
|
|
293
|
-
operation: { type: 'string' }, // "insert", "update", "delete"
|
|
294
|
-
table: { type: 'string' },
|
|
295
|
-
data: { type: 'object' }
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
// BIEN - específica y clara
|
|
301
|
-
{
|
|
302
|
-
name: 'memory_create',
|
|
303
|
-
// ...
|
|
304
|
-
}
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
### NO: Tools con Demasiados Parámetros
|
|
308
|
-
|
|
309
|
-
```typescript
|
|
310
|
-
// MAL - 15 parámetros
|
|
311
|
-
{
|
|
312
|
-
name: 'complex_search',
|
|
313
|
-
inputSchema: {
|
|
314
|
-
properties: {
|
|
315
|
-
// ... 15 propiedades
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
// BIEN - dividir en tools más simples
|
|
321
|
-
{
|
|
322
|
-
name: 'search_by_content',
|
|
323
|
-
// 2-3 parámetros
|
|
324
|
-
}
|
|
325
|
-
{
|
|
326
|
-
name: 'search_by_metadata',
|
|
327
|
-
// 2-3 parámetros
|
|
328
|
-
}
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
### NO: Efectos Secundarios Ocultos
|
|
332
|
-
|
|
333
|
-
```typescript
|
|
334
|
-
// MAL - hace más de lo que dice
|
|
335
|
-
async function handleGetMemory(id: string) {
|
|
336
|
-
const memory = await getMemory(id)
|
|
337
|
-
await updateAccessCount(id) // Efecto secundario oculto
|
|
338
|
-
await logAccess(id) // Otro efecto secundario
|
|
339
|
-
return memory
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// BIEN - solo hace lo que dice
|
|
343
|
-
async function handleGetMemory(id: string) {
|
|
344
|
-
return await getMemory(id)
|
|
345
|
-
}
|
|
346
|
-
```
|
|
347
|
-
|
|
348
|
-
## Tips de Rendimiento
|
|
349
|
-
|
|
350
|
-
1. **Paginación obligatoria** para list operations
|
|
351
|
-
2. **Índices** en campos de búsqueda
|
|
352
|
-
3. **Caché** para datos que no cambian frecuentemente
|
|
353
|
-
4. **Parallel queries** con Promise.all cuando son independientes
|
|
354
|
-
5. **Streaming** para respuestas grandes (futuro de MCP)
|
|
1
|
+
# Patrones de Diseño para MCP Tools
|
|
2
|
+
|
|
3
|
+
## Patrón: CRUD Básico
|
|
4
|
+
|
|
5
|
+
Para entidades que necesitan operaciones estándar:
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// tools/entity.ts
|
|
9
|
+
export const entityTools = [
|
|
10
|
+
{
|
|
11
|
+
name: 'entity_create',
|
|
12
|
+
description: 'Create a new entity',
|
|
13
|
+
inputSchema: {
|
|
14
|
+
type: 'object',
|
|
15
|
+
properties: {
|
|
16
|
+
title: { type: 'string' },
|
|
17
|
+
data: { type: 'object' }
|
|
18
|
+
},
|
|
19
|
+
required: ['title']
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: 'entity_get',
|
|
24
|
+
description: 'Get entity by ID',
|
|
25
|
+
inputSchema: {
|
|
26
|
+
type: 'object',
|
|
27
|
+
properties: {
|
|
28
|
+
id: { type: 'string' }
|
|
29
|
+
},
|
|
30
|
+
required: ['id']
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: 'entity_list',
|
|
35
|
+
description: 'List entities with optional filters',
|
|
36
|
+
inputSchema: {
|
|
37
|
+
type: 'object',
|
|
38
|
+
properties: {
|
|
39
|
+
limit: { type: 'number', default: 10 },
|
|
40
|
+
filter: { type: 'object' }
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'entity_update',
|
|
46
|
+
description: 'Update entity by ID',
|
|
47
|
+
inputSchema: {
|
|
48
|
+
type: 'object',
|
|
49
|
+
properties: {
|
|
50
|
+
id: { type: 'string' },
|
|
51
|
+
updates: { type: 'object' }
|
|
52
|
+
},
|
|
53
|
+
required: ['id', 'updates']
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: 'entity_delete',
|
|
58
|
+
description: 'Delete entity by ID',
|
|
59
|
+
inputSchema: {
|
|
60
|
+
type: 'object',
|
|
61
|
+
properties: {
|
|
62
|
+
id: { type: 'string' }
|
|
63
|
+
},
|
|
64
|
+
required: ['id']
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Patrón: Search Tool
|
|
71
|
+
|
|
72
|
+
Para búsquedas con múltiples criterios:
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
{
|
|
76
|
+
name: 'memory_search',
|
|
77
|
+
description: 'Search memories by content, domain, tags, or date range',
|
|
78
|
+
inputSchema: {
|
|
79
|
+
type: 'object',
|
|
80
|
+
properties: {
|
|
81
|
+
query: {
|
|
82
|
+
type: 'string',
|
|
83
|
+
description: 'Text to search in title and body'
|
|
84
|
+
},
|
|
85
|
+
domain: {
|
|
86
|
+
type: 'string',
|
|
87
|
+
description: 'Filter by domain (e.g., "architecture", "performance")'
|
|
88
|
+
},
|
|
89
|
+
tags: {
|
|
90
|
+
type: 'array',
|
|
91
|
+
items: { type: 'string' },
|
|
92
|
+
description: 'Filter by tags (AND logic)'
|
|
93
|
+
},
|
|
94
|
+
dateFrom: {
|
|
95
|
+
type: 'string',
|
|
96
|
+
description: 'ISO date string for start range'
|
|
97
|
+
},
|
|
98
|
+
dateTo: {
|
|
99
|
+
type: 'string',
|
|
100
|
+
description: 'ISO date string for end range'
|
|
101
|
+
},
|
|
102
|
+
limit: {
|
|
103
|
+
type: 'number',
|
|
104
|
+
default: 10,
|
|
105
|
+
description: 'Max results to return'
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Handler Pattern:**
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
async function handleSearch(args: SearchArgs) {
|
|
116
|
+
const conditions: SQL[] = []
|
|
117
|
+
|
|
118
|
+
if (args.query) {
|
|
119
|
+
conditions.push(
|
|
120
|
+
or(
|
|
121
|
+
like(memories.title, `%${args.query}%`),
|
|
122
|
+
like(memories.body, `%${args.query}%`)
|
|
123
|
+
)
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (args.domain) {
|
|
128
|
+
conditions.push(eq(memories.domain, args.domain))
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Build query with all conditions
|
|
132
|
+
const results = await db.query.memories.findMany({
|
|
133
|
+
where: and(...conditions),
|
|
134
|
+
limit: args.limit ?? 10,
|
|
135
|
+
orderBy: desc(memories.createdAt)
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
return results
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Patrón: Batch Operations
|
|
143
|
+
|
|
144
|
+
Para operaciones sobre múltiples items:
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
{
|
|
148
|
+
name: 'tasks_batch_update',
|
|
149
|
+
description: 'Update status of multiple tasks at once',
|
|
150
|
+
inputSchema: {
|
|
151
|
+
type: 'object',
|
|
152
|
+
properties: {
|
|
153
|
+
ids: {
|
|
154
|
+
type: 'array',
|
|
155
|
+
items: { type: 'string' },
|
|
156
|
+
description: 'Task IDs to update'
|
|
157
|
+
},
|
|
158
|
+
status: {
|
|
159
|
+
type: 'string',
|
|
160
|
+
enum: ['pending', 'in_progress', 'completed']
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
required: ['ids', 'status']
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Handler con Promise.all:**
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
async function handleBatchUpdate(args: BatchUpdateArgs) {
|
|
172
|
+
const results = await Promise.allSettled(
|
|
173
|
+
args.ids.map(id =>
|
|
174
|
+
db.update(tasks)
|
|
175
|
+
.set({ status: args.status, updatedAt: new Date() })
|
|
176
|
+
.where(eq(tasks.id, id))
|
|
177
|
+
)
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
const succeeded = results.filter(r => r.status === 'fulfilled').length
|
|
181
|
+
const failed = results.filter(r => r.status === 'rejected').length
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
total: args.ids.length,
|
|
185
|
+
succeeded,
|
|
186
|
+
failed
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Patrón: Aggregation Tool
|
|
192
|
+
|
|
193
|
+
Para datos agregados/estadísticas:
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
{
|
|
197
|
+
name: 'analytics_summary',
|
|
198
|
+
description: 'Get aggregated analytics for a time period',
|
|
199
|
+
inputSchema: {
|
|
200
|
+
type: 'object',
|
|
201
|
+
properties: {
|
|
202
|
+
period: {
|
|
203
|
+
type: 'string',
|
|
204
|
+
enum: ['day', 'week', 'month'],
|
|
205
|
+
default: 'week'
|
|
206
|
+
},
|
|
207
|
+
metrics: {
|
|
208
|
+
type: 'array',
|
|
209
|
+
items: {
|
|
210
|
+
type: 'string',
|
|
211
|
+
enum: ['memories_created', 'patterns_detected', 'tasks_completed']
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Patrón: Composite Tool
|
|
220
|
+
|
|
221
|
+
Cuando una operación necesita múltiples pasos:
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
{
|
|
225
|
+
name: 'session_init',
|
|
226
|
+
description: 'Initialize a new work session with context loading',
|
|
227
|
+
inputSchema: {
|
|
228
|
+
type: 'object',
|
|
229
|
+
properties: {
|
|
230
|
+
projectPath: { type: 'string' },
|
|
231
|
+
loadMemories: { type: 'boolean', default: true },
|
|
232
|
+
checkPatterns: { type: 'boolean', default: true }
|
|
233
|
+
},
|
|
234
|
+
required: ['projectPath']
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
**Handler:**
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
async function handleSessionInit(args: SessionInitArgs) {
|
|
243
|
+
const results: Record<string, unknown> = {}
|
|
244
|
+
|
|
245
|
+
// Step 1: Load project config
|
|
246
|
+
results.config = await loadProjectConfig(args.projectPath)
|
|
247
|
+
|
|
248
|
+
// Step 2: Parallel operations
|
|
249
|
+
const [memories, patterns] = await Promise.all([
|
|
250
|
+
args.loadMemories ? loadRecentMemories() : [],
|
|
251
|
+
args.checkPatterns ? detectPatterns() : []
|
|
252
|
+
])
|
|
253
|
+
|
|
254
|
+
results.memories = memories
|
|
255
|
+
results.patterns = patterns
|
|
256
|
+
|
|
257
|
+
// Step 3: Generate context summary
|
|
258
|
+
results.summary = generateContextSummary(results)
|
|
259
|
+
|
|
260
|
+
return results
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Patrón: Validation Tool
|
|
265
|
+
|
|
266
|
+
Para validar datos antes de operaciones costosas:
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
{
|
|
270
|
+
name: 'schema_validate',
|
|
271
|
+
description: 'Validate data against a schema before processing',
|
|
272
|
+
inputSchema: {
|
|
273
|
+
type: 'object',
|
|
274
|
+
properties: {
|
|
275
|
+
schemaName: { type: 'string' },
|
|
276
|
+
data: { type: 'object' }
|
|
277
|
+
},
|
|
278
|
+
required: ['schemaName', 'data']
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## Anti-Patterns
|
|
284
|
+
|
|
285
|
+
### NO: Tools Demasiado Genéricas
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
// MAL - demasiado genérica
|
|
289
|
+
{
|
|
290
|
+
name: 'do_database_operation',
|
|
291
|
+
inputSchema: {
|
|
292
|
+
properties: {
|
|
293
|
+
operation: { type: 'string' }, // "insert", "update", "delete"
|
|
294
|
+
table: { type: 'string' },
|
|
295
|
+
data: { type: 'object' }
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// BIEN - específica y clara
|
|
301
|
+
{
|
|
302
|
+
name: 'memory_create',
|
|
303
|
+
// ...
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### NO: Tools con Demasiados Parámetros
|
|
308
|
+
|
|
309
|
+
```typescript
|
|
310
|
+
// MAL - 15 parámetros
|
|
311
|
+
{
|
|
312
|
+
name: 'complex_search',
|
|
313
|
+
inputSchema: {
|
|
314
|
+
properties: {
|
|
315
|
+
// ... 15 propiedades
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// BIEN - dividir en tools más simples
|
|
321
|
+
{
|
|
322
|
+
name: 'search_by_content',
|
|
323
|
+
// 2-3 parámetros
|
|
324
|
+
}
|
|
325
|
+
{
|
|
326
|
+
name: 'search_by_metadata',
|
|
327
|
+
// 2-3 parámetros
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### NO: Efectos Secundarios Ocultos
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
// MAL - hace más de lo que dice
|
|
335
|
+
async function handleGetMemory(id: string) {
|
|
336
|
+
const memory = await getMemory(id)
|
|
337
|
+
await updateAccessCount(id) // Efecto secundario oculto
|
|
338
|
+
await logAccess(id) // Otro efecto secundario
|
|
339
|
+
return memory
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// BIEN - solo hace lo que dice
|
|
343
|
+
async function handleGetMemory(id: string) {
|
|
344
|
+
return await getMemory(id)
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
## Tips de Rendimiento
|
|
349
|
+
|
|
350
|
+
1. **Paginación obligatoria** para list operations
|
|
351
|
+
2. **Índices** en campos de búsqueda
|
|
352
|
+
3. **Caché** para datos que no cambian frecuentemente
|
|
353
|
+
4. **Parallel queries** con Promise.all cuando son independientes
|
|
354
|
+
5. **Streaming** para respuestas grandes (futuro de MCP)
|