@nbiish/cognitive-tools-mcp 0.8.5 → 0.9.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/LICENSE +4 -4
- package/README.md +4 -3
- package/build/index.js +364 -151
- package/integration-prompts/integration-prompt-13.md +81 -0
- package/integration-prompts/new-prompts/integration-prompt.md +81 -0
- package/integration-tool-descriptions/new-description/tool-schema.ts +506 -0
- package/package.json +2 -2
- /package/integration-prompts/{integration-prompt-01.md → old-prompts/integration-prompt-01.md} +0 -0
- /package/integration-prompts/{integration-prompt-02.md → old-prompts/integration-prompt-02.md} +0 -0
- /package/integration-prompts/{integration-prompt-03.md → old-prompts/integration-prompt-03.md} +0 -0
- /package/integration-prompts/{integration-prompt-04.md → old-prompts/integration-prompt-04.md} +0 -0
- /package/integration-prompts/{integration-prompt-05.md → old-prompts/integration-prompt-05.md} +0 -0
- /package/integration-prompts/{integration-prompt-06.md → old-prompts/integration-prompt-06.md} +0 -0
- /package/integration-prompts/{integration-prompt-07.md → old-prompts/integration-prompt-07.md} +0 -0
- /package/integration-prompts/{integration-prompt-08.md → old-prompts/integration-prompt-08.md} +0 -0
- /package/integration-prompts/{integration-prompt-09.md → old-prompts/integration-prompt-09.md} +0 -0
- /package/integration-prompts/{integration-prompt-10.md → old-prompts/integration-prompt-10.md} +0 -0
- /package/integration-prompts/{integration-prompt-11.md → old-prompts/integration-prompt-11.md} +0 -0
- /package/integration-prompts/{integration-prompt-12.md → old-prompts/integration-prompt-12.md} +0 -0
- /package/integration-tool-descriptions/{tool-descriptions-01.ts → old-descriptions/tool-descriptions-01.ts} +0 -0
- /package/integration-tool-descriptions/{tool-descriptions-02.ts → old-descriptions/tool-descriptions-02.ts} +0 -0
- /package/integration-tool-descriptions/{tool-descriptions-03.ts → old-descriptions/tool-descriptions-03.ts} +0 -0
- /package/integration-tool-descriptions/{tool-descriptions-04.ts → old-descriptions/tool-descriptions-04.ts} +0 -0
- /package/integration-tool-descriptions/{tool-descriptions-05.md → old-descriptions/tool-descriptions-05.md} +0 -0
package/build/index.js
CHANGED
|
@@ -1,196 +1,409 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* -----------------------------------------------------------------------------
|
|
4
|
+
* Gikendaasowin Aabajichiganan - Cognitive Tools MCP Server
|
|
5
|
+
*
|
|
6
|
+
* Description: Provides a suite of cognitive tools for an AI Pair Programmer
|
|
7
|
+
* to structure its reasoning, plan actions, analyze results,
|
|
8
|
+
* and iteratively refine its work (Chain of Draft). Integrates
|
|
9
|
+
* with generic external environment tools for comprehensive interaction.
|
|
10
|
+
* Designed to be used with the corresponding integration prompt
|
|
11
|
+
* focused on iterative refinement and tool integration.
|
|
12
|
+
* Protocol: Model Context Protocol (MCP) over stdio.
|
|
13
|
+
* -----------------------------------------------------------------------------
|
|
14
|
+
*/
|
|
2
15
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
16
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
17
|
import { z } from "zod";
|
|
5
|
-
|
|
18
|
+
import { exec } from 'child_process'; // For executeTerminalCommand
|
|
19
|
+
import vm from 'vm'; // For safer executeCode
|
|
20
|
+
import fs from 'fs/promises'; // For file operations
|
|
21
|
+
// Helper function to promisify exec
|
|
22
|
+
import { promisify } from 'util';
|
|
23
|
+
const execPromise = promisify(exec);
|
|
24
|
+
// --- Server Definition ---
|
|
6
25
|
const server = new McpServer({
|
|
7
26
|
name: "gikendaasowin-aabajichiganan-mcp",
|
|
8
|
-
version: "0.
|
|
9
|
-
description: "ᑭᑫᓐᑖᓱᐎᓐ ᐋᐸᒋᒋᑲᓇᓐ -
|
|
10
|
-
});
|
|
11
|
-
// ---
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
27
|
+
version: "0.9.0", // Version required by MCP SDK
|
|
28
|
+
description: "ᑭᑫᓐᑖᓱᐎᓐ ᐋᐸᒋᒋᑲᓇᓐ - Cognitive Tools Suite: Enables structured, iterative reasoning (Chain of Draft), planning, analysis, and external tool integration for AI Pair Programming."
|
|
29
|
+
});
|
|
30
|
+
// --- Logging Helper ---
|
|
31
|
+
function logToolCall(toolName, details) {
|
|
32
|
+
console.error(`[MCP Server] > Tool Call: ${toolName}${details ? ` - ${details}` : ''}`);
|
|
33
|
+
}
|
|
34
|
+
function logToolResult(toolName, success, resultDetails) {
|
|
35
|
+
console.error(`[MCP Server] < Tool Result: ${toolName} - ${success ? 'Success' : 'Failure'}${resultDetails ? ` - ${resultDetails}` : ''}`);
|
|
36
|
+
}
|
|
37
|
+
function logToolError(toolName, error) {
|
|
38
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
39
|
+
console.error(`[MCP Server] ! Tool Error: ${toolName} - ${errorMessage}`);
|
|
40
|
+
logToolResult(toolName, false, errorMessage); // Log failure result as well
|
|
41
|
+
// Return a structured error message suitable for the LLM
|
|
42
|
+
return { content: [{ type: "text", text: `Error in ${toolName}: ${errorMessage}` }] };
|
|
43
|
+
}
|
|
44
|
+
// --- Core Cognitive Deliberation & Refinement Tools ---
|
|
45
|
+
server.tool("assess_cuc_n_mode", "**Mandatory Pre-Deliberation/Pre-Sequence Assessment.** Evaluates task Complexity, Uncertainty, Consequence, Novelty (CUC-N) to determine required cognitive depth and initial strategy. MUST be called before starting complex tasks or changing strategy.", {
|
|
46
|
+
assessment_and_choice: z.string().describe("Structured assessment including: 1) Situation Description, 2) CUC-N Ratings (L/M/H), 3) Recommended Initial Strategy (e.g., 'Need to read relevant file for context'), 4) Explicit Mode Selection ('Selected Mode: think' or 'Selected Mode: quick_think').")
|
|
47
|
+
}, async ({ assessment_and_choice }) => {
|
|
48
|
+
logToolCall('assess_cuc_n_mode');
|
|
49
|
+
try {
|
|
50
|
+
// Basic validation for required components
|
|
51
|
+
if (!assessment_and_choice.includes("Selected Mode:") || !assessment_and_choice.includes("CUC-N Ratings:") || !assessment_and_choice.includes("Recommended Initial Strategy:")) {
|
|
52
|
+
throw new Error('Invalid assessment: String must include CUC-N ratings, Recommended Initial Strategy, and explicit Selected Mode.');
|
|
53
|
+
}
|
|
54
|
+
const mode = assessment_and_choice.includes("Selected Mode: think") ? "think" : "quick_think";
|
|
55
|
+
const resultText = `Cognitive Assessment Completed. Proceeding with selected mode: ${mode}. Full Assessment:\n${assessment_and_choice}`;
|
|
56
|
+
logToolResult('assess_cuc_n_mode', true, `Selected mode: ${mode}`);
|
|
57
|
+
return { content: [{ type: "text", text: resultText }] };
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
return logToolError('assess_cuc_n_mode', error);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
server.tool("think", "**MANDATORY Central Hub for Analysis, Planning, and Refinement.** Called after assessment, complex cognitive tools, *any* external tool execution, or internal draft generation. Analyzes previous step's outcome/draft, plans immediate next action (cognitive or external), verifies, assesses risk, and self-corrects. Returns the thought text for grounding.", {
|
|
64
|
+
thought: z.string().describe("Your **detailed** internal monologue following the MANDATORY structure: ## Analysis (critically evaluate last result/draft, incl. tool errors/warnings), ## Plan (define *immediate* next action & purpose), ## Verification (how to check next step), ## Anticipated Challenges & Contingency, ## Risk Assessment, ## Lookahead, ## Self-Correction & Learning.")
|
|
17
65
|
}, async ({ thought }) => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
66
|
+
logToolCall('think');
|
|
67
|
+
try {
|
|
68
|
+
if (!thought || typeof thought !== 'string' || thought.trim().length === 0) {
|
|
69
|
+
throw new Error('Invalid thought: Must be a non-empty string.');
|
|
70
|
+
}
|
|
71
|
+
// Basic check for mandatory sections (can be made more robust)
|
|
72
|
+
const requiredSections = ["## Analysis:", "## Plan:", "## Verification:", "## Anticipated Challenges & Contingency:", "## Risk Assessment:", "## Lookahead:", "## Self-Correction & Learning:"];
|
|
73
|
+
const missingSections = requiredSections.filter(section => !thought.includes(section));
|
|
74
|
+
if (missingSections.length > 0) {
|
|
75
|
+
console.warn(`[MCP Server] Warning: 'think' input might be missing sections: ${missingSections.join(', ')}`);
|
|
76
|
+
// Allow processing but log warning. Could throw error if strictness is desired.
|
|
77
|
+
}
|
|
78
|
+
logToolResult('think', true, `Thought logged (length: ${thought.length})`);
|
|
79
|
+
// Returns the same thought text received, making it explicit in context.
|
|
80
|
+
return { content: [{ type: "text", text: thought }] };
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
return logToolError('think', error);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
server.tool("quick_think", "Cognitive Checkpoint ONLY for situations explicitly assessed as strictly Low CUC-N (via assess_cuc_n_mode) or for trivial confirmations where detailed analysis via `think` is unnecessary. Use sparingly.", {
|
|
87
|
+
brief_thought: z.string().describe("Your **concise** thought for strictly simple, low CUC-N situations or brief confirmations.")
|
|
38
88
|
}, async ({ brief_thought }) => {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}, async ({ assessment_and_choice }) => {
|
|
53
|
-
const requiredPhrases = ["Complexity", "Uncertainty", "Consequence", "Novelty", "Recommended Initial Strategy", "Selected Mode:"];
|
|
54
|
-
const hasRequiredPhrases = requiredPhrases.every(phrase => assessment_and_choice.includes(phrase));
|
|
55
|
-
const hasModeSelection = assessment_and_choice.includes("Selected Mode: think") || assessment_and_choice.includes("Selected Mode: quick_think");
|
|
56
|
-
if (!assessment_and_choice || typeof assessment_and_choice !== 'string' || !hasRequiredPhrases || !hasModeSelection) {
|
|
57
|
-
throw new Error('Invalid assessment: String must include CUC-N ratings, Recommended Initial Strategy, and explicit Selected Mode ("think" or "quick_think").');
|
|
58
|
-
}
|
|
59
|
-
console.error(`[CognitiveToolsServer v0.8.5] AssessComplexity Tool Signaled: ${assessment_and_choice.substring(0, 150)}...`);
|
|
60
|
-
const mode = assessment_and_choice.includes("Selected Mode: think") ? "think" : "quick_think";
|
|
61
|
-
// Confirmation guides the next step.
|
|
62
|
-
return { content: [{ type: "text", text: `Cognitive Assessment Completed. Proceeding with selected mode: ${mode}. Full Assessment: ${assessment_and_choice}` }] };
|
|
63
|
-
});
|
|
64
|
-
server.tool("gauge_confidence",
|
|
65
|
-
// Main Description: Emphasizes mandatory analysis.
|
|
66
|
-
"Meta-Cognitive Checkpoint. Guides internal stating of **confidence (High/Medium/Low) and justification**. Output MUST be analyzed in the mandatory `think` step immediately after; Low/Medium confidence requires specific action planning.", {
|
|
67
|
-
// Parameter Description: Unchanged.
|
|
89
|
+
logToolCall('quick_think');
|
|
90
|
+
try {
|
|
91
|
+
if (!brief_thought || typeof brief_thought !== 'string' || brief_thought.trim().length === 0) {
|
|
92
|
+
throw new Error('Invalid brief_thought: Must be non-empty.');
|
|
93
|
+
}
|
|
94
|
+
logToolResult('quick_think', true, `Logged: ${brief_thought.substring(0, 50)}...`);
|
|
95
|
+
return { content: [{ type: "text", text: `Quick Thought logged successfully.` }] };
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
return logToolError('quick_think', error);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
server.tool("gauge_confidence", "Meta-Cognitive Checkpoint. Guides internal stating of **confidence (High/Medium/Low) and justification** regarding a plan, analysis, or draft. Output MUST be analyzed in the mandatory `think` step immediately after.", {
|
|
68
102
|
assessment_and_confidence: z.string().describe("Input item being assessed. *Internally determine and state*: 1) Confidence Level (H/M/L). 2) Justification. Call this tool *after* making the assessment.")
|
|
69
103
|
}, async ({ assessment_and_confidence }) => {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
104
|
+
logToolCall('gauge_confidence');
|
|
105
|
+
try {
|
|
106
|
+
const confidenceRegex = /Confidence Level: (High|Medium|Low)/i;
|
|
107
|
+
if (!assessment_and_confidence || typeof assessment_and_confidence !== 'string' || !confidenceRegex.test(assessment_and_confidence)) {
|
|
108
|
+
throw new Error('Invalid confidence assessment: String must include "Confidence Level: High/Medium/Low" and justification.');
|
|
109
|
+
}
|
|
110
|
+
const match = assessment_and_confidence.match(confidenceRegex);
|
|
111
|
+
const level = match ? match[1] : "Unknown";
|
|
112
|
+
const resultText = `Confidence Gauge Completed. Level: ${level}. Assessment Text: ${assessment_and_confidence}. Ready for mandatory post-assessment 'think' analysis (action required if Low/Medium).`;
|
|
113
|
+
logToolResult('gauge_confidence', true, `Level: ${level}`);
|
|
114
|
+
return { content: [{ type: "text", text: resultText }] };
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
return logToolError('gauge_confidence', error);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
server.tool("plan_and_solve", "Guides internal generation of a **structured plan draft**. Call this tool *with* the generated plan text. Returns the plan text for mandatory `think` analysis to critically evaluate feasibility, refine, and confirm the first action step.", {
|
|
121
|
+
generated_plan_text: z.string().describe("The **full, structured plan draft** you generated internally, including goals, steps, potential tool needs, and risks."),
|
|
86
122
|
task_objective: z.string().describe("The original high-level task objective this plan addresses.")
|
|
87
123
|
}, async ({ generated_plan_text, task_objective }) => {
|
|
88
|
-
|
|
89
|
-
|
|
124
|
+
logToolCall('plan_and_solve', `Objective: ${task_objective.substring(0, 50)}...`);
|
|
125
|
+
try {
|
|
126
|
+
if (!generated_plan_text || typeof generated_plan_text !== 'string' || generated_plan_text.trim().length === 0) {
|
|
127
|
+
throw new Error('Invalid generated_plan_text: Must be non-empty.');
|
|
128
|
+
}
|
|
129
|
+
if (!task_objective || typeof task_objective !== 'string' || task_objective.trim().length === 0) {
|
|
130
|
+
throw new Error('Invalid task_objective.');
|
|
131
|
+
}
|
|
132
|
+
logToolResult('plan_and_solve', true, `Returned plan draft (length: ${generated_plan_text.length})`);
|
|
133
|
+
// Returns the actual plan text received for analysis.
|
|
134
|
+
return { content: [{ type: "text", text: generated_plan_text }] };
|
|
90
135
|
}
|
|
91
|
-
|
|
92
|
-
|
|
136
|
+
catch (error) {
|
|
137
|
+
return logToolError('plan_and_solve', error);
|
|
93
138
|
}
|
|
94
|
-
console.error(`[CognitiveToolsServer v0.8.5] PlanAndSolve Tool Received Plan for Objective: ${task_objective.substring(0, 100)}...`);
|
|
95
|
-
// Returns the actual plan text received for analysis.
|
|
96
|
-
return { content: [{ type: "text", text: generated_plan_text }] };
|
|
97
139
|
});
|
|
98
|
-
server.tool("chain_of_thought",
|
|
99
|
-
|
|
100
|
-
"Guides internal generation of **detailed, step-by-step reasoning text (CoT)**. Call this tool *with* the generated CoT text. Returns the CoT text for mandatory `think` analysis to extract insights and plan the next action.", {
|
|
101
|
-
// Parameter: Accepts the generated CoT.
|
|
102
|
-
generated_cot_text: z.string().describe("The **full, step-by-step Chain of Thought text** you generated internally, potentially noting needs for other tools."),
|
|
140
|
+
server.tool("chain_of_thought", "Guides internal generation of **detailed, step-by-step reasoning draft (CoT)**. Call this tool *with* the generated CoT text. Returns the CoT text for mandatory `think` analysis to extract insights, identify flaws/gaps, and plan the next concrete action.", {
|
|
141
|
+
generated_cot_text: z.string().describe("The **full, step-by-step Chain of Thought draft** you generated internally."),
|
|
103
142
|
problem_statement: z.string().describe("The original problem statement this CoT addresses.")
|
|
104
143
|
}, async ({ generated_cot_text, problem_statement }) => {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
144
|
+
logToolCall('chain_of_thought', `Problem: ${problem_statement.substring(0, 50)}...`);
|
|
145
|
+
try {
|
|
146
|
+
if (!generated_cot_text || typeof generated_cot_text !== 'string' || generated_cot_text.trim().length === 0) {
|
|
147
|
+
throw new Error('Invalid generated_cot_text: Must be non-empty.');
|
|
148
|
+
}
|
|
149
|
+
if (!problem_statement || typeof problem_statement !== 'string' || problem_statement.trim().length === 0) {
|
|
150
|
+
throw new Error('Invalid problem_statement.');
|
|
151
|
+
}
|
|
152
|
+
logToolResult('chain_of_thought', true, `Returned CoT draft (length: ${generated_cot_text.length})`);
|
|
153
|
+
// Returns the actual CoT text received for analysis.
|
|
154
|
+
return { content: [{ type: "text", text: generated_cot_text }] };
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
return logToolError('chain_of_thought', error);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
server.tool("chain_of_draft", "Signals that one or more **internal drafts** (code, text, plan fragments) have been generated or refined and are ready for analysis. Call this tool *after* generating/refining draft(s) internally. Response confirms readiness; drafts MUST be analyzed via mandatory `think`.", {
|
|
161
|
+
draft_description: z.string().describe("Brief description of the draft(s) generated/refined internally (e.g., 'Initial code snippet for function X', 'Refined plan section 3').")
|
|
162
|
+
}, async ({ draft_description }) => {
|
|
163
|
+
logToolCall('chain_of_draft', `Description: ${draft_description}`);
|
|
164
|
+
try {
|
|
165
|
+
if (!draft_description || typeof draft_description !== 'string' || draft_description.trim().length === 0) {
|
|
166
|
+
throw new Error('Invalid draft_description.');
|
|
167
|
+
}
|
|
168
|
+
const resultText = `Internal draft(s) ready for analysis: ${draft_description}. MANDATORY: Analyze these draft(s) now in your next 'think' step.`;
|
|
169
|
+
logToolResult('chain_of_draft', true);
|
|
170
|
+
return { content: [{ type: "text", text: resultText }] };
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
return logToolError('chain_of_draft', error);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
server.tool("reflection", "Guides internal critical self-evaluation on a prior step, draft, or outcome. Call this tool *with* the **generated critique text**. Returns the critique text for mandatory `think` analysis to plan specific corrective actions or refinements.", {
|
|
177
|
+
generated_critique_text: z.string().describe("The **full critique text** you generated internally, identifying flaws, strengths, and suggesting improvements."),
|
|
178
|
+
input_subject_description: z.string().describe("A brief description of the original reasoning, plan, code draft, or action result that was critiqued.")
|
|
179
|
+
}, async ({ generated_critique_text, input_subject_description }) => {
|
|
180
|
+
logToolCall('reflection', `Subject: ${input_subject_description}`);
|
|
181
|
+
try {
|
|
182
|
+
if (!generated_critique_text || typeof generated_critique_text !== 'string' || generated_critique_text.trim().length === 0) {
|
|
183
|
+
throw new Error('Invalid generated_critique_text: Must be non-empty.');
|
|
184
|
+
}
|
|
185
|
+
if (!input_subject_description || typeof input_subject_description !== 'string' || input_subject_description.trim().length === 0) {
|
|
186
|
+
throw new Error('Invalid input_subject_description.');
|
|
187
|
+
}
|
|
188
|
+
logToolResult('reflection', true, `Returned critique (length: ${generated_critique_text.length})`);
|
|
189
|
+
// Returns the actual critique text received for analysis.
|
|
190
|
+
return { content: [{ type: "text", text: generated_critique_text }] };
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
return logToolError('reflection', error);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
server.tool("synthesize_prior_reasoning", "Context Management Tool. Guides internal generation of a **structured summary** of preceding steps, decisions, or context. Call this tool *with* the generated summary text. Returns the summary for mandatory `think` analysis to consolidate understanding and inform next steps.", {
|
|
197
|
+
generated_summary_text: z.string().describe("The **full, structured summary text** you generated internally (e.g., key decisions, open questions, current state)."),
|
|
198
|
+
context_to_summarize_description: z.string().describe("Description of the reasoning span or context that was summarized.")
|
|
151
199
|
}, async ({ generated_summary_text, context_to_summarize_description }) => {
|
|
152
|
-
|
|
153
|
-
|
|
200
|
+
logToolCall('synthesize_prior_reasoning', `Context: ${context_to_summarize_description}`);
|
|
201
|
+
try {
|
|
202
|
+
if (!generated_summary_text || typeof generated_summary_text !== 'string' || generated_summary_text.trim().length === 0) {
|
|
203
|
+
throw new Error('Invalid generated_summary_text: Must be non-empty.');
|
|
204
|
+
}
|
|
205
|
+
if (!context_to_summarize_description || typeof context_to_summarize_description !== 'string' || context_to_summarize_description.trim().length === 0) {
|
|
206
|
+
throw new Error('Invalid context_to_summarize_description.');
|
|
207
|
+
}
|
|
208
|
+
logToolResult('synthesize_prior_reasoning', true, `Returned summary (length: ${generated_summary_text.length})`);
|
|
209
|
+
// Returns the actual summary text received for analysis.
|
|
210
|
+
return { content: [{ type: "text", text: generated_summary_text }] };
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
return logToolError('synthesize_prior_reasoning', error);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
// --- Generic External Environment Tools ---
|
|
217
|
+
// ** File System Operations **
|
|
218
|
+
server.tool("readFile", "Reads the content of a specified file. Essential for getting context before analysis or modification.", {
|
|
219
|
+
filePath: z.string().describe("The path to the file relative to the project root.")
|
|
220
|
+
}, async ({ filePath }) => {
|
|
221
|
+
logToolCall('readFile', `Path: ${filePath}`);
|
|
222
|
+
try {
|
|
223
|
+
const fileContent = await fs.readFile(filePath, 'utf8');
|
|
224
|
+
// Consider limiting the size returned to avoid overwhelming the context window
|
|
225
|
+
const maxSize = 10000; // Example limit: 10k characters
|
|
226
|
+
const truncatedContent = fileContent.length > maxSize ? fileContent.substring(0, maxSize) + "\n... [File truncated]" : fileContent;
|
|
227
|
+
logToolResult('readFile', true, `Read ${truncatedContent.length} chars from ${filePath}`);
|
|
228
|
+
return { content: [{ type: "text", text: truncatedContent }] };
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
return logToolError('readFile', error);
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
server.tool("writeFile", "Writes the provided content to a specified file, overwriting existing content. Use to apply generated code or modifications.", {
|
|
235
|
+
filePath: z.string().describe("The path to the file relative to the project root."),
|
|
236
|
+
content: z.string().describe("The full content to write to the file.")
|
|
237
|
+
}, async ({ filePath, content }) => {
|
|
238
|
+
logToolCall('writeFile', `Path: ${filePath}, Content Length: ${content.length}`);
|
|
239
|
+
try {
|
|
240
|
+
// Ensure directory exists before writing? (Optional, adds robustness)
|
|
241
|
+
// await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
242
|
+
await fs.writeFile(filePath, content, 'utf8');
|
|
243
|
+
logToolResult('writeFile', true, `Wrote ${content.length} chars to ${filePath}`);
|
|
244
|
+
return { content: [{ type: "text", text: `Successfully wrote content to ${filePath}.` }] };
|
|
245
|
+
}
|
|
246
|
+
catch (error) {
|
|
247
|
+
return logToolError('writeFile', error);
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
server.tool("listFiles", "Lists files and directories within a specified directory path.", {
|
|
251
|
+
directoryPath: z.string().describe("The path to the directory relative to the project root (e.g., '.', 'src/components').")
|
|
252
|
+
}, async ({ directoryPath }) => {
|
|
253
|
+
logToolCall('listFiles', `Path: ${directoryPath}`);
|
|
254
|
+
try {
|
|
255
|
+
const entries = await fs.readdir(directoryPath, { withFileTypes: true });
|
|
256
|
+
const listing = entries.map(entry => `${entry.name}${entry.isDirectory() ? '/' : ''}`).join('\n');
|
|
257
|
+
logToolResult('listFiles', true, `Found ${entries.length} entries in ${directoryPath}`);
|
|
258
|
+
return { content: [{ type: "text", text: listing || "[Directory is empty]" }] };
|
|
259
|
+
}
|
|
260
|
+
catch (error) {
|
|
261
|
+
return logToolError('listFiles', error);
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
server.tool("createDirectory", "Creates a new directory at the specified path. Use `recursive: true` to create parent directories if needed.", {
|
|
265
|
+
directoryPath: z.string().describe("The path for the new directory relative to the project root."),
|
|
266
|
+
recursive: z.boolean().optional().describe("If true, create parent directories as needed. Defaults to false.")
|
|
267
|
+
}, async ({ directoryPath, recursive = false }) => {
|
|
268
|
+
logToolCall('createDirectory', `Path: ${directoryPath}, Recursive: ${recursive}`);
|
|
269
|
+
try {
|
|
270
|
+
await fs.mkdir(directoryPath, { recursive: recursive });
|
|
271
|
+
logToolResult('createDirectory', true, `Created directory ${directoryPath}`);
|
|
272
|
+
return { content: [{ type: "text", text: `Successfully created directory ${directoryPath}.` }] };
|
|
273
|
+
}
|
|
274
|
+
catch (error) {
|
|
275
|
+
// Handle 'EEXIST' gracefully if directory already exists? Or let it fail?
|
|
276
|
+
// if (error.code === 'EEXIST' && recursive) { /* handle existing */ }
|
|
277
|
+
return logToolError('createDirectory', error);
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
server.tool("deleteFile", "Deletes the specified file. Use with caution.", {
|
|
281
|
+
filePath: z.string().describe("The path to the file to delete relative to the project root.")
|
|
282
|
+
}, async ({ filePath }) => {
|
|
283
|
+
logToolCall('deleteFile', `Path: ${filePath}`);
|
|
284
|
+
try {
|
|
285
|
+
await fs.unlink(filePath);
|
|
286
|
+
logToolResult('deleteFile', true, `Deleted file ${filePath}`);
|
|
287
|
+
return { content: [{ type: "text", text: `Successfully deleted file ${filePath}.` }] };
|
|
154
288
|
}
|
|
155
|
-
|
|
156
|
-
|
|
289
|
+
catch (error) {
|
|
290
|
+
// Handle 'ENOENT' (file not found) gracefully?
|
|
291
|
+
return logToolError('deleteFile', error);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
// ** Code Execution & Terminal **
|
|
295
|
+
server.tool("executeCode", "Executes a provided code snippet in a sandboxed environment. Crucial for testing drafts/logic. Currently supports JavaScript.", {
|
|
296
|
+
codeSnippet: z.string().describe("The code snippet to execute (currently JavaScript)."),
|
|
297
|
+
language: z.string().optional().describe("The language of the snippet (defaults to javascript). Informational for now.")
|
|
298
|
+
}, async ({ codeSnippet, language = 'javascript' }) => {
|
|
299
|
+
// Basic check for language - could expand later
|
|
300
|
+
if (language.toLowerCase() !== 'javascript') {
|
|
301
|
+
return logToolError('executeCode', new Error(`Unsupported language: ${language}. Only JavaScript is currently supported.`));
|
|
302
|
+
}
|
|
303
|
+
logToolCall('executeCode', `Lang: ${language}, Snippet: ${codeSnippet.substring(0, 50)}...`);
|
|
304
|
+
try {
|
|
305
|
+
// Use Node.js vm module for basic sandboxing (better than eval)
|
|
306
|
+
const context = vm.createContext({}); // Create an empty context
|
|
307
|
+
const script = new vm.Script(codeSnippet);
|
|
308
|
+
const result = script.runInContext(context, { timeout: 5000 }); // Add a timeout
|
|
309
|
+
const resultString = typeof result === 'undefined' ? 'undefined' : JSON.stringify(result);
|
|
310
|
+
logToolResult('executeCode', true, `Result: ${resultString.substring(0, 100)}...`);
|
|
311
|
+
return { content: [{ type: "text", text: `Execution Result: ${resultString}` }] };
|
|
312
|
+
}
|
|
313
|
+
catch (error) {
|
|
314
|
+
return logToolError('executeCode', error);
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
server.tool("executeTerminalCommand", "Executes a shell command in the project's root directory. Useful for build steps, git operations, running test suites, etc.", {
|
|
318
|
+
command: z.string().describe("The shell command to execute (e.g., 'npm run test', 'git status').")
|
|
319
|
+
}, async ({ command }) => {
|
|
320
|
+
logToolCall('executeTerminalCommand', `Command: ${command}`);
|
|
321
|
+
try {
|
|
322
|
+
// Execute command - consider security implications carefully in production
|
|
323
|
+
// Set a timeout? Limit allowed commands?
|
|
324
|
+
const { stdout, stderr } = await execPromise(command, { timeout: 30000, encoding: 'utf8' }); // 30s timeout
|
|
325
|
+
let resultText = "";
|
|
326
|
+
if (stderr) {
|
|
327
|
+
resultText += `Standard Error:\n${stderr}\n`;
|
|
328
|
+
logToolResult('executeTerminalCommand', false, `Command finished with stderr.`); // Consider stderr as potential failure
|
|
329
|
+
}
|
|
330
|
+
resultText += `Standard Output:\n${stdout}`;
|
|
331
|
+
logToolResult('executeTerminalCommand', true, `Command finished.`);
|
|
332
|
+
// Limit output size?
|
|
333
|
+
const maxSize = 5000;
|
|
334
|
+
if (resultText.length > maxSize) {
|
|
335
|
+
resultText = resultText.substring(0, maxSize) + "\n... [Output truncated]";
|
|
336
|
+
}
|
|
337
|
+
return { content: [{ type: "text", text: resultText }] };
|
|
338
|
+
}
|
|
339
|
+
catch (error) {
|
|
340
|
+
// Error object from exec often includes stdout/stderr which might be useful
|
|
341
|
+
let errorDetails = error instanceof Error ? error.message : String(error);
|
|
342
|
+
if (error.stdout)
|
|
343
|
+
errorDetails += `\nSTDOUT:\n${error.stdout}`;
|
|
344
|
+
if (error.stderr)
|
|
345
|
+
errorDetails += `\nSTDERR:\n${error.stderr}`;
|
|
346
|
+
return logToolError('executeTerminalCommand', errorDetails);
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
// ** Web & Information Retrieval **
|
|
350
|
+
server.tool("webSearch", "Performs a web search using an external service (stubbed). Useful for finding API documentation, error explanations, or concepts.", {
|
|
351
|
+
query: z.string().describe("The search query.")
|
|
352
|
+
}, async ({ query }) => {
|
|
353
|
+
logToolCall('webSearch', `Query: ${query}`);
|
|
354
|
+
// --- STUB IMPLEMENTATION ---
|
|
355
|
+
// In a real scenario, this would call a search API (Google, Bing, DuckDuckGo, Brave Search etc.)
|
|
356
|
+
// For now, return a placeholder message.
|
|
357
|
+
const resultText = `[Web Search Stub] Would search for: "${query}". No live search configured.`;
|
|
358
|
+
logToolResult('webSearch', true, 'Stub executed');
|
|
359
|
+
return { content: [{ type: "text", text: resultText }] };
|
|
360
|
+
// --- END STUB ---
|
|
361
|
+
/* // Example using a hypothetical search API client
|
|
362
|
+
try {
|
|
363
|
+
// const searchResults = await searchApiClient.search(query);
|
|
364
|
+
// const formattedResults = formatSearchResults(searchResults); // Process results
|
|
365
|
+
// logToolResult('webSearch', true, `Found results for ${query}`);
|
|
366
|
+
// return { content: [{ type: "text", text: formattedResults }] };
|
|
367
|
+
} catch (error: any) {
|
|
368
|
+
return logToolError('webSearch', error);
|
|
157
369
|
}
|
|
158
|
-
|
|
159
|
-
// Returns the actual summary text received for analysis.
|
|
160
|
-
return { content: [{ type: "text", text: generated_summary_text }] };
|
|
370
|
+
*/
|
|
161
371
|
});
|
|
162
|
-
// --- Server Lifecycle and Error Handling
|
|
372
|
+
// --- Server Lifecycle and Error Handling ---
|
|
163
373
|
process.on('SIGINT', async () => {
|
|
164
|
-
console.error('\n[
|
|
374
|
+
console.error('\n[MCP Server] Received SIGINT, shutting down gracefully.');
|
|
165
375
|
await server.close();
|
|
166
376
|
process.exit(0);
|
|
167
377
|
});
|
|
168
378
|
process.on('SIGTERM', async () => {
|
|
169
|
-
console.error('\n[
|
|
379
|
+
console.error('\n[MCP Server] Received SIGTERM, shutting down gracefully.');
|
|
170
380
|
await server.close();
|
|
171
381
|
process.exit(0);
|
|
172
382
|
});
|
|
173
|
-
process.on('uncaughtException', (error) => {
|
|
174
|
-
console.error(
|
|
175
|
-
server.close().catch(err => console.error('[
|
|
383
|
+
process.on('uncaughtException', (error, origin) => {
|
|
384
|
+
console.error(`[MCP Server] FATAL: Uncaught Exception at: ${origin}`, error);
|
|
385
|
+
server.close().catch(err => console.error('[MCP Server] Error during shutdown on uncaughtException:', err)).finally(() => {
|
|
176
386
|
process.exit(1);
|
|
177
387
|
});
|
|
178
388
|
});
|
|
179
389
|
process.on('unhandledRejection', (reason, promise) => {
|
|
180
|
-
console.error('[
|
|
181
|
-
server.close().catch(err => console.error('[
|
|
390
|
+
console.error('[MCP Server] FATAL: Unhandled Promise Rejection:', reason);
|
|
391
|
+
server.close().catch(err => console.error('[MCP Server] Error during shutdown on unhandledRejection:', err)).finally(() => {
|
|
182
392
|
process.exit(1);
|
|
183
393
|
});
|
|
184
394
|
});
|
|
185
|
-
// Start the
|
|
395
|
+
// --- Start the Server ---
|
|
186
396
|
async function main() {
|
|
187
397
|
try {
|
|
188
398
|
const transport = new StdioServerTransport();
|
|
189
399
|
await server.connect(transport);
|
|
190
|
-
console.error('
|
|
400
|
+
console.error('-----------------------------------------------------');
|
|
401
|
+
console.error(' ᑭᑫᓐᑖᓱᐎᓐ ᐋᐸᒋᒋᑲᓇᓐ - Cognitive Tools MCP Server');
|
|
402
|
+
console.error(' Status: Running on stdio');
|
|
403
|
+
console.error('-----------------------------------------------------');
|
|
191
404
|
}
|
|
192
405
|
catch (error) {
|
|
193
|
-
console.error('[
|
|
406
|
+
console.error('[MCP Server] Fatal error during startup:', error);
|
|
194
407
|
process.exit(1);
|
|
195
408
|
}
|
|
196
409
|
}
|