@aws/ml-container-creator 0.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/LICENSE +202 -0
- package/LICENSE-THIRD-PARTY +68620 -0
- package/NOTICE +2 -0
- package/README.md +106 -0
- package/bin/cli.js +365 -0
- package/config/defaults.json +32 -0
- package/config/presets/transformers-djl.json +26 -0
- package/config/presets/transformers-gpu.json +24 -0
- package/config/presets/transformers-lmi.json +27 -0
- package/package.json +129 -0
- package/servers/README.md +419 -0
- package/servers/base-image-picker/catalogs/model-servers.json +1191 -0
- package/servers/base-image-picker/catalogs/python-slim.json +38 -0
- package/servers/base-image-picker/catalogs/triton-backends.json +51 -0
- package/servers/base-image-picker/catalogs/triton.json +38 -0
- package/servers/base-image-picker/index.js +495 -0
- package/servers/base-image-picker/manifest.json +17 -0
- package/servers/base-image-picker/package.json +15 -0
- package/servers/hyperpod-cluster-picker/LICENSE +202 -0
- package/servers/hyperpod-cluster-picker/index.js +424 -0
- package/servers/hyperpod-cluster-picker/manifest.json +14 -0
- package/servers/hyperpod-cluster-picker/package.json +17 -0
- package/servers/instance-recommender/LICENSE +202 -0
- package/servers/instance-recommender/catalogs/instances.json +852 -0
- package/servers/instance-recommender/index.js +284 -0
- package/servers/instance-recommender/manifest.json +16 -0
- package/servers/instance-recommender/package.json +15 -0
- package/servers/lib/LICENSE +202 -0
- package/servers/lib/bedrock-client.js +160 -0
- package/servers/lib/custom-validators.js +46 -0
- package/servers/lib/dynamic-resolver.js +36 -0
- package/servers/lib/package.json +11 -0
- package/servers/lib/schemas/image-catalog.schema.json +185 -0
- package/servers/lib/schemas/instances.schema.json +124 -0
- package/servers/lib/schemas/manifest.schema.json +64 -0
- package/servers/lib/schemas/model-catalog.schema.json +91 -0
- package/servers/lib/schemas/regions.schema.json +26 -0
- package/servers/lib/schemas/triton-backends.schema.json +51 -0
- package/servers/model-picker/catalogs/jumpstart-public.json +66 -0
- package/servers/model-picker/catalogs/popular-diffusors.json +88 -0
- package/servers/model-picker/catalogs/popular-transformers.json +226 -0
- package/servers/model-picker/index.js +1693 -0
- package/servers/model-picker/manifest.json +18 -0
- package/servers/model-picker/package.json +20 -0
- package/servers/region-picker/LICENSE +202 -0
- package/servers/region-picker/catalogs/regions.json +263 -0
- package/servers/region-picker/index.js +230 -0
- package/servers/region-picker/manifest.json +16 -0
- package/servers/region-picker/package.json +15 -0
- package/src/app.js +1007 -0
- package/src/copy-tpl.js +77 -0
- package/src/lib/accelerator-validator.js +39 -0
- package/src/lib/asset-manager.js +385 -0
- package/src/lib/aws-profile-parser.js +181 -0
- package/src/lib/bootstrap-command-handler.js +1647 -0
- package/src/lib/bootstrap-config.js +238 -0
- package/src/lib/ci-register-helpers.js +124 -0
- package/src/lib/ci-report-helpers.js +158 -0
- package/src/lib/ci-stage-helpers.js +268 -0
- package/src/lib/cli-handler.js +529 -0
- package/src/lib/comment-generator.js +544 -0
- package/src/lib/community-reports-validator.js +91 -0
- package/src/lib/config-manager.js +2106 -0
- package/src/lib/configuration-exporter.js +204 -0
- package/src/lib/configuration-manager.js +695 -0
- package/src/lib/configuration-matcher.js +221 -0
- package/src/lib/cpu-validator.js +36 -0
- package/src/lib/cuda-validator.js +57 -0
- package/src/lib/deployment-config-resolver.js +103 -0
- package/src/lib/deployment-entry-schema.js +125 -0
- package/src/lib/deployment-registry.js +598 -0
- package/src/lib/docker-introspection-validator.js +51 -0
- package/src/lib/engine-prefix-resolver.js +60 -0
- package/src/lib/huggingface-client.js +172 -0
- package/src/lib/key-value-parser.js +37 -0
- package/src/lib/known-flags-validator.js +200 -0
- package/src/lib/manifest-cli.js +280 -0
- package/src/lib/mcp-client.js +303 -0
- package/src/lib/mcp-command-handler.js +532 -0
- package/src/lib/neuron-validator.js +80 -0
- package/src/lib/parameter-schema-validator.js +284 -0
- package/src/lib/prompt-runner.js +1349 -0
- package/src/lib/prompts.js +1138 -0
- package/src/lib/registry-command-handler.js +519 -0
- package/src/lib/registry-loader.js +198 -0
- package/src/lib/rocm-validator.js +80 -0
- package/src/lib/schema-validator.js +157 -0
- package/src/lib/sensitive-redactor.js +59 -0
- package/src/lib/template-engine.js +156 -0
- package/src/lib/template-manager.js +341 -0
- package/src/lib/validation-engine.js +314 -0
- package/src/prompt-adapter.js +63 -0
- package/templates/Dockerfile +300 -0
- package/templates/IAM_PERMISSIONS.md +84 -0
- package/templates/MIGRATION.md +488 -0
- package/templates/PROJECT_README.md +439 -0
- package/templates/TEMPLATE_SYSTEM.md +243 -0
- package/templates/buildspec.yml +64 -0
- package/templates/code/chat_template.jinja +1 -0
- package/templates/code/flask/gunicorn_config.py +35 -0
- package/templates/code/flask/wsgi.py +10 -0
- package/templates/code/model_handler.py +387 -0
- package/templates/code/serve +300 -0
- package/templates/code/serve.py +175 -0
- package/templates/code/serving.properties +105 -0
- package/templates/code/start_server.py +39 -0
- package/templates/code/start_server.sh +39 -0
- package/templates/diffusors/Dockerfile +72 -0
- package/templates/diffusors/patch_image_api.py +35 -0
- package/templates/diffusors/serve +115 -0
- package/templates/diffusors/start_server.sh +114 -0
- package/templates/do/.gitkeep +1 -0
- package/templates/do/README.md +541 -0
- package/templates/do/build +83 -0
- package/templates/do/ci +681 -0
- package/templates/do/clean +811 -0
- package/templates/do/config +260 -0
- package/templates/do/deploy +1560 -0
- package/templates/do/export +306 -0
- package/templates/do/logs +319 -0
- package/templates/do/manifest +12 -0
- package/templates/do/push +119 -0
- package/templates/do/register +580 -0
- package/templates/do/run +113 -0
- package/templates/do/submit +417 -0
- package/templates/do/test +1147 -0
- package/templates/hyperpod/configmap.yaml +24 -0
- package/templates/hyperpod/deployment.yaml +71 -0
- package/templates/hyperpod/pvc.yaml +42 -0
- package/templates/hyperpod/service.yaml +17 -0
- package/templates/nginx-diffusors.conf +74 -0
- package/templates/nginx-predictors.conf +47 -0
- package/templates/nginx-tensorrt.conf +74 -0
- package/templates/requirements.txt +61 -0
- package/templates/sample_model/test_inference.py +123 -0
- package/templates/sample_model/train_abalone.py +252 -0
- package/templates/test/test_endpoint.sh +79 -0
- package/templates/test/test_local_image.sh +80 -0
- package/templates/test/test_model_handler.py +180 -0
- package/templates/triton/Dockerfile +128 -0
- package/templates/triton/config.pbtxt +163 -0
- package/templates/triton/model.py +130 -0
- package/templates/triton/requirements.txt +11 -0
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* MCP Client
|
|
6
|
+
*
|
|
7
|
+
* Spawns an MCP server as a child process via stdio transport,
|
|
8
|
+
* performs the protocol handshake, calls the configured tool,
|
|
9
|
+
* and returns parsed configuration values.
|
|
10
|
+
*
|
|
11
|
+
* All errors are caught and returned as null with a diagnostic
|
|
12
|
+
* message — never thrown.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
16
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
17
|
+
|
|
18
|
+
const DEFAULT_TOOL_NAME = 'get_ml_config';
|
|
19
|
+
const DEFAULT_LIMIT = 10;
|
|
20
|
+
const DEFAULT_TIMEOUT = 10000; // 10 seconds
|
|
21
|
+
// const KILL_GRACE_PERIOD = 2000; // reserved for future graceful-shutdown logic
|
|
22
|
+
|
|
23
|
+
class McpClient {
|
|
24
|
+
/**
|
|
25
|
+
* @param {object} serverConfig - { command, args, env, toolName, limit }
|
|
26
|
+
* @param {object} options - { timeout, parameterMatrix }
|
|
27
|
+
*/
|
|
28
|
+
constructor(serverConfig, options = {}) {
|
|
29
|
+
this.serverConfig = serverConfig;
|
|
30
|
+
this.toolName = serverConfig.toolName || DEFAULT_TOOL_NAME;
|
|
31
|
+
this.limit = serverConfig.limit || DEFAULT_LIMIT;
|
|
32
|
+
this.timeout = options.timeout || DEFAULT_TIMEOUT;
|
|
33
|
+
this.parameterMatrix = options.parameterMatrix || {};
|
|
34
|
+
this.smart = options.smart || false;
|
|
35
|
+
this.discover = options.discover || false;
|
|
36
|
+
this._transport = null;
|
|
37
|
+
this._client = null;
|
|
38
|
+
this._diagnosticMessage = null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Connect to the MCP server, perform handshake, query for config values.
|
|
43
|
+
* @returns {Promise<{ values: Record<string, any>, choices: Record<string, string[]> } | null>}
|
|
44
|
+
*/
|
|
45
|
+
async query() {
|
|
46
|
+
try {
|
|
47
|
+
return await this._queryWithTimeout();
|
|
48
|
+
} catch (err) {
|
|
49
|
+
this._diagnosticMessage = `MCP query failed: ${err.message}`;
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Wraps the actual query logic with a timeout that covers the
|
|
56
|
+
* entire lifecycle: spawn + handshake + tool call + response parsing.
|
|
57
|
+
*/
|
|
58
|
+
async _queryWithTimeout() {
|
|
59
|
+
return new Promise((resolve, _reject) => {
|
|
60
|
+
let settled = false;
|
|
61
|
+
const timer = setTimeout(() => {
|
|
62
|
+
if (!settled) {
|
|
63
|
+
settled = true;
|
|
64
|
+
this._diagnosticMessage = `MCP server timed out after ${this.timeout}ms`;
|
|
65
|
+
this.close().catch(() => {});
|
|
66
|
+
resolve(null);
|
|
67
|
+
}
|
|
68
|
+
}, this.timeout);
|
|
69
|
+
|
|
70
|
+
this._executeQuery()
|
|
71
|
+
.then(result => {
|
|
72
|
+
if (!settled) {
|
|
73
|
+
settled = true;
|
|
74
|
+
clearTimeout(timer);
|
|
75
|
+
resolve(result);
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
.catch(err => {
|
|
79
|
+
if (!settled) {
|
|
80
|
+
settled = true;
|
|
81
|
+
clearTimeout(timer);
|
|
82
|
+
this._diagnosticMessage = `MCP query failed: ${err.message}`;
|
|
83
|
+
resolve(null);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Performs the actual MCP protocol flow:
|
|
91
|
+
* 1. Spawn server via StdioClientTransport
|
|
92
|
+
* 2. Connect Client (performs initialize handshake + initialized notification)
|
|
93
|
+
* 3. Call the configured tool with unbounded parameter names and limit
|
|
94
|
+
* 4. Parse and return the response
|
|
95
|
+
*/
|
|
96
|
+
async _executeQuery() {
|
|
97
|
+
const { command, args = [], env } = this.serverConfig;
|
|
98
|
+
|
|
99
|
+
// Build environment: merge process.env with server-specific env
|
|
100
|
+
// When --smart flag is active, inject BEDROCK_SMART=true for this run
|
|
101
|
+
// When --discover flag is active, inject MCP_DISCOVER=true for this run
|
|
102
|
+
// Always pass process.env so child processes inherit AWS credentials, profiles, etc.
|
|
103
|
+
const smartEnv = this.smart ? { BEDROCK_SMART: 'true' } : {};
|
|
104
|
+
const discoverEnv = this.discover ? { MCP_DISCOVER: 'true' } : {};
|
|
105
|
+
const serverEnv = env && Object.keys(env).length > 0 ? env : {};
|
|
106
|
+
const spawnEnv = { ...process.env, ...smartEnv, ...discoverEnv, ...serverEnv };
|
|
107
|
+
|
|
108
|
+
// Create stdio transport — spawns the server process
|
|
109
|
+
this._transport = new StdioClientTransport({
|
|
110
|
+
command,
|
|
111
|
+
args,
|
|
112
|
+
env: spawnEnv,
|
|
113
|
+
stderr: 'pipe'
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Create MCP client
|
|
117
|
+
this._client = new Client(
|
|
118
|
+
{ name: 'ml-container-creator', version: '1.0.0' },
|
|
119
|
+
{ capabilities: {} }
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
// Connect performs the initialize handshake automatically
|
|
123
|
+
await this._client.connect(this._transport);
|
|
124
|
+
|
|
125
|
+
// Build the list of unbounded parameter names
|
|
126
|
+
const unboundedParams = this._getUnboundedParameterNames();
|
|
127
|
+
|
|
128
|
+
// Build context from bounded parameters that have defaults
|
|
129
|
+
const context = this._buildContext();
|
|
130
|
+
|
|
131
|
+
// Call the configured tool
|
|
132
|
+
const result = await this._client.callTool({
|
|
133
|
+
name: this.toolName,
|
|
134
|
+
arguments: {
|
|
135
|
+
parameters: unboundedParams,
|
|
136
|
+
limit: this.limit,
|
|
137
|
+
context
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Parse the response
|
|
142
|
+
return this._parseResponse(result);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Extract unbounded parameter names from the parameter matrix.
|
|
147
|
+
* @returns {string[]}
|
|
148
|
+
*/
|
|
149
|
+
_getUnboundedParameterNames() {
|
|
150
|
+
const names = [];
|
|
151
|
+
for (const [name, config] of Object.entries(this.parameterMatrix)) {
|
|
152
|
+
if (config.valueSpace === 'unbounded' && config.mcp === true) {
|
|
153
|
+
names.push(name);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return names;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Build context object from bounded parameters with known defaults.
|
|
161
|
+
* This gives the MCP server context about the current configuration.
|
|
162
|
+
* @returns {object}
|
|
163
|
+
*/
|
|
164
|
+
_buildContext() {
|
|
165
|
+
const context = {};
|
|
166
|
+
for (const [name, config] of Object.entries(this.parameterMatrix)) {
|
|
167
|
+
if (config.valueSpace === 'bounded' && config.default !== null && config.default !== undefined) {
|
|
168
|
+
context[name] = config.default;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return context;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Parse the MCP tool call response into { values, choices }.
|
|
176
|
+
* The response content is an array of content blocks; we look for
|
|
177
|
+
* a text block containing JSON with values and/or choices.
|
|
178
|
+
* @param {object} result - The callTool result
|
|
179
|
+
* @returns {{ values: Record<string, any>, choices: Record<string, string[]> } | null}
|
|
180
|
+
*/
|
|
181
|
+
_parseResponse(result) {
|
|
182
|
+
if (!result) {
|
|
183
|
+
this._diagnosticMessage = 'MCP server returned empty result';
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Check for error flag
|
|
188
|
+
if (result.isError) {
|
|
189
|
+
const errorText = this._extractTextContent(result);
|
|
190
|
+
this._diagnosticMessage = `MCP server returned error: ${errorText || 'unknown error'}`;
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Extract text content from the response
|
|
195
|
+
const textContent = this._extractTextContent(result);
|
|
196
|
+
if (!textContent) {
|
|
197
|
+
this._diagnosticMessage = 'MCP server returned no text content';
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Parse JSON from text content
|
|
202
|
+
let parsed;
|
|
203
|
+
try {
|
|
204
|
+
parsed = JSON.parse(textContent);
|
|
205
|
+
} catch (err) {
|
|
206
|
+
this._diagnosticMessage = `MCP server returned malformed JSON: ${err.message}`;
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Validate structure
|
|
211
|
+
if (typeof parsed !== 'object' || parsed === null) {
|
|
212
|
+
this._diagnosticMessage = 'MCP server returned non-object response';
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const values = {};
|
|
217
|
+
const choices = {};
|
|
218
|
+
const metadata = {};
|
|
219
|
+
|
|
220
|
+
// Extract values — only for unbounded parameters
|
|
221
|
+
if (parsed.values && typeof parsed.values === 'object') {
|
|
222
|
+
for (const [key, value] of Object.entries(parsed.values)) {
|
|
223
|
+
values[key] = value;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Extract choices — only for unbounded parameters
|
|
228
|
+
if (parsed.choices && typeof parsed.choices === 'object') {
|
|
229
|
+
for (const [key, choiceList] of Object.entries(parsed.choices)) {
|
|
230
|
+
if (Array.isArray(choiceList)) {
|
|
231
|
+
choices[key] = choiceList;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Extract metadata — pass through for rich display (e.g., ImageEntry objects)
|
|
237
|
+
if (parsed.metadata && typeof parsed.metadata === 'object') {
|
|
238
|
+
for (const [key, value] of Object.entries(parsed.metadata)) {
|
|
239
|
+
metadata[key] = value;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const response = { values, choices, message: parsed.message || null };
|
|
244
|
+
if (Object.keys(metadata).length > 0) {
|
|
245
|
+
response.metadata = metadata;
|
|
246
|
+
}
|
|
247
|
+
return response;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Extract text content from an MCP tool result.
|
|
252
|
+
* @param {object} result
|
|
253
|
+
* @returns {string | null}
|
|
254
|
+
*/
|
|
255
|
+
_extractTextContent(result) {
|
|
256
|
+
if (!result.content || !Array.isArray(result.content)) {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const textBlock = result.content.find(block => block.type === 'text');
|
|
261
|
+
return textBlock ? textBlock.text : null;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Get the diagnostic message from the last operation.
|
|
266
|
+
* @returns {string | null}
|
|
267
|
+
*/
|
|
268
|
+
getDiagnosticMessage() {
|
|
269
|
+
return this._diagnosticMessage;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Cleanly terminate the server process.
|
|
274
|
+
* Sends SIGTERM first, then SIGKILL after grace period.
|
|
275
|
+
*/
|
|
276
|
+
async close() {
|
|
277
|
+
try {
|
|
278
|
+
if (this._client) {
|
|
279
|
+
await this._client.close();
|
|
280
|
+
this._client = null;
|
|
281
|
+
}
|
|
282
|
+
if (this._transport) {
|
|
283
|
+
await this._transport.close();
|
|
284
|
+
this._transport = null;
|
|
285
|
+
}
|
|
286
|
+
} catch (err) {
|
|
287
|
+
// If graceful close fails, force kill via transport
|
|
288
|
+
if (this._transport) {
|
|
289
|
+
try {
|
|
290
|
+
// The transport's close() handles SIGTERM + SIGKILL
|
|
291
|
+
await this._transport.close();
|
|
292
|
+
} catch (_) {
|
|
293
|
+
// Ignore — process may already be dead
|
|
294
|
+
}
|
|
295
|
+
this._transport = null;
|
|
296
|
+
}
|
|
297
|
+
this._client = null;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export default McpClient;
|
|
303
|
+
export { McpClient, DEFAULT_TOOL_NAME, DEFAULT_LIMIT, DEFAULT_TIMEOUT };
|