vcluster-yaml-mcp-server 1.1.1 → 1.2.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/README.md CHANGED
@@ -52,7 +52,7 @@ Run the server locally via npx:
52
52
  "mcpServers": {
53
53
  "vcluster-yaml": {
54
54
  "command": "npx",
55
- "args": ["-y", "vcluster-yaml-mcp-server"]
55
+ "args": ["-y", "vcluster-yaml-mcp-server@latest"]
56
56
  }
57
57
  }
58
58
  }
@@ -287,10 +287,12 @@ npm run start:http
287
287
 
288
288
  ## Technical Details
289
289
 
290
- - **SDK**: `@modelcontextprotocol/sdk` v1.20.1 (Streamable HTTP transport)
290
+ - **SDK**: `@modelcontextprotocol/sdk` v1.25.2 using `McpServer` high-level API
291
291
  - **Node**: >=18
292
292
  - **Transport**: Both stdio (local) and HTTP/SSE (remote)
293
293
  - **Dependencies**: `js-yaml` for parsing, `node-jq` for querying, `node-fetch` for GitHub API
294
+ - **Tool Annotations**: All tools include `readOnlyHint`/`destructiveHint` for client optimization
295
+ - **Server Instructions**: Includes instructions for MCP tool search auto mode
294
296
 
295
297
  ## Release Process
296
298
 
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "vcluster-yaml-mcp-server",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "MCP server for querying vcluster YAML configurations using jq",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/Piotr1215/vcluster-yaml-mcp"
8
+ },
5
9
  "main": "src/index.js",
6
10
  "type": "module",
7
11
  "bin": {
8
- "vcluster-yaml-mcp-server": "./src/cli.js",
9
- "vcluster-yaml-mcp": "./src/index.js",
12
+ "vcluster-yaml-mcp-server": "./src/index.js",
10
13
  "vcluster-yaml": "./src/cli.js"
11
14
  },
12
15
  "files": [
@@ -25,14 +28,14 @@
25
28
  "test:ci": "vitest run tests/ci/",
26
29
  "test:all": "vitest run",
27
30
  "test:watch": "vitest --exclude tests/integration/**/*.test.js",
28
- "test:coverage": "vitest run --coverage --exclude tests/integration/**/*.test.js",
31
+ "test:coverage": "vitest run --coverage --exclude tests/integration/**/*.test.js --exclude tests/ci/**/*.test.js --exclude tests/performance.test.js",
29
32
  "test:mutation": "stryker run",
30
33
  "complexity": "eslint --config eslint.config.complexity.js src/**/*.js",
31
34
  "complexity:json": "eslint --config eslint.config.complexity.js --format json --output-file reports/complexity.json src/**/*.js || true",
32
35
  "lint:workflows": "actionlint .github/workflows/*.yml"
33
36
  },
34
37
  "dependencies": {
35
- "@modelcontextprotocol/sdk": "^1.20.1",
38
+ "@modelcontextprotocol/sdk": "^1.25.2",
36
39
  "@opentelemetry/api": "^1.9.0",
37
40
  "@opentelemetry/auto-instrumentations-node": "^0.66.0",
38
41
  "@opentelemetry/exporter-trace-otlp-grpc": "^0.207.0",
@@ -70,3 +70,17 @@ export function getMcpServerInfo() {
70
70
  version: packageJson.version
71
71
  };
72
72
  }
73
+
74
+ /**
75
+ * Get server options including instructions for MCP clients
76
+ * @returns {Object} MCP server options
77
+ */
78
+ export function getMcpServerOptions() {
79
+ return {
80
+ capabilities: {
81
+ tools: {},
82
+ resources: {}
83
+ },
84
+ instructions: "vCluster configuration assistant. Use smart-query for any configuration questions (natural language search). Use create-vcluster-config when generating configs - it auto-validates. Use list-versions first to discover available versions. Use validate-config for user-provided YAML. Use extract-validation-rules to understand semantic constraints."
85
+ };
86
+ }
package/src/server.js CHANGED
@@ -1,168 +1,190 @@
1
- import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
- import {
3
- ListToolsRequestSchema,
4
- CallToolRequestSchema,
5
- ListResourcesRequestSchema,
6
- ReadResourceRequestSchema
7
- } from '@modelcontextprotocol/sdk/types.js';
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
8
2
  import { githubClient } from './github.js';
9
- import { executeToolHandler } from './tool-registry.js';
10
- import { getMcpServerInfo, getServerInfo } from './server-info.js';
3
+ import {
4
+ handleCreateConfig,
5
+ handleListVersions,
6
+ handleSmartQuery,
7
+ handleExtractRules,
8
+ handleValidateConfig
9
+ } from './tool-handlers.js';
10
+ import { getMcpServerInfo, getMcpServerOptions, getServerInfo } from './server-info.js';
11
11
 
12
12
  export function createServer() {
13
- const server = new Server(
14
- getMcpServerInfo(),
13
+ const serverInfo = getMcpServerInfo();
14
+ const serverOptions = getMcpServerOptions();
15
+
16
+ const server = new McpServer(serverInfo, serverOptions);
17
+
18
+ // Register: list-versions
19
+ server.registerTool(
20
+ 'list-versions',
15
21
  {
16
- capabilities: {
17
- tools: {},
18
- resources: {}
22
+ description: 'DISCOVERY: Find all available vCluster versions. Returns GitHub tags (stable releases) and branches (development versions). Use this to discover what versions are available before querying specific versions.',
23
+ inputSchema: {
24
+ type: 'object',
25
+ properties: {},
26
+ required: []
27
+ },
28
+ annotations: {
29
+ readOnlyHint: true
19
30
  }
31
+ },
32
+ async () => {
33
+ const result = await handleListVersions({}, githubClient);
34
+ return result;
20
35
  }
21
36
  );
22
37
 
23
- // Tool definitions
24
- server.setRequestHandler(ListToolsRequestSchema, async () => {
25
- return {
26
- tools: [
27
- {
28
- name: 'list-versions',
29
- description: 'DISCOVERY: Find all available vCluster versions. Returns GitHub tags (stable releases) and branches (development versions). Use this to discover what versions are available before querying specific versions.',
30
- inputSchema: {
31
- type: 'object',
32
- properties: {},
33
- required: []
38
+ // Register: smart-query
39
+ server.registerTool(
40
+ 'smart-query',
41
+ {
42
+ description: 'UNIVERSAL SEARCH: Your go-to tool for finding ANY vCluster configuration! Understands natural language, searches intelligently, and finds related settings. USE THIS FIRST for any config questions! Examples: "show me namespace settings", "how is etcd configured?", "what networking options exist?", "find service CIDR". Searches chart/values.yaml by default.',
43
+ inputSchema: {
44
+ type: 'object',
45
+ properties: {
46
+ query: {
47
+ type: 'string',
48
+ description: 'Natural language query (e.g., "namespace syncing", "high availability", "storage options")'
49
+ },
50
+ file: {
51
+ type: 'string',
52
+ description: 'Optional: specific file to search (default: "chart/values.yaml")'
53
+ },
54
+ version: {
55
+ type: 'string',
56
+ description: 'Version tag or branch (e.g., "v0.24.0", "main"). Defaults to "main".'
34
57
  }
35
58
  },
36
- {
37
- name: 'smart-query',
38
- description: 'UNIVERSAL SEARCH: Your go-to tool for finding ANY vCluster configuration! Understands natural language, searches intelligently, and finds related settings. USE THIS FIRST for any config questions! Examples: "show me namespace settings", "how is etcd configured?", "what networking options exist?", "find service CIDR". Searches chart/values.yaml by default.',
39
- inputSchema: {
40
- type: 'object',
41
- properties: {
42
- query: {
43
- type: 'string',
44
- description: 'Natural language query (e.g., "namespace syncing", "high availability", "storage options")'
45
- },
46
- file: {
47
- type: 'string',
48
- description: 'Optional: specific file to search (default: "chart/values.yaml")'
49
- },
50
- version: {
51
- type: 'string',
52
- description: 'Version tag or branch (e.g., "v0.24.0", "main"). Defaults to "main".'
53
- }
54
- },
55
- required: ['query']
59
+ required: ['query']
60
+ },
61
+ annotations: {
62
+ readOnlyHint: true
63
+ }
64
+ },
65
+ async ({ query, file, version }) => {
66
+ const result = await handleSmartQuery({ query, file, version }, githubClient);
67
+ return result;
68
+ }
69
+ );
70
+
71
+ // Register: create-vcluster-config
72
+ server.registerTool(
73
+ 'create-vcluster-config',
74
+ {
75
+ description: 'CONFIG CREATION WORKFLOW: Use this when generating vCluster configurations for users. This tool REQUIRES you to provide the YAML you created and automatically validates it before returning to the user. Returns validation result + formatted config. This ensures every config you create is validated.',
76
+ inputSchema: {
77
+ type: 'object',
78
+ properties: {
79
+ yaml_content: {
80
+ type: 'string',
81
+ description: 'The vCluster YAML configuration you generated (required)'
82
+ },
83
+ description: {
84
+ type: 'string',
85
+ description: 'Brief description of what this config does (optional, helpful for user)'
86
+ },
87
+ version: {
88
+ type: 'string',
89
+ description: 'Version tag or branch (e.g., "v0.24.0", "main"). Defaults to "main".'
56
90
  }
57
91
  },
58
- {
59
- name: 'create-vcluster-config',
60
- description: 'CONFIG CREATION WORKFLOW: Use this when generating vCluster configurations for users. This tool REQUIRES you to provide the YAML you created and automatically validates it before returning to the user. Returns validation result + formatted config. This ensures every config you create is validated.',
61
- inputSchema: {
62
- type: 'object',
63
- properties: {
64
- yaml_content: {
65
- type: 'string',
66
- description: 'The vCluster YAML configuration you generated (required)'
67
- },
68
- description: {
69
- type: 'string',
70
- description: 'Brief description of what this config does (optional, helpful for user)'
71
- },
72
- version: {
73
- type: 'string',
74
- description: 'Version tag or branch (e.g., "v0.24.0", "main"). Defaults to "main".'
75
- }
76
- },
77
- required: ['yaml_content']
92
+ required: ['yaml_content']
93
+ },
94
+ annotations: {
95
+ readOnlyHint: false
96
+ }
97
+ },
98
+ async ({ yaml_content, description, version }) => {
99
+ const result = await handleCreateConfig({ yaml_content, description, version }, githubClient);
100
+ return result;
101
+ }
102
+ );
103
+
104
+ // Register: validate-config
105
+ server.registerTool(
106
+ 'validate-config',
107
+ {
108
+ description: 'VALIDATION ONLY: Validates existing vCluster YAML (full config or partial snippet) against the schema. Use create-vcluster-config for configs you generate. Use this to validate user-provided configs or files from GitHub.',
109
+ inputSchema: {
110
+ type: 'object',
111
+ properties: {
112
+ file: {
113
+ type: 'string',
114
+ description: 'File path in GitHub repo to validate. Optional if content is provided.'
115
+ },
116
+ content: {
117
+ type: 'string',
118
+ description: 'YAML content to validate (full config or partial snippet)'
119
+ },
120
+ version: {
121
+ type: 'string',
122
+ description: 'Version tag or branch (e.g., "v0.24.0", "main"). Defaults to "main".'
78
123
  }
79
124
  },
80
- {
81
- name: 'validate-config',
82
- description: 'VALIDATION ONLY: Validates existing vCluster YAML (full config or partial snippet) against the schema. Use create-vcluster-config for configs you generate. Use this to validate user-provided configs or files from GitHub.',
83
- inputSchema: {
84
- type: 'object',
85
- properties: {
86
- file: {
87
- type: 'string',
88
- description: 'File path in GitHub repo to validate. Optional if content is provided.'
89
- },
90
- content: {
91
- type: 'string',
92
- description: 'YAML content to validate (full config or partial snippet)'
93
- },
94
- version: {
95
- type: 'string',
96
- description: 'Version tag or branch (e.g., "v0.24.0", "main"). Defaults to "main".'
97
- }
98
- },
99
- required: []
125
+ required: []
126
+ },
127
+ annotations: {
128
+ readOnlyHint: true
129
+ }
130
+ },
131
+ async ({ file, content, version }) => {
132
+ const result = await handleValidateConfig({ file, content, version }, githubClient);
133
+ return result;
134
+ }
135
+ );
136
+
137
+ // Register: extract-validation-rules
138
+ server.registerTool(
139
+ 'extract-validation-rules',
140
+ {
141
+ description: 'AI ASSISTANT: Extract validation rules, constraints, and best practices directly from values.yaml comments. Returns structured rules for AI to understand complex relationships and semantic validations that procedural code cannot handle. USE THIS when you need to understand the "why" behind configurations or validate semantic correctness beyond syntax.',
142
+ inputSchema: {
143
+ type: 'object',
144
+ properties: {
145
+ file: {
146
+ type: 'string',
147
+ description: 'File path in GitHub repo (default: "chart/values.yaml")'
148
+ },
149
+ section: {
150
+ type: 'string',
151
+ description: 'Focus on specific section (e.g., "controlPlane", "sync", "networking")'
152
+ },
153
+ version: {
154
+ type: 'string',
155
+ description: 'Version tag or branch (e.g., "v0.24.0", "main"). Defaults to "main".'
100
156
  }
101
157
  },
102
- {
103
- name: 'extract-validation-rules',
104
- description: 'AI ASSISTANT: Extract validation rules, constraints, and best practices directly from values.yaml comments. Returns structured rules for AI to understand complex relationships and semantic validations that procedural code cannot handle. USE THIS when you need to understand the "why" behind configurations or validate semantic correctness beyond syntax.',
105
- inputSchema: {
106
- type: 'object',
107
- properties: {
108
- file: {
109
- type: 'string',
110
- description: 'File path in GitHub repo (default: "chart/values.yaml")',
111
- default: 'chart/values.yaml'
112
- },
113
- section: {
114
- type: 'string',
115
- description: 'Focus on specific section (e.g., "controlPlane", "sync", "networking")'
116
- },
117
- version: {
118
- type: 'string',
119
- description: 'Version tag or branch (e.g., "v0.24.0", "main"). Defaults to "main".'
120
- }
121
- },
122
- required: []
123
- }
124
- }
125
- ]
126
- };
127
- });
128
-
129
- // Tool handler
130
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
131
- const { name, arguments: args } = request.params;
132
- return executeToolHandler(name, args, githubClient);
133
- });
158
+ required: []
159
+ },
160
+ annotations: {
161
+ readOnlyHint: true
162
+ }
163
+ },
164
+ async ({ file, section, version }) => {
165
+ const result = await handleExtractRules({ file, section, version }, githubClient);
166
+ return result;
167
+ }
168
+ );
134
169
 
135
- // Resource handlers
136
- server.setRequestHandler(ListResourcesRequestSchema, async () => {
137
- return {
138
- resources: [
170
+ // Register resource: server://info
171
+ server.registerResource(
172
+ 'server-info',
173
+ 'server://info',
174
+ {
175
+ description: 'Version, build info, and metadata about this MCP server',
176
+ mimeType: 'application/json'
177
+ },
178
+ async (uri) => ({
179
+ contents: [
139
180
  {
140
- uri: 'server://info',
141
- name: 'Server Information',
142
- description: 'Version, build info, and metadata about this MCP server',
143
- mimeType: 'application/json'
181
+ uri: uri.href,
182
+ mimeType: 'application/json',
183
+ text: JSON.stringify(getServerInfo(), null, 2)
144
184
  }
145
185
  ]
146
- };
147
- });
148
-
149
- server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
150
- const { uri } = request.params;
151
-
152
- if (uri === 'server://info') {
153
- return {
154
- contents: [
155
- {
156
- uri: 'server://info',
157
- mimeType: 'application/json',
158
- text: JSON.stringify(getServerInfo(), null, 2)
159
- }
160
- ]
161
- };
162
- }
163
-
164
- throw new Error(`Unknown resource: ${uri}`);
165
- });
186
+ })
187
+ );
166
188
 
167
189
  return server;
168
190
  }