autodev-cli 1.4.150 → 1.4.152
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/media/gimp/gimp_mcp_client.py +204 -0
- package/media/gimp/gimp_mcp_server.py +310 -211
- package/out/commands/mcp.js +36 -30
- package/out/commands/mcp.js.map +1 -1
- package/out/configManager.js +54 -0
- package/out/configManager.js.map +1 -1
- package/out/core/gimpClientSource.d.ts +4 -0
- package/out/core/gimpClientSource.js +221 -0
- package/out/core/gimpClientSource.js.map +1 -0
- package/out/core/gimpPluginInstall.d.ts +45 -6
- package/out/core/gimpPluginInstall.js +184 -63
- package/out/core/gimpPluginInstall.js.map +1 -1
- package/out/core/gimpPluginSource.d.ts +4 -0
- package/out/core/gimpPluginSource.js +383 -0
- package/out/core/gimpPluginSource.js.map +1 -0
- package/out/core/mcpCatalog.d.ts +25 -17
- package/out/core/mcpCatalog.js +68 -36
- package/out/core/mcpCatalog.js.map +1 -1
- package/out/core/mcpCatalogMigrate.d.ts +9 -1
- package/out/core/mcpCatalogMigrate.js +34 -22
- package/out/core/mcpCatalogMigrate.js.map +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// gimpPluginSource.ts — GENERATED. Do not edit by hand.
|
|
4
|
+
//
|
|
5
|
+
// Source of truth: media/gimp/gimp_mcp_server.py (GPL-3.0; see media/gimp/LICENSE).
|
|
6
|
+
// Regenerate with: node scripts/gen-gimp-plugin-source.mjs (runs in `npm run build`).
|
|
7
|
+
//
|
|
8
|
+
// Embeds the user-verified GIMP 3.x MCP server plug-in as a string so the installer works even when bundled
|
|
9
|
+
// (VS Code extension esbuild) with no media file on disk.
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.GIMP_PLUGIN_SOURCE = exports.GIMP_PLUGIN_SOURCE_HASH = void 0;
|
|
13
|
+
/** sha256 (first 12 hex) of the canonical media/gimp/gimp_mcp_server.py. */
|
|
14
|
+
exports.GIMP_PLUGIN_SOURCE_HASH = "c4b85cccece9";
|
|
15
|
+
/** Full body of the user-verified GIMP 3.x MCP server plug-in (media/gimp/gimp_mcp_server.py). */
|
|
16
|
+
exports.GIMP_PLUGIN_SOURCE = `#!/usr/bin/env python3
|
|
17
|
+
# ---------------------------------------------------------------------------
|
|
18
|
+
# gimp_mcp_server.py — vendored, USER-VERIFIED GIMP 3.2 MCP bridge (plug-in).
|
|
19
|
+
#
|
|
20
|
+
# Derived from libreearth/gimp-mcp (GPL-3.0; see media/gimp/LICENSE) and fixed by
|
|
21
|
+
# the user / AutoDev for GIMP 3.2 (Store / MSIX). Verified working on real GIMP
|
|
22
|
+
# 3.2.44: a menu-triggered PLUGIN (Tools -> MCP / Filters -> Development -> Start
|
|
23
|
+
# MCP Server) that listens on 127.0.0.1:9876 and drives GIMP. Keep the "GIMP MCP
|
|
24
|
+
# Server" window open — GLib.MainLoop() holds the out-of-process plug-in alive.
|
|
25
|
+
#
|
|
26
|
+
# This is the user's verified file; the body below is kept byte-for-byte. The
|
|
27
|
+
# lines in THIS block are a provenance comment only — do not edit the code below.
|
|
28
|
+
# ---------------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
# GIMP MCP Server Plugin (GIMP 3.2)
|
|
31
|
+
# Listens on localhost:9876 so the libreearth gimp-mcp client can drive GIMP.
|
|
32
|
+
|
|
33
|
+
import gi
|
|
34
|
+
gi.require_version('Gimp', '3.0')
|
|
35
|
+
from gi.repository import Gimp
|
|
36
|
+
from gi.repository import GLib
|
|
37
|
+
from gi.repository import Gio
|
|
38
|
+
from gi.repository import GObject
|
|
39
|
+
|
|
40
|
+
import io
|
|
41
|
+
import json
|
|
42
|
+
import os
|
|
43
|
+
import socket
|
|
44
|
+
import sys
|
|
45
|
+
import threading
|
|
46
|
+
import traceback
|
|
47
|
+
|
|
48
|
+
HOST = '127.0.0.1'
|
|
49
|
+
PORT = 9876
|
|
50
|
+
# Store GIMP redirects GLib config dir into the MSIX LocalCache. Also write
|
|
51
|
+
# to the real roaming profile so the log is findable.
|
|
52
|
+
_LOG_PATHS = [
|
|
53
|
+
os.path.join(GLib.get_user_config_dir(), 'GIMP', '3.2', 'gimp_mcp_server.log'),
|
|
54
|
+
os.path.join(os.environ.get('APPDATA', ''), 'GIMP', '3.2', 'gimp_mcp_server.log'),
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
_server_lock = threading.Lock()
|
|
58
|
+
_server_started = False
|
|
59
|
+
_exec_globals = None
|
|
60
|
+
_main_loop = None
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _log(msg):
|
|
64
|
+
line = msg.rstrip() + '\\n'
|
|
65
|
+
for path in _LOG_PATHS:
|
|
66
|
+
if not path:
|
|
67
|
+
continue
|
|
68
|
+
try:
|
|
69
|
+
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
70
|
+
with open(path, 'a', encoding='utf-8') as fh:
|
|
71
|
+
fh.write(line)
|
|
72
|
+
except Exception:
|
|
73
|
+
pass
|
|
74
|
+
print(msg, flush=True)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def N_(message):
|
|
78
|
+
return message
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _(message):
|
|
82
|
+
return GLib.dgettext(None, message)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _serialize(obj):
|
|
86
|
+
if obj is None or isinstance(obj, (str, int, float, bool)):
|
|
87
|
+
return obj
|
|
88
|
+
if isinstance(obj, (list, tuple)):
|
|
89
|
+
return [_serialize(item) for item in obj]
|
|
90
|
+
if isinstance(obj, dict):
|
|
91
|
+
return {str(k): _serialize(v) for k, v in obj.items()}
|
|
92
|
+
data = {'type': obj.__class__.__name__}
|
|
93
|
+
if hasattr(obj, 'get_id'):
|
|
94
|
+
try:
|
|
95
|
+
data['id'] = int(obj.get_id())
|
|
96
|
+
except Exception:
|
|
97
|
+
pass
|
|
98
|
+
elif hasattr(obj, 'ID'):
|
|
99
|
+
data['id'] = obj.ID
|
|
100
|
+
if hasattr(obj, 'get_name'):
|
|
101
|
+
try:
|
|
102
|
+
data['name'] = obj.get_name()
|
|
103
|
+
except Exception:
|
|
104
|
+
pass
|
|
105
|
+
if 'id' not in data and len(data) == 1:
|
|
106
|
+
return str(obj)
|
|
107
|
+
return data
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _resolve_api(api_path):
|
|
111
|
+
parts = [p for p in str(api_path).split('.') if p]
|
|
112
|
+
if parts and parts[0] == 'Gimp':
|
|
113
|
+
parts = parts[1:]
|
|
114
|
+
elif len(parts) >= 3 and parts[0] == 'gi' and parts[1] == 'repository' and parts[2] == 'Gimp':
|
|
115
|
+
parts = parts[3:]
|
|
116
|
+
|
|
117
|
+
aliases = {
|
|
118
|
+
'list_images': 'get_images',
|
|
119
|
+
'list_fonts': 'get_fonts',
|
|
120
|
+
'fonts_get_list': 'get_fonts',
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if not parts:
|
|
124
|
+
return Gimp
|
|
125
|
+
|
|
126
|
+
obj = Gimp
|
|
127
|
+
for part in parts:
|
|
128
|
+
part = aliases.get(part, part)
|
|
129
|
+
obj = getattr(obj, part)
|
|
130
|
+
return obj
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _exec_namespace():
|
|
134
|
+
global _exec_globals
|
|
135
|
+
if _exec_globals is None:
|
|
136
|
+
ns = {
|
|
137
|
+
'__builtins__': __builtins__,
|
|
138
|
+
'__name__': '__main__',
|
|
139
|
+
'Gimp': Gimp,
|
|
140
|
+
'GLib': GLib,
|
|
141
|
+
'Gio': Gio,
|
|
142
|
+
'GObject': GObject,
|
|
143
|
+
'sys': sys,
|
|
144
|
+
'os': os,
|
|
145
|
+
'json': json,
|
|
146
|
+
}
|
|
147
|
+
try:
|
|
148
|
+
gi.require_version('Gegl', '0.4')
|
|
149
|
+
from gi.repository import Gegl
|
|
150
|
+
ns['Gegl'] = Gegl
|
|
151
|
+
except Exception as exc:
|
|
152
|
+
_log(f'Gegl import failed: {exc}')
|
|
153
|
+
try:
|
|
154
|
+
gi.require_version('Babl', '0.1')
|
|
155
|
+
from gi.repository import Babl
|
|
156
|
+
ns['Babl'] = Babl
|
|
157
|
+
except Exception:
|
|
158
|
+
pass
|
|
159
|
+
_exec_globals = ns
|
|
160
|
+
return _exec_globals
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _extract_code(args, kwargs):
|
|
164
|
+
if kwargs.get('code'):
|
|
165
|
+
return str(kwargs['code'])
|
|
166
|
+
if not args:
|
|
167
|
+
return ''
|
|
168
|
+
if len(args) >= 2 and args[0] in ('exec', 'eval', 'pyGObject-console'):
|
|
169
|
+
payload = args[1]
|
|
170
|
+
if isinstance(payload, (list, tuple)):
|
|
171
|
+
return '\\n'.join(str(item) for item in payload)
|
|
172
|
+
return str(payload)
|
|
173
|
+
if isinstance(args[0], (list, tuple)):
|
|
174
|
+
return '\\n'.join(str(item) for item in args[0])
|
|
175
|
+
return str(args[0])
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def _run_python(code):
|
|
179
|
+
ns = _exec_namespace()
|
|
180
|
+
stdout = io.StringIO()
|
|
181
|
+
old_stdout = sys.stdout
|
|
182
|
+
sys.stdout = stdout
|
|
183
|
+
try:
|
|
184
|
+
exec(code, ns)
|
|
185
|
+
finally:
|
|
186
|
+
sys.stdout = old_stdout
|
|
187
|
+
printed = stdout.getvalue()
|
|
188
|
+
result = ns.get('_result')
|
|
189
|
+
if result is not None:
|
|
190
|
+
return {'printed': printed, 'result': _serialize(result)}
|
|
191
|
+
return {'printed': printed, 'result': None}
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class MCPPlugin(Gimp.PlugIn):
|
|
195
|
+
def do_set_i18n(self, name):
|
|
196
|
+
return False
|
|
197
|
+
|
|
198
|
+
def do_query_procedures(self):
|
|
199
|
+
return ['plug-in-mcp-server']
|
|
200
|
+
|
|
201
|
+
def do_create_procedure(self, name):
|
|
202
|
+
procedure = Gimp.Procedure.new(
|
|
203
|
+
self, name, Gimp.PDBProcType.PLUGIN, self.run, None
|
|
204
|
+
)
|
|
205
|
+
procedure.set_menu_label(_('Start MCP Server'))
|
|
206
|
+
procedure.set_documentation(
|
|
207
|
+
_('Starts an MCP server to control GIMP externally'),
|
|
208
|
+
_('Listens on 127.0.0.1:9876 for the GIMP MCP client'),
|
|
209
|
+
name,
|
|
210
|
+
)
|
|
211
|
+
procedure.set_attribution('GIMP MCP', 'GIMP MCP', '2026')
|
|
212
|
+
procedure.set_sensitivity_mask(Gimp.ProcedureSensitivityMask.ALWAYS)
|
|
213
|
+
procedure.add_enum_argument(
|
|
214
|
+
'run-mode',
|
|
215
|
+
_('Run mode'),
|
|
216
|
+
_('The run mode'),
|
|
217
|
+
Gimp.RunMode,
|
|
218
|
+
Gimp.RunMode.INTERACTIVE,
|
|
219
|
+
GObject.ParamFlags.READWRITE,
|
|
220
|
+
)
|
|
221
|
+
procedure.add_menu_path('<Image>/Tools/MCP')
|
|
222
|
+
procedure.add_menu_path('<Image>/Filters/Development/')
|
|
223
|
+
return procedure
|
|
224
|
+
|
|
225
|
+
def run(self, procedure, config, data):
|
|
226
|
+
global _main_loop
|
|
227
|
+
started, message = self.ensure_server()
|
|
228
|
+
_log(message)
|
|
229
|
+
try:
|
|
230
|
+
Gimp.message(message)
|
|
231
|
+
except Exception:
|
|
232
|
+
pass
|
|
233
|
+
if not started:
|
|
234
|
+
return procedure.new_return_values(Gimp.PDBStatusType.EXECUTION_ERROR, GLib.Error(message))
|
|
235
|
+
|
|
236
|
+
# GIMP 3 launches Python plug-ins out of process. Returning from run()
|
|
237
|
+
# would exit that process and kill the socket thread. Stay alive and
|
|
238
|
+
# dispatch GLib.idle_add work (API calls) on this main loop.
|
|
239
|
+
# A visible window is required: otherwise "Start MCP Server" looks like
|
|
240
|
+
# it did not open anything.
|
|
241
|
+
try:
|
|
242
|
+
self._show_status_window(message)
|
|
243
|
+
except Exception as exc:
|
|
244
|
+
_log(f'Status window failed: {exc}\\n{traceback.format_exc()}')
|
|
245
|
+
|
|
246
|
+
_main_loop = GLib.MainLoop()
|
|
247
|
+
_log('Entering GLib.MainLoop to keep MCP server process alive')
|
|
248
|
+
try:
|
|
249
|
+
_main_loop.run()
|
|
250
|
+
except Exception as exc:
|
|
251
|
+
_log(f'MainLoop exited: {exc}')
|
|
252
|
+
return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS, GLib.Error())
|
|
253
|
+
|
|
254
|
+
def _show_status_window(self, message):
|
|
255
|
+
gi.require_version('Gtk', '3.0')
|
|
256
|
+
gi.require_version('GimpUi', '3.0')
|
|
257
|
+
from gi.repository import Gtk
|
|
258
|
+
from gi.repository import GimpUi
|
|
259
|
+
|
|
260
|
+
GimpUi.init('gimp_mcp_server.py')
|
|
261
|
+
window = Gtk.Window(title='GIMP MCP Server')
|
|
262
|
+
window.set_default_size(420, 160)
|
|
263
|
+
window.set_keep_above(True)
|
|
264
|
+
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=8)
|
|
265
|
+
box.set_border_width(16)
|
|
266
|
+
label = Gtk.Label(label=message + '\\n\\nLeave this window open while Grok talks to GIMP.')
|
|
267
|
+
label.set_line_wrap(True)
|
|
268
|
+
box.pack_start(label, True, True, 0)
|
|
269
|
+
button = Gtk.Button(label='Stop server')
|
|
270
|
+
button.connect('clicked', lambda *_: window.destroy())
|
|
271
|
+
box.pack_start(button, False, False, 0)
|
|
272
|
+
window.add(box)
|
|
273
|
+
window.connect('destroy', self._on_status_closed)
|
|
274
|
+
window.show_all()
|
|
275
|
+
window.present()
|
|
276
|
+
_log('Status window opened')
|
|
277
|
+
|
|
278
|
+
def _on_status_closed(self, *_args):
|
|
279
|
+
global _main_loop
|
|
280
|
+
_log('Status window closed; stopping MCP server')
|
|
281
|
+
if _main_loop is not None:
|
|
282
|
+
_main_loop.quit()
|
|
283
|
+
|
|
284
|
+
def ensure_server(self):
|
|
285
|
+
global _server_started
|
|
286
|
+
with _server_lock:
|
|
287
|
+
if _server_started:
|
|
288
|
+
return True, f'MCP Server already listening on {HOST}:{PORT}'
|
|
289
|
+
try:
|
|
290
|
+
thread = threading.Thread(target=self.start_server, daemon=True)
|
|
291
|
+
thread.start()
|
|
292
|
+
_server_started = True
|
|
293
|
+
return True, f'MCP Server started on {HOST}:{PORT}'
|
|
294
|
+
except Exception as exc:
|
|
295
|
+
return False, f'Failed to start MCP Server: {exc}'
|
|
296
|
+
|
|
297
|
+
def start_server(self):
|
|
298
|
+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
299
|
+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
300
|
+
try:
|
|
301
|
+
sock.bind((HOST, PORT))
|
|
302
|
+
sock.listen(8)
|
|
303
|
+
_log(f'Server listening on {HOST}:{PORT}')
|
|
304
|
+
except Exception as exc:
|
|
305
|
+
_log(f'Bind/listen failed: {exc}')
|
|
306
|
+
return
|
|
307
|
+
|
|
308
|
+
while True:
|
|
309
|
+
try:
|
|
310
|
+
client, addr = sock.accept()
|
|
311
|
+
_log(f'Connected to {addr}')
|
|
312
|
+
threading.Thread(target=self.handle_client, args=(client,), daemon=True).start()
|
|
313
|
+
except Exception as exc:
|
|
314
|
+
_log(f'Server accept error: {exc}')
|
|
315
|
+
break
|
|
316
|
+
sock.close()
|
|
317
|
+
|
|
318
|
+
def handle_client(self, client):
|
|
319
|
+
buffer = b''
|
|
320
|
+
try:
|
|
321
|
+
client.settimeout(120)
|
|
322
|
+
while True:
|
|
323
|
+
chunk = client.recv(65536)
|
|
324
|
+
if not chunk:
|
|
325
|
+
break
|
|
326
|
+
buffer += chunk
|
|
327
|
+
while buffer:
|
|
328
|
+
try:
|
|
329
|
+
command = json.loads(buffer.decode('utf-8'))
|
|
330
|
+
buffer = b''
|
|
331
|
+
except json.JSONDecodeError:
|
|
332
|
+
break
|
|
333
|
+
GLib.idle_add(self.execute_command, command, client)
|
|
334
|
+
except Exception as exc:
|
|
335
|
+
_log(f'Client error: {exc}')
|
|
336
|
+
finally:
|
|
337
|
+
try:
|
|
338
|
+
client.close()
|
|
339
|
+
except Exception:
|
|
340
|
+
pass
|
|
341
|
+
|
|
342
|
+
def execute_command(self, command, client):
|
|
343
|
+
cmd_type = command.get('type')
|
|
344
|
+
params = command.get('params', {}) or {}
|
|
345
|
+
try:
|
|
346
|
+
if cmd_type == 'ping':
|
|
347
|
+
response = {'status': 'success', 'result': 'pong'}
|
|
348
|
+
elif cmd_type == 'exec':
|
|
349
|
+
code = _extract_code(params.get('args', []), params.get('kwargs', {}))
|
|
350
|
+
if not code:
|
|
351
|
+
code = str(params.get('code', ''))
|
|
352
|
+
response = {'status': 'success', 'result': _run_python(code)}
|
|
353
|
+
elif cmd_type == 'call_api':
|
|
354
|
+
api_path = params.get('api_path', '')
|
|
355
|
+
args = params.get('args', []) or []
|
|
356
|
+
kwargs = params.get('kwargs', {}) or {}
|
|
357
|
+
if api_path in ('exec', 'eval', '__exec__'):
|
|
358
|
+
response = {'status': 'success', 'result': _run_python(_extract_code(args, kwargs))}
|
|
359
|
+
else:
|
|
360
|
+
method = _resolve_api(api_path)
|
|
361
|
+
result = method(*args, **kwargs)
|
|
362
|
+
response = {'status': 'success', 'result': _serialize(result)}
|
|
363
|
+
else:
|
|
364
|
+
response = {'status': 'error', 'message': f'Unknown command: {cmd_type}'}
|
|
365
|
+
except Exception as exc:
|
|
366
|
+
response = {
|
|
367
|
+
'status': 'error',
|
|
368
|
+
'message': str(exc),
|
|
369
|
+
'traceback': traceback.format_exc(),
|
|
370
|
+
}
|
|
371
|
+
_log(f'Command error: {response["message"]}\\n{response["traceback"]}')
|
|
372
|
+
|
|
373
|
+
try:
|
|
374
|
+
payload = json.dumps(response).encode('utf-8')
|
|
375
|
+
client.sendall(payload)
|
|
376
|
+
except Exception as exc:
|
|
377
|
+
_log(f'Response send failed: {exc}')
|
|
378
|
+
return False
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
Gimp.main(MCPPlugin.__gtype__, sys.argv)
|
|
382
|
+
`;
|
|
383
|
+
//# sourceMappingURL=gimpPluginSource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gimpPluginSource.js","sourceRoot":"","sources":["../../src/core/gimpPluginSource.ts"],"names":[],"mappings":";AAAA,8EAA8E;AAC9E,wDAAwD;AACxD,EAAE;AACF,oFAAoF;AACpF,wFAAwF;AACxF,EAAE;AACF,4GAA4G;AAC5G,0DAA0D;AAC1D,8EAA8E;;;AAE9E,4EAA4E;AAC/D,QAAA,uBAAuB,GAAG,cAAc,CAAC;AAEtD,kGAAkG;AACrF,QAAA,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8WjC,CAAC"}
|
package/out/core/mcpCatalog.d.ts
CHANGED
|
@@ -20,22 +20,18 @@ export interface McpCatalogEntry {
|
|
|
20
20
|
notes: string[];
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
23
|
+
* Display placeholder for the gimp client path BEFORE install (path unknown).
|
|
24
|
+
* `serverSpecFor('gimp', …)` with no resolved client path emits this so the
|
|
25
|
+
* catalog/detect JSON never bakes in a machine-specific path — and, crucially,
|
|
26
|
+
* never the broken raw-github upstream client. It also lets the migration
|
|
27
|
+
* recognise a not-yet-resolved gimp entry and upgrade it once GIMP is detected.
|
|
26
28
|
*/
|
|
27
|
-
export declare const GIMP_CLIENT_PLACEHOLDER = "<
|
|
29
|
+
export declare const GIMP_CLIENT_PLACEHOLDER = "<GIMP config>/mcp/gimp_mcp_client.py";
|
|
28
30
|
/**
|
|
29
|
-
* The
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* stdio server (it lazily connects to GIMP on localhost:9876, so it starts even
|
|
33
|
-
* without GIMP running). Verified end-to-end (valid MCP initialize handshake,
|
|
34
|
-
* clean exit). `mcp==1.2.0` is load-bearing — current mcp releases break this
|
|
35
|
-
* client on a removed `description=` kwarg.
|
|
31
|
+
* The pinned mcp SDK version the client runs under. Load-bearing — current mcp
|
|
32
|
+
* releases break the client on a removed `description=` kwarg. `uv run --with
|
|
33
|
+
* mcp==1.2.0 <client>` installs exactly this into an ephemeral env.
|
|
36
34
|
*/
|
|
37
|
-
export declare const GIMP_MCP_COMMIT = "49c46dd6146cb7393b42a9ecda630583b3117b33";
|
|
38
|
-
export declare const GIMP_MCP_CLIENT_URL = "https://raw.githubusercontent.com/libreearth/gimp-mcp/49c46dd6146cb7393b42a9ecda630583b3117b33/gimp_mcp_client.py";
|
|
39
35
|
export declare const GIMP_MCP_PIN = "mcp==1.2.0";
|
|
40
36
|
/** Per-platform install hint for the `uv`/`uvx` toolchain (never `pip install uv`). */
|
|
41
37
|
export declare function uvInstallHint(platform: NodeJS.Platform): string;
|
|
@@ -60,14 +56,26 @@ export declare const BLENDER_LAB_FROM = "git+https://projects.blender.org/lab/bl
|
|
|
60
56
|
* from Blender Lab" add-on. NEVER bare `uvx blender-mcp` (no --from) — that
|
|
61
57
|
* pulls the incompatible community PyPI package. (The exact launcher form is
|
|
62
58
|
* under review; the args are the load-bearing part the migration re-resolves.)
|
|
63
|
-
* - GIMP: the
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
59
|
+
* - GIMP: the LOCALLY-INSTALLED, user-verified client run by bare `uv`
|
|
60
|
+
* (`uv run --with mcp==1.2.0 <clientPath>`) on every platform. `clientPath`
|
|
61
|
+
* is the client installGimpPlugin() writes to <GIMP-config>/<ver>/mcp/. Pass
|
|
62
|
+
* the resolved path via `opts.gimpClientPath`; without it we emit the display
|
|
63
|
+
* placeholder (never the broken raw-github upstream client). Experimental.
|
|
67
64
|
*/
|
|
68
65
|
export declare function serverSpecFor(app: CreativeAppId, platform: NodeJS.Platform, opts?: {
|
|
69
66
|
gimpClientPath?: string;
|
|
70
67
|
}): McpJsonEntry;
|
|
68
|
+
/** The client-path argument carried by a gimp .mcp.json entry, whatever the command form. */
|
|
69
|
+
export declare function gimpClientArgOf(entry: {
|
|
70
|
+
command?: string;
|
|
71
|
+
args?: string[];
|
|
72
|
+
}): string | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* Is `arg` a CONCRETE local client path — a real filesystem path we must not
|
|
75
|
+
* clobber (a user's own checkout, or the client we already installed)? False for
|
|
76
|
+
* the display placeholder and for ANY URL (incl. the broken raw-github client).
|
|
77
|
+
*/
|
|
78
|
+
export declare function isConcreteGimpClientArg(arg: string | undefined): boolean;
|
|
71
79
|
/** Build the catalog for a given platform (install hints are platform-specific). */
|
|
72
80
|
export declare function getCatalog(platform: NodeJS.Platform): McpCatalogEntry[];
|
|
73
81
|
/** Lookup a single catalog entry. */
|
package/out/core/mcpCatalog.js
CHANGED
|
@@ -10,32 +10,29 @@
|
|
|
10
10
|
// flagged experimental because upstream ships no packaged launcher — see below.
|
|
11
11
|
// ---------------------------------------------------------------------------
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
exports.BLENDER_LAB_FROM = exports.GIMP_MCP_PIN = exports.
|
|
13
|
+
exports.BLENDER_LAB_FROM = exports.GIMP_MCP_PIN = exports.GIMP_CLIENT_PLACEHOLDER = void 0;
|
|
14
14
|
exports.uvInstallHint = uvInstallHint;
|
|
15
15
|
exports.pythonInstallHint = pythonInstallHint;
|
|
16
16
|
exports.gitInstallHint = gitInstallHint;
|
|
17
17
|
exports.serverSpecFor = serverSpecFor;
|
|
18
|
+
exports.gimpClientArgOf = gimpClientArgOf;
|
|
19
|
+
exports.isConcreteGimpClientArg = isConcreteGimpClientArg;
|
|
18
20
|
exports.getCatalog = getCatalog;
|
|
19
21
|
exports.catalogEntry = catalogEntry;
|
|
20
22
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
23
|
+
* Display placeholder for the gimp client path BEFORE install (path unknown).
|
|
24
|
+
* `serverSpecFor('gimp', …)` with no resolved client path emits this so the
|
|
25
|
+
* catalog/detect JSON never bakes in a machine-specific path — and, crucially,
|
|
26
|
+
* never the broken raw-github upstream client. It also lets the migration
|
|
27
|
+
* recognise a not-yet-resolved gimp entry and upgrade it once GIMP is detected.
|
|
24
28
|
*/
|
|
25
|
-
exports.GIMP_CLIENT_PLACEHOLDER = '<
|
|
29
|
+
exports.GIMP_CLIENT_PLACEHOLDER = '<GIMP config>/mcp/gimp_mcp_client.py';
|
|
26
30
|
/**
|
|
27
|
-
* The
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* stdio server (it lazily connects to GIMP on localhost:9876, so it starts even
|
|
31
|
-
* without GIMP running). Verified end-to-end (valid MCP initialize handshake,
|
|
32
|
-
* clean exit). `mcp==1.2.0` is load-bearing — current mcp releases break this
|
|
33
|
-
* client on a removed `description=` kwarg.
|
|
31
|
+
* The pinned mcp SDK version the client runs under. Load-bearing — current mcp
|
|
32
|
+
* releases break the client on a removed `description=` kwarg. `uv run --with
|
|
33
|
+
* mcp==1.2.0 <client>` installs exactly this into an ephemeral env.
|
|
34
34
|
*/
|
|
35
|
-
exports.GIMP_MCP_COMMIT = '49c46dd6146cb7393b42a9ecda630583b3117b33';
|
|
36
|
-
exports.GIMP_MCP_CLIENT_URL = `https://raw.githubusercontent.com/libreearth/gimp-mcp/${exports.GIMP_MCP_COMMIT}/gimp_mcp_client.py`;
|
|
37
35
|
exports.GIMP_MCP_PIN = 'mcp==1.2.0';
|
|
38
|
-
const GIMP_GIT_ARGS = ['run', '--with', exports.GIMP_MCP_PIN, exports.GIMP_MCP_CLIENT_URL];
|
|
39
36
|
/** Per-platform install hint for the `uv`/`uvx` toolchain (never `pip install uv`). */
|
|
40
37
|
function uvInstallHint(platform) {
|
|
41
38
|
if (platform === 'win32') {
|
|
@@ -84,10 +81,11 @@ const BLENDER_LAB_ARGS = ['--from', exports.BLENDER_LAB_FROM, '--with', 'mcp<2',
|
|
|
84
81
|
* from Blender Lab" add-on. NEVER bare `uvx blender-mcp` (no --from) — that
|
|
85
82
|
* pulls the incompatible community PyPI package. (The exact launcher form is
|
|
86
83
|
* under review; the args are the load-bearing part the migration re-resolves.)
|
|
87
|
-
* - GIMP: the
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
84
|
+
* - GIMP: the LOCALLY-INSTALLED, user-verified client run by bare `uv`
|
|
85
|
+
* (`uv run --with mcp==1.2.0 <clientPath>`) on every platform. `clientPath`
|
|
86
|
+
* is the client installGimpPlugin() writes to <GIMP-config>/<ver>/mcp/. Pass
|
|
87
|
+
* the resolved path via `opts.gimpClientPath`; without it we emit the display
|
|
88
|
+
* placeholder (never the broken raw-github upstream client). Experimental.
|
|
91
89
|
*/
|
|
92
90
|
function serverSpecFor(app, platform, opts) {
|
|
93
91
|
if (app === 'blender') {
|
|
@@ -95,15 +93,41 @@ function serverSpecFor(app, platform, opts) {
|
|
|
95
93
|
// official Blender Lab `--from git+…lab…` client.
|
|
96
94
|
return { command: 'uvx', args: [...BLENDER_LAB_ARGS] };
|
|
97
95
|
}
|
|
98
|
-
// gimp —
|
|
99
|
-
//
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
96
|
+
// gimp — run the locally-installed client via `uv` with the pinned mcp SDK.
|
|
97
|
+
// Same command shape on every platform; only the client path differs.
|
|
98
|
+
const client = (opts?.gimpClientPath && opts.gimpClientPath.trim()) || exports.GIMP_CLIENT_PLACEHOLDER;
|
|
99
|
+
return { command: 'uv', args: ['run', '--with', exports.GIMP_MCP_PIN, client] };
|
|
100
|
+
}
|
|
101
|
+
/** The client-path argument carried by a gimp .mcp.json entry, whatever the command form. */
|
|
102
|
+
function gimpClientArgOf(entry) {
|
|
103
|
+
const args = Array.isArray(entry.args) ? entry.args : [];
|
|
104
|
+
if (entry.command === 'python' || entry.command === 'python3') {
|
|
105
|
+
return args[0];
|
|
106
|
+
}
|
|
107
|
+
if (entry.command === 'uv') {
|
|
108
|
+
return args[args.length - 1];
|
|
109
|
+
}
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Is `arg` a CONCRETE local client path — a real filesystem path we must not
|
|
114
|
+
* clobber (a user's own checkout, or the client we already installed)? False for
|
|
115
|
+
* the display placeholder and for ANY URL (incl. the broken raw-github client).
|
|
116
|
+
*/
|
|
117
|
+
function isConcreteGimpClientArg(arg) {
|
|
118
|
+
if (typeof arg !== 'string' || arg.length === 0) {
|
|
119
|
+
return false;
|
|
103
120
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
121
|
+
if (arg === exports.GIMP_CLIENT_PLACEHOLDER) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
if (/^https?:\/\//i.test(arg)) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
if (/raw\.githubusercontent\.com/i.test(arg)) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
return true;
|
|
107
131
|
}
|
|
108
132
|
/** Build the catalog for a given platform (install hints are platform-specific). */
|
|
109
133
|
function getCatalog(platform) {
|
|
@@ -135,25 +159,33 @@ function getCatalog(platform) {
|
|
|
135
159
|
serverName: 'gimp',
|
|
136
160
|
prerequisites: [{ id: 'uv', installHint: uvInstallHint(platform) }],
|
|
137
161
|
postSetup: [
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
'Requires GIMP 3.
|
|
162
|
+
`Plugin + client are installed automatically into your GIMP 3.x config (${gimpPluginDir(platform)}) — you copy nothing. Re-run any time with: autodev mcp gimp-install-plugin`,
|
|
163
|
+
"In GIMP: Tools → MCP → Start MCP Server (or Filters → Development → Start MCP Server), and KEEP the 'GIMP MCP Server' window open — it holds the plug-in process alive and the :9876 socket. One click per GIMP session (the window may hide behind other apps; use the taskbar).",
|
|
164
|
+
'Requires GIMP 3.x (the plugin uses the GIMP 3.0 Python API).',
|
|
141
165
|
"Port 9876 collides with Blender — don't run both MCP servers at once.",
|
|
142
166
|
],
|
|
143
167
|
notes: [
|
|
144
|
-
|
|
145
|
-
`The client
|
|
168
|
+
`Log: ${gimpLogPath(platform)} (Store/MSIX GIMP also mirrors a copy inside its sandbox LocalCache).`,
|
|
169
|
+
`The client runs via \`uv run --with ${exports.GIMP_MCP_PIN} <installed client>\`; the ${exports.GIMP_MCP_PIN} pin is load-bearing (current mcp releases break the client on a removed description= kwarg).`,
|
|
146
170
|
],
|
|
147
171
|
},
|
|
148
172
|
];
|
|
149
173
|
}
|
|
150
|
-
/** GIMP 3.
|
|
174
|
+
/** GIMP 3.x config directory, per OS (where plug-ins/ and mcp/ get installed). */
|
|
151
175
|
function gimpPluginDir(platform) {
|
|
152
176
|
return platform === 'win32'
|
|
153
|
-
? '%APPDATA%\\GIMP\\3.x\\
|
|
177
|
+
? '%APPDATA%\\GIMP\\3.x\\'
|
|
178
|
+
: platform === 'darwin'
|
|
179
|
+
? '~/Library/Application Support/GIMP/3.x/'
|
|
180
|
+
: '~/.config/GIMP/3.x/';
|
|
181
|
+
}
|
|
182
|
+
/** GIMP MCP server log path, per OS (dual-written by the plug-in). */
|
|
183
|
+
function gimpLogPath(platform) {
|
|
184
|
+
return platform === 'win32'
|
|
185
|
+
? '%APPDATA%\\GIMP\\3.x\\gimp_mcp_server.log'
|
|
154
186
|
: platform === 'darwin'
|
|
155
|
-
? '~/Library/Application Support/GIMP/3.x/
|
|
156
|
-
: '~/.config/GIMP/3.x/
|
|
187
|
+
? '~/Library/Application Support/GIMP/3.x/gimp_mcp_server.log'
|
|
188
|
+
: '~/.config/GIMP/3.x/gimp_mcp_server.log';
|
|
157
189
|
}
|
|
158
190
|
/** Lookup a single catalog entry. */
|
|
159
191
|
function catalogEntry(app, platform) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcpCatalog.js","sourceRoot":"","sources":["../../src/core/mcpCatalog.ts"],"names":[],"mappings":";AAAA,8EAA8E;AAC9E,gFAAgF;AAChF,2EAA2E;AAC3E,gFAAgF;AAChF,wEAAwE;AACxE,EAAE;AACF,uEAAuE;AACvE,+EAA+E;AAC/E,gFAAgF;AAChF,8EAA8E;;;
|
|
1
|
+
{"version":3,"file":"mcpCatalog.js","sourceRoot":"","sources":["../../src/core/mcpCatalog.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,14 @@
|
|
|
1
|
+
export interface MigrateOpts {
|
|
2
|
+
/**
|
|
3
|
+
* Resolve the local gimp client path for this machine, or null when GIMP 3.x is
|
|
4
|
+
* absent. Defaults to resolveGimpClientPath() (real detection). Injectable for
|
|
5
|
+
* tests. When null, a gimp entry that needs upgrading is left as-is.
|
|
6
|
+
*/
|
|
7
|
+
resolveGimpClient?: () => string | null;
|
|
8
|
+
}
|
|
1
9
|
/**
|
|
2
10
|
* Re-resolve stale creative-app user entries in <root>/.mcp.json from the current
|
|
3
11
|
* catalog. Persists the upgraded set back to .mcp.json when anything changed and
|
|
4
12
|
* logs each upgrade. Returns true iff at least one entry was migrated.
|
|
5
13
|
*/
|
|
6
|
-
export declare function migrateCreativeMcpEntries(root: string, platform: NodeJS.Platform, log?: (m: string) => void): boolean;
|
|
14
|
+
export declare function migrateCreativeMcpEntries(root: string, platform: NodeJS.Platform, log?: (m: string) => void, opts?: MigrateOpts): boolean;
|