vme-mcp-server 0.1.5 → 0.1.6

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.
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleCreateVM = exports.createVMTool = void 0;
4
+ const vm_parsing_js_1 = require("../lib/vm-parsing.js");
5
+ const api_utils_js_1 = require("../lib/api-utils.js");
6
+ exports.createVMTool = {
7
+ name: "create_vm",
8
+ description: "Provision a new virtual machine",
9
+ inputSchema: {
10
+ type: "object",
11
+ properties: {
12
+ name: {
13
+ type: "string",
14
+ description: "Name for VM(s). Supports patterns like 'web01' or 'web01->web03' for multiple VMs"
15
+ },
16
+ group: {
17
+ type: "string",
18
+ description: "Group/site where VM will be created"
19
+ },
20
+ cloud: {
21
+ type: "string",
22
+ description: "Cloud/zone where VM will be provisioned (also accepts 'zone')"
23
+ },
24
+ zone: {
25
+ type: "string",
26
+ description: "Zone/cloud where VM will be provisioned (alias for 'cloud')"
27
+ },
28
+ template: {
29
+ type: "string",
30
+ description: "VM template or operating system"
31
+ },
32
+ size: {
33
+ type: "string",
34
+ description: "VM size (small, medium, 4GB, 8GB, etc.)"
35
+ },
36
+ distribution: {
37
+ type: "string",
38
+ description: "VM distribution strategy: 'auto' (default), 'spread' (across all nodes), or 'node1,node2,node3' (specific nodes)"
39
+ },
40
+ count: {
41
+ type: "number",
42
+ description: "Number of VMs to create (alternative to name patterns)"
43
+ }
44
+ },
45
+ required: ["name", "group", "template", "size"]
46
+ }
47
+ };
48
+ async function handleCreateVM(args) {
49
+ const { name, group, cloud, zone, template, size, distribution, count } = args;
50
+ // Allow both 'cloud' and 'zone' parameters interchangeably
51
+ const location = cloud || zone;
52
+ if (!location) {
53
+ return {
54
+ content: [
55
+ {
56
+ type: "text",
57
+ text: JSON.stringify({
58
+ error: {
59
+ code: "missing_location",
60
+ message: "Either 'cloud' or 'zone' parameter is required"
61
+ }
62
+ }, null, 2)
63
+ }
64
+ ],
65
+ isError: true
66
+ };
67
+ }
68
+ // Parse VM names and determine distribution strategy
69
+ const vmNames = (0, vm_parsing_js_1.parseVMNames)(name, count);
70
+ const nodes = await (0, api_utils_js_1.getClusterNodes)();
71
+ // Calculate node assignments
72
+ const nodeAssignments = (0, vm_parsing_js_1.calculateNodeAssignments)(vmNames, nodes, distribution);
73
+ const resolved = await (0, api_utils_js_1.resolveInput)({ group, cloud: location, template, size });
74
+ const { groupId, cloudId, instanceTypeId, servicePlanId, imageId } = resolved;
75
+ if (!groupId || !cloudId || !instanceTypeId || !servicePlanId || !imageId) {
76
+ const errors = [];
77
+ if (!groupId)
78
+ errors.push(`Group '${group}' not found. Available: ${resolved.availableGroups.join(', ')}`);
79
+ if (!cloudId)
80
+ errors.push(`Zone/Cloud '${location}' not found. Available: ${resolved.availableZones.join(', ')}`);
81
+ if (!instanceTypeId)
82
+ errors.push(`Instance type could not be resolved`);
83
+ if (!servicePlanId)
84
+ errors.push(`Size '${size}' could not be resolved to service plan`);
85
+ if (!imageId)
86
+ errors.push(`Template '${template}' could not be resolved to OS image`);
87
+ return {
88
+ content: [
89
+ {
90
+ type: "text",
91
+ text: JSON.stringify({
92
+ error: {
93
+ code: "resolution_failed",
94
+ message: `Failed to resolve parameters:\n${errors.join('\n')}`
95
+ }
96
+ }, null, 2)
97
+ }
98
+ ],
99
+ isError: true
100
+ };
101
+ }
102
+ // Create VMs sequentially
103
+ const results = [];
104
+ const errors = [];
105
+ for (const assignment of nodeAssignments) {
106
+ const vmConfig = {
107
+ resourcePoolId: 'pool-1',
108
+ poolProviderType: 'mvm',
109
+ imageId: imageId,
110
+ createUser: true
111
+ };
112
+ // Add kvmHostId only if explicitly specified
113
+ if (assignment.kvmHostId) {
114
+ vmConfig.kvmHostId = assignment.kvmHostId;
115
+ }
116
+ const payload = {
117
+ zoneId: cloudId,
118
+ instance: {
119
+ name: assignment.name,
120
+ cloud: 'tc-lab',
121
+ hostName: assignment.name,
122
+ type: 'mvm',
123
+ instanceType: {
124
+ code: 'mvm'
125
+ },
126
+ site: {
127
+ id: groupId
128
+ },
129
+ layout: {
130
+ id: 2, // Single HPE VM
131
+ code: 'mvm-1.0-single'
132
+ },
133
+ plan: {
134
+ id: servicePlanId
135
+ }
136
+ },
137
+ config: vmConfig,
138
+ volumes: [
139
+ {
140
+ id: -1,
141
+ rootVolume: true,
142
+ name: 'root',
143
+ size: 10,
144
+ storageType: 1,
145
+ datastoreId: 5
146
+ }
147
+ ],
148
+ networkInterfaces: [
149
+ {
150
+ primaryInterface: true,
151
+ ipMode: 'dhcp',
152
+ network: {
153
+ id: 'network-2'
154
+ },
155
+ networkInterfaceTypeId: 10
156
+ }
157
+ ],
158
+ layoutSize: 1
159
+ };
160
+ try {
161
+ const response = await api_utils_js_1.api.post("/instances", payload);
162
+ const vm = response.data?.instance;
163
+ const nodeInfo = assignment.kvmHostId ? ` on node ${assignment.kvmHostId}` : ' (auto-placed)';
164
+ results.push(`VM '${vm.name}' created (ID: ${vm.id})${nodeInfo}`);
165
+ }
166
+ catch (err) {
167
+ const nodeInfo = assignment.kvmHostId ? ` on node ${assignment.kvmHostId}` : '';
168
+ errors.push(`VM '${assignment.name}' failed${nodeInfo}: ${err.response?.data?.message || err.message}`);
169
+ }
170
+ }
171
+ // Prepare response
172
+ const summary = [];
173
+ if (results.length > 0) {
174
+ summary.push(`Successfully created ${results.length} VM(s):`);
175
+ summary.push(...results);
176
+ }
177
+ if (errors.length > 0) {
178
+ summary.push(`\nFailed to create ${errors.length} VM(s):`);
179
+ summary.push(...errors);
180
+ }
181
+ summary.push(`\nResolved parameters:`);
182
+ summary.push(`- Group: ${resolved.resolvedGroup}`);
183
+ summary.push(`- Zone/Cloud: ${resolved.resolvedCloud}`);
184
+ summary.push(`- Template: ${resolved.resolvedImage}`);
185
+ summary.push(`- Plan: ${resolved.resolvedPlan}`);
186
+ if (distribution === 'spread' || (vmNames.length > 1 && !distribution)) {
187
+ summary.push(`- Distribution: Spread across nodes ${nodes.join(', ')}`);
188
+ }
189
+ else if (nodeAssignments.some(a => a.kvmHostId)) {
190
+ summary.push(`- Distribution: Specific node placement`);
191
+ }
192
+ else {
193
+ summary.push(`- Distribution: Auto-placement`);
194
+ }
195
+ return {
196
+ content: [
197
+ {
198
+ type: "text",
199
+ text: summary.join('\n')
200
+ }
201
+ ],
202
+ isError: errors.length > 0 && results.length === 0
203
+ };
204
+ }
205
+ exports.handleCreateVM = handleCreateVM;
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleExportTrainingData = exports.exportTrainingDataTool = void 0;
4
+ const fs_1 = require("fs");
5
+ const path_1 = require("path");
6
+ exports.exportTrainingDataTool = {
7
+ name: "export_training_data",
8
+ description: "Export AI training data for model improvement (requires ENABLE_AI_TRAINING_DATA=true)",
9
+ inputSchema: {
10
+ type: "object",
11
+ properties: {
12
+ format: {
13
+ type: "string",
14
+ description: "Export format: 'jsonl' or 'csv'",
15
+ enum: ["jsonl", "csv"]
16
+ },
17
+ days: {
18
+ type: "number",
19
+ description: "Number of days of data to export (default: 7)"
20
+ }
21
+ },
22
+ required: []
23
+ }
24
+ };
25
+ async function handleExportTrainingData(args) {
26
+ const AI_TRAINING_ENABLED = process.env.ENABLE_AI_TRAINING_DATA === 'true';
27
+ if (!AI_TRAINING_ENABLED) {
28
+ return {
29
+ content: [
30
+ {
31
+ type: "text",
32
+ text: JSON.stringify({
33
+ error: "Training data collection is disabled",
34
+ message: "Set ENABLE_AI_TRAINING_DATA=true in .env to enable data collection and export"
35
+ }, null, 2)
36
+ }
37
+ ],
38
+ isError: true
39
+ };
40
+ }
41
+ const { format = "jsonl", days = 7 } = args;
42
+ try {
43
+ const logsDir = (0, path_1.join)(process.cwd(), 'ai-training-logs');
44
+ if (!(0, fs_1.existsSync)(logsDir)) {
45
+ return {
46
+ content: [
47
+ {
48
+ type: "text",
49
+ text: JSON.stringify({
50
+ message: "No training data found",
51
+ data_count: 0
52
+ }, null, 2)
53
+ }
54
+ ],
55
+ isError: false
56
+ };
57
+ }
58
+ // Collect data from last N days
59
+ const cutoffDate = new Date(Date.now() - (days * 24 * 60 * 60 * 1000));
60
+ const allData = [];
61
+ // Read log files and aggregate data
62
+ const logFiles = (0, fs_1.readdirSync)(logsDir).filter((file) => file.startsWith('interactions-') && file.endsWith('.jsonl'));
63
+ for (const file of logFiles) {
64
+ const fileDate = new Date(file.replace('interactions-', '').replace('.jsonl', ''));
65
+ if (fileDate >= cutoffDate) {
66
+ const content = (0, fs_1.readFileSync)((0, path_1.join)(logsDir, file), 'utf-8');
67
+ const lines = content.trim().split('\n').filter(line => line.trim());
68
+ for (const line of lines) {
69
+ try {
70
+ allData.push(JSON.parse(line));
71
+ }
72
+ catch (e) {
73
+ // Skip malformed lines
74
+ }
75
+ }
76
+ }
77
+ }
78
+ return {
79
+ content: [
80
+ {
81
+ type: "text",
82
+ text: JSON.stringify({
83
+ message: `Exported ${allData.length} training data records from last ${days} days`,
84
+ format: format,
85
+ data_count: allData.length,
86
+ data: format === 'jsonl' ? allData : allData.map(item => ({
87
+ timestamp: item.timestamp,
88
+ tool: item.tool_name,
89
+ user_input: JSON.stringify(item.user_input),
90
+ parsed_output: JSON.stringify(item.parsed_output),
91
+ success: item.success_metrics?.operation_success,
92
+ confidence: item.success_metrics?.confidence_score
93
+ }))
94
+ }, null, 2)
95
+ }
96
+ ],
97
+ isError: false
98
+ };
99
+ }
100
+ catch (error) {
101
+ return {
102
+ content: [
103
+ {
104
+ type: "text",
105
+ text: JSON.stringify({
106
+ error: "Failed to export training data",
107
+ message: error.message
108
+ }, null, 2)
109
+ }
110
+ ],
111
+ isError: true
112
+ };
113
+ }
114
+ }
115
+ exports.handleExportTrainingData = handleExportTrainingData;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleGetResources = exports.getResourcesTool = void 0;
4
+ const api_utils_js_1 = require("../lib/api-utils.js");
5
+ exports.getResourcesTool = {
6
+ name: "get_resources",
7
+ description: "Discover and explore available VME infrastructure resources with intelligent filtering",
8
+ inputSchema: {
9
+ type: "object",
10
+ properties: {
11
+ type: {
12
+ type: "string",
13
+ description: "Resource type filter: 'compute', 'network', 'storage', 'vm', or leave empty for all"
14
+ },
15
+ intent: {
16
+ type: "string",
17
+ description: "Intent-based filtering: 'create', 'provision', 'list', 'discover', or natural language description"
18
+ },
19
+ role: {
20
+ type: "string",
21
+ description: "User role for permission-aware filtering (future enhancement)"
22
+ }
23
+ },
24
+ required: []
25
+ }
26
+ };
27
+ async function handleGetResources(args) {
28
+ const { type, intent, role } = args;
29
+ const resources = await (0, api_utils_js_1.getResources)(type, intent, role);
30
+ return {
31
+ content: [
32
+ {
33
+ type: "text",
34
+ text: JSON.stringify(resources, null, 2)
35
+ }
36
+ ],
37
+ isError: !!resources.error
38
+ };
39
+ }
40
+ exports.handleGetResources = handleGetResources;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toolHandlers = exports.allTools = exports.handleProvideFeedback = exports.provideFeedbackTool = exports.handleExportTrainingData = exports.exportTrainingDataTool = exports.handleCreateVM = exports.createVMTool = exports.handleParseIntent = exports.parseIntentTool = exports.handleGetResources = exports.getResourcesTool = void 0;
4
+ // Import and re-export all tools and their handlers
5
+ const get_resources_js_1 = require("./get-resources.js");
6
+ const parse_intent_js_1 = require("./parse-intent.js");
7
+ const create_vm_js_1 = require("./create-vm.js");
8
+ const export_training_data_js_1 = require("./export-training-data.js");
9
+ const provide_feedback_js_1 = require("./provide-feedback.js");
10
+ // Re-export for external use
11
+ var get_resources_js_2 = require("./get-resources.js");
12
+ Object.defineProperty(exports, "getResourcesTool", { enumerable: true, get: function () { return get_resources_js_2.getResourcesTool; } });
13
+ Object.defineProperty(exports, "handleGetResources", { enumerable: true, get: function () { return get_resources_js_2.handleGetResources; } });
14
+ var parse_intent_js_2 = require("./parse-intent.js");
15
+ Object.defineProperty(exports, "parseIntentTool", { enumerable: true, get: function () { return parse_intent_js_2.parseIntentTool; } });
16
+ Object.defineProperty(exports, "handleParseIntent", { enumerable: true, get: function () { return parse_intent_js_2.handleParseIntent; } });
17
+ var create_vm_js_2 = require("./create-vm.js");
18
+ Object.defineProperty(exports, "createVMTool", { enumerable: true, get: function () { return create_vm_js_2.createVMTool; } });
19
+ Object.defineProperty(exports, "handleCreateVM", { enumerable: true, get: function () { return create_vm_js_2.handleCreateVM; } });
20
+ var export_training_data_js_2 = require("./export-training-data.js");
21
+ Object.defineProperty(exports, "exportTrainingDataTool", { enumerable: true, get: function () { return export_training_data_js_2.exportTrainingDataTool; } });
22
+ Object.defineProperty(exports, "handleExportTrainingData", { enumerable: true, get: function () { return export_training_data_js_2.handleExportTrainingData; } });
23
+ var provide_feedback_js_2 = require("./provide-feedback.js");
24
+ Object.defineProperty(exports, "provideFeedbackTool", { enumerable: true, get: function () { return provide_feedback_js_2.provideFeedbackTool; } });
25
+ Object.defineProperty(exports, "handleProvideFeedback", { enumerable: true, get: function () { return provide_feedback_js_2.handleProvideFeedback; } });
26
+ // Collect all tool definitions
27
+ exports.allTools = [
28
+ get_resources_js_1.getResourcesTool,
29
+ parse_intent_js_1.parseIntentTool,
30
+ create_vm_js_1.createVMTool,
31
+ export_training_data_js_1.exportTrainingDataTool,
32
+ provide_feedback_js_1.provideFeedbackTool
33
+ ];
34
+ // Export tool handlers map for easy lookup
35
+ exports.toolHandlers = {
36
+ get_resources: get_resources_js_1.handleGetResources,
37
+ parse_vm_intent: parse_intent_js_1.handleParseIntent,
38
+ create_vm: create_vm_js_1.handleCreateVM,
39
+ export_training_data: export_training_data_js_1.handleExportTrainingData,
40
+ provide_feedback: provide_feedback_js_1.handleProvideFeedback
41
+ };
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleParseIntent = exports.parseIntentTool = void 0;
4
+ const intent_recognition_js_1 = require("../lib/intent-recognition.js");
5
+ const session_js_1 = require("../lib/session.js");
6
+ exports.parseIntentTool = {
7
+ name: "parse_vm_intent",
8
+ description: "Parse natural language VM requests into structured parameters with confidence scoring",
9
+ inputSchema: {
10
+ type: "object",
11
+ properties: {
12
+ naturalLanguageInput: {
13
+ type: "string",
14
+ description: "Natural language description of VM provisioning request"
15
+ }
16
+ },
17
+ required: ["naturalLanguageInput"]
18
+ }
19
+ };
20
+ async function handleParseIntent(args) {
21
+ const startTime = Date.now();
22
+ const { naturalLanguageInput } = args;
23
+ const sessionId = (0, session_js_1.generateSessionId)();
24
+ const parsedIntent = (0, intent_recognition_js_1.parseVMIntent)(naturalLanguageInput);
25
+ const parseTime = Date.now() - startTime;
26
+ // Log interaction for AI training (respects privacy settings)
27
+ (0, session_js_1.logInteraction)({
28
+ session_id: sessionId,
29
+ tool_name: 'parse_vm_intent',
30
+ user_input: { naturalLanguageInput },
31
+ parsed_output: parsedIntent,
32
+ success_metrics: {
33
+ operation_success: parsedIntent.action !== 'unknown',
34
+ confidence_score: parsedIntent.confidence,
35
+ entities_extracted: Object.keys(parsedIntent.entities).length
36
+ },
37
+ timing: {
38
+ parse_duration_ms: parseTime,
39
+ total_duration_ms: parseTime
40
+ }
41
+ });
42
+ return {
43
+ content: [
44
+ {
45
+ type: "text",
46
+ text: JSON.stringify(parsedIntent, null, 2)
47
+ }
48
+ ],
49
+ isError: parsedIntent.action === 'unknown' && parsedIntent.confidence < 0.3
50
+ };
51
+ }
52
+ exports.handleParseIntent = handleParseIntent;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleProvideFeedback = exports.provideFeedbackTool = void 0;
4
+ const session_js_1 = require("../lib/session.js");
5
+ exports.provideFeedbackTool = {
6
+ name: "provide_feedback",
7
+ description: "Provide feedback on intent parsing accuracy to improve future predictions",
8
+ inputSchema: {
9
+ type: "object",
10
+ properties: {
11
+ original_input: {
12
+ type: "string",
13
+ description: "Original natural language input"
14
+ },
15
+ parsed_result: {
16
+ type: "object",
17
+ description: "The parsed result that was incorrect"
18
+ },
19
+ correct_interpretation: {
20
+ type: "object",
21
+ description: "What the correct interpretation should have been"
22
+ },
23
+ feedback_notes: {
24
+ type: "string",
25
+ description: "Additional notes about what went wrong"
26
+ }
27
+ },
28
+ required: ["original_input", "feedback_notes"]
29
+ }
30
+ };
31
+ async function handleProvideFeedback(args) {
32
+ const { original_input, parsed_result, correct_interpretation, feedback_notes } = args;
33
+ const sessionId = (0, session_js_1.generateSessionId)();
34
+ // Log feedback for future model improvements
35
+ (0, session_js_1.logInteraction)({
36
+ session_id: sessionId,
37
+ tool_name: 'provide_feedback',
38
+ user_input: { original_input, feedback_notes },
39
+ parsed_output: { parsed_result, correct_interpretation },
40
+ user_feedback: feedback_notes,
41
+ success_metrics: {
42
+ operation_success: false, // This indicates the original parsing was wrong
43
+ user_satisfaction: 0 // User had to provide feedback = dissatisfied
44
+ }
45
+ });
46
+ return {
47
+ content: [
48
+ {
49
+ type: "text",
50
+ text: JSON.stringify({
51
+ message: "Thank you for the feedback! This will help improve future intent recognition.",
52
+ feedback_recorded: true,
53
+ original_input: original_input,
54
+ feedback_notes: feedback_notes
55
+ }, null, 2)
56
+ }
57
+ ],
58
+ isError: false
59
+ };
60
+ }
61
+ exports.handleProvideFeedback = handleProvideFeedback;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vme-mcp-server",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "VMware vCenter MCP Server - Natural language infrastructure management for Claude",
5
5
  "main": "dist/server.js",
6
6
  "bin": {