vme-mcp-server 0.1.9 → 0.1.12
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/dist/README.md +1 -1
- package/dist/lib/api-utils.js +41 -32
- package/dist/lib/capability-cache.js +4 -8
- package/dist/lib/capability-discovery.js +12 -16
- package/dist/lib/intent-recognition.js +3 -7
- package/dist/lib/name-resolver.js +4 -8
- package/dist/lib/session.js +9 -14
- package/dist/lib/vm-parsing.js +2 -7
- package/dist/server.js +29 -28
- package/dist/server_old.js +18 -23
- package/dist/tools/check-capability.js +4 -8
- package/dist/tools/create-vm.js +24 -28
- package/dist/tools/discover-capabilities.js +4 -8
- package/dist/tools/export-training-data.js +8 -12
- package/dist/tools/get-cache-status.js +5 -9
- package/dist/tools/get-resources.js +4 -8
- package/dist/tools/index.js +35 -56
- package/dist/tools/parse-intent.js +7 -11
- package/dist/tools/provide-feedback.js +5 -9
- package/dist/tools/query-resources.js +4 -8
- package/dist/types/interfaces.js +1 -2
- package/package.json +15 -7
package/dist/README.md
CHANGED
package/dist/lib/api-utils.js
CHANGED
@@ -1,23 +1,35 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
1
|
+
import axios from "axios";
|
2
|
+
// Lazy axios instance creation to ensure environment variables are loaded
|
3
|
+
let _api = null;
|
4
|
+
function createApiInstance() {
|
5
|
+
if (!_api) {
|
6
|
+
console.log('VME API Configuration:');
|
7
|
+
console.log(' Base URL:', process.env.VME_API_BASE_URL);
|
8
|
+
console.log(' Token:', process.env.VME_API_TOKEN ? '***configured***' : 'NOT SET');
|
9
|
+
if (!process.env.VME_API_BASE_URL || !process.env.VME_API_TOKEN) {
|
10
|
+
throw new Error('VME API credentials not configured. Please check your .env file.');
|
11
|
+
}
|
12
|
+
_api = axios.create({
|
13
|
+
baseURL: process.env.VME_API_BASE_URL,
|
14
|
+
headers: {
|
15
|
+
Authorization: `Bearer ${process.env.VME_API_TOKEN}`,
|
16
|
+
"Content-Type": "application/json"
|
17
|
+
}
|
18
|
+
});
|
14
19
|
}
|
15
|
-
|
20
|
+
return _api;
|
21
|
+
}
|
22
|
+
export const api = {
|
23
|
+
get: (url) => createApiInstance().get(url),
|
24
|
+
post: (url, data) => createApiInstance().post(url, data),
|
25
|
+
put: (url, data) => createApiInstance().put(url, data),
|
26
|
+
delete: (url) => createApiInstance().delete(url)
|
27
|
+
};
|
16
28
|
// Helper function to get available cluster nodes (hypervisor hosts, not VMs)
|
17
|
-
async function getClusterNodes() {
|
29
|
+
export async function getClusterNodes() {
|
18
30
|
try {
|
19
31
|
// Get actual cluster hypervisor nodes from /clusters endpoint
|
20
|
-
const clusters = await
|
32
|
+
const clusters = await api.get("/clusters");
|
21
33
|
let allNodes = [];
|
22
34
|
if (clusters.data.clusters) {
|
23
35
|
for (const cluster of clusters.data.clusters) {
|
@@ -41,14 +53,13 @@ async function getClusterNodes() {
|
|
41
53
|
console.warn('Using fallback hypervisor nodes [1, 2, 3] - could not detect cluster hosts');
|
42
54
|
return [1, 2, 3];
|
43
55
|
}
|
44
|
-
exports.getClusterNodes = getClusterNodes;
|
45
56
|
// Resolve user input parameters to VME API resource IDs
|
46
|
-
async function resolveInput({ group, cloud, template, size }) {
|
57
|
+
export async function resolveInput({ group, cloud, template, size }) {
|
47
58
|
const [groups, zones, instanceTypes, servicePlans] = await Promise.all([
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
59
|
+
api.get("/groups"),
|
60
|
+
api.get("/zones"),
|
61
|
+
api.get("/instance-types"),
|
62
|
+
api.get("/service-plans")
|
52
63
|
]);
|
53
64
|
// Find group (case-insensitive)
|
54
65
|
const foundGroup = groups.data.groups.find((g) => g.name.toLowerCase() === group.toLowerCase());
|
@@ -61,7 +72,7 @@ async function resolveInput({ group, cloud, template, size }) {
|
|
61
72
|
let selectedImage;
|
62
73
|
const templateLower = template.toLowerCase();
|
63
74
|
// Get available images to find the right one
|
64
|
-
const images = await
|
75
|
+
const images = await api.get("/virtual-images");
|
65
76
|
if (templateLower.includes('ubuntu')) {
|
66
77
|
// Find Ubuntu images using osType.category and prefer latest version
|
67
78
|
const ubuntuImages = images.data.virtualImages.filter((img) => img.osType && img.osType.category === 'ubuntu').sort((a, b) => {
|
@@ -156,18 +167,17 @@ async function resolveInput({ group, cloud, template, size }) {
|
|
156
167
|
availableZones: zones.data.zones.map((z) => z.name)
|
157
168
|
};
|
158
169
|
}
|
159
|
-
exports.resolveInput = resolveInput;
|
160
170
|
// Unified resource discovery function
|
161
|
-
async function getResources(type, intent, role) {
|
171
|
+
export async function getResources(type, intent, role) {
|
162
172
|
try {
|
163
173
|
// Fetch all resource types in parallel for comprehensive discovery
|
164
174
|
const [groups, zones, instanceTypes, servicePlans, virtualImages, clusters] = await Promise.all([
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
175
|
+
api.get("/groups"),
|
176
|
+
api.get("/zones"),
|
177
|
+
api.get("/instance-types"),
|
178
|
+
api.get("/service-plans"),
|
179
|
+
api.get("/virtual-images"),
|
180
|
+
api.get("/clusters")
|
171
181
|
]);
|
172
182
|
const allResources = {
|
173
183
|
groups: groups.data.groups || [],
|
@@ -261,4 +271,3 @@ async function getResources(type, intent, role) {
|
|
261
271
|
};
|
262
272
|
}
|
263
273
|
}
|
264
|
-
exports.getResources = getResources;
|
@@ -1,9 +1,6 @@
|
|
1
|
-
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.capabilityCache = exports.SmartCapabilityCache = void 0;
|
4
|
-
const api_utils_js_1 = require("./api-utils.js");
|
1
|
+
import { api } from "./api-utils.js";
|
5
2
|
// Smart capability cache with field-level TTL
|
6
|
-
class SmartCapabilityCache {
|
3
|
+
export class SmartCapabilityCache {
|
7
4
|
constructor() {
|
8
5
|
this.cache = new Map();
|
9
6
|
// TTL configuration based on VME resource change patterns
|
@@ -34,7 +31,7 @@ class SmartCapabilityCache {
|
|
34
31
|
// Fetch fresh data from VME API
|
35
32
|
const endpoint = this.getEndpointForField(fieldName);
|
36
33
|
try {
|
37
|
-
const response = await
|
34
|
+
const response = await api.get(endpoint);
|
38
35
|
// Store in cache with appropriate TTL
|
39
36
|
const cacheEntry = {
|
40
37
|
data: response.data,
|
@@ -126,6 +123,5 @@ class SmartCapabilityCache {
|
|
126
123
|
return endpointMap[fieldName] || `/${fieldName}`;
|
127
124
|
}
|
128
125
|
}
|
129
|
-
exports.SmartCapabilityCache = SmartCapabilityCache;
|
130
126
|
// Global cache instance
|
131
|
-
|
127
|
+
export const capabilityCache = new SmartCapabilityCache();
|
@@ -1,9 +1,6 @@
|
|
1
|
-
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.capabilityDiscovery = exports.CapabilityDiscoveryEngine = void 0;
|
4
|
-
const capability_cache_js_1 = require("./capability-cache.js");
|
1
|
+
import { capabilityCache } from "./capability-cache.js";
|
5
2
|
// Capability discovery engine
|
6
|
-
class CapabilityDiscoveryEngine {
|
3
|
+
export class CapabilityDiscoveryEngine {
|
7
4
|
/**
|
8
5
|
* Discover capabilities for specified domains
|
9
6
|
*/
|
@@ -108,10 +105,10 @@ class CapabilityDiscoveryEngine {
|
|
108
105
|
// Private discovery methods for each domain
|
109
106
|
async discoverComputeCapabilities(forceRefresh = false) {
|
110
107
|
const [clusters, servicePlans, instanceTypes, virtualImages] = await Promise.all([
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
108
|
+
capabilityCache.getField("clusters", forceRefresh),
|
109
|
+
capabilityCache.getField("service_plans", forceRefresh),
|
110
|
+
capabilityCache.getField("instance_types", forceRefresh),
|
111
|
+
capabilityCache.getField("virtual_images", forceRefresh),
|
115
112
|
]);
|
116
113
|
// Derive hypervisors from cluster data
|
117
114
|
const hypervisors = new Set();
|
@@ -172,8 +169,8 @@ class CapabilityDiscoveryEngine {
|
|
172
169
|
}
|
173
170
|
async discoverNetworkingCapabilities(forceRefresh = false) {
|
174
171
|
const [zones, networks] = await Promise.all([
|
175
|
-
|
176
|
-
|
172
|
+
capabilityCache.getField("zones", forceRefresh),
|
173
|
+
capabilityCache.getField("networks", forceRefresh).catch(() => null), // Optional
|
177
174
|
]);
|
178
175
|
const zoneList = zones?.zones?.map((zone) => ({
|
179
176
|
id: zone.id,
|
@@ -189,7 +186,7 @@ class CapabilityDiscoveryEngine {
|
|
189
186
|
}
|
190
187
|
async discoverStorageCapabilities(forceRefresh = false) {
|
191
188
|
// Get real data from VME API
|
192
|
-
const servicePlans = await
|
189
|
+
const servicePlans = await capabilityCache.getField("service_plans", forceRefresh);
|
193
190
|
// Derive storage capabilities from actual service plans and other data
|
194
191
|
const storageTypes = new Set();
|
195
192
|
let maxVolumeSize = "1TB"; // Default
|
@@ -214,7 +211,7 @@ class CapabilityDiscoveryEngine {
|
|
214
211
|
};
|
215
212
|
}
|
216
213
|
async discoverPlatformCapabilities(forceRefresh = false) {
|
217
|
-
const groups = await
|
214
|
+
const groups = await capabilityCache.getField("groups", forceRefresh);
|
218
215
|
const groupList = groups?.groups?.map((group) => ({
|
219
216
|
id: group.id,
|
220
217
|
name: group.name,
|
@@ -227,7 +224,7 @@ class CapabilityDiscoveryEngine {
|
|
227
224
|
};
|
228
225
|
}
|
229
226
|
getCacheStatusSummary() {
|
230
|
-
const statuses =
|
227
|
+
const statuses = capabilityCache.getCacheStatus();
|
231
228
|
return statuses.map(status => ({
|
232
229
|
field: status.field_name,
|
233
230
|
fresh: status.is_fresh,
|
@@ -235,6 +232,5 @@ class CapabilityDiscoveryEngine {
|
|
235
232
|
}));
|
236
233
|
}
|
237
234
|
}
|
238
|
-
exports.CapabilityDiscoveryEngine = CapabilityDiscoveryEngine;
|
239
235
|
// Global discovery engine instance
|
240
|
-
|
236
|
+
export const capabilityDiscovery = new CapabilityDiscoveryEngine();
|
@@ -1,9 +1,6 @@
|
|
1
|
-
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.parseVMIntent = void 0;
|
4
|
-
const vm_parsing_js_1 = require("./vm-parsing.js");
|
1
|
+
import { parseVMNames } from "./vm-parsing.js";
|
5
2
|
// Intent recognition system for natural language processing
|
6
|
-
function parseVMIntent(naturalLanguageInput) {
|
3
|
+
export function parseVMIntent(naturalLanguageInput) {
|
7
4
|
const input = naturalLanguageInput.toLowerCase().trim();
|
8
5
|
const result = {
|
9
6
|
action: 'unknown',
|
@@ -71,7 +68,7 @@ function parseVMIntent(naturalLanguageInput) {
|
|
71
68
|
const match = input.match(pattern);
|
72
69
|
if (match) {
|
73
70
|
const nameInput = match[1] || match[2];
|
74
|
-
result.entities.vmNames =
|
71
|
+
result.entities.vmNames = parseVMNames(nameInput);
|
75
72
|
break;
|
76
73
|
}
|
77
74
|
}
|
@@ -156,4 +153,3 @@ function parseVMIntent(naturalLanguageInput) {
|
|
156
153
|
}
|
157
154
|
return result;
|
158
155
|
}
|
159
|
-
exports.parseVMIntent = parseVMIntent;
|
@@ -1,9 +1,6 @@
|
|
1
|
-
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.nameResolver = exports.NameResolver = void 0;
|
4
|
-
const capability_discovery_js_1 = require("./capability-discovery.js");
|
1
|
+
import { capabilityDiscovery } from "./capability-discovery.js";
|
5
2
|
// Generic name->ID resolver using capability discovery data
|
6
|
-
class NameResolver {
|
3
|
+
export class NameResolver {
|
7
4
|
constructor() {
|
8
5
|
this.capabilitiesCache = null;
|
9
6
|
this.cacheTimestamp = 0;
|
@@ -12,7 +9,7 @@ class NameResolver {
|
|
12
9
|
async getCapabilities() {
|
13
10
|
const now = Date.now();
|
14
11
|
if (!this.capabilitiesCache || (now - this.cacheTimestamp) > this.CACHE_TTL) {
|
15
|
-
this.capabilitiesCache = await
|
12
|
+
this.capabilitiesCache = await capabilityDiscovery.discoverCapabilities(['all']);
|
16
13
|
this.cacheTimestamp = now;
|
17
14
|
}
|
18
15
|
return this.capabilitiesCache;
|
@@ -169,6 +166,5 @@ class NameResolver {
|
|
169
166
|
return results;
|
170
167
|
}
|
171
168
|
}
|
172
|
-
exports.NameResolver = NameResolver;
|
173
169
|
// Global resolver instance
|
174
|
-
|
170
|
+
export const nameResolver = new NameResolver();
|
package/dist/lib/session.js
CHANGED
@@ -1,27 +1,23 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
exports.logInteraction = exports.generateSessionId = void 0;
|
4
|
-
const fs_1 = require("fs");
|
5
|
-
const path_1 = require("path");
|
1
|
+
import { writeFileSync, existsSync, mkdirSync } from "fs";
|
2
|
+
import { join } from "path";
|
6
3
|
// AI Training Data Collection Configuration
|
7
4
|
const AI_TRAINING_ENABLED = process.env.ENABLE_AI_TRAINING_DATA === 'true';
|
8
5
|
const AI_TRAINING_FIELDS = (process.env.AI_TRAINING_DATA_FIELDS || 'user_input,parsed_output,success_metrics').split(',');
|
9
6
|
const AI_TRAINING_RETENTION_DAYS = parseInt(process.env.AI_TRAINING_DATA_RETENTION_DAYS || '30');
|
10
7
|
// Generate session ID for interaction tracking
|
11
|
-
function generateSessionId() {
|
8
|
+
export function generateSessionId() {
|
12
9
|
return `session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
13
10
|
}
|
14
|
-
exports.generateSessionId = generateSessionId;
|
15
11
|
// Privacy-aware interaction logging
|
16
|
-
function logInteraction(interaction) {
|
12
|
+
export function logInteraction(interaction) {
|
17
13
|
if (!AI_TRAINING_ENABLED) {
|
18
14
|
return; // Respect user privacy choice
|
19
15
|
}
|
20
16
|
try {
|
21
17
|
// Ensure logs directory exists
|
22
|
-
const logsDir =
|
23
|
-
if (!
|
24
|
-
|
18
|
+
const logsDir = join(process.cwd(), 'ai-training-logs');
|
19
|
+
if (!existsSync(logsDir)) {
|
20
|
+
mkdirSync(logsDir, { recursive: true });
|
25
21
|
}
|
26
22
|
// Filter fields based on user preferences
|
27
23
|
const filteredInteraction = {
|
@@ -47,13 +43,12 @@ function logInteraction(interaction) {
|
|
47
43
|
filteredInteraction.timing = interaction.timing;
|
48
44
|
}
|
49
45
|
// Append to daily log file (JSONL format)
|
50
|
-
const logFile =
|
46
|
+
const logFile = join(logsDir, `interactions-${new Date().toISOString().split('T')[0]}.jsonl`);
|
51
47
|
const logEntry = JSON.stringify(filteredInteraction) + '\n';
|
52
|
-
|
48
|
+
writeFileSync(logFile, logEntry, { flag: 'a' });
|
53
49
|
}
|
54
50
|
catch (error) {
|
55
51
|
// Fail silently to not disrupt user experience
|
56
52
|
console.warn('AI training data logging failed:', error);
|
57
53
|
}
|
58
54
|
}
|
59
|
-
exports.logInteraction = logInteraction;
|
package/dist/lib/vm-parsing.js
CHANGED
@@ -1,8 +1,5 @@
|
|
1
|
-
"use strict";
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.calculateNodeAssignments = exports.parseVMNames = void 0;
|
4
1
|
// Helper function to parse VM name patterns
|
5
|
-
function parseVMNames(nameInput, count) {
|
2
|
+
export function parseVMNames(nameInput, count) {
|
6
3
|
// Handle letter range patterns like "ws-a->ws-x" or "ws-a -> ws-x"
|
7
4
|
const letterRangeMatch = nameInput.match(/^(.+?)([a-z])\s*->\s*(.+?)([a-z])$/i);
|
8
5
|
if (letterRangeMatch) {
|
@@ -62,9 +59,8 @@ function parseVMNames(nameInput, count) {
|
|
62
59
|
// Single VM
|
63
60
|
return [nameInput];
|
64
61
|
}
|
65
|
-
exports.parseVMNames = parseVMNames;
|
66
62
|
// Determine node assignment strategy for VMs
|
67
|
-
function calculateNodeAssignments(vmNames, nodes, distribution) {
|
63
|
+
export function calculateNodeAssignments(vmNames, nodes, distribution) {
|
68
64
|
let nodeAssignments = [];
|
69
65
|
if (distribution === 'spread' || (vmNames.length > 1 && !distribution)) {
|
70
66
|
// Distribute VMs across all available nodes
|
@@ -87,4 +83,3 @@ function calculateNodeAssignments(vmNames, nodes, distribution) {
|
|
87
83
|
}
|
88
84
|
return nodeAssignments;
|
89
85
|
}
|
90
|
-
exports.calculateNodeAssignments = calculateNodeAssignments;
|
package/dist/server.js
CHANGED
@@ -1,35 +1,36 @@
|
|
1
1
|
#!/usr/bin/env node
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
};
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
const
|
14
|
-
const
|
15
|
-
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
5
|
+
import dotenv from "dotenv";
|
6
|
+
import { existsSync } from "fs";
|
7
|
+
import { join } from "path";
|
8
|
+
import { homedir } from "os";
|
9
|
+
import { readFileSync } from "fs";
|
10
|
+
import { allTools, toolHandlers } from "./tools/index.js";
|
11
|
+
// Get version from package.json
|
12
|
+
function getPackageVersion() {
|
13
|
+
const packagePath = new URL('../package.json', import.meta.url);
|
14
|
+
const packageJson = JSON.parse(readFileSync(packagePath, 'utf8'));
|
15
|
+
return packageJson.version;
|
16
|
+
}
|
16
17
|
// Load environment variables from multiple locations for global install support
|
17
18
|
function loadEnvironmentConfig() {
|
18
19
|
// Priority order for .env file locations:
|
19
20
|
const envPaths = [
|
20
21
|
// 1. Current working directory (for local development)
|
21
|
-
|
22
|
+
join(process.cwd(), '.env'),
|
22
23
|
// 2. Home directory (for global installs)
|
23
|
-
|
24
|
+
join(homedir(), '.env'),
|
24
25
|
// 3. XDG config directory (Linux/Mac standard)
|
25
|
-
|
26
|
+
join(homedir(), '.config', 'vme-mcp-server', '.env'),
|
26
27
|
// 4. User's Documents folder (Windows-friendly)
|
27
|
-
|
28
|
+
join(homedir(), 'Documents', '.env.vme-mcp-server')
|
28
29
|
];
|
29
30
|
// Try to load .env from the first available location
|
30
31
|
for (const envPath of envPaths) {
|
31
|
-
if (
|
32
|
-
|
32
|
+
if (existsSync(envPath)) {
|
33
|
+
dotenv.config({ path: envPath });
|
33
34
|
console.error(`VME MCP: Loaded config from ${envPath}`);
|
34
35
|
return;
|
35
36
|
}
|
@@ -41,25 +42,25 @@ loadEnvironmentConfig();
|
|
41
42
|
// Disable TLS verification for VME API (if needed)
|
42
43
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
43
44
|
// Create VME MCP server with modular architecture
|
44
|
-
const server = new
|
45
|
+
const server = new Server({
|
45
46
|
name: "vme-mcp-server",
|
46
|
-
version:
|
47
|
+
version: getPackageVersion(),
|
47
48
|
}, {
|
48
49
|
capabilities: {
|
49
50
|
tools: {},
|
50
51
|
},
|
51
52
|
});
|
52
53
|
// Register all tools using the modular tool definitions
|
53
|
-
server.setRequestHandler(
|
54
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
54
55
|
return {
|
55
|
-
tools:
|
56
|
+
tools: allTools,
|
56
57
|
};
|
57
58
|
});
|
58
59
|
// Handle tool calls using the modular tool handlers
|
59
|
-
server.setRequestHandler(
|
60
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
60
61
|
const { name, arguments: args } = request.params;
|
61
62
|
// Look up the handler for this tool
|
62
|
-
const handler =
|
63
|
+
const handler = toolHandlers[name];
|
63
64
|
if (!handler) {
|
64
65
|
throw new Error(`Unknown tool: ${name}`);
|
65
66
|
}
|
@@ -68,9 +69,9 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
68
69
|
});
|
69
70
|
// Start the server
|
70
71
|
async function main() {
|
71
|
-
const transport = new
|
72
|
+
const transport = new StdioServerTransport();
|
72
73
|
await server.connect(transport);
|
73
|
-
console.error(
|
74
|
+
console.error(`VME MCP Server v${getPackageVersion()} running on stdio with modular architecture`);
|
74
75
|
}
|
75
76
|
main().catch((error) => {
|
76
77
|
console.error("Failed to start server:", error);
|
package/dist/server_old.js
CHANGED
@@ -1,15 +1,10 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
const axios_1 = __importDefault(require("axios"));
|
9
|
-
const dotenv_1 = __importDefault(require("dotenv"));
|
10
|
-
const fs_1 = require("fs");
|
11
|
-
const path_1 = require("path");
|
12
|
-
dotenv_1.default.config();
|
1
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
3
|
+
import axios from "axios";
|
4
|
+
import dotenv from "dotenv";
|
5
|
+
import { writeFileSync, readFileSync, existsSync, mkdirSync } from "fs";
|
6
|
+
import { join } from "path";
|
7
|
+
dotenv.config();
|
13
8
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
14
9
|
// AI Training Data Collection Configuration
|
15
10
|
const AI_TRAINING_ENABLED = process.env.ENABLE_AI_TRAINING_DATA === 'true';
|
@@ -22,9 +17,9 @@ function logInteraction(interaction) {
|
|
22
17
|
}
|
23
18
|
try {
|
24
19
|
// Ensure logs directory exists
|
25
|
-
const logsDir =
|
26
|
-
if (!
|
27
|
-
|
20
|
+
const logsDir = join(process.cwd(), 'ai-training-logs');
|
21
|
+
if (!existsSync(logsDir)) {
|
22
|
+
mkdirSync(logsDir, { recursive: true });
|
28
23
|
}
|
29
24
|
// Filter fields based on user preferences
|
30
25
|
const filteredInteraction = {
|
@@ -50,9 +45,9 @@ function logInteraction(interaction) {
|
|
50
45
|
filteredInteraction.timing = interaction.timing;
|
51
46
|
}
|
52
47
|
// Append to daily log file (JSONL format)
|
53
|
-
const logFile =
|
48
|
+
const logFile = join(logsDir, `interactions-${new Date().toISOString().split('T')[0]}.jsonl`);
|
54
49
|
const logEntry = JSON.stringify(filteredInteraction) + '\n';
|
55
|
-
|
50
|
+
writeFileSync(logFile, logEntry, { flag: 'a' });
|
56
51
|
}
|
57
52
|
catch (error) {
|
58
53
|
// Fail silently to not disrupt user experience
|
@@ -63,7 +58,7 @@ function logInteraction(interaction) {
|
|
63
58
|
function generateSessionId() {
|
64
59
|
return `session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
65
60
|
}
|
66
|
-
const api =
|
61
|
+
const api = axios.create({
|
67
62
|
baseURL: process.env.VME_API_BASE_URL,
|
68
63
|
headers: {
|
69
64
|
Authorization: `Bearer ${process.env.VME_API_TOKEN}`,
|
@@ -500,7 +495,7 @@ async function getResources(type, intent, role) {
|
|
500
495
|
};
|
501
496
|
}
|
502
497
|
}
|
503
|
-
const server = new
|
498
|
+
const server = new Server({
|
504
499
|
name: "vm-create-server",
|
505
500
|
version: "1.0.0"
|
506
501
|
}, {
|
@@ -679,8 +674,8 @@ const server = new index_js_1.Server({
|
|
679
674
|
}
|
680
675
|
const { format = "jsonl", days = 7 } = req.arguments;
|
681
676
|
try {
|
682
|
-
const logsDir =
|
683
|
-
if (!
|
677
|
+
const logsDir = join(process.cwd(), 'ai-training-logs');
|
678
|
+
if (!existsSync(logsDir)) {
|
684
679
|
return {
|
685
680
|
toolResult: JSON.stringify({
|
686
681
|
message: "No training data found",
|
@@ -698,7 +693,7 @@ const server = new index_js_1.Server({
|
|
698
693
|
for (const file of logFiles) {
|
699
694
|
const fileDate = new Date(file.replace('interactions-', '').replace('.jsonl', ''));
|
700
695
|
if (fileDate >= cutoffDate) {
|
701
|
-
const content =
|
696
|
+
const content = readFileSync(join(logsDir, file), 'utf-8');
|
702
697
|
const lines = content.trim().split('\n').filter(line => line.trim());
|
703
698
|
for (const line of lines) {
|
704
699
|
try {
|
@@ -929,5 +924,5 @@ const server = new index_js_1.Server({
|
|
929
924
|
}
|
930
925
|
}
|
931
926
|
});
|
932
|
-
const transport = new
|
927
|
+
const transport = new StdioServerTransport();
|
933
928
|
server.connect(transport);
|
@@ -1,8 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
exports.handleCheckCapability = exports.checkCapabilityTool = void 0;
|
4
|
-
const capability_discovery_js_1 = require("../lib/capability-discovery.js");
|
5
|
-
exports.checkCapabilityTool = {
|
1
|
+
import { capabilityDiscovery } from "../lib/capability-discovery.js";
|
2
|
+
export const checkCapabilityTool = {
|
6
3
|
name: "check_capability",
|
7
4
|
description: "Check if a specific capability is available using natural language queries",
|
8
5
|
inputSchema: {
|
@@ -21,7 +18,7 @@ exports.checkCapabilityTool = {
|
|
21
18
|
required: ["question"]
|
22
19
|
}
|
23
20
|
};
|
24
|
-
async function handleCheckCapability(args) {
|
21
|
+
export async function handleCheckCapability(args) {
|
25
22
|
try {
|
26
23
|
const { question, capability_type } = args;
|
27
24
|
if (!question || typeof question !== 'string') {
|
@@ -39,7 +36,7 @@ async function handleCheckCapability(args) {
|
|
39
36
|
};
|
40
37
|
}
|
41
38
|
// Use the capability discovery engine to check the capability
|
42
|
-
const result = await
|
39
|
+
const result = await capabilityDiscovery.checkCapability(question, capability_type);
|
43
40
|
// Prepare comprehensive response
|
44
41
|
const response = {
|
45
42
|
question: question,
|
@@ -81,4 +78,3 @@ async function handleCheckCapability(args) {
|
|
81
78
|
};
|
82
79
|
}
|
83
80
|
}
|
84
|
-
exports.handleCheckCapability = handleCheckCapability;
|
package/dist/tools/create-vm.js
CHANGED
@@ -1,10 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
const
|
5
|
-
const api_utils_js_1 = require("../lib/api-utils.js");
|
6
|
-
const name_resolver_js_1 = require("../lib/name-resolver.js");
|
7
|
-
exports.createVMTool = {
|
1
|
+
import { parseVMNames, calculateNodeAssignments } from "../lib/vm-parsing.js";
|
2
|
+
import { api, getClusterNodes } from "../lib/api-utils.js";
|
3
|
+
import { nameResolver } from "../lib/name-resolver.js";
|
4
|
+
export const createVMTool = {
|
8
5
|
name: "create_vm",
|
9
6
|
description: "Provision a new virtual machine. ⚡ TIP: Run discover_capabilities first to see available groups, zones, templates, and sizes in your environment.",
|
10
7
|
inputSchema: {
|
@@ -46,7 +43,7 @@ exports.createVMTool = {
|
|
46
43
|
required: ["name", "group", "template", "size"]
|
47
44
|
}
|
48
45
|
};
|
49
|
-
async function handleCreateVM(args) {
|
46
|
+
export async function handleCreateVM(args) {
|
50
47
|
const { name, group, cloud, zone, template, size, distribution, count } = args;
|
51
48
|
// Allow both 'cloud' and 'zone' parameters interchangeably
|
52
49
|
const location = cloud || zone;
|
@@ -67,16 +64,16 @@ async function handleCreateVM(args) {
|
|
67
64
|
};
|
68
65
|
}
|
69
66
|
// Parse VM names and determine distribution strategy
|
70
|
-
const vmNames =
|
71
|
-
const nodes = await
|
67
|
+
const vmNames = parseVMNames(name, count);
|
68
|
+
const nodes = await getClusterNodes();
|
72
69
|
// Calculate node assignments
|
73
|
-
const nodeAssignments =
|
70
|
+
const nodeAssignments = calculateNodeAssignments(vmNames, nodes, distribution);
|
74
71
|
// Resolve any node names to IDs
|
75
72
|
for (const assignment of nodeAssignments) {
|
76
73
|
if (assignment.nodeNameToResolve) {
|
77
74
|
// Query servers to find node with matching name
|
78
75
|
try {
|
79
|
-
const servers = await
|
76
|
+
const servers = await api.get("/servers");
|
80
77
|
if (servers.data.servers) {
|
81
78
|
const foundServer = servers.data.servers.find((server) => server.name?.toLowerCase() === assignment.nodeNameToResolve?.toLowerCase());
|
82
79
|
if (foundServer) {
|
@@ -96,28 +93,28 @@ async function handleCreateVM(args) {
|
|
96
93
|
}
|
97
94
|
}
|
98
95
|
// Use name resolver to get IDs from actual VME environment
|
99
|
-
const groupId = await
|
100
|
-
const cloudId = await
|
101
|
-
const imageId = await
|
102
|
-
const servicePlanId = await
|
103
|
-
const instanceTypeId = await
|
96
|
+
const groupId = await nameResolver.resolveNameToId('group', group);
|
97
|
+
const cloudId = await nameResolver.resolveNameToId('zone', location);
|
98
|
+
const imageId = await nameResolver.resolveNameToId('virtualImage', template);
|
99
|
+
const servicePlanId = await nameResolver.resolveNameToId('servicePlan', size);
|
100
|
+
const instanceTypeId = await nameResolver.resolveNameToId('instanceType', 'HPE VM'); // Default for VME
|
104
101
|
// Validate all required IDs were resolved
|
105
102
|
if (!groupId || !cloudId || !servicePlanId || !imageId) {
|
106
103
|
const errors = [];
|
107
104
|
if (!groupId) {
|
108
|
-
const availableGroups = await
|
105
|
+
const availableGroups = await nameResolver.getAvailableNames('group');
|
109
106
|
errors.push(`Group '${group}' not found. Available: ${availableGroups.join(', ')}`);
|
110
107
|
}
|
111
108
|
if (!cloudId) {
|
112
|
-
const availableZones = await
|
109
|
+
const availableZones = await nameResolver.getAvailableNames('zone');
|
113
110
|
errors.push(`Zone/Cloud '${location}' not found. Available: ${availableZones.join(', ')}`);
|
114
111
|
}
|
115
112
|
if (!servicePlanId) {
|
116
|
-
const availablePlans = await
|
113
|
+
const availablePlans = await nameResolver.getAvailableNames('servicePlan');
|
117
114
|
errors.push(`Size '${size}' could not be resolved to service plan. Available: ${availablePlans.join(', ')}`);
|
118
115
|
}
|
119
116
|
if (!imageId) {
|
120
|
-
const availableImages = await
|
117
|
+
const availableImages = await nameResolver.getAvailableNames('virtualImage');
|
121
118
|
errors.push(`Template '${template}' could not be resolved to OS image. Available: ${availableImages.join(', ')}`);
|
122
119
|
}
|
123
120
|
return {
|
@@ -143,10 +140,10 @@ async function handleCreateVM(args) {
|
|
143
140
|
try {
|
144
141
|
// Try to get real resource pool, datastore, network IDs from VME
|
145
142
|
const [resourcePools, datastores, networks, layouts] = await Promise.allSettled([
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
143
|
+
api.get('/resource-pools').catch(() => null),
|
144
|
+
api.get('/datastores').catch(() => null),
|
145
|
+
api.get('/networks').catch(() => null),
|
146
|
+
api.get('/layouts').catch(() => null)
|
150
147
|
]);
|
151
148
|
// Use first available resource pool
|
152
149
|
if (resourcePools.status === 'fulfilled' && resourcePools.value?.data?.resourcePools?.[0]) {
|
@@ -189,7 +186,7 @@ async function handleCreateVM(args) {
|
|
189
186
|
zoneId: cloudId,
|
190
187
|
instance: {
|
191
188
|
name: assignment.name,
|
192
|
-
cloud: await
|
189
|
+
cloud: await nameResolver.getAvailableNames('zone').then(zones => zones[0]) || 'tc-lab',
|
193
190
|
hostName: assignment.name,
|
194
191
|
type: 'mvm',
|
195
192
|
instanceType: {
|
@@ -230,7 +227,7 @@ async function handleCreateVM(args) {
|
|
230
227
|
layoutSize: 1
|
231
228
|
};
|
232
229
|
try {
|
233
|
-
const response = await
|
230
|
+
const response = await api.post("/instances", payload);
|
234
231
|
const vm = response.data?.instance;
|
235
232
|
const nodeInfo = assignment.kvmHostId ? ` on node ${assignment.kvmHostId}` : ' (auto-placed)';
|
236
233
|
results.push(`VM '${vm.name}' created (ID: ${vm.id})${nodeInfo}`);
|
@@ -274,4 +271,3 @@ async function handleCreateVM(args) {
|
|
274
271
|
isError: errors.length > 0 && results.length === 0
|
275
272
|
};
|
276
273
|
}
|
277
|
-
exports.handleCreateVM = handleCreateVM;
|
@@ -1,8 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
exports.handleDiscoverCapabilities = exports.discoverCapabilitiesTool = void 0;
|
4
|
-
const capability_discovery_js_1 = require("../lib/capability-discovery.js");
|
5
|
-
exports.discoverCapabilitiesTool = {
|
1
|
+
import { capabilityDiscovery } from "../lib/capability-discovery.js";
|
2
|
+
export const discoverCapabilitiesTool = {
|
6
3
|
name: "discover_capabilities",
|
7
4
|
description: "⚡ RECOMMENDED FIRST STEP: Discover VME infrastructure capabilities to learn available resources. Run this tool at least once per session to cache environment data for optimal performance with other tools.",
|
8
5
|
inputSchema: {
|
@@ -28,12 +25,12 @@ exports.discoverCapabilitiesTool = {
|
|
28
25
|
required: []
|
29
26
|
}
|
30
27
|
};
|
31
|
-
async function handleDiscoverCapabilities(args) {
|
28
|
+
export async function handleDiscoverCapabilities(args) {
|
32
29
|
try {
|
33
30
|
const { domain = "all", refresh = false, include_limits = true } = args;
|
34
31
|
// Convert single domain to array for discovery engine
|
35
32
|
const domains = domain === "all" ? ["all"] : [domain];
|
36
|
-
const capabilities = await
|
33
|
+
const capabilities = await capabilityDiscovery.discoverCapabilities(domains, refresh);
|
37
34
|
// Filter out license limits if not requested
|
38
35
|
if (!include_limits && capabilities.platform) {
|
39
36
|
delete capabilities.platform.license_limits;
|
@@ -76,4 +73,3 @@ async function handleDiscoverCapabilities(args) {
|
|
76
73
|
};
|
77
74
|
}
|
78
75
|
}
|
79
|
-
exports.handleDiscoverCapabilities = handleDiscoverCapabilities;
|
@@ -1,9 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
const fs_1 = require("fs");
|
5
|
-
const path_1 = require("path");
|
6
|
-
exports.exportTrainingDataTool = {
|
1
|
+
import { readFileSync, existsSync, readdirSync } from "fs";
|
2
|
+
import { join } from "path";
|
3
|
+
export const exportTrainingDataTool = {
|
7
4
|
name: "export_training_data",
|
8
5
|
description: "Export AI training data for model improvement (requires ENABLE_AI_TRAINING_DATA=true)",
|
9
6
|
inputSchema: {
|
@@ -22,7 +19,7 @@ exports.exportTrainingDataTool = {
|
|
22
19
|
required: []
|
23
20
|
}
|
24
21
|
};
|
25
|
-
async function handleExportTrainingData(args) {
|
22
|
+
export async function handleExportTrainingData(args) {
|
26
23
|
const AI_TRAINING_ENABLED = process.env.ENABLE_AI_TRAINING_DATA === 'true';
|
27
24
|
if (!AI_TRAINING_ENABLED) {
|
28
25
|
return {
|
@@ -40,8 +37,8 @@ async function handleExportTrainingData(args) {
|
|
40
37
|
}
|
41
38
|
const { format = "jsonl", days = 7 } = args;
|
42
39
|
try {
|
43
|
-
const logsDir =
|
44
|
-
if (!
|
40
|
+
const logsDir = join(process.cwd(), 'ai-training-logs');
|
41
|
+
if (!existsSync(logsDir)) {
|
45
42
|
return {
|
46
43
|
content: [
|
47
44
|
{
|
@@ -59,11 +56,11 @@ async function handleExportTrainingData(args) {
|
|
59
56
|
const cutoffDate = new Date(Date.now() - (days * 24 * 60 * 60 * 1000));
|
60
57
|
const allData = [];
|
61
58
|
// Read log files and aggregate data
|
62
|
-
const logFiles =
|
59
|
+
const logFiles = readdirSync(logsDir).filter((file) => file.startsWith('interactions-') && file.endsWith('.jsonl'));
|
63
60
|
for (const file of logFiles) {
|
64
61
|
const fileDate = new Date(file.replace('interactions-', '').replace('.jsonl', ''));
|
65
62
|
if (fileDate >= cutoffDate) {
|
66
|
-
const content =
|
63
|
+
const content = readFileSync(join(logsDir, file), 'utf-8');
|
67
64
|
const lines = content.trim().split('\n').filter(line => line.trim());
|
68
65
|
for (const line of lines) {
|
69
66
|
try {
|
@@ -112,4 +109,3 @@ async function handleExportTrainingData(args) {
|
|
112
109
|
};
|
113
110
|
}
|
114
111
|
}
|
115
|
-
exports.handleExportTrainingData = handleExportTrainingData;
|
@@ -1,8 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
exports.handleGetCacheStatus = exports.getCacheStatusTool = void 0;
|
4
|
-
const capability_cache_js_1 = require("../lib/capability-cache.js");
|
5
|
-
exports.getCacheStatusTool = {
|
1
|
+
import { capabilityCache } from "../lib/capability-cache.js";
|
2
|
+
export const getCacheStatusTool = {
|
6
3
|
name: "get_cache_status",
|
7
4
|
description: "Show freshness and status of cached capability data for transparency and debugging",
|
8
5
|
inputSchema: {
|
@@ -22,11 +19,11 @@ exports.getCacheStatusTool = {
|
|
22
19
|
required: []
|
23
20
|
}
|
24
21
|
};
|
25
|
-
async function handleGetCacheStatus(args) {
|
22
|
+
export async function handleGetCacheStatus(args) {
|
26
23
|
try {
|
27
24
|
const { field, include_statistics = false } = args;
|
28
25
|
// Get cache status for specific field or all fields
|
29
|
-
const cacheStatuses =
|
26
|
+
const cacheStatuses = capabilityCache.getCacheStatus(field);
|
30
27
|
// Calculate summary statistics
|
31
28
|
const totalFields = cacheStatuses.length;
|
32
29
|
const freshFields = cacheStatuses.filter(s => s.is_fresh).length;
|
@@ -54,7 +51,7 @@ async function handleGetCacheStatus(args) {
|
|
54
51
|
};
|
55
52
|
// Include statistics if requested
|
56
53
|
if (include_statistics) {
|
57
|
-
const stats =
|
54
|
+
const stats = capabilityCache.getStatistics();
|
58
55
|
response.statistics = {
|
59
56
|
cache_hits: stats.hits,
|
60
57
|
cache_misses: stats.misses,
|
@@ -87,7 +84,6 @@ async function handleGetCacheStatus(args) {
|
|
87
84
|
};
|
88
85
|
}
|
89
86
|
}
|
90
|
-
exports.handleGetCacheStatus = handleGetCacheStatus;
|
91
87
|
// Helper function to format duration in human-readable format
|
92
88
|
function formatDuration(seconds) {
|
93
89
|
if (seconds < 60) {
|
@@ -1,8 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
exports.handleGetResources = exports.getResourcesTool = void 0;
|
4
|
-
const api_utils_js_1 = require("../lib/api-utils.js");
|
5
|
-
exports.getResourcesTool = {
|
1
|
+
import { getResources } from "../lib/api-utils.js";
|
2
|
+
export const getResourcesTool = {
|
6
3
|
name: "get_resources",
|
7
4
|
description: "Discover and explore available VME infrastructure resources with intelligent filtering. ⚡ TIP: Use discover_capabilities for comprehensive environment discovery first.",
|
8
5
|
inputSchema: {
|
@@ -24,9 +21,9 @@ exports.getResourcesTool = {
|
|
24
21
|
required: []
|
25
22
|
}
|
26
23
|
};
|
27
|
-
async function handleGetResources(args) {
|
24
|
+
export async function handleGetResources(args) {
|
28
25
|
const { type, intent, role } = args;
|
29
|
-
const resources = await
|
26
|
+
const resources = await getResources(type, intent, role);
|
30
27
|
return {
|
31
28
|
content: [
|
32
29
|
{
|
@@ -37,4 +34,3 @@ async function handleGetResources(args) {
|
|
37
34
|
isError: !!resources.error
|
38
35
|
};
|
39
36
|
}
|
40
|
-
exports.handleGetResources = handleGetResources;
|
package/dist/tools/index.js
CHANGED
@@ -1,68 +1,47 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
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");
|
1
|
+
import { parseIntentTool, handleParseIntent } from "./parse-intent.js";
|
2
|
+
import { createVMTool, handleCreateVM } from "./create-vm.js";
|
3
|
+
import { exportTrainingDataTool, handleExportTrainingData } from "./export-training-data.js";
|
4
|
+
import { provideFeedbackTool, handleProvideFeedback } from "./provide-feedback.js";
|
8
5
|
// Sprint 2: Capability Discovery Tools
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
6
|
+
import { discoverCapabilitiesTool, handleDiscoverCapabilities } from "./discover-capabilities.js";
|
7
|
+
import { checkCapabilityTool, handleCheckCapability } from "./check-capability.js";
|
8
|
+
import { getCacheStatusTool, handleGetCacheStatus } from "./get-cache-status.js";
|
9
|
+
import { queryResourcesTool, handleQueryResources } from "./query-resources.js";
|
13
10
|
// Re-export for external use
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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; } });
|
11
|
+
export { getResourcesTool, handleGetResources } from "./get-resources.js";
|
12
|
+
export { parseIntentTool, handleParseIntent } from "./parse-intent.js";
|
13
|
+
export { createVMTool, handleCreateVM } from "./create-vm.js";
|
14
|
+
export { exportTrainingDataTool, handleExportTrainingData } from "./export-training-data.js";
|
15
|
+
export { provideFeedbackTool, handleProvideFeedback } from "./provide-feedback.js";
|
16
|
+
export { discoverCapabilitiesTool, handleDiscoverCapabilities } from "./discover-capabilities.js";
|
17
|
+
export { checkCapabilityTool, handleCheckCapability } from "./check-capability.js";
|
18
|
+
export { getCacheStatusTool, handleGetCacheStatus } from "./get-cache-status.js";
|
19
|
+
export { queryResourcesTool, handleQueryResources } from "./query-resources.js";
|
41
20
|
// Collect all tool definitions
|
42
|
-
|
21
|
+
export const allTools = [
|
43
22
|
// Sprint 1.5 tools
|
44
23
|
// getResourcesTool, // DISABLED - caused 37K+ token responses, replaced by Sprint 2 capability discovery
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
24
|
+
parseIntentTool,
|
25
|
+
createVMTool,
|
26
|
+
exportTrainingDataTool,
|
27
|
+
provideFeedbackTool,
|
49
28
|
// Sprint 2 capability discovery tools
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
29
|
+
discoverCapabilitiesTool,
|
30
|
+
checkCapabilityTool,
|
31
|
+
getCacheStatusTool,
|
32
|
+
queryResourcesTool
|
54
33
|
];
|
55
34
|
// Export tool handlers map for easy lookup
|
56
|
-
|
35
|
+
export const toolHandlers = {
|
57
36
|
// Sprint 1.5 handlers
|
58
37
|
// get_resources: handleGetResources, // DISABLED - caused 37K+ token responses
|
59
|
-
parse_vm_intent:
|
60
|
-
create_vm:
|
61
|
-
export_training_data:
|
62
|
-
provide_feedback:
|
38
|
+
parse_vm_intent: handleParseIntent,
|
39
|
+
create_vm: handleCreateVM,
|
40
|
+
export_training_data: handleExportTrainingData,
|
41
|
+
provide_feedback: handleProvideFeedback,
|
63
42
|
// Sprint 2 capability discovery handlers
|
64
|
-
discover_capabilities:
|
65
|
-
check_capability:
|
66
|
-
get_cache_status:
|
67
|
-
query_resources:
|
43
|
+
discover_capabilities: handleDiscoverCapabilities,
|
44
|
+
check_capability: handleCheckCapability,
|
45
|
+
get_cache_status: handleGetCacheStatus,
|
46
|
+
query_resources: handleQueryResources
|
68
47
|
};
|
@@ -1,9 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
const intent_recognition_js_1 = require("../lib/intent-recognition.js");
|
5
|
-
const session_js_1 = require("../lib/session.js");
|
6
|
-
exports.parseIntentTool = {
|
1
|
+
import { parseVMIntent } from "../lib/intent-recognition.js";
|
2
|
+
import { generateSessionId, logInteraction } from "../lib/session.js";
|
3
|
+
export const parseIntentTool = {
|
7
4
|
name: "parse_vm_intent",
|
8
5
|
description: "Parse natural language VM requests into structured parameters with confidence scoring",
|
9
6
|
inputSchema: {
|
@@ -17,14 +14,14 @@ exports.parseIntentTool = {
|
|
17
14
|
required: ["naturalLanguageInput"]
|
18
15
|
}
|
19
16
|
};
|
20
|
-
async function handleParseIntent(args) {
|
17
|
+
export async function handleParseIntent(args) {
|
21
18
|
const startTime = Date.now();
|
22
19
|
const { naturalLanguageInput } = args;
|
23
|
-
const sessionId =
|
24
|
-
const parsedIntent =
|
20
|
+
const sessionId = generateSessionId();
|
21
|
+
const parsedIntent = parseVMIntent(naturalLanguageInput);
|
25
22
|
const parseTime = Date.now() - startTime;
|
26
23
|
// Log interaction for AI training (respects privacy settings)
|
27
|
-
|
24
|
+
logInteraction({
|
28
25
|
session_id: sessionId,
|
29
26
|
tool_name: 'parse_vm_intent',
|
30
27
|
user_input: { naturalLanguageInput },
|
@@ -49,4 +46,3 @@ async function handleParseIntent(args) {
|
|
49
46
|
isError: parsedIntent.action === 'unknown' && parsedIntent.confidence < 0.3
|
50
47
|
};
|
51
48
|
}
|
52
|
-
exports.handleParseIntent = handleParseIntent;
|
@@ -1,8 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
exports.handleProvideFeedback = exports.provideFeedbackTool = void 0;
|
4
|
-
const session_js_1 = require("../lib/session.js");
|
5
|
-
exports.provideFeedbackTool = {
|
1
|
+
import { generateSessionId, logInteraction } from "../lib/session.js";
|
2
|
+
export const provideFeedbackTool = {
|
6
3
|
name: "provide_feedback",
|
7
4
|
description: "Provide feedback on intent parsing accuracy to improve future predictions",
|
8
5
|
inputSchema: {
|
@@ -28,11 +25,11 @@ exports.provideFeedbackTool = {
|
|
28
25
|
required: ["original_input", "feedback_notes"]
|
29
26
|
}
|
30
27
|
};
|
31
|
-
async function handleProvideFeedback(args) {
|
28
|
+
export async function handleProvideFeedback(args) {
|
32
29
|
const { original_input, parsed_result, correct_interpretation, feedback_notes } = args;
|
33
|
-
const sessionId =
|
30
|
+
const sessionId = generateSessionId();
|
34
31
|
// Log feedback for future model improvements
|
35
|
-
|
32
|
+
logInteraction({
|
36
33
|
session_id: sessionId,
|
37
34
|
tool_name: 'provide_feedback',
|
38
35
|
user_input: { original_input, feedback_notes },
|
@@ -58,4 +55,3 @@ async function handleProvideFeedback(args) {
|
|
58
55
|
isError: false
|
59
56
|
};
|
60
57
|
}
|
61
|
-
exports.handleProvideFeedback = handleProvideFeedback;
|
@@ -1,8 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
exports.handleQueryResources = exports.queryResourcesTool = void 0;
|
4
|
-
const api_utils_js_1 = require("../lib/api-utils.js");
|
5
|
-
exports.queryResourcesTool = {
|
1
|
+
import { api } from "../lib/api-utils.js";
|
2
|
+
export const queryResourcesTool = {
|
6
3
|
name: "query_resources",
|
7
4
|
description: "Query actual infrastructure resources (VMs, cluster nodes, networks) with natural language. Supports network placement queries. ⚡ TIP: Run discover_capabilities first to learn available OS types, groups, and statuses in your environment.",
|
8
5
|
inputSchema: {
|
@@ -280,7 +277,7 @@ function formatResponse(parsedQuery, results, totalCount, detailLevel = 2) {
|
|
280
277
|
query_summary: `Showing ${limitedResults.length} of ${results.length} ${resource} matching criteria`
|
281
278
|
};
|
282
279
|
}
|
283
|
-
async function handleQueryResources(args) {
|
280
|
+
export async function handleQueryResources(args) {
|
284
281
|
try {
|
285
282
|
const { natural_query, limit = 10, detail_level = 2 } = args;
|
286
283
|
if (!natural_query || typeof natural_query !== 'string') {
|
@@ -308,7 +305,7 @@ async function handleQueryResources(args) {
|
|
308
305
|
};
|
309
306
|
const endpoint = endpointMap[parsedQuery.resource];
|
310
307
|
// Query the VME API
|
311
|
-
const response = await
|
308
|
+
const response = await api.get(endpoint);
|
312
309
|
// Extract data array from response
|
313
310
|
let rawData = [];
|
314
311
|
if (parsedQuery.resource === 'instances' && response.data.instances) {
|
@@ -368,4 +365,3 @@ async function handleQueryResources(args) {
|
|
368
365
|
};
|
369
366
|
}
|
370
367
|
}
|
371
|
-
exports.handleQueryResources = handleQueryResources;
|
package/dist/types/interfaces.js
CHANGED
@@ -1,2 +1 @@
|
|
1
|
-
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
1
|
+
export {};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "vme-mcp-server",
|
3
|
-
"version": "0.1.
|
3
|
+
"version": "0.1.12",
|
4
4
|
"description": "",
|
5
5
|
"main": "dist/server.js",
|
6
6
|
"bin": {
|
@@ -10,13 +10,19 @@
|
|
10
10
|
"build": "tsc",
|
11
11
|
"start": "node dist/server.js",
|
12
12
|
"dev": "tsx watch src/server.ts",
|
13
|
-
"
|
14
|
-
"
|
13
|
+
"prepare": "husky install",
|
14
|
+
"prepublishOnly": "npm run build && chmod +x dist/server.js && cp README-NPM.md dist/README.md",
|
15
|
+
"test": "npm run test:critical",
|
15
16
|
"test:unit": "mocha tests/unit/*.test.js",
|
17
|
+
"test:binary": "mocha tests/binary/*.test.js",
|
18
|
+
"test:critical": "npm run test:binary && npm run test:mcp",
|
16
19
|
"test:integration": "mocha tests/integration/*.test.js",
|
17
|
-
"test:
|
18
|
-
"test:
|
19
|
-
"test:
|
20
|
+
"test:mcp": "mocha tests/integration/mcp-protocol.test.js",
|
21
|
+
"test:package": "mocha tests/package/*.test.js",
|
22
|
+
"test:all": "mocha tests/**/*.test.js",
|
23
|
+
"test:coverage": "nyc mocha tests/**/*.test.js",
|
24
|
+
"lint": "echo 'Linting not configured yet'",
|
25
|
+
"precommit": "npm run lint && npm run test:critical && npm run build && npm run test:package"
|
20
26
|
},
|
21
27
|
"keywords": [
|
22
28
|
"mcp",
|
@@ -43,11 +49,13 @@
|
|
43
49
|
"axios": "^1.9.0",
|
44
50
|
"dotenv": "^16.5.0",
|
45
51
|
"tsx": "^4.19.4",
|
46
|
-
"typescript": "^5.3.3"
|
52
|
+
"typescript": "^5.3.3",
|
53
|
+
"vme-mcp-server": "^0.1.9"
|
47
54
|
},
|
48
55
|
"devDependencies": {
|
49
56
|
"@types/node": "^22.15.29",
|
50
57
|
"chai": "^5.2.0",
|
58
|
+
"husky": "^9.1.7",
|
51
59
|
"mocha": "^10.2.0",
|
52
60
|
"nyc": "^15.1.0"
|
53
61
|
}
|