awslabs.finch-mcp-server 0.1.1__py3-none-any.whl
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.
- awslabs/__init__.py +12 -0
- awslabs/finch_mcp_server/__init__.py +14 -0
- awslabs/finch_mcp_server/consts.py +40 -0
- awslabs/finch_mcp_server/models.py +19 -0
- awslabs/finch_mcp_server/server.py +442 -0
- awslabs/finch_mcp_server/utils/__init__.py +16 -0
- awslabs/finch_mcp_server/utils/build.py +141 -0
- awslabs/finch_mcp_server/utils/common.py +167 -0
- awslabs/finch_mcp_server/utils/ecr.py +87 -0
- awslabs/finch_mcp_server/utils/push.py +125 -0
- awslabs/finch_mcp_server/utils/vm.py +417 -0
- awslabs_finch_mcp_server-0.1.1.dist-info/METADATA +212 -0
- awslabs_finch_mcp_server-0.1.1.dist-info/RECORD +17 -0
- awslabs_finch_mcp_server-0.1.1.dist-info/WHEEL +4 -0
- awslabs_finch_mcp_server-0.1.1.dist-info/entry_points.txt +2 -0
- awslabs_finch_mcp_server-0.1.1.dist-info/licenses/LICENSE +201 -0
- awslabs_finch_mcp_server-0.1.1.dist-info/licenses/NOTICE +2 -0
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
"""Utility functions for managing the Finch VM.
|
|
2
|
+
|
|
3
|
+
This module provides functions to check, initialize, start, stop, and configure
|
|
4
|
+
the Finch virtual machine that runs containers.
|
|
5
|
+
|
|
6
|
+
Note: These tools are intended for development and prototyping purposes only
|
|
7
|
+
and are not meant for production use cases.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
import subprocess
|
|
12
|
+
import sys
|
|
13
|
+
import yaml
|
|
14
|
+
from ..consts import (
|
|
15
|
+
FINCH_YAML_PATH,
|
|
16
|
+
STATUS_ERROR,
|
|
17
|
+
STATUS_SUCCESS,
|
|
18
|
+
VM_STATE_NONEXISTENT,
|
|
19
|
+
VM_STATE_RUNNING,
|
|
20
|
+
VM_STATE_STOPPED,
|
|
21
|
+
VM_STATE_UNKNOWN,
|
|
22
|
+
)
|
|
23
|
+
from .common import execute_command, format_result
|
|
24
|
+
from loguru import logger
|
|
25
|
+
from shutil import which
|
|
26
|
+
from typing import Dict, Literal
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def get_vm_status() -> subprocess.CompletedProcess:
|
|
30
|
+
"""Get the current status of the Finch VM.
|
|
31
|
+
|
|
32
|
+
This function executes 'finch vm status' and returns the raw result.
|
|
33
|
+
It's a wrapper around execute_command that simplifies checking
|
|
34
|
+
the VM status, which is a common operation used by multiple tools.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
CompletedProcess with the status command result, containing:
|
|
38
|
+
- returncode: The exit code of the command
|
|
39
|
+
- stdout: Standard output containing status information
|
|
40
|
+
- stderr: Standard error output, may also contain status information
|
|
41
|
+
|
|
42
|
+
"""
|
|
43
|
+
return execute_command(['finch', 'vm', 'status'])
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def is_vm_nonexistent(status_result: subprocess.CompletedProcess) -> bool:
|
|
47
|
+
"""Check if the Finch VM is nonexistent based on status result.
|
|
48
|
+
|
|
49
|
+
This function analyzes the output of 'finch vm status' to determine
|
|
50
|
+
if the VM has not been created yet.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
status_result: CompletedProcess object from running 'finch vm status'
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
bool: True if the VM is nonexistent, False otherwise
|
|
57
|
+
|
|
58
|
+
"""
|
|
59
|
+
return (
|
|
60
|
+
'nonexistent' in status_result.stderr.lower()
|
|
61
|
+
or 'nonexistent' in status_result.stdout.lower()
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def is_vm_stopped(status_result: subprocess.CompletedProcess) -> bool:
|
|
66
|
+
"""Check if the Finch VM is stopped based on status result.
|
|
67
|
+
|
|
68
|
+
This function analyzes the output of 'finch vm status' to determine
|
|
69
|
+
if the VM exists but is not currently running.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
status_result: CompletedProcess object from running 'finch vm status'
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
bool: True if the VM is stopped, False otherwise
|
|
76
|
+
|
|
77
|
+
"""
|
|
78
|
+
return 'stopped' in status_result.stderr.lower() or 'stopped' in status_result.stdout.lower()
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def is_vm_running(status_result: subprocess.CompletedProcess) -> bool:
|
|
82
|
+
"""Check if the Finch VM is running based on status result.
|
|
83
|
+
|
|
84
|
+
This function analyzes the output of 'finch vm status' to determine
|
|
85
|
+
if the VM is currently active and operational.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
status_result: CompletedProcess object from running 'finch vm status'
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
bool: True if the VM is running, False otherwise
|
|
92
|
+
|
|
93
|
+
"""
|
|
94
|
+
return 'running' in status_result.stdout.lower() or 'running' in status_result.stderr.lower()
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def initialize_vm() -> Dict[str, str]:
|
|
98
|
+
"""Initialize a new Finch VM.
|
|
99
|
+
|
|
100
|
+
This function runs 'finch vm init' to create a new Finch VM instance.
|
|
101
|
+
It's used when the VM doesn't exist yet and needs to be created.
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
Dict[str, Any]: Result dictionary with:
|
|
105
|
+
- status: "success" if initialization succeeded, "error" otherwise
|
|
106
|
+
- message: Details about the initialization result
|
|
107
|
+
|
|
108
|
+
"""
|
|
109
|
+
if sys.platform == 'linux':
|
|
110
|
+
logger.debug('Linux OS detected. Finch does not use a VM on Linux...')
|
|
111
|
+
return format_result(STATUS_SUCCESS, 'Finch does not use a VM on Linux..')
|
|
112
|
+
|
|
113
|
+
logger.warning('Finch VM non existent, Initializing a new vm instance...')
|
|
114
|
+
init_result = execute_command(['finch', 'vm', 'init'])
|
|
115
|
+
|
|
116
|
+
if init_result.returncode == 0:
|
|
117
|
+
return format_result(STATUS_SUCCESS, 'Finch VM was initialized successfully.')
|
|
118
|
+
else:
|
|
119
|
+
return format_result(STATUS_ERROR, f'Failed to initialize Finch VM: {init_result.stderr}')
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def start_stopped_vm() -> Dict[str, str]:
|
|
123
|
+
"""Start a stopped Finch VM.
|
|
124
|
+
|
|
125
|
+
This function runs 'finch vm start' to start a VM that exists but is
|
|
126
|
+
currently stopped. It's used to make the VM operational when it's not running.
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
Dict[str, Any]: Result dictionary with:
|
|
130
|
+
- status: "success" if the VM was started successfully, "error" otherwise
|
|
131
|
+
- message: Details about the start operation result
|
|
132
|
+
|
|
133
|
+
"""
|
|
134
|
+
if sys.platform == 'linux':
|
|
135
|
+
logger.debug('Linux OS detected. Finch does not use a VM on Linux...')
|
|
136
|
+
return format_result(STATUS_SUCCESS, 'Finch does not use a VM on Linux..')
|
|
137
|
+
|
|
138
|
+
logger.info('Finch VM is stopped. Starting it...')
|
|
139
|
+
start_result = execute_command(['finch', 'vm', 'start'])
|
|
140
|
+
|
|
141
|
+
if start_result.returncode == 0:
|
|
142
|
+
return format_result(
|
|
143
|
+
STATUS_SUCCESS, 'Finch VM was stopped and has been started successfully.'
|
|
144
|
+
)
|
|
145
|
+
else:
|
|
146
|
+
return format_result(STATUS_ERROR, f'Failed to start Finch VM: {start_result.stderr}')
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def stop_vm(force: bool = False) -> Dict[str, str]:
|
|
150
|
+
"""Stop a running Finch VM.
|
|
151
|
+
|
|
152
|
+
This function runs 'finch vm stop' to shut down a running VM.
|
|
153
|
+
If force is True, it adds the '--force' flag to forcefully terminate
|
|
154
|
+
the VM even if it's in use.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
force: Whether to force stop the VM. Use this when the VM might be
|
|
158
|
+
in an inconsistent state or when normal shutdown fails.
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
Dict[str, Any]: Result dictionary with:
|
|
162
|
+
- status: "success" if the VM was stopped successfully, "error" otherwise
|
|
163
|
+
- message: Details about the stop operation result
|
|
164
|
+
|
|
165
|
+
"""
|
|
166
|
+
if sys.platform == 'linux':
|
|
167
|
+
logger.debug('Linux OS detected. Finch does not use a VM on Linux...')
|
|
168
|
+
return format_result(STATUS_SUCCESS, 'Finch does not use a VM on Linux..')
|
|
169
|
+
|
|
170
|
+
command = ['finch', 'vm', 'stop']
|
|
171
|
+
if force:
|
|
172
|
+
command.append('--force')
|
|
173
|
+
|
|
174
|
+
stop_result = execute_command(command)
|
|
175
|
+
|
|
176
|
+
if stop_result.returncode == 0:
|
|
177
|
+
return format_result(STATUS_SUCCESS, 'Finch VM has been stopped successfully.')
|
|
178
|
+
else:
|
|
179
|
+
return format_result(STATUS_ERROR, f'Failed to stop Finch VM: {stop_result.stderr}')
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def remove_vm(force: bool = False) -> Dict[str, str]:
|
|
183
|
+
"""Remove the Finch VM.
|
|
184
|
+
|
|
185
|
+
This function runs 'finch vm rm' to remove the VM.
|
|
186
|
+
If force is True, it adds the '--force' flag to forcefully remove
|
|
187
|
+
the VM even if it's in use.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
force: Whether to force remove the VM. Use this when the VM might be
|
|
191
|
+
in an inconsistent state or when normal removal fails.
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
Dict[str, Any]: Result dictionary with:
|
|
195
|
+
- status: "success" if the VM was removed successfully, "error" otherwise
|
|
196
|
+
- message: Details about the remove operation result
|
|
197
|
+
|
|
198
|
+
"""
|
|
199
|
+
if sys.platform == 'linux':
|
|
200
|
+
logger.debug('Linux OS detected. Finch does not use a VM on Linux...')
|
|
201
|
+
return format_result(STATUS_SUCCESS, 'Finch does not use a VM on Linux..')
|
|
202
|
+
|
|
203
|
+
command = ['finch', 'vm', 'rm']
|
|
204
|
+
if force:
|
|
205
|
+
command.append('--force')
|
|
206
|
+
|
|
207
|
+
remove_result = execute_command(command)
|
|
208
|
+
|
|
209
|
+
if remove_result.returncode == 0:
|
|
210
|
+
return format_result(STATUS_SUCCESS, 'Finch VM has been removed successfully.')
|
|
211
|
+
else:
|
|
212
|
+
return format_result(STATUS_ERROR, f'Failed to remove Finch VM: {remove_result.stderr}')
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def restart_running_vm() -> Dict[str, str]:
|
|
216
|
+
"""Restart a running Finch VM (stop then start).
|
|
217
|
+
|
|
218
|
+
This function performs a full restart of the VM by first stopping it
|
|
219
|
+
(with force=True to ensure it stops) and then starting it again.
|
|
220
|
+
It's useful when you need to refresh the VM state completely.
|
|
221
|
+
|
|
222
|
+
Returns:
|
|
223
|
+
Dict[str, Any]: Result dictionary with:
|
|
224
|
+
- status: "success" if the VM was restarted successfully, "error" otherwise
|
|
225
|
+
- message: Details about the restart operation result
|
|
226
|
+
|
|
227
|
+
"""
|
|
228
|
+
if sys.platform == 'linux':
|
|
229
|
+
logger.debug('Linux OS detected. Finch does not use a VM on Linux...')
|
|
230
|
+
return format_result(STATUS_SUCCESS, 'Finch does not use a VM on Linux..')
|
|
231
|
+
|
|
232
|
+
logger.info('Finch VM is running. Restarting it...')
|
|
233
|
+
|
|
234
|
+
stop_result = stop_vm(force=True)
|
|
235
|
+
if stop_result['status'] == STATUS_ERROR:
|
|
236
|
+
return stop_result
|
|
237
|
+
|
|
238
|
+
start_result = start_stopped_vm()
|
|
239
|
+
|
|
240
|
+
return start_result
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def check_finch_installation() -> Dict[str, str]:
|
|
244
|
+
"""Check if the Finch CLI tool is installed on the system.
|
|
245
|
+
|
|
246
|
+
This function uses 'which finch' on macOS/Linux to determine if the
|
|
247
|
+
Finch command-line tool is available in the system PATH. It's a
|
|
248
|
+
prerequisite check before attempting to use any Finch functionality.
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
Dict[str, Any]: Result dictionary with:
|
|
252
|
+
- status: "success" if Finch is installed, "error" otherwise
|
|
253
|
+
- message: Details about the installation status
|
|
254
|
+
|
|
255
|
+
"""
|
|
256
|
+
try:
|
|
257
|
+
if which('finch') is not None:
|
|
258
|
+
return format_result(STATUS_SUCCESS, 'Finch is installed.')
|
|
259
|
+
else:
|
|
260
|
+
return format_result(STATUS_ERROR, 'Finch is not installed.')
|
|
261
|
+
except Exception as e:
|
|
262
|
+
return format_result(STATUS_ERROR, f'Error checking Finch installation: {str(e)}')
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def configure_ecr() -> tuple[Dict[str, str], bool]:
|
|
266
|
+
r"""Configure Finch to use ECR (Amazon Elastic Container Registry).
|
|
267
|
+
|
|
268
|
+
This function updates the Finch YAML configuration file:
|
|
269
|
+
- macOS: ~/.finch/finch.yaml
|
|
270
|
+
- Windows: %LocalAppData%\.finch\finch.yaml
|
|
271
|
+
|
|
272
|
+
It adds 'ecr-login' to the creds_helpers list while preserving other settings.
|
|
273
|
+
|
|
274
|
+
This enables Finch to authenticate with Amazon ECR. The config.json file is not modified
|
|
275
|
+
as it is automatically handled when adding the ecr-login credential helper in finch.yaml.
|
|
276
|
+
|
|
277
|
+
Returns:
|
|
278
|
+
tuple[Dict[str, str], bool]: A tuple containing:
|
|
279
|
+
- Result dictionary with:
|
|
280
|
+
- status: "success" if the configuration was updated successfully, "error" otherwise
|
|
281
|
+
- message: Details about the configuration result
|
|
282
|
+
- Boolean indicating if the configuration was changed (True if changed, False otherwise)
|
|
283
|
+
|
|
284
|
+
"""
|
|
285
|
+
try:
|
|
286
|
+
if sys.platform == 'linux':
|
|
287
|
+
(
|
|
288
|
+
logger.info(
|
|
289
|
+
'Linux OS detected. config.json set in DOCKER_CONFIG is used for credentials'
|
|
290
|
+
),
|
|
291
|
+
False,
|
|
292
|
+
)
|
|
293
|
+
return format_result(
|
|
294
|
+
'success', 'config.json set in DOCKER_CONFIG is used for credentials'
|
|
295
|
+
), False
|
|
296
|
+
|
|
297
|
+
changed_yaml = False
|
|
298
|
+
# For Windows, FINCH_YAML_PATH is already an absolute path
|
|
299
|
+
# For macOS, we need to expand the ~ in the path
|
|
300
|
+
finch_yaml_path = FINCH_YAML_PATH
|
|
301
|
+
if sys.platform != 'win32':
|
|
302
|
+
finch_yaml_path = os.path.expanduser(FINCH_YAML_PATH)
|
|
303
|
+
|
|
304
|
+
if os.path.exists(finch_yaml_path):
|
|
305
|
+
try:
|
|
306
|
+
with open(finch_yaml_path, 'r') as f:
|
|
307
|
+
yaml_content = yaml.safe_load(f) or {}
|
|
308
|
+
|
|
309
|
+
if 'creds_helpers' in yaml_content:
|
|
310
|
+
if not isinstance(yaml_content['creds_helpers'], list):
|
|
311
|
+
yaml_content['creds_helpers'] = (
|
|
312
|
+
[yaml_content['creds_helpers']]
|
|
313
|
+
if yaml_content['creds_helpers']
|
|
314
|
+
else []
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
if 'ecr-login' not in yaml_content['creds_helpers']:
|
|
318
|
+
yaml_content['creds_helpers'].append('ecr-login')
|
|
319
|
+
changed_yaml = True
|
|
320
|
+
else:
|
|
321
|
+
yaml_content['creds_helpers'] = ['ecr-login']
|
|
322
|
+
changed_yaml = True
|
|
323
|
+
|
|
324
|
+
if changed_yaml:
|
|
325
|
+
with open(finch_yaml_path, 'w') as f:
|
|
326
|
+
yaml.dump(yaml_content, f, default_flow_style=False)
|
|
327
|
+
|
|
328
|
+
except Exception as e:
|
|
329
|
+
logger.warning(f'Error updating {finch_yaml_path} with PyYAML: {str(e)}')
|
|
330
|
+
return format_result(
|
|
331
|
+
STATUS_ERROR, f'Failed to update finch YAML file: {str(e)}'
|
|
332
|
+
), False
|
|
333
|
+
else:
|
|
334
|
+
if sys.platform == 'win32':
|
|
335
|
+
error_msg = f'finch yaml file not found at {finch_yaml_path}'
|
|
336
|
+
else:
|
|
337
|
+
error_msg = 'finch yaml file not found in finch.yaml'
|
|
338
|
+
return format_result(STATUS_ERROR, error_msg), False
|
|
339
|
+
|
|
340
|
+
if changed_yaml:
|
|
341
|
+
# Log the change status
|
|
342
|
+
logger.debug('ECR configuration was updated in finch.yaml')
|
|
343
|
+
result = format_result(
|
|
344
|
+
STATUS_SUCCESS,
|
|
345
|
+
'ECR configuration updated successfully in finch.yaml.',
|
|
346
|
+
)
|
|
347
|
+
else:
|
|
348
|
+
# Log that no changes were needed
|
|
349
|
+
logger.debug('ECR was already configured correctly in finch.yaml')
|
|
350
|
+
result = format_result(
|
|
351
|
+
STATUS_SUCCESS,
|
|
352
|
+
'ECR was already configured correctly in finch.yaml.',
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
return result, changed_yaml
|
|
356
|
+
|
|
357
|
+
except Exception as e:
|
|
358
|
+
return format_result(STATUS_ERROR, f'Failed to configure ECR: {str(e)}'), False
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def validate_vm_state(
|
|
362
|
+
expected_state: Literal['running', 'stopped', 'nonexistent'],
|
|
363
|
+
) -> Dict[str, str]:
|
|
364
|
+
"""Validate that the Finch VM is in the expected state.
|
|
365
|
+
|
|
366
|
+
This function checks the current state of the VM and compares it to the expected state.
|
|
367
|
+
It's used to verify that operations like start, stop, and remove have the desired effect.
|
|
368
|
+
|
|
369
|
+
Args:
|
|
370
|
+
expected_state: The state the VM should be in ("running", "stopped", or "nonexistent")
|
|
371
|
+
|
|
372
|
+
Returns:
|
|
373
|
+
Dict[str, str]: Result dictionary with:
|
|
374
|
+
- status: "success" if the VM is in the expected state, "error" otherwise
|
|
375
|
+
- message: Details about the validation result
|
|
376
|
+
|
|
377
|
+
"""
|
|
378
|
+
try:
|
|
379
|
+
status_result = get_vm_status()
|
|
380
|
+
|
|
381
|
+
if expected_state == VM_STATE_RUNNING and is_vm_running(status_result):
|
|
382
|
+
logger.debug('VM state validation passed: running')
|
|
383
|
+
return format_result(
|
|
384
|
+
STATUS_SUCCESS,
|
|
385
|
+
'Validation passed: Finch VM is running as expected.',
|
|
386
|
+
)
|
|
387
|
+
elif expected_state == VM_STATE_STOPPED and is_vm_stopped(status_result):
|
|
388
|
+
logger.debug('VM state validation passed: stopped')
|
|
389
|
+
return format_result(
|
|
390
|
+
STATUS_SUCCESS,
|
|
391
|
+
'Validation passed: Finch VM is stopped as expected.',
|
|
392
|
+
)
|
|
393
|
+
elif expected_state == VM_STATE_NONEXISTENT and is_vm_nonexistent(status_result):
|
|
394
|
+
logger.debug('VM state validation passed: nonexistent')
|
|
395
|
+
return format_result(
|
|
396
|
+
STATUS_SUCCESS,
|
|
397
|
+
'Validation passed: Finch VM is nonexistent as expected.',
|
|
398
|
+
)
|
|
399
|
+
else:
|
|
400
|
+
actual_state = VM_STATE_UNKNOWN
|
|
401
|
+
if is_vm_running(status_result):
|
|
402
|
+
actual_state = VM_STATE_RUNNING
|
|
403
|
+
elif is_vm_stopped(status_result):
|
|
404
|
+
actual_state = VM_STATE_STOPPED
|
|
405
|
+
elif is_vm_nonexistent(status_result):
|
|
406
|
+
actual_state = VM_STATE_NONEXISTENT
|
|
407
|
+
|
|
408
|
+
logger.debug(
|
|
409
|
+
f'VM state validation failed: expected={expected_state}, actual={actual_state}'
|
|
410
|
+
)
|
|
411
|
+
return format_result(
|
|
412
|
+
STATUS_ERROR,
|
|
413
|
+
f'Validation failed: Expected Finch VM to be {expected_state}, but it is {actual_state}.',
|
|
414
|
+
)
|
|
415
|
+
except Exception as e:
|
|
416
|
+
logger.error(f'Error during VM state validation: {str(e)}')
|
|
417
|
+
return format_result(STATUS_ERROR, f'Error validating VM state: {str(e)}')
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: awslabs.finch-mcp-server
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: A Model Context Protocol server for Finch to build and push container images
|
|
5
|
+
Project-URL: Homepage, https://awslabs.github.io/mcp/
|
|
6
|
+
Project-URL: Documentation, https://awslabs.github.io/mcp/servers/finch-mcp-server/
|
|
7
|
+
Project-URL: Source, https://github.com/awslabs/mcp.git
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/awslabs/mcp/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/awslabs/mcp/blob/main/src/finch-mcp-server/CHANGELOG.md
|
|
10
|
+
Author: Amazon Web Services
|
|
11
|
+
Author-email: AWSLabs MCP <203918161+awslabs-mcp@users.noreply.github.com>
|
|
12
|
+
License: Apache-2.0
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
License-File: NOTICE
|
|
15
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Requires-Dist: boto3>=1.28.0
|
|
25
|
+
Requires-Dist: loguru>=0.7.0
|
|
26
|
+
Requires-Dist: mcp[cli]>=1.6.0
|
|
27
|
+
Requires-Dist: pydantic>=2.0.0
|
|
28
|
+
Requires-Dist: pyyaml>=6.0
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# Finch MCP Server
|
|
32
|
+
|
|
33
|
+
A Model Context Protocol (MCP) server for Finch that enables generative AI models to build and push container images through finch cli leveraged MCP tools.
|
|
34
|
+
|
|
35
|
+
## Features
|
|
36
|
+
|
|
37
|
+
This MCP server acts as a bridge between MCP clients and Finch, allowing generative AI models to build and push container images to repositories, and create ECR repositories as needed. The server provides a secure way to interact with Finch, ensuring that the Finch VM is properly initialized and running before performing operations.
|
|
38
|
+
|
|
39
|
+
## Key Capabilities
|
|
40
|
+
|
|
41
|
+
- Build container images using Finch
|
|
42
|
+
- Push container images to repositories, including Amazon ECR
|
|
43
|
+
- Check if ECR repositories exist and create them if needed
|
|
44
|
+
- Automatic management of the Finch VM on macos and windows (initialization, starting, etc.)
|
|
45
|
+
- Automatic configuration of ECR credential helpers when needed (only modifies finch.yaml as config.json is automatically handled)
|
|
46
|
+
|
|
47
|
+
## Prerequisites
|
|
48
|
+
|
|
49
|
+
1. Install `uv` from [Astral](https://docs.astral.sh/uv/getting-started/installation/) or the [GitHub README](https://github.com/astral-sh/uv#installation)
|
|
50
|
+
2. Install Python using `uv python install 3.10`
|
|
51
|
+
3. Install [Finch](https://github.com/runfinch/finch) on your system
|
|
52
|
+
4. For ECR operations, AWS credentials with permissions to push to ECR repositories and create/describe ECR repositories
|
|
53
|
+
|
|
54
|
+
## Setup
|
|
55
|
+
|
|
56
|
+
### Installation
|
|
57
|
+
|
|
58
|
+
Configure the MCP server in your MCP client configuration:
|
|
59
|
+
|
|
60
|
+
#### Default Mode (Read-only AWS Resources)
|
|
61
|
+
|
|
62
|
+
By default, the server runs in a mode that prevents the creation of new AWS resources. This is useful for environments where you want to limit resource creation or for users who should only be able to build and push to existing repositories.
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"mcpServers": {
|
|
67
|
+
"awslabs.finch-mcp-server": {
|
|
68
|
+
"command": "uvx",
|
|
69
|
+
"args": ["awslabs.finch-mcp-server@latest"],
|
|
70
|
+
"env": {
|
|
71
|
+
"AWS_PROFILE": "default",
|
|
72
|
+
"AWS_REGION": "us-west-2",
|
|
73
|
+
"FASTMCP_LOG_LEVEL": "INFO"
|
|
74
|
+
},
|
|
75
|
+
"transportType": "stdio",
|
|
76
|
+
"disabled": false,
|
|
77
|
+
"autoApprove": []
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
In this default mode:
|
|
84
|
+
- The `finch_build_container_image` tools will work normally
|
|
85
|
+
- The `finch_create_ecr_repo` and `finch_push_image` tool will return an error and will not create or modify AWS resources.
|
|
86
|
+
|
|
87
|
+
#### AWS Resource Write Mode
|
|
88
|
+
|
|
89
|
+
The server can also be set to enable AWS resource creation and modification by using the `--enable-aws-resource-write` flag.
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"mcpServers": {
|
|
94
|
+
"awslabs.finch-mcp-server": {
|
|
95
|
+
"command": "uvx",
|
|
96
|
+
"args": [
|
|
97
|
+
"awslabs.finch-mcp-server@latest",
|
|
98
|
+
"--enable-aws-resource-write"
|
|
99
|
+
],
|
|
100
|
+
"env": {
|
|
101
|
+
"AWS_PROFILE": "default",
|
|
102
|
+
"AWS_REGION": "us-west-2",
|
|
103
|
+
"FASTMCP_LOG_LEVEL": "INFO"
|
|
104
|
+
},
|
|
105
|
+
"transportType": "stdio",
|
|
106
|
+
"disabled": false,
|
|
107
|
+
"autoApprove": []
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Available Tools
|
|
114
|
+
|
|
115
|
+
### `finch_build_container_image`
|
|
116
|
+
|
|
117
|
+
Build a container image using Finch.
|
|
118
|
+
|
|
119
|
+
The tool builds a Docker image using the specified Dockerfile and context directory. It supports a range of build options including tags, platforms, and more.
|
|
120
|
+
|
|
121
|
+
Arguments:
|
|
122
|
+
- `dockerfile_path` (str): Absolute path to the Dockerfile
|
|
123
|
+
- `context_path` (str): Absolute path to the build context directory
|
|
124
|
+
- `tags` (List[str], optional): List of tags to apply to the image (e.g., ["myimage:latest", "myimage:v1"])
|
|
125
|
+
- `platforms` (List[str], optional): List of target platforms (e.g., ["linux/amd64", "linux/arm64"])
|
|
126
|
+
- `target` (str, optional): Target build stage to build
|
|
127
|
+
- `no_cache` (bool, optional): Whether to disable cache. Defaults to False.
|
|
128
|
+
- `pull` (bool, optional): Whether to always pull base images. Defaults to False.
|
|
129
|
+
- `build_contexts` (List[str], optional): List of additional build contexts
|
|
130
|
+
- `outputs` (str, optional): Output destination
|
|
131
|
+
- `cache_from` (List[str], optional): List of external cache sources
|
|
132
|
+
- `quiet` (bool, optional): Whether to suppress build output. Defaults to False.
|
|
133
|
+
- `progress` (str, optional): Type of progress output. Defaults to "auto".
|
|
134
|
+
|
|
135
|
+
### `finch_push_image`
|
|
136
|
+
|
|
137
|
+
Push a container image to a repository using Finch, replacing the tag with the image hash.
|
|
138
|
+
|
|
139
|
+
If the image URL is an ECR repository, it verifies that ECR login credential helper is configured. This tool gets the image hash, creates a new tag using the hash, and pushes the image with the hash tag to the repository.
|
|
140
|
+
|
|
141
|
+
The workflow is:
|
|
142
|
+
1. Get the image hash using `finch image inspect`
|
|
143
|
+
2. Create a new tag for the image using the short form of the hash (first 12 characters)
|
|
144
|
+
3. Push the hash-tagged image to the repository
|
|
145
|
+
|
|
146
|
+
Arguments:
|
|
147
|
+
- `image` (str): The full image name to push, including the repository URL and tag. For ECR repositories, it must follow the format: `<aws_account_id>.dkr.ecr.<region>.amazonaws.com/<repository_name>:<tag>`
|
|
148
|
+
|
|
149
|
+
Example:
|
|
150
|
+
```
|
|
151
|
+
# Original image: myrepo/myimage:latest
|
|
152
|
+
# After processing: myrepo/myimage:1a2b3c4d5e6f (where 1a2b3c4d5e6f is the short hash)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### `finch_create_ecr_repo`
|
|
156
|
+
|
|
157
|
+
Check if an ECR repository exists and create it if it doesn't.
|
|
158
|
+
|
|
159
|
+
This tool checks if the specified ECR repository exists using boto3. If the repository doesn't exist, it creates a new one with the given name with scan on push enabled and immutable tags for enhanced security. The tool requires appropriate AWS credentials configured.
|
|
160
|
+
|
|
161
|
+
**Note:** When the server is running in readonly mode, this tool will return an error and will not create any AWS resources.
|
|
162
|
+
|
|
163
|
+
Arguments:
|
|
164
|
+
- `app_name` (str): The name of the application/repository to check or create in ECR
|
|
165
|
+
- `region` (str, optional): AWS region for the ECR repository. If not provided, uses the default region from AWS configuration
|
|
166
|
+
|
|
167
|
+
Example:
|
|
168
|
+
```
|
|
169
|
+
# Check if 'my-app' repository exists in us-west-2 region, create it if it doesn't
|
|
170
|
+
{
|
|
171
|
+
"app_name": "my-app",
|
|
172
|
+
"region": "us-west-2"
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
# Response if repository already exists:
|
|
176
|
+
{
|
|
177
|
+
"status": "success",
|
|
178
|
+
"message": "ECR repository 'my-app' already exists.",
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
# Response if repository was created:
|
|
182
|
+
{
|
|
183
|
+
"status": "success",
|
|
184
|
+
"message": "Successfully created ECR repository 'my-app'.",
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
# Response if server is in readonly mode:
|
|
188
|
+
{
|
|
189
|
+
"status": "error",
|
|
190
|
+
"message": "Server running in read-only mode, unable to perform the action"
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Best Practices
|
|
195
|
+
|
|
196
|
+
- **Development and Prototyping Only**: The tools provided by this MCP server are intended for development and prototyping purposes only. They are not meant for production use cases.
|
|
197
|
+
- **Security Considerations**: Always review the Dockerfiles and container configurations before building and pushing images.
|
|
198
|
+
- **Resource Management**: Regularly clean up unused images and containers to free up disk space.
|
|
199
|
+
- **Version Control**: Keep track of image versions and tags to ensure reproducibility.
|
|
200
|
+
- **Error Handling**: Implement proper error handling in your applications when using these tools.
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
## Troubleshooting
|
|
204
|
+
|
|
205
|
+
- If you encounter permission errors with ECR, verify your AWS credentials and boto3 configuration are properly set up
|
|
206
|
+
- For Finch VM issues, try running `finch vm stop` and then `finch vm start` manually
|
|
207
|
+
- If the build fails with errors about missing files, check that your context path is correct
|
|
208
|
+
- For general Finch issues, consult the [Finch documentation](https://github.com/runfinch/finch)
|
|
209
|
+
|
|
210
|
+
## Version
|
|
211
|
+
|
|
212
|
+
Current MCP server version: 0.1.0
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
awslabs/__init__.py,sha256=bfTactAnM5TLDj8DEa7bm8LM2Vq5MeYeTevjwbmnkR4,598
|
|
2
|
+
awslabs/finch_mcp_server/__init__.py,sha256=x5tDHoZMLCDVZzVBHKWcT2a5BIWpYqSvs4PdYTRjeek,613
|
|
3
|
+
awslabs/finch_mcp_server/consts.py,sha256=jzmhiSIq6_AkRtelWFBp3Wa8DE1m-RVWEsVNZtmHWGk,1040
|
|
4
|
+
awslabs/finch_mcp_server/models.py,sha256=LZ-KSea6dvLk_8eo6q3nYR0kT_l-Qqh7Ib0E5F1uyX0,678
|
|
5
|
+
awslabs/finch_mcp_server/server.py,sha256=jZt5e8ind0R9YzZVr9T2PkHlcya54Q1xI26MYt7HOSk,16783
|
|
6
|
+
awslabs/finch_mcp_server/utils/__init__.py,sha256=CWQ6u4iR80Z_gP2SxEMl4TIkrQTTeA_xj9Nc_29l5FE,689
|
|
7
|
+
awslabs/finch_mcp_server/utils/build.py,sha256=2uEZMrVZR5c-00LLzivWjGDAU1PouHpel5bFN0e11g4,4644
|
|
8
|
+
awslabs/finch_mcp_server/utils/common.py,sha256=GG0lU6rLvZmjLshzDcD_McejtQSEZaMK3AKjPm-XeHo,5609
|
|
9
|
+
awslabs/finch_mcp_server/utils/ecr.py,sha256=Ca7ncv8IhVnL3H-kDUZmxiWqZpNSs49ZCNffeRaFDC0,3251
|
|
10
|
+
awslabs/finch_mcp_server/utils/push.py,sha256=PNKEMhrf37ferdfxNjcBMdEn9Wbt_eES18HauLtiPf4,4064
|
|
11
|
+
awslabs/finch_mcp_server/utils/vm.py,sha256=3Zh95RWjU-59EmqKEvoRuza8sTGw9xaR6dcjxY_fOSE,15572
|
|
12
|
+
awslabs_finch_mcp_server-0.1.1.dist-info/METADATA,sha256=g--kJ7vhs0T6kDAQcXCZL9jcGV9Ph__EdfxNOOQvZ68,8578
|
|
13
|
+
awslabs_finch_mcp_server-0.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
14
|
+
awslabs_finch_mcp_server-0.1.1.dist-info/entry_points.txt,sha256=4fJNznnCPk2jY2ztTYAvEpLeYXcS3wDkgx2gAYdezPY,82
|
|
15
|
+
awslabs_finch_mcp_server-0.1.1.dist-info/licenses/LICENSE,sha256=UOZ1F5fFDe3XXvG4oNnkL1-Ecun7zpHzRxjp-XsMeAo,11324
|
|
16
|
+
awslabs_finch_mcp_server-0.1.1.dist-info/licenses/NOTICE,sha256=W4rmEHanXgUYNeoEh6oB-pfuI1RtX4XIvX067GmL-i0,92
|
|
17
|
+
awslabs_finch_mcp_server-0.1.1.dist-info/RECORD,,
|