vme-mcp-server 0.1.5 → 0.1.7

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,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,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toolHandlers = exports.allTools = exports.handleQueryResources = exports.queryResourcesTool = exports.handleGetCacheStatus = exports.getCacheStatusTool = exports.handleCheckCapability = exports.checkCapabilityTool = exports.handleDiscoverCapabilities = exports.discoverCapabilitiesTool = exports.handleProvideFeedback = exports.provideFeedbackTool = exports.handleExportTrainingData = exports.exportTrainingDataTool = exports.handleCreateVM = exports.createVMTool = exports.handleParseIntent = exports.parseIntentTool = exports.handleGetResources = exports.getResourcesTool = void 0;
4
+ const parse_intent_js_1 = require("./parse-intent.js");
5
+ const create_vm_js_1 = require("./create-vm.js");
6
+ const export_training_data_js_1 = require("./export-training-data.js");
7
+ const provide_feedback_js_1 = require("./provide-feedback.js");
8
+ // Sprint 2: Capability Discovery Tools
9
+ const discover_capabilities_js_1 = require("./discover-capabilities.js");
10
+ const check_capability_js_1 = require("./check-capability.js");
11
+ const get_cache_status_js_1 = require("./get-cache-status.js");
12
+ const query_resources_js_1 = require("./query-resources.js");
13
+ // Re-export for external use
14
+ var get_resources_js_1 = require("./get-resources.js");
15
+ Object.defineProperty(exports, "getResourcesTool", { enumerable: true, get: function () { return get_resources_js_1.getResourcesTool; } });
16
+ Object.defineProperty(exports, "handleGetResources", { enumerable: true, get: function () { return get_resources_js_1.handleGetResources; } });
17
+ var parse_intent_js_2 = require("./parse-intent.js");
18
+ Object.defineProperty(exports, "parseIntentTool", { enumerable: true, get: function () { return parse_intent_js_2.parseIntentTool; } });
19
+ Object.defineProperty(exports, "handleParseIntent", { enumerable: true, get: function () { return parse_intent_js_2.handleParseIntent; } });
20
+ var create_vm_js_2 = require("./create-vm.js");
21
+ Object.defineProperty(exports, "createVMTool", { enumerable: true, get: function () { return create_vm_js_2.createVMTool; } });
22
+ Object.defineProperty(exports, "handleCreateVM", { enumerable: true, get: function () { return create_vm_js_2.handleCreateVM; } });
23
+ var export_training_data_js_2 = require("./export-training-data.js");
24
+ Object.defineProperty(exports, "exportTrainingDataTool", { enumerable: true, get: function () { return export_training_data_js_2.exportTrainingDataTool; } });
25
+ Object.defineProperty(exports, "handleExportTrainingData", { enumerable: true, get: function () { return export_training_data_js_2.handleExportTrainingData; } });
26
+ var provide_feedback_js_2 = require("./provide-feedback.js");
27
+ Object.defineProperty(exports, "provideFeedbackTool", { enumerable: true, get: function () { return provide_feedback_js_2.provideFeedbackTool; } });
28
+ Object.defineProperty(exports, "handleProvideFeedback", { enumerable: true, get: function () { return provide_feedback_js_2.handleProvideFeedback; } });
29
+ var discover_capabilities_js_2 = require("./discover-capabilities.js");
30
+ Object.defineProperty(exports, "discoverCapabilitiesTool", { enumerable: true, get: function () { return discover_capabilities_js_2.discoverCapabilitiesTool; } });
31
+ Object.defineProperty(exports, "handleDiscoverCapabilities", { enumerable: true, get: function () { return discover_capabilities_js_2.handleDiscoverCapabilities; } });
32
+ var check_capability_js_2 = require("./check-capability.js");
33
+ Object.defineProperty(exports, "checkCapabilityTool", { enumerable: true, get: function () { return check_capability_js_2.checkCapabilityTool; } });
34
+ Object.defineProperty(exports, "handleCheckCapability", { enumerable: true, get: function () { return check_capability_js_2.handleCheckCapability; } });
35
+ var get_cache_status_js_2 = require("./get-cache-status.js");
36
+ Object.defineProperty(exports, "getCacheStatusTool", { enumerable: true, get: function () { return get_cache_status_js_2.getCacheStatusTool; } });
37
+ Object.defineProperty(exports, "handleGetCacheStatus", { enumerable: true, get: function () { return get_cache_status_js_2.handleGetCacheStatus; } });
38
+ var query_resources_js_2 = require("./query-resources.js");
39
+ Object.defineProperty(exports, "queryResourcesTool", { enumerable: true, get: function () { return query_resources_js_2.queryResourcesTool; } });
40
+ Object.defineProperty(exports, "handleQueryResources", { enumerable: true, get: function () { return query_resources_js_2.handleQueryResources; } });
41
+ // Collect all tool definitions
42
+ exports.allTools = [
43
+ // Sprint 1.5 tools
44
+ // getResourcesTool, // DISABLED - caused 37K+ token responses, replaced by Sprint 2 capability discovery
45
+ parse_intent_js_1.parseIntentTool,
46
+ create_vm_js_1.createVMTool,
47
+ export_training_data_js_1.exportTrainingDataTool,
48
+ provide_feedback_js_1.provideFeedbackTool,
49
+ // Sprint 2 capability discovery tools
50
+ discover_capabilities_js_1.discoverCapabilitiesTool,
51
+ check_capability_js_1.checkCapabilityTool,
52
+ get_cache_status_js_1.getCacheStatusTool,
53
+ query_resources_js_1.queryResourcesTool
54
+ ];
55
+ // Export tool handlers map for easy lookup
56
+ exports.toolHandlers = {
57
+ // Sprint 1.5 handlers
58
+ // get_resources: handleGetResources, // DISABLED - caused 37K+ token responses
59
+ parse_vm_intent: parse_intent_js_1.handleParseIntent,
60
+ create_vm: create_vm_js_1.handleCreateVM,
61
+ export_training_data: export_training_data_js_1.handleExportTrainingData,
62
+ provide_feedback: provide_feedback_js_1.handleProvideFeedback,
63
+ // Sprint 2 capability discovery handlers
64
+ discover_capabilities: discover_capabilities_js_1.handleDiscoverCapabilities,
65
+ check_capability: check_capability_js_1.handleCheckCapability,
66
+ get_cache_status: get_cache_status_js_1.handleGetCacheStatus,
67
+ query_resources: query_resources_js_1.handleQueryResources
68
+ };
@@ -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,248 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleQueryResources = exports.queryResourcesTool = void 0;
4
+ const api_utils_js_1 = require("../lib/api-utils.js");
5
+ exports.queryResourcesTool = {
6
+ name: "query_resources",
7
+ description: "Query actual infrastructure resources (VMs, hosts, networks) with natural language. Use discover_capabilities first to learn available OS types, groups, and statuses in your environment.",
8
+ inputSchema: {
9
+ type: "object",
10
+ properties: {
11
+ natural_query: {
12
+ type: "string",
13
+ description: "Natural language query like 'Windows VMs', 'stopped VMs in production', 'any VMs?', 'Ubuntu hosts', 'VMs in development group'"
14
+ },
15
+ limit: {
16
+ type: "number",
17
+ description: "Maximum number of results to return (default: 10, max: 100)",
18
+ default: 10
19
+ }
20
+ },
21
+ required: ["natural_query"]
22
+ }
23
+ };
24
+ function parseResourceQuery(query, limit = 10) {
25
+ const q = query.toLowerCase().trim();
26
+ // Determine resource type
27
+ let resource = 'instances'; // default
28
+ if (q.includes('host') || q.includes('server') || q.includes('node')) {
29
+ resource = 'hosts';
30
+ }
31
+ else if (q.includes('network')) {
32
+ resource = 'networks';
33
+ }
34
+ // Determine action
35
+ let action = 'list';
36
+ if (q.includes('how many') || q.includes('count')) {
37
+ action = 'count';
38
+ }
39
+ else if (q.includes('any ') || q.includes('summary')) {
40
+ action = 'summary';
41
+ }
42
+ // Extract filters
43
+ const filters = {};
44
+ // OS Type patterns
45
+ if (q.includes('windows'))
46
+ filters.osType = 'windows';
47
+ if (q.includes('linux'))
48
+ filters.osType = 'linux';
49
+ if (q.includes('ubuntu'))
50
+ filters.osType = 'ubuntu';
51
+ if (q.includes('centos'))
52
+ filters.osType = 'centos';
53
+ if (q.includes('rocky'))
54
+ filters.osType = 'rocky';
55
+ if (q.includes('debian'))
56
+ filters.osType = 'debian';
57
+ if (q.includes('rhel'))
58
+ filters.osType = 'rhel';
59
+ // Status patterns
60
+ if (q.includes('running'))
61
+ filters.status = 'running';
62
+ if (q.includes('stopped'))
63
+ filters.status = 'stopped';
64
+ if (q.includes('failed') || q.includes('error'))
65
+ filters.status = 'failed';
66
+ if (q.includes('provisioning'))
67
+ filters.status = 'provisioning';
68
+ // Group patterns
69
+ if (q.includes('production') || q.includes('prod'))
70
+ filters.group = 'production';
71
+ if (q.includes('development') || q.includes('dev'))
72
+ filters.group = 'development';
73
+ if (q.includes('test') || q.includes('testing'))
74
+ filters.group = 'test';
75
+ // Name patterns (exact matches)
76
+ const nameMatch = q.match(/named?\s+["']?([a-zA-Z0-9\-_]+)["']?/);
77
+ if (nameMatch) {
78
+ filters.name = nameMatch[1];
79
+ }
80
+ return { resource, action, filters, limit };
81
+ }
82
+ function filterResults(data, filters) {
83
+ return data.filter(item => {
84
+ // OS Type filtering
85
+ if (filters.osType) {
86
+ const itemOS = item.osType?.toLowerCase() || '';
87
+ const filterOS = filters.osType.toLowerCase();
88
+ if (filterOS === 'windows' && !itemOS.includes('windows'))
89
+ return false;
90
+ if (filterOS === 'linux' && !itemOS.includes('linux') && !itemOS.includes('ubuntu') && !itemOS.includes('centos') && !itemOS.includes('rocky') && !itemOS.includes('debian') && !itemOS.includes('rhel'))
91
+ return false;
92
+ if (filterOS !== 'windows' && filterOS !== 'linux' && !itemOS.includes(filterOS))
93
+ return false;
94
+ }
95
+ // Status filtering
96
+ if (filters.status) {
97
+ const itemStatus = item.status?.toLowerCase() || '';
98
+ if (!itemStatus.includes(filters.status.toLowerCase()))
99
+ return false;
100
+ }
101
+ // Group filtering
102
+ if (filters.group) {
103
+ const itemGroup = item.group?.name?.toLowerCase() || item.site?.name?.toLowerCase() || '';
104
+ if (!itemGroup.includes(filters.group.toLowerCase()))
105
+ return false;
106
+ }
107
+ // Name filtering
108
+ if (filters.name) {
109
+ const itemName = item.name?.toLowerCase() || '';
110
+ if (!itemName.includes(filters.name.toLowerCase()))
111
+ return false;
112
+ }
113
+ return true;
114
+ });
115
+ }
116
+ function formatResponse(parsedQuery, results, totalCount) {
117
+ const { action, resource, filters } = parsedQuery;
118
+ if (action === 'count') {
119
+ return {
120
+ action: 'count',
121
+ resource: resource,
122
+ filters_applied: filters,
123
+ total_count: results.length,
124
+ query_summary: `Found ${results.length} ${resource} matching criteria`
125
+ };
126
+ }
127
+ if (action === 'summary') {
128
+ const statusCounts = {};
129
+ const osCounts = {};
130
+ results.forEach(item => {
131
+ const status = item.status || 'unknown';
132
+ const os = item.osType || 'unknown';
133
+ statusCounts[status] = (statusCounts[status] || 0) + 1;
134
+ osCounts[os] = (osCounts[os] || 0) + 1;
135
+ });
136
+ return {
137
+ action: 'summary',
138
+ resource: resource,
139
+ filters_applied: filters,
140
+ total_count: results.length,
141
+ summary: {
142
+ by_status: statusCounts,
143
+ by_os_type: osCounts
144
+ },
145
+ query_summary: `Found ${results.length} ${resource} matching criteria`
146
+ };
147
+ }
148
+ // Default: list action
149
+ const limitedResults = results.slice(0, parsedQuery.limit);
150
+ return {
151
+ action: 'list',
152
+ resource: resource,
153
+ filters_applied: filters,
154
+ total_count: results.length,
155
+ returned_count: limitedResults.length,
156
+ items: limitedResults.map(item => ({
157
+ id: item.id,
158
+ name: item.name,
159
+ status: item.status,
160
+ osType: item.osType,
161
+ group: item.group?.name || item.site?.name || 'unknown',
162
+ ...(resource === 'instances' && {
163
+ plan: item.plan?.name,
164
+ powerState: item.powerState,
165
+ ipAddress: item.externalIp || item.internalIp
166
+ })
167
+ })),
168
+ query_summary: `Showing ${limitedResults.length} of ${results.length} ${resource} matching criteria`
169
+ };
170
+ }
171
+ async function handleQueryResources(args) {
172
+ try {
173
+ const { natural_query, limit = 10 } = args;
174
+ if (!natural_query || typeof natural_query !== 'string') {
175
+ return {
176
+ content: [
177
+ {
178
+ type: "text",
179
+ text: JSON.stringify({
180
+ error: "Invalid input",
181
+ message: "natural_query parameter is required and must be a string",
182
+ examples: ["any VMs?", "Windows VMs", "stopped VMs in production", "Ubuntu hosts"]
183
+ }, null, 2)
184
+ }
185
+ ],
186
+ isError: true
187
+ };
188
+ }
189
+ const parsedQuery = parseResourceQuery(natural_query, Math.min(limit, 100));
190
+ // Map resource type to API endpoint
191
+ const endpointMap = {
192
+ 'instances': '/instances',
193
+ 'hosts': '/servers',
194
+ 'networks': '/networks'
195
+ };
196
+ const endpoint = endpointMap[parsedQuery.resource];
197
+ // Query the VME API
198
+ const response = await api_utils_js_1.api.get(endpoint);
199
+ // Extract data array from response
200
+ let rawData = [];
201
+ if (parsedQuery.resource === 'instances' && response.data.instances) {
202
+ rawData = response.data.instances;
203
+ }
204
+ else if (parsedQuery.resource === 'hosts' && response.data.servers) {
205
+ rawData = response.data.servers;
206
+ }
207
+ else if (parsedQuery.resource === 'networks' && response.data.networks) {
208
+ rawData = response.data.networks;
209
+ }
210
+ else {
211
+ // Fallback: try to find array in response
212
+ const possibleArrays = Object.values(response.data).filter(Array.isArray);
213
+ if (possibleArrays.length > 0) {
214
+ rawData = possibleArrays[0];
215
+ }
216
+ }
217
+ // Apply filters
218
+ const filteredResults = filterResults(rawData, parsedQuery.filters);
219
+ // Format response based on action
220
+ const formattedResponse = formatResponse(parsedQuery, filteredResults, rawData.length);
221
+ return {
222
+ content: [
223
+ {
224
+ type: "text",
225
+ text: JSON.stringify(formattedResponse, null, 2)
226
+ }
227
+ ],
228
+ isError: false
229
+ };
230
+ }
231
+ catch (error) {
232
+ return {
233
+ content: [
234
+ {
235
+ type: "text",
236
+ text: JSON.stringify({
237
+ error: "Resource query failed",
238
+ message: error.message,
239
+ natural_query: args?.natural_query || "unknown",
240
+ suggestion: "Check VME API connectivity or try discover_capabilities first to see available resources"
241
+ }, null, 2)
242
+ }
243
+ ],
244
+ isError: true
245
+ };
246
+ }
247
+ }
248
+ exports.handleQueryResources = handleQueryResources;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vme-mcp-server",
3
- "version": "0.1.5",
4
- "description": "VMware vCenter MCP Server - Natural language infrastructure management for Claude",
3
+ "version": "0.1.7",
4
+ "description": "",
5
5
  "main": "dist/server.js",
6
6
  "bin": {
7
7
  "vme-mcp-server": "./dist/server.js"
@@ -47,8 +47,8 @@
47
47
  },
48
48
  "devDependencies": {
49
49
  "@types/node": "^22.15.29",
50
+ "chai": "^5.2.0",
50
51
  "mocha": "^10.2.0",
51
52
  "nyc": "^15.1.0"
52
- },
53
- "description": ""
53
+ }
54
54
  }