smart-context-mcp 1.16.2 → 1.16.4
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 +1 -1
- package/package.json +1 -1
- package/server.json +2 -2
- package/src/client-contract.js +17 -1
- package/src/orchestration/adapters/claude-adapter.js +64 -4
- package/src/orchestration/adapters/cursor-adapter.js +64 -4
- package/src/server.js +15 -4
- package/src/storage/sqlite.js +459 -5
- package/src/tools/smart-summary.js +306 -5
- package/src/tools/smart-turn.js +11 -0
package/README.md
CHANGED
|
@@ -56,7 +56,7 @@ Restart your AI client. Done.
|
|
|
56
56
|
# Check installed version
|
|
57
57
|
npm list -g smart-context-mcp
|
|
58
58
|
|
|
59
|
-
# Should show: smart-context-mcp@1.16.
|
|
59
|
+
# Should show: smart-context-mcp@1.16.4 (or later)
|
|
60
60
|
|
|
61
61
|
# Update to latest version
|
|
62
62
|
npm update -g smart-context-mcp
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "smart-context-mcp",
|
|
3
3
|
"mcpName": "io.github.Arrayo/smart-context-mcp",
|
|
4
|
-
"version": "1.16.
|
|
4
|
+
"version": "1.16.4",
|
|
5
5
|
"description": "MCP server that reduces agent token usage by 90% with intelligent context compression, task checkpoint persistence, and workflow-aware agent guidance.",
|
|
6
6
|
"author": "Francisco Caballero Portero <fcp1978@hotmail.com>",
|
|
7
7
|
"type": "module",
|
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/Arrayo/smart-context-mcp",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "1.16.
|
|
9
|
+
"version": "1.16.4",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "smart-context-mcp",
|
|
14
|
-
"version": "1.16.
|
|
14
|
+
"version": "1.16.4",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|
package/src/client-contract.js
CHANGED
|
@@ -74,11 +74,17 @@ export const buildOperationalContextLines = (
|
|
|
74
74
|
const summary = result?.summary;
|
|
75
75
|
const continuityState = result?.continuity?.state;
|
|
76
76
|
const storageIssue = result?.storageHealth?.issue;
|
|
77
|
+
const task = result?.task ?? null;
|
|
78
|
+
const handoff = result?.handoff ?? null;
|
|
77
79
|
|
|
78
80
|
if (result?.found && summary) {
|
|
79
81
|
const label = sessionStart ? 'resume' : continuityState ?? 'resume';
|
|
80
82
|
lines.push(`devctx ${label}: session ${result.sessionId}`);
|
|
81
83
|
|
|
84
|
+
if (task?.taskId) {
|
|
85
|
+
lines.push(`task: ${truncate(task.taskId, maxLineLength)}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
82
88
|
if (summary.goal) {
|
|
83
89
|
lines.push(`goal: ${truncate(summary.goal, maxLineLength)}`);
|
|
84
90
|
}
|
|
@@ -106,10 +112,20 @@ export const buildOperationalContextLines = (
|
|
|
106
112
|
lines.push(`devctx new task session: ${truncate(summary.goal, maxLineLength)}`);
|
|
107
113
|
}
|
|
108
114
|
|
|
109
|
-
if (result?.continuity?.reason) {
|
|
115
|
+
if (!mutationSafety?.blocked && result?.continuity?.reason) {
|
|
110
116
|
lines.push(`context status: ${truncate(result.continuity.reason, maxLineLength)}`);
|
|
111
117
|
}
|
|
112
118
|
|
|
119
|
+
if (handoff?.fromAgentId || handoff?.summary?.nextStep || handoff?.summary?.pending?.length > 0) {
|
|
120
|
+
lines.push(`handoff: ${truncate(`from ${handoff?.fromAgentId ?? 'previous agent'} via ${handoff?.trigger ?? 'handoff'}`, maxLineLength)}`);
|
|
121
|
+
if (handoff?.summary?.pending?.[0]) {
|
|
122
|
+
lines.push(`pending: ${truncate(handoff.summary.pending[0], maxLineLength)}`);
|
|
123
|
+
}
|
|
124
|
+
if (handoff?.summary?.nextStep) {
|
|
125
|
+
lines.push(`handoff next: ${truncate(handoff.summary.nextStep, maxLineLength)}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
113
129
|
if (mutationSafety?.blocked) {
|
|
114
130
|
const reasons = mutationSafety.blockedBy?.join(' and ') || 'blocked';
|
|
115
131
|
lines.push(`repo safety: ${mutationSafety.stateDbPath} is ${reasons}; context writes are blocked.`);
|
|
@@ -7,7 +7,9 @@ import { smartTurn } from '../../tools/smart-turn.js';
|
|
|
7
7
|
import {
|
|
8
8
|
deleteHookTurnState,
|
|
9
9
|
getHookTurnState,
|
|
10
|
+
persistTaskHandoff,
|
|
10
11
|
setHookTurnState,
|
|
12
|
+
upsertAgentRun,
|
|
11
13
|
} from '../../storage/sqlite.js';
|
|
12
14
|
import { DEFAULT_START_MAX_TOKENS, resolveManagedStart } from '../base-orchestrator.js';
|
|
13
15
|
import { extractNextStep, normalizeWhitespace, truncate } from '../policy/event-policy.js';
|
|
@@ -25,8 +27,20 @@ export const WRITE_TOOLS = new Set(['Write', 'Edit', 'MultiEdit']);
|
|
|
25
27
|
|
|
26
28
|
const uniq = (values) => [...new Set(values.filter((value) => typeof value === 'string' && value.trim().length > 0))];
|
|
27
29
|
|
|
30
|
+
const resolveAgentId = (input = {}) => {
|
|
31
|
+
const value = input.agent_id ?? input.agentId ?? input.assistant_id ?? input.worker_id ?? null;
|
|
32
|
+
return typeof value === 'string' && value.trim().length > 0 ? value.trim() : 'main';
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const resolveParentAgentId = (input = {}) => {
|
|
36
|
+
const value = input.parent_agent_id ?? input.parentAgentId ?? null;
|
|
37
|
+
return typeof value === 'string' && value.trim().length > 0 ? value.trim() : null;
|
|
38
|
+
};
|
|
39
|
+
|
|
28
40
|
export const buildClaudeHookKey = ({ sessionId, agentId = null }) =>
|
|
29
|
-
agentId
|
|
41
|
+
agentId && agentId !== 'main'
|
|
42
|
+
? `${HOOK_CLIENT}:subagent:${sessionId}:${agentId}`
|
|
43
|
+
: `${HOOK_CLIENT}:main:${sessionId}`;
|
|
30
44
|
|
|
31
45
|
const countPromptTerms = (value) =>
|
|
32
46
|
normalizeWhitespace(value)
|
|
@@ -148,6 +162,8 @@ export const createClaudeAdapter = ({
|
|
|
148
162
|
summaryTool = smartSummary,
|
|
149
163
|
resolveStart = resolveManagedStart,
|
|
150
164
|
persistMetric = persistMetrics,
|
|
165
|
+
writeAgentRun = upsertAgentRun,
|
|
166
|
+
writeTaskHandoff = persistTaskHandoff,
|
|
151
167
|
getMutationSafety = getRepoMutationSafety,
|
|
152
168
|
readHookState = null,
|
|
153
169
|
writeHookState = ({ hookKey, state }) => setHookTurnState({ hookKey, state }),
|
|
@@ -215,7 +231,11 @@ export const createClaudeAdapter = ({
|
|
|
215
231
|
const maybeTrackTurn = async ({
|
|
216
232
|
hookKey,
|
|
217
233
|
claudeSessionId,
|
|
234
|
+
conversationId,
|
|
218
235
|
projectSessionId,
|
|
236
|
+
taskId,
|
|
237
|
+
agentId,
|
|
238
|
+
parentAgentId,
|
|
219
239
|
prompt,
|
|
220
240
|
continuityState,
|
|
221
241
|
}) => {
|
|
@@ -232,7 +252,11 @@ export const createClaudeAdapter = ({
|
|
|
232
252
|
state: {
|
|
233
253
|
client: HOOK_CLIENT,
|
|
234
254
|
claudeSessionId,
|
|
255
|
+
conversationId,
|
|
235
256
|
projectSessionId,
|
|
257
|
+
taskId,
|
|
258
|
+
agentId,
|
|
259
|
+
parentAgentId,
|
|
236
260
|
turnId: `${claudeSessionId}:${Date.now()}`,
|
|
237
261
|
promptPreview: truncate(prompt, MAX_PROMPT_PREVIEW),
|
|
238
262
|
continuityState,
|
|
@@ -262,6 +286,8 @@ export const createClaudeAdapter = ({
|
|
|
262
286
|
};
|
|
263
287
|
|
|
264
288
|
const handleUserPromptSubmit = async (input) => {
|
|
289
|
+
const agentId = resolveAgentId(input);
|
|
290
|
+
const parentAgentId = resolveParentAgentId(input);
|
|
265
291
|
const startResolution = await resolveStart({
|
|
266
292
|
prompt: input.prompt,
|
|
267
293
|
ensureSession: true,
|
|
@@ -272,10 +298,27 @@ export const createClaudeAdapter = ({
|
|
|
272
298
|
});
|
|
273
299
|
const result = startResolution.startResult;
|
|
274
300
|
|
|
301
|
+
if (!getMutationSafety().shouldBlock) {
|
|
302
|
+
await writeAgentRun({
|
|
303
|
+
runId: buildClaudeHookKey({ sessionId: input.session_id, agentId }),
|
|
304
|
+
taskId: result.task?.taskId ?? null,
|
|
305
|
+
agentId,
|
|
306
|
+
parentAgentId,
|
|
307
|
+
client: HOOK_CLIENT,
|
|
308
|
+
conversationId: input.session_id,
|
|
309
|
+
sessionId: result.sessionId ?? null,
|
|
310
|
+
role: agentId === 'main' ? 'main' : 'subagent',
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
|
|
275
314
|
const trackedState = await maybeTrackTurn({
|
|
276
|
-
hookKey: buildClaudeHookKey({ sessionId: input.session_id }),
|
|
315
|
+
hookKey: buildClaudeHookKey({ sessionId: input.session_id, agentId }),
|
|
277
316
|
claudeSessionId: input.session_id,
|
|
317
|
+
conversationId: input.session_id,
|
|
278
318
|
projectSessionId: result.sessionId ?? null,
|
|
319
|
+
taskId: result.task?.taskId ?? null,
|
|
320
|
+
agentId,
|
|
321
|
+
parentAgentId,
|
|
279
322
|
prompt: input.prompt,
|
|
280
323
|
continuityState: result.continuity?.state ?? '',
|
|
281
324
|
});
|
|
@@ -291,7 +334,7 @@ export const createClaudeAdapter = ({
|
|
|
291
334
|
};
|
|
292
335
|
|
|
293
336
|
const handlePostToolUse = async (input) => {
|
|
294
|
-
const hookKey = buildClaudeHookKey({ sessionId: input.session_id });
|
|
337
|
+
const hookKey = buildClaudeHookKey({ sessionId: input.session_id, agentId: resolveAgentId(input) });
|
|
295
338
|
const existing = await readTrackedState(hookKey);
|
|
296
339
|
if (!existing) {
|
|
297
340
|
return null;
|
|
@@ -329,7 +372,7 @@ export const createClaudeAdapter = ({
|
|
|
329
372
|
};
|
|
330
373
|
|
|
331
374
|
const handleStop = async (input) => {
|
|
332
|
-
const hookKey = buildClaudeHookKey({ sessionId: input.session_id });
|
|
375
|
+
const hookKey = buildClaudeHookKey({ sessionId: input.session_id, agentId: resolveAgentId(input) });
|
|
333
376
|
const state = await readTrackedState(hookKey);
|
|
334
377
|
if (!state) {
|
|
335
378
|
return null;
|
|
@@ -371,6 +414,23 @@ export const createClaudeAdapter = ({
|
|
|
371
414
|
});
|
|
372
415
|
}
|
|
373
416
|
|
|
417
|
+
if (state.taskId) {
|
|
418
|
+
await writeTaskHandoff({
|
|
419
|
+
taskId: state.taskId,
|
|
420
|
+
sessionId: state.projectSessionId,
|
|
421
|
+
fromAgentId: state.agentId ?? null,
|
|
422
|
+
toAgentId: null,
|
|
423
|
+
trigger: state.agentId && state.agentId !== 'main' ? 'subagent_delegate' : 'stop',
|
|
424
|
+
summary: {
|
|
425
|
+
currentFocus: update.currentFocus ?? state.promptPreview,
|
|
426
|
+
touchedFiles: state.touchedFiles,
|
|
427
|
+
pending: update.nextStep ? [update.nextStep] : [],
|
|
428
|
+
nextStep: update.nextStep ?? null,
|
|
429
|
+
evidence: state.touchedFiles.length > 0 ? [`Touched files: ${state.touchedFiles.join(', ')}`] : [],
|
|
430
|
+
},
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
|
|
374
434
|
await recordHookMetrics({
|
|
375
435
|
action: 'Stop',
|
|
376
436
|
sessionId: state.projectSessionId,
|
|
@@ -7,7 +7,9 @@ import { smartTurn } from '../../tools/smart-turn.js';
|
|
|
7
7
|
import {
|
|
8
8
|
deleteHookTurnState,
|
|
9
9
|
getHookTurnState,
|
|
10
|
+
persistTaskHandoff,
|
|
10
11
|
setHookTurnState,
|
|
12
|
+
upsertAgentRun,
|
|
11
13
|
} from '../../storage/sqlite.js';
|
|
12
14
|
import { DEFAULT_START_MAX_TOKENS, resolveManagedStart } from '../base-orchestrator.js';
|
|
13
15
|
import { extractNextStep, normalizeWhitespace, truncate } from '../policy/event-policy.js';
|
|
@@ -25,8 +27,20 @@ export const WRITE_TOOLS = new Set(['Write', 'StrReplace', 'Delete', 'EditNotebo
|
|
|
25
27
|
|
|
26
28
|
const uniq = (values) => [...new Set(values.filter((value) => typeof value === 'string' && value.trim().length > 0))];
|
|
27
29
|
|
|
30
|
+
const resolveAgentId = (input = {}) => {
|
|
31
|
+
const value = input.agent_id ?? input.agentId ?? input.worker_id ?? null;
|
|
32
|
+
return typeof value === 'string' && value.trim().length > 0 ? value.trim() : 'main';
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const resolveParentAgentId = (input = {}) => {
|
|
36
|
+
const value = input.parent_agent_id ?? input.parentAgentId ?? null;
|
|
37
|
+
return typeof value === 'string' && value.trim().length > 0 ? value.trim() : null;
|
|
38
|
+
};
|
|
39
|
+
|
|
28
40
|
export const buildCursorHookKey = ({ conversationId, agentId = null }) =>
|
|
29
|
-
agentId
|
|
41
|
+
agentId && agentId !== 'main'
|
|
42
|
+
? `${HOOK_CLIENT}:subagent:${conversationId}:${agentId}`
|
|
43
|
+
: `${HOOK_CLIENT}:main:${conversationId}`;
|
|
30
44
|
|
|
31
45
|
const countPromptTerms = (value) =>
|
|
32
46
|
normalizeWhitespace(value)
|
|
@@ -151,6 +165,8 @@ export const createCursorAdapter = ({
|
|
|
151
165
|
summaryTool = smartSummary,
|
|
152
166
|
resolveStart = resolveManagedStart,
|
|
153
167
|
persistMetric = persistMetrics,
|
|
168
|
+
writeAgentRun = upsertAgentRun,
|
|
169
|
+
writeTaskHandoff = persistTaskHandoff,
|
|
154
170
|
getMutationSafety = getRepoMutationSafety,
|
|
155
171
|
readHookState = null,
|
|
156
172
|
writeHookState = ({ hookKey, state }) => setHookTurnState({ hookKey, state }),
|
|
@@ -218,7 +234,11 @@ export const createCursorAdapter = ({
|
|
|
218
234
|
const maybeTrackTurn = async ({
|
|
219
235
|
hookKey,
|
|
220
236
|
cursorConversationId,
|
|
237
|
+
conversationId,
|
|
221
238
|
projectSessionId,
|
|
239
|
+
taskId,
|
|
240
|
+
agentId,
|
|
241
|
+
parentAgentId,
|
|
222
242
|
prompt,
|
|
223
243
|
continuityState,
|
|
224
244
|
}) => {
|
|
@@ -235,7 +255,11 @@ export const createCursorAdapter = ({
|
|
|
235
255
|
state: {
|
|
236
256
|
client: HOOK_CLIENT,
|
|
237
257
|
cursorConversationId,
|
|
258
|
+
conversationId,
|
|
238
259
|
projectSessionId,
|
|
260
|
+
taskId,
|
|
261
|
+
agentId,
|
|
262
|
+
parentAgentId,
|
|
239
263
|
turnId: `${cursorConversationId}:${Date.now()}`,
|
|
240
264
|
promptPreview: truncate(prompt, MAX_PROMPT_PREVIEW),
|
|
241
265
|
continuityState,
|
|
@@ -265,6 +289,8 @@ export const createCursorAdapter = ({
|
|
|
265
289
|
};
|
|
266
290
|
|
|
267
291
|
const handleUserMessageSubmit = async (input) => {
|
|
292
|
+
const agentId = resolveAgentId(input);
|
|
293
|
+
const parentAgentId = resolveParentAgentId(input);
|
|
268
294
|
const startResolution = await resolveStart({
|
|
269
295
|
prompt: input.user_message,
|
|
270
296
|
ensureSession: true,
|
|
@@ -275,10 +301,27 @@ export const createCursorAdapter = ({
|
|
|
275
301
|
});
|
|
276
302
|
const result = startResolution.startResult;
|
|
277
303
|
|
|
304
|
+
if (!getMutationSafety().shouldBlock) {
|
|
305
|
+
await writeAgentRun({
|
|
306
|
+
runId: buildCursorHookKey({ conversationId: input.conversation_id, agentId }),
|
|
307
|
+
taskId: result.task?.taskId ?? null,
|
|
308
|
+
agentId,
|
|
309
|
+
parentAgentId,
|
|
310
|
+
client: HOOK_CLIENT,
|
|
311
|
+
conversationId: input.conversation_id,
|
|
312
|
+
sessionId: result.sessionId ?? null,
|
|
313
|
+
role: agentId === 'main' ? 'main' : 'subagent',
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
278
317
|
const trackedState = await maybeTrackTurn({
|
|
279
|
-
hookKey: buildCursorHookKey({ conversationId: input.conversation_id }),
|
|
318
|
+
hookKey: buildCursorHookKey({ conversationId: input.conversation_id, agentId }),
|
|
280
319
|
cursorConversationId: input.conversation_id,
|
|
320
|
+
conversationId: input.conversation_id,
|
|
281
321
|
projectSessionId: result.sessionId ?? null,
|
|
322
|
+
taskId: result.task?.taskId ?? null,
|
|
323
|
+
agentId,
|
|
324
|
+
parentAgentId,
|
|
282
325
|
prompt: input.user_message,
|
|
283
326
|
continuityState: result.continuity?.state ?? '',
|
|
284
327
|
});
|
|
@@ -294,7 +337,7 @@ export const createCursorAdapter = ({
|
|
|
294
337
|
};
|
|
295
338
|
|
|
296
339
|
const handlePostToolUse = async (input) => {
|
|
297
|
-
const hookKey = buildCursorHookKey({ conversationId: input.conversation_id });
|
|
340
|
+
const hookKey = buildCursorHookKey({ conversationId: input.conversation_id, agentId: resolveAgentId(input) });
|
|
298
341
|
const existing = await readTrackedState(hookKey);
|
|
299
342
|
if (!existing) {
|
|
300
343
|
return null;
|
|
@@ -332,7 +375,7 @@ export const createCursorAdapter = ({
|
|
|
332
375
|
};
|
|
333
376
|
|
|
334
377
|
const handleConversationEnd = async (input) => {
|
|
335
|
-
const hookKey = buildCursorHookKey({ conversationId: input.conversation_id });
|
|
378
|
+
const hookKey = buildCursorHookKey({ conversationId: input.conversation_id, agentId: resolveAgentId(input) });
|
|
336
379
|
const state = await readTrackedState(hookKey);
|
|
337
380
|
if (!state) {
|
|
338
381
|
return null;
|
|
@@ -374,6 +417,23 @@ export const createCursorAdapter = ({
|
|
|
374
417
|
});
|
|
375
418
|
}
|
|
376
419
|
|
|
420
|
+
if (state.taskId) {
|
|
421
|
+
await writeTaskHandoff({
|
|
422
|
+
taskId: state.taskId,
|
|
423
|
+
sessionId: state.projectSessionId,
|
|
424
|
+
fromAgentId: state.agentId ?? null,
|
|
425
|
+
toAgentId: null,
|
|
426
|
+
trigger: state.agentId && state.agentId !== 'main' ? 'subagent_delegate' : 'session_end',
|
|
427
|
+
summary: {
|
|
428
|
+
currentFocus: update.currentFocus ?? state.promptPreview,
|
|
429
|
+
touchedFiles: state.touchedFiles,
|
|
430
|
+
pending: update.nextStep ? [update.nextStep] : [],
|
|
431
|
+
nextStep: update.nextStep ?? null,
|
|
432
|
+
evidence: state.touchedFiles.length > 0 ? [`Touched files: ${state.touchedFiles.join(', ')}`] : [],
|
|
433
|
+
},
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
|
|
377
437
|
await recordHookMetrics({
|
|
378
438
|
action: 'ConversationEnd',
|
|
379
439
|
sessionId: state.projectSessionId,
|
package/src/server.js
CHANGED
|
@@ -35,6 +35,17 @@ import {
|
|
|
35
35
|
const require = createRequire(import.meta.url);
|
|
36
36
|
const { version } = require('../package.json');
|
|
37
37
|
|
|
38
|
+
const SERVER_INSTRUCTIONS = `devctx — compressed context, search, and session handoff for long work (migrations, multi-file refactors, multi-session tasks).
|
|
39
|
+
|
|
40
|
+
smart_turn (session continuity — read this before calling):
|
|
41
|
+
- START: phase "start". Pass userPrompt (current goal). ensureSession true recommended when you want persistence. Use at the beginning of substantial work or when resuming after a break — not for one-line fixes or single-shot questions.
|
|
42
|
+
- END: phase "end". Pass event: milestone | blocker | task_complete. Pass sessionId if you have it; include update (nextStep, completed, etc.) when checkpointing progress. Call after a meaningful slice of work (close a phase), not after every trivial edit.
|
|
43
|
+
- SKIP smart_turn entirely for trivial or same-session point tasks (the tool schema also warns about this).
|
|
44
|
+
|
|
45
|
+
Source of truth: devctx does not replace git history, PRs, or repo docs (e.g. MIGRATION.md). If end was not called or work was not committed, those remain authoritative.
|
|
46
|
+
|
|
47
|
+
Other entry points: smart_context for curated multi-file context; smart_search with intent for exploration; smart_read in outline|signatures|symbol before full reads; smart_shell for safe git/npm diagnostics.`;
|
|
48
|
+
|
|
38
49
|
export const asTextResult = (result) => ({
|
|
39
50
|
content: [
|
|
40
51
|
{
|
|
@@ -52,10 +63,10 @@ export const createDevctxServer = () => {
|
|
|
52
63
|
process.exit(1);
|
|
53
64
|
}
|
|
54
65
|
|
|
55
|
-
const server = new McpServer(
|
|
56
|
-
name: 'devctx',
|
|
57
|
-
|
|
58
|
-
|
|
66
|
+
const server = new McpServer(
|
|
67
|
+
{ name: 'devctx', version },
|
|
68
|
+
{ instructions: SERVER_INSTRUCTIONS },
|
|
69
|
+
);
|
|
59
70
|
|
|
60
71
|
setServerForStreaming(server);
|
|
61
72
|
|