it-tools-mcp 4.1.14 → 5.0.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/build/index.js +164 -302
- package/package.json +4 -2
package/build/index.js
CHANGED
|
@@ -252,14 +252,21 @@ const server = new McpServer({
|
|
|
252
252
|
license: packageInfo.license,
|
|
253
253
|
}, {
|
|
254
254
|
capabilities: {
|
|
255
|
-
tools: {
|
|
256
|
-
|
|
257
|
-
|
|
255
|
+
tools: {
|
|
256
|
+
listChanged: true
|
|
257
|
+
},
|
|
258
|
+
resources: {
|
|
259
|
+
listChanged: true
|
|
260
|
+
},
|
|
261
|
+
prompts: {
|
|
262
|
+
listChanged: true
|
|
263
|
+
},
|
|
258
264
|
sampling: {},
|
|
259
265
|
roots: {
|
|
260
266
|
listChanged: true
|
|
261
267
|
},
|
|
262
|
-
logging: {}
|
|
268
|
+
logging: {},
|
|
269
|
+
completions: {}
|
|
263
270
|
}
|
|
264
271
|
});
|
|
265
272
|
// MCP Logging Functions
|
|
@@ -468,250 +475,6 @@ export function mcpToolHandler(handler, identifier = 'default') {
|
|
|
468
475
|
}
|
|
469
476
|
};
|
|
470
477
|
}
|
|
471
|
-
// Demo tools for MCP utilities
|
|
472
|
-
server.registerTool("mcp_utilities_demo", {
|
|
473
|
-
description: "Demonstrate MCP utilities: ping, progress tracking, and cancellation support",
|
|
474
|
-
inputSchema: {
|
|
475
|
-
operation: z.enum(['ping', 'long_task', 'cancellable_task']).describe("The MCP utility operation to demonstrate"),
|
|
476
|
-
duration: z.number().optional().describe("Duration in seconds for long-running tasks (default: 10)"),
|
|
477
|
-
steps: z.number().optional().describe("Number of progress steps for demonstrating progress tracking (default: 5)")
|
|
478
|
-
}
|
|
479
|
-
}, async (args) => {
|
|
480
|
-
const { operation, duration = 10, steps = 5 } = args;
|
|
481
|
-
if (operation === 'ping') {
|
|
482
|
-
return {
|
|
483
|
-
content: [{
|
|
484
|
-
type: "text",
|
|
485
|
-
text: JSON.stringify({
|
|
486
|
-
operation: 'ping',
|
|
487
|
-
status: 'success',
|
|
488
|
-
message: 'MCP ping utility is working correctly',
|
|
489
|
-
timestamp: new Date().toISOString(),
|
|
490
|
-
usage: 'Send a "ping" request to test connection health'
|
|
491
|
-
}, null, 2)
|
|
492
|
-
}]
|
|
493
|
-
};
|
|
494
|
-
}
|
|
495
|
-
if (operation === 'long_task') {
|
|
496
|
-
// Simulate a long-running task with progress updates
|
|
497
|
-
const totalMs = duration * 1000;
|
|
498
|
-
const stepMs = totalMs / steps;
|
|
499
|
-
return {
|
|
500
|
-
content: [{
|
|
501
|
-
type: "text",
|
|
502
|
-
text: JSON.stringify({
|
|
503
|
-
operation: 'long_task',
|
|
504
|
-
status: 'completed',
|
|
505
|
-
message: `Simulated ${duration}s task with ${steps} progress updates`,
|
|
506
|
-
note: 'Use _meta.progressToken in your request to receive progress notifications',
|
|
507
|
-
example: {
|
|
508
|
-
request: {
|
|
509
|
-
jsonrpc: "2.0",
|
|
510
|
-
id: 1,
|
|
511
|
-
method: "tools/call",
|
|
512
|
-
params: {
|
|
513
|
-
name: "mcp_utilities_demo",
|
|
514
|
-
arguments: { operation: "long_task", duration: 5, steps: 3 },
|
|
515
|
-
_meta: { progressToken: "demo123" }
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
}, null, 2)
|
|
520
|
-
}]
|
|
521
|
-
};
|
|
522
|
-
}
|
|
523
|
-
if (operation === 'cancellable_task') {
|
|
524
|
-
return {
|
|
525
|
-
content: [{
|
|
526
|
-
type: "text",
|
|
527
|
-
text: JSON.stringify({
|
|
528
|
-
operation: 'cancellable_task',
|
|
529
|
-
status: 'completed',
|
|
530
|
-
message: 'Simulated cancellable task',
|
|
531
|
-
note: 'Send a notifications/cancelled message to cancel in-progress requests',
|
|
532
|
-
example: {
|
|
533
|
-
cancel_notification: {
|
|
534
|
-
jsonrpc: "2.0",
|
|
535
|
-
method: "notifications/cancelled",
|
|
536
|
-
params: {
|
|
537
|
-
requestId: "your_request_id",
|
|
538
|
-
reason: "User requested cancellation"
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
}, null, 2)
|
|
543
|
-
}]
|
|
544
|
-
};
|
|
545
|
-
}
|
|
546
|
-
return {
|
|
547
|
-
content: [{
|
|
548
|
-
type: "text",
|
|
549
|
-
text: JSON.stringify({ error: 'Unknown operation' }, null, 2)
|
|
550
|
-
}]
|
|
551
|
-
};
|
|
552
|
-
});
|
|
553
|
-
// Sampling demo tool
|
|
554
|
-
server.registerTool("mcp_sampling_demo", {
|
|
555
|
-
description: "Demonstrate MCP sampling capabilities and test sampling/createMessage requests",
|
|
556
|
-
inputSchema: {
|
|
557
|
-
message: z.string().describe("The message to send in the sampling request"),
|
|
558
|
-
modelPreference: z.enum(['claude', 'gpt', 'gemini', 'generic']).optional().describe("Preferred model family for demonstration"),
|
|
559
|
-
systemPrompt: z.string().optional().describe("System prompt to include in the sampling request"),
|
|
560
|
-
maxTokens: z.number().positive().optional().describe("Maximum tokens for the response (default: 100)"),
|
|
561
|
-
intelligence: z.number().min(0).max(1).optional().describe("Intelligence priority (0-1, higher = more capable models)"),
|
|
562
|
-
speed: z.number().min(0).max(1).optional().describe("Speed priority (0-1, higher = faster models)"),
|
|
563
|
-
cost: z.number().min(0).max(1).optional().describe("Cost priority (0-1, higher = cheaper models)")
|
|
564
|
-
}
|
|
565
|
-
}, async (args) => {
|
|
566
|
-
const { message, modelPreference, systemPrompt, maxTokens = 100, intelligence = 0.7, speed = 0.5, cost = 0.3 } = args;
|
|
567
|
-
// Build model preferences based on user input
|
|
568
|
-
const modelPreferences = {
|
|
569
|
-
intelligencePriority: intelligence,
|
|
570
|
-
speedPriority: speed,
|
|
571
|
-
costPriority: cost
|
|
572
|
-
};
|
|
573
|
-
// Add model hints based on preference
|
|
574
|
-
if (modelPreference) {
|
|
575
|
-
const hintMap = {
|
|
576
|
-
'claude': [{ name: 'claude-4-sonnet' }, { name: 'claude' }],
|
|
577
|
-
'gpt': [{ name: 'gpt-4' }, { name: 'gpt' }],
|
|
578
|
-
'gemini': [{ name: 'gemini-1.5-pro' }, { name: 'gemini' }],
|
|
579
|
-
'generic': [{ name: 'general-purpose' }]
|
|
580
|
-
};
|
|
581
|
-
modelPreferences.hints = hintMap[modelPreference];
|
|
582
|
-
}
|
|
583
|
-
// Create the sampling request
|
|
584
|
-
const samplingRequest = {
|
|
585
|
-
method: "sampling/createMessage",
|
|
586
|
-
params: {
|
|
587
|
-
messages: [
|
|
588
|
-
{
|
|
589
|
-
role: "user",
|
|
590
|
-
content: {
|
|
591
|
-
type: "text",
|
|
592
|
-
text: message
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
],
|
|
596
|
-
modelPreferences,
|
|
597
|
-
...(systemPrompt && { systemPrompt }),
|
|
598
|
-
maxTokens
|
|
599
|
-
}
|
|
600
|
-
};
|
|
601
|
-
return {
|
|
602
|
-
content: [{
|
|
603
|
-
type: "text",
|
|
604
|
-
text: JSON.stringify({
|
|
605
|
-
demo: 'MCP Sampling Protocol Demonstration',
|
|
606
|
-
status: 'request_prepared',
|
|
607
|
-
message: 'Here is the sampling request that would be sent to the MCP client',
|
|
608
|
-
request: samplingRequest,
|
|
609
|
-
explanation: {
|
|
610
|
-
protocol: 'MCP 2025-06-18 sampling/createMessage',
|
|
611
|
-
purpose: 'This demonstrates how servers can request LLM completions from clients',
|
|
612
|
-
modelSelection: modelPreferences.hints ?
|
|
613
|
-
`Prefers ${modelPreference} models with intelligence=${intelligence}, speed=${speed}, cost=${cost}` :
|
|
614
|
-
`No specific model preference, using priorities: intelligence=${intelligence}, speed=${speed}, cost=${cost}`,
|
|
615
|
-
flow: [
|
|
616
|
-
'1. Server sends sampling/createMessage request to client',
|
|
617
|
-
'2. Client selects appropriate model based on preferences',
|
|
618
|
-
'3. Client processes the message through the selected LLM',
|
|
619
|
-
'4. Client returns the LLM response to the server',
|
|
620
|
-
'5. Server can use the response for its tool operations'
|
|
621
|
-
],
|
|
622
|
-
security: 'Clients SHOULD implement user approval controls for sampling requests'
|
|
623
|
-
},
|
|
624
|
-
nextSteps: 'In production, this request would be sent to the MCP client for actual LLM processing'
|
|
625
|
-
}, null, 2)
|
|
626
|
-
}]
|
|
627
|
-
};
|
|
628
|
-
});
|
|
629
|
-
// MCP Sampling Implementation - Server-side LLM request handling
|
|
630
|
-
server.server.setRequestHandler(z.object({
|
|
631
|
-
method: z.literal("sampling/createMessage"),
|
|
632
|
-
params: z.object({
|
|
633
|
-
messages: z.array(z.object({
|
|
634
|
-
role: z.enum(["user", "assistant", "system"]),
|
|
635
|
-
content: z.union([
|
|
636
|
-
z.object({
|
|
637
|
-
type: z.literal("text"),
|
|
638
|
-
text: z.string()
|
|
639
|
-
}),
|
|
640
|
-
z.object({
|
|
641
|
-
type: z.literal("image"),
|
|
642
|
-
data: z.string(),
|
|
643
|
-
mimeType: z.string()
|
|
644
|
-
}),
|
|
645
|
-
z.object({
|
|
646
|
-
type: z.literal("audio"),
|
|
647
|
-
data: z.string(),
|
|
648
|
-
mimeType: z.string()
|
|
649
|
-
})
|
|
650
|
-
])
|
|
651
|
-
})),
|
|
652
|
-
modelPreferences: z.object({
|
|
653
|
-
hints: z.array(z.object({
|
|
654
|
-
name: z.string()
|
|
655
|
-
})).optional(),
|
|
656
|
-
costPriority: z.number().min(0).max(1).optional(),
|
|
657
|
-
speedPriority: z.number().min(0).max(1).optional(),
|
|
658
|
-
intelligencePriority: z.number().min(0).max(1).optional()
|
|
659
|
-
}).optional(),
|
|
660
|
-
systemPrompt: z.string().optional(),
|
|
661
|
-
maxTokens: z.number().positive().optional(),
|
|
662
|
-
temperature: z.number().min(0).max(2).optional(),
|
|
663
|
-
stopSequences: z.array(z.string()).optional(),
|
|
664
|
-
metadata: z.record(z.any()).optional()
|
|
665
|
-
})
|
|
666
|
-
}), async (request) => {
|
|
667
|
-
const { messages, modelPreferences, systemPrompt, maxTokens, temperature, stopSequences, metadata } = request.params;
|
|
668
|
-
mcpLog('info', 'Sampling request received', {
|
|
669
|
-
messageCount: messages.length,
|
|
670
|
-
modelPreferences: modelPreferences ? Object.keys(modelPreferences) : undefined,
|
|
671
|
-
hasSystemPrompt: !!systemPrompt,
|
|
672
|
-
maxTokens
|
|
673
|
-
});
|
|
674
|
-
// In a real implementation, this would:
|
|
675
|
-
// 1. Forward the request to the client's LLM service
|
|
676
|
-
// 2. Apply model preferences and selection logic
|
|
677
|
-
// 3. Handle different content types (text, image, audio)
|
|
678
|
-
// 4. Return the LLM response
|
|
679
|
-
// For this MCP server implementation, we return a helpful response
|
|
680
|
-
// explaining that this is a demonstration of the sampling protocol
|
|
681
|
-
// and that the actual LLM processing would be handled by the client
|
|
682
|
-
const demoResponse = {
|
|
683
|
-
role: "assistant",
|
|
684
|
-
content: {
|
|
685
|
-
type: "text",
|
|
686
|
-
text: `This is a demonstration of MCP sampling protocol support.
|
|
687
|
-
|
|
688
|
-
In a production environment, this request would be forwarded to an LLM service based on your model preferences:
|
|
689
|
-
${modelPreferences?.hints?.length ? `- Preferred models: ${modelPreferences.hints.map(h => h.name).join(', ')}` : '- No specific model preferences'}
|
|
690
|
-
${modelPreferences?.intelligencePriority ? `- Intelligence priority: ${modelPreferences.intelligencePriority}` : ''}
|
|
691
|
-
${modelPreferences?.speedPriority ? `- Speed priority: ${modelPreferences.speedPriority}` : ''}
|
|
692
|
-
${modelPreferences?.costPriority ? `- Cost priority: ${modelPreferences.costPriority}` : ''}
|
|
693
|
-
|
|
694
|
-
Your message: "${messages[messages.length - 1]?.content?.type === 'text' ? messages[messages.length - 1].content.text : 'Non-text content'}"
|
|
695
|
-
|
|
696
|
-
${systemPrompt ? `System prompt: "${systemPrompt}"` : 'No system prompt provided'}
|
|
697
|
-
${maxTokens ? `Max tokens: ${maxTokens}` : 'No token limit specified'}
|
|
698
|
-
|
|
699
|
-
This server supports the full MCP 2025-06-18 sampling specification and is ready for production use with proper LLM integration.`
|
|
700
|
-
},
|
|
701
|
-
model: "mcp-demo-server",
|
|
702
|
-
stopReason: "endTurn",
|
|
703
|
-
usage: {
|
|
704
|
-
inputTokens: messages.reduce((sum, msg) => sum + (msg.content.type === 'text' ? msg.content.text.length / 4 : 100), 0),
|
|
705
|
-
outputTokens: 150
|
|
706
|
-
}
|
|
707
|
-
};
|
|
708
|
-
mcpLog('debug', 'Sampling response generated', {
|
|
709
|
-
model: demoResponse.model,
|
|
710
|
-
stopReason: demoResponse.stopReason,
|
|
711
|
-
outputTokens: demoResponse.usage.outputTokens
|
|
712
|
-
});
|
|
713
|
-
return demoResponse;
|
|
714
|
-
});
|
|
715
478
|
// VS Code MCP Compliance: Implement Resources
|
|
716
479
|
server.registerResource("server-manifest", new ResourceTemplate("manifest://{type}", {
|
|
717
480
|
list: async () => ({
|
|
@@ -759,7 +522,7 @@ server.registerResource("system-logs", new ResourceTemplate("logs://{type}", {
|
|
|
759
522
|
}]
|
|
760
523
|
};
|
|
761
524
|
});
|
|
762
|
-
server.registerResource("tool-documentation", new ResourceTemplate("docs://{category}
|
|
525
|
+
server.registerResource("tool-documentation", new ResourceTemplate("docs://{category}", {
|
|
763
526
|
list: async () => {
|
|
764
527
|
const { toolCategories } = await discoverTools();
|
|
765
528
|
const resources = Object.keys(toolCategories).map(category => ({
|
|
@@ -780,8 +543,8 @@ server.registerResource("tool-documentation", new ResourceTemplate("docs://{cate
|
|
|
780
543
|
description: "Documentation for available tools by category"
|
|
781
544
|
}, async (uri, params) => {
|
|
782
545
|
const category = params.category;
|
|
783
|
-
|
|
784
|
-
const docs = await getToolDocumentation(category
|
|
546
|
+
// For this simpler template, we only handle category-level documentation
|
|
547
|
+
const docs = await getToolDocumentation(category);
|
|
785
548
|
return {
|
|
786
549
|
contents: [{
|
|
787
550
|
uri: uri.href,
|
|
@@ -917,16 +680,125 @@ async function getManifestContent(type) {
|
|
|
917
680
|
};
|
|
918
681
|
return manifests[type] || { error: "Manifest type not found" };
|
|
919
682
|
}
|
|
683
|
+
// Helper function to extract tool documentation from the main README table
|
|
684
|
+
function extractToolFromReadme(readmeContent, toolName) {
|
|
685
|
+
// Look for the tool in the Available Tools table
|
|
686
|
+
const lines = readmeContent.split('\n');
|
|
687
|
+
const toolRegex = new RegExp(`\\|\s*\`${toolName}\`\\s*\\|`, 'i');
|
|
688
|
+
for (let i = 0; i < lines.length; i++) {
|
|
689
|
+
const line = lines[i];
|
|
690
|
+
if (toolRegex.test(line)) {
|
|
691
|
+
// Found the tool, extract the row
|
|
692
|
+
const parts = line.split('|').map(part => part.trim()).filter(part => part.length > 0);
|
|
693
|
+
if (parts.length >= 2) {
|
|
694
|
+
const cleanToolName = parts[0].replace(/`/g, ''); // Remove backticks from tool name
|
|
695
|
+
const descCell = parts[1]; // Description cell
|
|
696
|
+
const paramsCell = parts.length > 2 ? parts[2] : ''; // Parameters cell
|
|
697
|
+
return `# ${cleanToolName} Documentation\n\n**Description:** ${descCell}\n\n${paramsCell ? `**Parameters:** ${paramsCell}\n\n` : ''}**Usage:** ${descCell}`;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
return null;
|
|
702
|
+
}
|
|
703
|
+
// Helper function to extract category section from the main README
|
|
704
|
+
function extractCategoryFromReadme(readmeContent, category) {
|
|
705
|
+
// Map category names to README section names
|
|
706
|
+
const categoryMappings = {
|
|
707
|
+
'ansible': 'Ansible Tools',
|
|
708
|
+
'color': 'Color Tools',
|
|
709
|
+
'data_format': 'Data Format',
|
|
710
|
+
'development': 'Development Tools',
|
|
711
|
+
'docker': 'Docker Tools',
|
|
712
|
+
'encoding': 'Encoding & Decoding',
|
|
713
|
+
'forensic': 'Forensic Tools',
|
|
714
|
+
'id_generators': 'ID & Code Generators',
|
|
715
|
+
'math': 'Math & Calculations',
|
|
716
|
+
'network': 'Network & System',
|
|
717
|
+
'physics': 'Physics',
|
|
718
|
+
'crypto': 'Security & Crypto',
|
|
719
|
+
'text': 'Text Processing',
|
|
720
|
+
'utility': 'Utility Tools'
|
|
721
|
+
};
|
|
722
|
+
const sectionName = categoryMappings[category];
|
|
723
|
+
if (!sectionName) {
|
|
724
|
+
return null;
|
|
725
|
+
}
|
|
726
|
+
// Find the section in the README table
|
|
727
|
+
const lines = readmeContent.split('\n');
|
|
728
|
+
let inTargetSection = false;
|
|
729
|
+
let tableRows = [];
|
|
730
|
+
for (let i = 0; i < lines.length; i++) {
|
|
731
|
+
const line = lines[i];
|
|
732
|
+
// Check if we're entering the target section
|
|
733
|
+
if (line.includes(`**${sectionName}**`)) {
|
|
734
|
+
inTargetSection = true;
|
|
735
|
+
continue;
|
|
736
|
+
}
|
|
737
|
+
// Check if we're entering a new section (exit current)
|
|
738
|
+
if (inTargetSection && line.includes('**') && line.includes('**') && !line.includes(sectionName)) {
|
|
739
|
+
break;
|
|
740
|
+
}
|
|
741
|
+
// Collect table rows while in target section
|
|
742
|
+
if (inTargetSection && line.includes('|') && !line.includes('---')) {
|
|
743
|
+
tableRows.push(line);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
if (tableRows.length === 0) {
|
|
747
|
+
return null;
|
|
748
|
+
}
|
|
749
|
+
// Parse and clean up the table
|
|
750
|
+
const cleanedContent = [`# ${sectionName} Documentation\n`];
|
|
751
|
+
for (const row of tableRows) {
|
|
752
|
+
const cells = row.split('|').map(cell => cell.trim()).filter(cell => cell.length > 0);
|
|
753
|
+
if (cells.length >= 2) {
|
|
754
|
+
const toolName = cells[0].replace(/`/g, ''); // Remove backticks
|
|
755
|
+
const description = cells[1];
|
|
756
|
+
const parameters = cells.length > 2 ? cells[2] : '';
|
|
757
|
+
cleanedContent.push(`## ${toolName}`);
|
|
758
|
+
cleanedContent.push(`**Description:** ${description}`);
|
|
759
|
+
if (parameters) {
|
|
760
|
+
cleanedContent.push(`**Parameters:** ${parameters}`);
|
|
761
|
+
}
|
|
762
|
+
cleanedContent.push(''); // Add empty line for spacing
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
return cleanedContent.join('\n');
|
|
766
|
+
}
|
|
920
767
|
async function getToolDocumentation(category, tool) {
|
|
768
|
+
// When compiled, __dirname will be the build/ directory, so we need to go up one level
|
|
769
|
+
const readmePath = path.join(__dirname, '../README.md');
|
|
921
770
|
if (tool) {
|
|
771
|
+
// For specific tools, try to find them in the README table
|
|
772
|
+
try {
|
|
773
|
+
const readmeContent = fs.readFileSync(readmePath, 'utf-8');
|
|
774
|
+
const toolSection = extractToolFromReadme(readmeContent, tool);
|
|
775
|
+
if (toolSection) {
|
|
776
|
+
return toolSection;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
catch (error) {
|
|
780
|
+
mcpLog('warning', `Failed to read README for tool documentation: ${readmePath}`, error instanceof Error ? error.message : 'Unknown error');
|
|
781
|
+
}
|
|
922
782
|
return `# ${tool} Documentation\n\nCategory: ${category}\n\nThis tool provides ${category} functionality.\n\nUsage: See tool description for specific parameters and examples.`;
|
|
923
783
|
}
|
|
784
|
+
// Try to read category documentation from README
|
|
785
|
+
try {
|
|
786
|
+
const readmeContent = fs.readFileSync(readmePath, 'utf-8');
|
|
787
|
+
const categorySection = extractCategoryFromReadme(readmeContent, category);
|
|
788
|
+
if (categorySection) {
|
|
789
|
+
return categorySection;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
catch (error) {
|
|
793
|
+
mcpLog('warning', `Failed to read README for category documentation: ${readmePath}`, error instanceof Error ? error.message : 'Unknown error');
|
|
794
|
+
}
|
|
795
|
+
// Fallback to dynamic generation
|
|
924
796
|
const { toolCategories } = await discoverTools();
|
|
925
797
|
const categoryInfo = toolCategories[category];
|
|
926
798
|
if (!categoryInfo) {
|
|
927
|
-
return `# Category Not Found\n\nThe category '${category}' was not found
|
|
799
|
+
return `# Category Not Found\n\nThe category '${category}' was not found.\n\nAvailable categories: ${Object.keys(toolCategories).join(', ')}`;
|
|
928
800
|
}
|
|
929
|
-
return `# ${category} Category Documentation\n\n${categoryInfo.description}\n\n## Available Tools\n\n${categoryInfo.tools.map(t => `- ${t}`).join('\n')}
|
|
801
|
+
return `# ${category} Category Documentation\n\n${categoryInfo.description}\n\n## Available Tools\n\n${categoryInfo.tools.map(t => `- ${t}`).join('\n')}\n\n*This documentation was generated automatically. For detailed documentation, see the main README.md file.*`;
|
|
930
802
|
}
|
|
931
803
|
function generateWorkflowPrompt(taskType, context) {
|
|
932
804
|
const workflows = {
|
|
@@ -1271,79 +1143,71 @@ async function main() {
|
|
|
1271
1143
|
try {
|
|
1272
1144
|
// VS Code MCP Compliance: Dev Mode Support
|
|
1273
1145
|
const isTest = process.env.NODE_ENV === 'test' && process.env.MCP_TEST_MODE === 'true';
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
}
|
|
1146
|
+
mcpLog('info', 'Starting IT Tools MCP Server', {
|
|
1147
|
+
version: packageInfo.version,
|
|
1148
|
+
environment: isDevelopment ? 'development' : 'production',
|
|
1149
|
+
nodeVersion: process.version
|
|
1150
|
+
});
|
|
1280
1151
|
// Add error handling for unhandled rejections
|
|
1281
1152
|
process.on('unhandledRejection', (reason, promise) => {
|
|
1282
|
-
|
|
1153
|
+
// Only log to stderr in development or for critical errors
|
|
1154
|
+
if (isDevelopment) {
|
|
1155
|
+
mcpLog('error', 'Unhandled Rejection', { promise: promise.toString(), reason });
|
|
1156
|
+
}
|
|
1283
1157
|
});
|
|
1284
1158
|
process.on('uncaughtException', (error) => {
|
|
1285
1159
|
mcpLog('critical', 'Uncaught Exception', error.message);
|
|
1286
1160
|
process.exit(1);
|
|
1287
1161
|
});
|
|
1162
|
+
// Register tools and connect
|
|
1163
|
+
mcpLog('debug', 'Registering tools...');
|
|
1164
|
+
const startTime = Date.now();
|
|
1288
1165
|
await registerAllTools(server);
|
|
1166
|
+
const toolLoadTime = Date.now() - startTime;
|
|
1167
|
+
const { totalToolCount, toolCategories } = await discoverTools();
|
|
1168
|
+
mcpLog('info', 'Tools registered successfully', {
|
|
1169
|
+
totalTools: totalToolCount,
|
|
1170
|
+
categories: Object.keys(toolCategories).length,
|
|
1171
|
+
loadTimeMs: toolLoadTime
|
|
1172
|
+
});
|
|
1173
|
+
mcpLog('debug', 'Connecting to MCP transport...');
|
|
1289
1174
|
const transport = new StdioServerTransport();
|
|
1290
1175
|
await server.connect(transport);
|
|
1291
1176
|
// Mark MCP transport as ready for logging
|
|
1292
1177
|
mcpTransportReady = true;
|
|
1293
|
-
|
|
1178
|
+
mcpLog('info', 'MCP Server started successfully', {
|
|
1179
|
+
transport: 'stdio',
|
|
1180
|
+
ready: true
|
|
1181
|
+
});
|
|
1182
|
+
// Exit handler for test automation
|
|
1294
1183
|
if (isTest) {
|
|
1295
|
-
mcpLog('
|
|
1296
|
-
// Exit after stdin closes (for test automation)
|
|
1184
|
+
mcpLog('debug', 'Test mode: Setting up exit handler');
|
|
1297
1185
|
process.stdin.on('end', () => {
|
|
1186
|
+
mcpLog('debug', 'Test mode: stdin ended, exiting...');
|
|
1298
1187
|
setTimeout(() => process.exit(0), 100);
|
|
1299
1188
|
});
|
|
1300
1189
|
}
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
mcpLog('
|
|
1304
|
-
mcpLog('info', `🔗 Protocol: Model Context Protocol (MCP) via stdio`);
|
|
1305
|
-
mcpLog('info', `📦 Version: ${packageInfo.version}`);
|
|
1306
|
-
}
|
|
1307
|
-
else {
|
|
1308
|
-
// Production mode - simple ready message
|
|
1309
|
-
mcpLog('info', `IT Tools MCP Server v${packageInfo.version} ready - ${await getToolCount()} tools loaded`);
|
|
1310
|
-
}
|
|
1311
|
-
// Enhanced monitoring in development mode
|
|
1312
|
-
if (isDevelopment && !isTest) {
|
|
1313
|
-
// More frequent monitoring in dev mode (every minute)
|
|
1190
|
+
// Production monitoring (every 5 minutes) - no logging unless critical
|
|
1191
|
+
if (!isTest) {
|
|
1192
|
+
mcpLog('debug', 'Setting up production monitoring');
|
|
1314
1193
|
setInterval(() => {
|
|
1315
1194
|
const usage = getResourceUsage();
|
|
1316
1195
|
if (usage.memory.heapUsedBytes > 200 * 1024 * 1024) {
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
// Log periodic status in dev mode
|
|
1320
|
-
mcpLog('debug', `📈 Status: Memory ${usage.memory.heapUsed}, CPU ${usage.cpu.user}ms user, ${usage.cpu.system}ms system`);
|
|
1321
|
-
}, 60 * 1000); // Every minute in dev mode
|
|
1322
|
-
}
|
|
1323
|
-
else if (!isTest) {
|
|
1324
|
-
// Production monitoring (every 5 minutes)
|
|
1325
|
-
setInterval(() => {
|
|
1326
|
-
const usage = getResourceUsage();
|
|
1327
|
-
if (usage.memory.heapUsedBytes > 200 * 1024 * 1024) {
|
|
1328
|
-
mcpLog('warning', "High memory usage detected", usage.memory);
|
|
1196
|
+
// Critical memory issues
|
|
1197
|
+
mcpLog('critical', 'High memory usage detected', usage.memory);
|
|
1329
1198
|
}
|
|
1330
1199
|
}, 5 * 60 * 1000);
|
|
1331
1200
|
}
|
|
1332
1201
|
// Handle graceful shutdown
|
|
1333
1202
|
const shutdown = () => {
|
|
1334
|
-
|
|
1335
|
-
mcpLog('info', "🛑 Shutting down IT Tools MCP Server (Development Mode)...");
|
|
1336
|
-
}
|
|
1337
|
-
else {
|
|
1338
|
-
mcpLog('info', "Shutting down IT Tools MCP Server...");
|
|
1339
|
-
}
|
|
1203
|
+
mcpLog('info', 'Graceful shutdown initiated');
|
|
1340
1204
|
process.exit(0);
|
|
1341
1205
|
};
|
|
1342
1206
|
process.on('SIGINT', shutdown);
|
|
1343
1207
|
process.on('SIGTERM', shutdown);
|
|
1344
1208
|
}
|
|
1345
1209
|
catch (error) {
|
|
1346
|
-
mcpLog('
|
|
1210
|
+
mcpLog('emergency', 'Fatal error starting MCP server', error instanceof Error ? error.message : 'Unknown error');
|
|
1347
1211
|
process.exit(1);
|
|
1348
1212
|
}
|
|
1349
1213
|
}
|
|
@@ -1384,10 +1248,8 @@ function extractReadmeSection(content, heading) {
|
|
|
1384
1248
|
: lines.slice(startIndex, endIndex);
|
|
1385
1249
|
return sectionLines.join('\n');
|
|
1386
1250
|
}
|
|
1387
|
-
// Start the server
|
|
1388
|
-
|
|
1389
|
-
main()
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
});
|
|
1393
|
-
}
|
|
1251
|
+
// Start the server
|
|
1252
|
+
main().catch((error) => {
|
|
1253
|
+
console.error("Fatal error in main():", error);
|
|
1254
|
+
process.exit(1);
|
|
1255
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "it-tools-mcp",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Full MCP 2025-06-18 compliant server with 121+ IT tools, logging, ping, progress tracking, cancellation, and sampling utilities",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./build/index.js",
|
|
@@ -72,8 +72,10 @@
|
|
|
72
72
|
"tools",
|
|
73
73
|
"resources",
|
|
74
74
|
"prompts",
|
|
75
|
+
"completions",
|
|
75
76
|
"sampling",
|
|
76
|
-
"roots"
|
|
77
|
+
"roots",
|
|
78
|
+
"logging"
|
|
77
79
|
],
|
|
78
80
|
"toolCount": 116,
|
|
79
81
|
"categories": [
|