mcp-taskflow 0.1.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/CHANGELOG.md +13 -0
- package/LICENSE.md +21 -0
- package/README.md +275 -0
- package/dist/config/pathResolver.d.ts +33 -0
- package/dist/config/pathResolver.d.ts.map +1 -0
- package/dist/config/pathResolver.js +130 -0
- package/dist/config/pathResolver.js.map +1 -0
- package/dist/data/fileOperations.d.ts +43 -0
- package/dist/data/fileOperations.d.ts.map +1 -0
- package/dist/data/fileOperations.js +248 -0
- package/dist/data/fileOperations.js.map +1 -0
- package/dist/data/memoryStore.d.ts +86 -0
- package/dist/data/memoryStore.d.ts.map +1 -0
- package/dist/data/memoryStore.js +216 -0
- package/dist/data/memoryStore.js.map +1 -0
- package/dist/data/rulesStore.d.ts +63 -0
- package/dist/data/rulesStore.d.ts.map +1 -0
- package/dist/data/rulesStore.js +196 -0
- package/dist/data/rulesStore.js.map +1 -0
- package/dist/data/schemas.d.ts +840 -0
- package/dist/data/schemas.d.ts.map +1 -0
- package/dist/data/schemas.js +265 -0
- package/dist/data/schemas.js.map +1 -0
- package/dist/data/taskSearchService.d.ts +110 -0
- package/dist/data/taskSearchService.d.ts.map +1 -0
- package/dist/data/taskSearchService.js +165 -0
- package/dist/data/taskSearchService.js.map +1 -0
- package/dist/data/taskStore.d.ts +192 -0
- package/dist/data/taskStore.d.ts.map +1 -0
- package/dist/data/taskStore.js +347 -0
- package/dist/data/taskStore.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +86 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/index.d.ts +12 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +17 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/projectPromptBuilder.d.ts +13 -0
- package/dist/prompts/projectPromptBuilder.d.ts.map +1 -0
- package/dist/prompts/projectPromptBuilder.js +29 -0
- package/dist/prompts/projectPromptBuilder.js.map +1 -0
- package/dist/prompts/researchPromptBuilder.d.ts +10 -0
- package/dist/prompts/researchPromptBuilder.d.ts.map +1 -0
- package/dist/prompts/researchPromptBuilder.js +20 -0
- package/dist/prompts/researchPromptBuilder.js.map +1 -0
- package/dist/prompts/taskPromptBuilders.d.ts +87 -0
- package/dist/prompts/taskPromptBuilders.d.ts.map +1 -0
- package/dist/prompts/taskPromptBuilders.js +529 -0
- package/dist/prompts/taskPromptBuilders.js.map +1 -0
- package/dist/prompts/templateEngine.d.ts +102 -0
- package/dist/prompts/templateEngine.d.ts.map +1 -0
- package/dist/prompts/templateEngine.js +145 -0
- package/dist/prompts/templateEngine.js.map +1 -0
- package/dist/prompts/templateLoader.d.ts +61 -0
- package/dist/prompts/templateLoader.d.ts.map +1 -0
- package/dist/prompts/templateLoader.js +129 -0
- package/dist/prompts/templateLoader.js.map +1 -0
- package/dist/prompts/templates/v1/templates_en/analyzeTask/index.md +65 -0
- package/dist/prompts/templates/v1/templates_en/analyzeTask/iteration.md +12 -0
- package/dist/prompts/templates/v1/templates_en/clearAllTasks/backupInfo.md +1 -0
- package/dist/prompts/templates/v1/templates_en/clearAllTasks/cancel.md +7 -0
- package/dist/prompts/templates/v1/templates_en/clearAllTasks/empty.md +5 -0
- package/dist/prompts/templates/v1/templates_en/clearAllTasks/index.md +5 -0
- package/dist/prompts/templates/v1/templates_en/clearAllTasks/result.md +7 -0
- package/dist/prompts/templates/v1/templates_en/clearAllTasks/success.md +5 -0
- package/dist/prompts/templates/v1/templates_en/deleteTask/completed.md +5 -0
- package/dist/prompts/templates/v1/templates_en/deleteTask/index.md +5 -0
- package/dist/prompts/templates/v1/templates_en/deleteTask/notFound.md +5 -0
- package/dist/prompts/templates/v1/templates_en/deleteTask/result.md +5 -0
- package/dist/prompts/templates/v1/templates_en/deleteTask/success.md +5 -0
- package/dist/prompts/templates/v1/templates_en/executeTask/analysisResult.md +3 -0
- package/dist/prompts/templates/v1/templates_en/executeTask/complexity.md +15 -0
- package/dist/prompts/templates/v1/templates_en/executeTask/dependencies.md +3 -0
- package/dist/prompts/templates/v1/templates_en/executeTask/dependencyTasks.md +3 -0
- package/dist/prompts/templates/v1/templates_en/executeTask/implementationGuide.md +3 -0
- package/dist/prompts/templates/v1/templates_en/executeTask/index.md +39 -0
- package/dist/prompts/templates/v1/templates_en/executeTask/notes.md +1 -0
- package/dist/prompts/templates/v1/templates_en/executeTask/relatedFilesSummary.md +5 -0
- package/dist/prompts/templates/v1/templates_en/executeTask/verificationCriteria.md +3 -0
- package/dist/prompts/templates/v1/templates_en/getTaskDetail/complatedSummary.md +5 -0
- package/dist/prompts/templates/v1/templates_en/getTaskDetail/dependencies.md +1 -0
- package/dist/prompts/templates/v1/templates_en/getTaskDetail/error.md +3 -0
- package/dist/prompts/templates/v1/templates_en/getTaskDetail/implementationGuide.md +3 -0
- package/dist/prompts/templates/v1/templates_en/getTaskDetail/index.md +25 -0
- package/dist/prompts/templates/v1/templates_en/getTaskDetail/notFound.md +3 -0
- package/dist/prompts/templates/v1/templates_en/getTaskDetail/notes.md +1 -0
- package/dist/prompts/templates/v1/templates_en/getTaskDetail/relatedFiles.md +3 -0
- package/dist/prompts/templates/v1/templates_en/getTaskDetail/verificationCriteria.md +3 -0
- package/dist/prompts/templates/v1/templates_en/initProjectRules/index.md +81 -0
- package/dist/prompts/templates/v1/templates_en/listTasks/index.md +7 -0
- package/dist/prompts/templates/v1/templates_en/listTasks/notFound.md +3 -0
- package/dist/prompts/templates/v1/templates_en/listTasks/taskDetails.md +13 -0
- package/dist/prompts/templates/v1/templates_en/planTask/hasThought.md +4 -0
- package/dist/prompts/templates/v1/templates_en/planTask/index.md +96 -0
- package/dist/prompts/templates/v1/templates_en/planTask/noThought.md +4 -0
- package/dist/prompts/templates/v1/templates_en/planTask/tasks.md +17 -0
- package/dist/prompts/templates/v1/templates_en/processThought/complatedThought.md +6 -0
- package/dist/prompts/templates/v1/templates_en/processThought/index.md +13 -0
- package/dist/prompts/templates/v1/templates_en/processThought/moreThought.md +1 -0
- package/dist/prompts/templates/v1/templates_en/queryTask/index.md +24 -0
- package/dist/prompts/templates/v1/templates_en/queryTask/notFound.md +15 -0
- package/dist/prompts/templates/v1/templates_en/queryTask/taskDetails.md +5 -0
- package/dist/prompts/templates/v1/templates_en/reflectTask/index.md +57 -0
- package/dist/prompts/templates/v1/templates_en/researchMode/index.md +95 -0
- package/dist/prompts/templates/v1/templates_en/researchMode/previousState.md +9 -0
- package/dist/prompts/templates/v1/templates_en/splitTasks/index.md +34 -0
- package/dist/prompts/templates/v1/templates_en/splitTasks/taskDetails.md +12 -0
- package/dist/prompts/templates/v1/templates_en/tests/basic.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/analyzeTask.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/clearAllTasks.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/deleteTask.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/executeTask.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/getTaskDetail.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/initProjectRules.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/listTasks.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/planTask.md +3 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/processThought.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/queryTask.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/reflectTask.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/researchMode.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/splitTasks.md +83 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/updateTask.md +1 -0
- package/dist/prompts/templates/v1/templates_en/toolsDescription/verifyTask.md +37 -0
- package/dist/prompts/templates/v1/templates_en/updateTaskContent/emptyUpdate.md +5 -0
- package/dist/prompts/templates/v1/templates_en/updateTaskContent/fileDetails.md +1 -0
- package/dist/prompts/templates/v1/templates_en/updateTaskContent/index.md +7 -0
- package/dist/prompts/templates/v1/templates_en/updateTaskContent/notFound.md +5 -0
- package/dist/prompts/templates/v1/templates_en/updateTaskContent/success.md +9 -0
- package/dist/prompts/templates/v1/templates_en/updateTaskContent/successDetails.md +3 -0
- package/dist/prompts/templates/v1/templates_en/updateTaskContent/validation.md +5 -0
- package/dist/prompts/templates/v1/templates_en/verifyTask/index.md +19 -0
- package/dist/prompts/templates/v1/templates_en/verifyTask/noPass.md +12 -0
- package/dist/prompts/thoughtPromptBuilder.d.ts +11 -0
- package/dist/prompts/thoughtPromptBuilder.d.ts.map +1 -0
- package/dist/prompts/thoughtPromptBuilder.js +30 -0
- package/dist/prompts/thoughtPromptBuilder.js.map +1 -0
- package/dist/server/container.d.ts +111 -0
- package/dist/server/container.d.ts.map +1 -0
- package/dist/server/container.js +135 -0
- package/dist/server/container.js.map +1 -0
- package/dist/server/logger.d.ts +98 -0
- package/dist/server/logger.d.ts.map +1 -0
- package/dist/server/logger.js +295 -0
- package/dist/server/logger.js.map +1 -0
- package/dist/server/mcpServer.d.ts +162 -0
- package/dist/server/mcpServer.d.ts.map +1 -0
- package/dist/server/mcpServer.js +236 -0
- package/dist/server/mcpServer.js.map +1 -0
- package/dist/tools/project/index.d.ts +7 -0
- package/dist/tools/project/index.d.ts.map +1 -0
- package/dist/tools/project/index.js +7 -0
- package/dist/tools/project/index.js.map +1 -0
- package/dist/tools/project/projectTools.d.ts +17 -0
- package/dist/tools/project/projectTools.d.ts.map +1 -0
- package/dist/tools/project/projectTools.js +73 -0
- package/dist/tools/project/projectTools.js.map +1 -0
- package/dist/tools/research/index.d.ts +7 -0
- package/dist/tools/research/index.d.ts.map +1 -0
- package/dist/tools/research/index.js +7 -0
- package/dist/tools/research/index.js.map +1 -0
- package/dist/tools/research/researchTools.d.ts +16 -0
- package/dist/tools/research/researchTools.d.ts.map +1 -0
- package/dist/tools/research/researchTools.js +41 -0
- package/dist/tools/research/researchTools.js.map +1 -0
- package/dist/tools/task/index.d.ts +8 -0
- package/dist/tools/task/index.d.ts.map +1 -0
- package/dist/tools/task/index.js +8 -0
- package/dist/tools/task/index.js.map +1 -0
- package/dist/tools/task/taskTools.d.ts +32 -0
- package/dist/tools/task/taskTools.d.ts.map +1 -0
- package/dist/tools/task/taskTools.js +542 -0
- package/dist/tools/task/taskTools.js.map +1 -0
- package/dist/tools/thought/index.d.ts +7 -0
- package/dist/tools/thought/index.d.ts.map +1 -0
- package/dist/tools/thought/index.js +7 -0
- package/dist/tools/thought/index.js.map +1 -0
- package/dist/tools/thought/thoughtTools.d.ts +16 -0
- package/dist/tools/thought/thoughtTools.d.ts.map +1 -0
- package/dist/tools/thought/thoughtTools.js +47 -0
- package/dist/tools/thought/thoughtTools.js.map +1 -0
- package/docs/API.md +32 -0
- package/docs/ARCHITECTURE.md +44 -0
- package/docs/COMPATIBILITY_REPORT.md +26 -0
- package/docs/PERFORMANCE.md +66 -0
- package/package.json +77 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logging Infrastructure with Pino
|
|
3
|
+
*
|
|
4
|
+
* Provides structured logging with:
|
|
5
|
+
* - Sensitive data redaction
|
|
6
|
+
* - Correlation IDs
|
|
7
|
+
* - Environment-aware formatting
|
|
8
|
+
* - Error serialization
|
|
9
|
+
*/
|
|
10
|
+
import pino, {} from 'pino';
|
|
11
|
+
import { randomUUID } from 'crypto';
|
|
12
|
+
/**
|
|
13
|
+
* Fields that contain sensitive data and should be redacted
|
|
14
|
+
*/
|
|
15
|
+
const SENSITIVE_FIELDS = [
|
|
16
|
+
'password',
|
|
17
|
+
'token',
|
|
18
|
+
'apiKey',
|
|
19
|
+
'api_key',
|
|
20
|
+
'secret',
|
|
21
|
+
'authorization',
|
|
22
|
+
'cookie',
|
|
23
|
+
'session',
|
|
24
|
+
'jwt',
|
|
25
|
+
'bearer',
|
|
26
|
+
'accessToken',
|
|
27
|
+
'refreshToken',
|
|
28
|
+
'privateKey',
|
|
29
|
+
'private_key',
|
|
30
|
+
'credentials',
|
|
31
|
+
];
|
|
32
|
+
const isDevelopment = process.env['NODE_ENV'] === 'development' || !process.env['NODE_ENV'];
|
|
33
|
+
/**
|
|
34
|
+
* Log level from environment or default to 'info'
|
|
35
|
+
*/
|
|
36
|
+
const LOG_LEVEL = process.env['LOG_LEVEL'] ?? 'info';
|
|
37
|
+
/**
|
|
38
|
+
* Sanitize object by redacting sensitive fields
|
|
39
|
+
*
|
|
40
|
+
* Recursively walks object and replaces sensitive field values with '[REDACTED]'
|
|
41
|
+
* Handles circular references with a WeakSet to prevent infinite recursion
|
|
42
|
+
*
|
|
43
|
+
* @param obj - Object to sanitize
|
|
44
|
+
* @param seen - WeakSet to track circular references
|
|
45
|
+
* @returns Sanitized copy of object
|
|
46
|
+
*/
|
|
47
|
+
function sanitizeObject(obj, seen = new WeakSet()) {
|
|
48
|
+
if (obj === null || obj === undefined) {
|
|
49
|
+
return obj;
|
|
50
|
+
}
|
|
51
|
+
// Handle Date objects specially - preserve them as-is
|
|
52
|
+
if (obj instanceof Date) {
|
|
53
|
+
return obj;
|
|
54
|
+
}
|
|
55
|
+
if (Array.isArray(obj)) {
|
|
56
|
+
// Check for circular reference
|
|
57
|
+
if (seen.has(obj)) {
|
|
58
|
+
return '[CIRCULAR]';
|
|
59
|
+
}
|
|
60
|
+
seen.add(obj);
|
|
61
|
+
return obj.map(item => sanitizeObject(item, seen));
|
|
62
|
+
}
|
|
63
|
+
if (typeof obj === 'object') {
|
|
64
|
+
// Check for circular reference
|
|
65
|
+
if (seen.has(obj)) {
|
|
66
|
+
return '[CIRCULAR]';
|
|
67
|
+
}
|
|
68
|
+
seen.add(obj);
|
|
69
|
+
const sanitized = {};
|
|
70
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
71
|
+
// Check if key is sensitive
|
|
72
|
+
const isSensitive = SENSITIVE_FIELDS.some(field => key.toLowerCase().includes(field.toLowerCase()));
|
|
73
|
+
if (isSensitive && (typeof value === 'string' || typeof value === 'number')) {
|
|
74
|
+
// Only redact primitive values, recurse into objects
|
|
75
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
76
|
+
sanitized[key] = '[REDACTED]';
|
|
77
|
+
}
|
|
78
|
+
else if (key === 'path' || key === 'filePath') {
|
|
79
|
+
// Redact full paths, show basename only
|
|
80
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
81
|
+
sanitized[key] = typeof value === 'string'
|
|
82
|
+
? value.split(/[/\\]/).pop() ?? '[PATH]'
|
|
83
|
+
: value;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// Recursively sanitize nested objects (including sensitive-named objects)
|
|
87
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
88
|
+
sanitized[key] = sanitizeObject(value, seen);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return sanitized;
|
|
92
|
+
}
|
|
93
|
+
return obj;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Create custom serializers for Pino
|
|
97
|
+
*
|
|
98
|
+
* Serializers control how objects are logged, allowing us to:
|
|
99
|
+
* - Redact sensitive data
|
|
100
|
+
* - Format errors appropriately
|
|
101
|
+
* - Add correlation context
|
|
102
|
+
*/
|
|
103
|
+
function createSerializers() {
|
|
104
|
+
return {
|
|
105
|
+
// Error serializer: Full stack in dev, message only in prod
|
|
106
|
+
err: (error) => {
|
|
107
|
+
const serialized = {
|
|
108
|
+
type: error.name,
|
|
109
|
+
message: error.message,
|
|
110
|
+
};
|
|
111
|
+
// Include stack trace in development only
|
|
112
|
+
if (isDevelopment && error['stack']) {
|
|
113
|
+
serialized['stack'] = error['stack'];
|
|
114
|
+
}
|
|
115
|
+
// Include additional error properties
|
|
116
|
+
if ('code' in error) {
|
|
117
|
+
serialized['code'] = error['code'];
|
|
118
|
+
}
|
|
119
|
+
return sanitizeObject(serialized);
|
|
120
|
+
},
|
|
121
|
+
// Request serializer: Sanitize request data
|
|
122
|
+
req: (req) => {
|
|
123
|
+
return sanitizeObject(req);
|
|
124
|
+
},
|
|
125
|
+
// Response serializer: Sanitize response data
|
|
126
|
+
res: (res) => {
|
|
127
|
+
return sanitizeObject(res);
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Create redaction paths for automatic field redaction
|
|
133
|
+
*
|
|
134
|
+
* Pino can automatically redact fields at log time using paths
|
|
135
|
+
*/
|
|
136
|
+
function createRedactionPaths() {
|
|
137
|
+
const paths = [];
|
|
138
|
+
for (const field of SENSITIVE_FIELDS) {
|
|
139
|
+
paths.push(field);
|
|
140
|
+
paths.push(`*.${field}`);
|
|
141
|
+
paths.push(`*[*].${field}`);
|
|
142
|
+
}
|
|
143
|
+
return paths;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Create Pino logger options
|
|
147
|
+
*/
|
|
148
|
+
function createLoggerOptions() {
|
|
149
|
+
const options = {
|
|
150
|
+
level: LOG_LEVEL,
|
|
151
|
+
// Custom serializers for error handling and sanitization
|
|
152
|
+
serializers: createSerializers(),
|
|
153
|
+
// Automatic field redaction
|
|
154
|
+
redact: {
|
|
155
|
+
paths: createRedactionPaths(),
|
|
156
|
+
censor: '[REDACTED]',
|
|
157
|
+
},
|
|
158
|
+
// Base context included in all logs
|
|
159
|
+
base: {
|
|
160
|
+
pid: process.pid,
|
|
161
|
+
hostname: process.env['HOSTNAME'] ?? 'unknown',
|
|
162
|
+
},
|
|
163
|
+
// Timestamp in ISO format
|
|
164
|
+
timestamp: () => `,"time":"${new Date().toISOString()}"`,
|
|
165
|
+
};
|
|
166
|
+
// Pretty printing in development for readable logs
|
|
167
|
+
if (isDevelopment) {
|
|
168
|
+
options.transport = {
|
|
169
|
+
target: 'pino-pretty',
|
|
170
|
+
options: {
|
|
171
|
+
colorize: true,
|
|
172
|
+
translateTime: 'SYS:standard',
|
|
173
|
+
ignore: 'pid,hostname',
|
|
174
|
+
singleLine: false,
|
|
175
|
+
messageFormat: '{correlationId} {msg}',
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
return options;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Root logger instance
|
|
183
|
+
*/
|
|
184
|
+
let rootLogger = null;
|
|
185
|
+
/**
|
|
186
|
+
* Get or create the root logger
|
|
187
|
+
*
|
|
188
|
+
* Singleton pattern ensures consistent configuration across application
|
|
189
|
+
*/
|
|
190
|
+
export function getLogger() {
|
|
191
|
+
if (!rootLogger) {
|
|
192
|
+
rootLogger = pino(createLoggerOptions());
|
|
193
|
+
}
|
|
194
|
+
return rootLogger;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Create child logger with correlation ID
|
|
198
|
+
*
|
|
199
|
+
* Child loggers inherit parent configuration but can add context.
|
|
200
|
+
* Correlation IDs enable request tracing across async operations.
|
|
201
|
+
*
|
|
202
|
+
* @param correlationId - Optional correlation ID (generates UUID if not provided)
|
|
203
|
+
* @param context - Additional context to include in all logs
|
|
204
|
+
* @returns Child logger with correlation context
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```typescript
|
|
208
|
+
* const logger = createLogger();
|
|
209
|
+
* logger.info('Processing request');
|
|
210
|
+
*
|
|
211
|
+
* // Later in async operation:
|
|
212
|
+
* logger.debug({ taskId: '123' }, 'Task created');
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
215
|
+
export function createLogger(correlationId, context) {
|
|
216
|
+
const baseLogger = getLogger();
|
|
217
|
+
const childContext = {
|
|
218
|
+
correlationId: correlationId ?? randomUUID(),
|
|
219
|
+
...context,
|
|
220
|
+
};
|
|
221
|
+
return baseLogger.child(childContext);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Create logger with automatic context
|
|
225
|
+
*
|
|
226
|
+
* Factory function for dependency injection pattern.
|
|
227
|
+
* Each module can create its own logger with appropriate context.
|
|
228
|
+
*
|
|
229
|
+
* @param moduleName - Name of the module (e.g., 'TaskStore', 'MCPServer')
|
|
230
|
+
* @returns Logger configured for the module
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* ```typescript
|
|
234
|
+
* export class TaskStore {
|
|
235
|
+
* private readonly logger = createModuleLogger('TaskStore');
|
|
236
|
+
*
|
|
237
|
+
* async createAsync(task: TaskItem): Promise<TaskItem> {
|
|
238
|
+
* this.logger.info({ taskId: task.id }, 'Creating task');
|
|
239
|
+
* // ... implementation
|
|
240
|
+
* }
|
|
241
|
+
* }
|
|
242
|
+
* ```
|
|
243
|
+
*/
|
|
244
|
+
export function createModuleLogger(moduleName) {
|
|
245
|
+
return getLogger().child({ module: moduleName });
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Log and rethrow error with context
|
|
249
|
+
*
|
|
250
|
+
* Utility for consistent error logging before rethrowing.
|
|
251
|
+
*
|
|
252
|
+
* @param logger - Logger instance
|
|
253
|
+
* @param error - Error to log
|
|
254
|
+
* @param context - Additional context about the error
|
|
255
|
+
* @param message - Custom error message
|
|
256
|
+
* @throws The original error after logging
|
|
257
|
+
*
|
|
258
|
+
* @example
|
|
259
|
+
* ```typescript
|
|
260
|
+
* try {
|
|
261
|
+
* await riskyOperation();
|
|
262
|
+
* } catch (error) {
|
|
263
|
+
* logAndThrow(logger, error, { taskId }, 'Failed to create task');
|
|
264
|
+
* }
|
|
265
|
+
* ```
|
|
266
|
+
*/
|
|
267
|
+
export function logAndThrow(logger, error, context, message) {
|
|
268
|
+
const errorObj = error instanceof Error ? error : new Error(String(error));
|
|
269
|
+
const sanitizedContext = sanitizeObject(context);
|
|
270
|
+
logger.error({
|
|
271
|
+
err: errorObj,
|
|
272
|
+
...sanitizedContext,
|
|
273
|
+
}, message);
|
|
274
|
+
throw error;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Sanitize log data before logging
|
|
278
|
+
*
|
|
279
|
+
* Use this to sanitize data that may contain sensitive information
|
|
280
|
+
* before passing to logger.
|
|
281
|
+
*
|
|
282
|
+
* @param data - Data to sanitize
|
|
283
|
+
* @returns Sanitized copy of data
|
|
284
|
+
*
|
|
285
|
+
* @example
|
|
286
|
+
* ```typescript
|
|
287
|
+
* const userData = { name: 'Alice', password: 'secret123' };
|
|
288
|
+
* logger.info(sanitizeLogData(userData), 'User logged in');
|
|
289
|
+
* // Logs: { name: 'Alice', password: '[REDACTED]' }
|
|
290
|
+
* ```
|
|
291
|
+
*/
|
|
292
|
+
export function sanitizeLogData(data) {
|
|
293
|
+
return sanitizeObject(data);
|
|
294
|
+
}
|
|
295
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/server/logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Server Setup & Tool Registration
|
|
3
|
+
*
|
|
4
|
+
* Implements the Model Context Protocol (MCP) server using @modelcontextprotocol/sdk.
|
|
5
|
+
* The server uses STDIO transport for universal compatibility and follows the
|
|
6
|
+
* JSON-RPC 2.0 protocol for request/response communication.
|
|
7
|
+
*
|
|
8
|
+
* Key Concepts:
|
|
9
|
+
* - STDIO Transport: Uses stdin for input, stdout for output, stderr for logs
|
|
10
|
+
* - JSON-RPC: Protocol for request correlation (id, method, params, result/error)
|
|
11
|
+
* - Tool Discovery: Clients call tools/list to see available capabilities
|
|
12
|
+
* - Stateless Design: Each request is independent (no session state)
|
|
13
|
+
*
|
|
14
|
+
* @see https://modelcontextprotocol.io/docs/concepts/architecture
|
|
15
|
+
* @see https://www.jsonrpc.org/specification
|
|
16
|
+
*/
|
|
17
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
18
|
+
import type { ServiceContainer } from './container.js';
|
|
19
|
+
/**
|
|
20
|
+
* MCP Server instance
|
|
21
|
+
*
|
|
22
|
+
* Manages the lifecycle of the MCP server including:
|
|
23
|
+
* - Tool registration and discovery
|
|
24
|
+
* - Request handling and routing
|
|
25
|
+
* - Error handling and logging
|
|
26
|
+
* - Graceful shutdown
|
|
27
|
+
*
|
|
28
|
+
* Dependencies are injected via the constructor (Dependency Injection pattern).
|
|
29
|
+
*/
|
|
30
|
+
export declare class McpServer {
|
|
31
|
+
private readonly server;
|
|
32
|
+
private readonly logger;
|
|
33
|
+
private readonly tools;
|
|
34
|
+
private readonly container;
|
|
35
|
+
/**
|
|
36
|
+
* Create a new MCP server instance
|
|
37
|
+
*
|
|
38
|
+
* @param container - Service container with all dependencies
|
|
39
|
+
*/
|
|
40
|
+
constructor(container: ServiceContainer);
|
|
41
|
+
/**
|
|
42
|
+
* Setup request handlers
|
|
43
|
+
*
|
|
44
|
+
* Registers handlers for MCP protocol methods:
|
|
45
|
+
* - tools/list: Returns available tools
|
|
46
|
+
* - tools/call: Executes a specific tool
|
|
47
|
+
*/
|
|
48
|
+
private setupHandlers;
|
|
49
|
+
/**
|
|
50
|
+
* Register a tool with the server
|
|
51
|
+
*
|
|
52
|
+
* @param handler - Tool handler with name, description, schema, and execute function
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* server.registerTool({
|
|
57
|
+
* name: 'list_tasks',
|
|
58
|
+
* description: 'List all tasks',
|
|
59
|
+
* inputSchema: {
|
|
60
|
+
* type: 'object',
|
|
61
|
+
* properties: {
|
|
62
|
+
* status: { type: 'string', enum: ['pending', 'in_progress', 'completed'] }
|
|
63
|
+
* }
|
|
64
|
+
* },
|
|
65
|
+
* execute: async (args) => {
|
|
66
|
+
* const tasks = await taskStore.listAsync();
|
|
67
|
+
* return { tasks };
|
|
68
|
+
* }
|
|
69
|
+
* });
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
registerTool(handler: ToolHandler): void;
|
|
73
|
+
/**
|
|
74
|
+
* Start the MCP server with STDIO transport
|
|
75
|
+
*
|
|
76
|
+
* The server will:
|
|
77
|
+
* 1. Connect to stdin/stdout for communication
|
|
78
|
+
* 2. Listen for initialize request from client
|
|
79
|
+
* 3. Process tool/list and tools/call requests
|
|
80
|
+
* 4. Handle graceful shutdown on SIGINT/SIGTERM
|
|
81
|
+
*
|
|
82
|
+
* @returns Promise that resolves when server starts
|
|
83
|
+
*/
|
|
84
|
+
start(): Promise<void>;
|
|
85
|
+
/**
|
|
86
|
+
* Get server instance (for testing)
|
|
87
|
+
*/
|
|
88
|
+
getServer(): Server;
|
|
89
|
+
/**
|
|
90
|
+
* Get the service container
|
|
91
|
+
*
|
|
92
|
+
* Provides access to all application services for tool implementations
|
|
93
|
+
*
|
|
94
|
+
* @returns The service container
|
|
95
|
+
*/
|
|
96
|
+
getContainer(): ServiceContainer;
|
|
97
|
+
/**
|
|
98
|
+
* Get registered tool count (for testing)
|
|
99
|
+
*/
|
|
100
|
+
getToolCount(): number;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Tool handler interface
|
|
104
|
+
*
|
|
105
|
+
* Defines the contract for MCP tools. Each tool must:
|
|
106
|
+
* - Have a unique name
|
|
107
|
+
* - Provide a human-readable description
|
|
108
|
+
* - Define input schema (JSON Schema format)
|
|
109
|
+
* - Implement execute function
|
|
110
|
+
*/
|
|
111
|
+
export interface ToolHandler {
|
|
112
|
+
/**
|
|
113
|
+
* Unique tool name (e.g., 'list_tasks', 'create_task')
|
|
114
|
+
*/
|
|
115
|
+
name: string;
|
|
116
|
+
/**
|
|
117
|
+
* Human-readable description of what the tool does
|
|
118
|
+
*/
|
|
119
|
+
description: string;
|
|
120
|
+
/**
|
|
121
|
+
* JSON Schema defining the tool's input parameters
|
|
122
|
+
* @see https://json-schema.org/
|
|
123
|
+
*/
|
|
124
|
+
inputSchema: {
|
|
125
|
+
type: 'object';
|
|
126
|
+
properties?: Record<string, unknown>;
|
|
127
|
+
required?: string[];
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Execute the tool with given arguments
|
|
131
|
+
*
|
|
132
|
+
* @param args - Tool arguments (validated against inputSchema by MCP SDK)
|
|
133
|
+
* @returns Tool result (will be serialized to JSON)
|
|
134
|
+
*/
|
|
135
|
+
execute: (args: Record<string, unknown>) => Promise<unknown>;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Create and configure MCP server
|
|
139
|
+
*
|
|
140
|
+
* Factory function that creates a server instance and registers all tools.
|
|
141
|
+
* Separates server creation from tool registration for testing.
|
|
142
|
+
*
|
|
143
|
+
* @returns Configured MCP server instance
|
|
144
|
+
*/
|
|
145
|
+
/**
|
|
146
|
+
* Factory function to create a configured MCP server
|
|
147
|
+
*
|
|
148
|
+
* This is the main entry point for server creation. It accepts a
|
|
149
|
+
* ServiceContainer with all dependencies already configured.
|
|
150
|
+
*
|
|
151
|
+
* @param container - Service container with all dependencies
|
|
152
|
+
* @returns Configured MCP server ready to start
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```typescript
|
|
156
|
+
* const container = createContainer();
|
|
157
|
+
* const server = createMcpServer(container);
|
|
158
|
+
* await server.start();
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
export declare function createMcpServer(container: ServiceContainer): McpServer;
|
|
162
|
+
//# sourceMappingURL=mcpServer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpServer.d.ts","sourceRoot":"","sources":["../../src/server/mcpServer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAQnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAOvD;;;;;;;;;;GAUG;AACH,qBAAa,SAAS;IAEpB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuC;IAC7D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmB;IAE7C;;;;OAIG;gBACS,SAAS,EAAE,gBAAgB;IAsBvC;;;;;;OAMG;IACH,OAAO,CAAC,aAAa;IAiDrB;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,YAAY,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAmBxC;;;;;;;;;;OAUG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAsB5B;;OAEG;IAEH,SAAS,IAAI,MAAM;IAInB;;;;;;OAMG;IACH,YAAY,IAAI,gBAAgB;IAIhC;;OAEG;IACH,YAAY,IAAI,MAAM;CAGvB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACrC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;IAEF;;;;;OAKG;IACH,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9D;AAED;;;;;;;GAOG;AACH;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,gBAAgB,GAAG,SAAS,CAYtE"}
|