GPU-Gate-MCP
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@GPU-Gate-MCPRun my ComfyUI batch of 6 images, then reload the local LLM."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
GPU-Gate-MCP
로컬 LLM 서버(Strata)를 잠시 내려 GPU 를 비운 채로 ComfyUI/VoiceStudio 배치를 돌리고, 끝나면 LLM 을 다시 올려 주는 MCP stdio 서버.
English summary
What it is. GPU-Gate-MCP is a small MCP stdio server (Python 3.10+, standard library only) for people who run a local LLM server and ComfyUI/VoiceStudio on the same GPU. An AI-agent client (opencode, Qwen Code, Hermes, ...) registers it and calls comfy_batch or voice_batch with all the jobs of a task. A detached worker unloads the local LLM server (Strata) once its running turn is finished, starts ComfyUI/VoiceStudio from your own start script, runs the jobs, stops the executor and always reloads the LLM, even if the client died or a step failed. The call blocks until the batch is done and returns per-job status and output paths; gate_status shows what the gate is doing. Tested on Windows. The full documentation below is in Korean; the agent instruction block in docs/clients.md is bilingual.
Install.
git clone https://github.com/ssain3d-lgtm/GPU-Gate-MCP GPU-Gate-MCP && cd GPU-Gate-MCP
python gpu_gate_server.py --init # writes config.json; edit it for this machine
python gpu_gate_server.py --selftest # then register the server in your client (docs/clients.md)Related MCP server: ComfyUI MCP Skills
무엇이고 왜 필요한가
GPU 한 장에서 로컬 LLM 과 ComfyUI/VoiceStudio 를 함께 올려 두면 VRAM 이 모자란다. 에이전트에게 이미지나 음성 작업을 시키려면 누군가 LLM 을 내리고, 작업 도구를 띄우고, 작업이 끝나면 도구를 끄고, LLM 을 다시 올려야 한다. 이 순서를 에이전트가 직접 하게 두면 LLM 을 끈 채로 잊거나, 작업 도중 다른 요청이 GPU 를 빼앗는 일이 생긴다.
GPU-Gate-MCP 는 이 순서 전체를 도구 호출 하나로 묶는다. 에이전트는 comfy_batch 또는 voice_batch 에 한 작업의 잡을 전부 담아 한 번 호출하고, 호출은 배치가 끝날 때까지 돌아오지 않는다(blocking). 실제 일은 서버와 분리된(detached) 워커 프로세스가 하므로, 클라이언트가 중간에 닫혀도 워커는 끝까지 가서 LLM 을 다시 올린다.
파이썬 표준 라이브러리만 쓰고 설치할 외부 패키지가 없다. ComfyUI 는 사용자가 쓰던 시작 .bat 을 그대로 읽어 같은 환경과 인자로 띄우므로, 게이트용으로 따로 설정을 옮길 필요가 없다. 현재 LLM 쪽 어댑터는 Strata 의 HTTP API 를 기준으로 한다(Strata 에게 바라는 것).
동작 순서
한 배치는 별도 워커 프로세스에서 다음 순서로 진행된다.
점검 — 잡 목록과
comfy_variant옵션(그.bat이comfyui.dir에 있는지)을 확인하고,other_llm_ports의 다른 LLM 서버가 응답하면 배치를 거부한다(force로 무시할 수 있다). 여기서 거부되면 Strata 는 건드리지 않는다.Strata 내리기 — 진행 중인 응답(턴)이 끝나기를 기다렸다가
POST /unload?wait=1로 엔진을 내린다. 서버가 바쁘면 1분마다 다시 시도하고, 15분이 지나도 바쁘면strata pause failed: busy로 배치를 포기한다(LLM 은 건드리지 않은 상태 그대로).실행기 시작 — ComfyUI(또는 VoiceStudio)를 사용자의 시작 스크립트로 띄우고 응답할 때까지 기다린다. 이미 떠 있으면 그것을 쓴다. 응답은 없지만 그 포트를 누가 이미 잡고 있으면(밖에서 막 띄운 ComfyUI 가 아직 뜨는 중) 새로 띄우지 않고
start_timeout_s까지 기다렸다가 그것을 쓴다(외부 실행기로 다룬다).잡 실행 — 잡을 순서대로 실행한다. 연달은 워크플로우는 한 묶음으로 큐에 넣고 순서대로 기다리며, 명령(command) 잡은 앞선 잡이 모두 끝난 뒤 하나씩 실행한다.
정리 — 큐에 남은 프롬프트를 지우고, ComfyUI 의
/free로 모델을 내리고, 실행기를 끈다(keep_executor인 경우 제외). 끈 프로세스가 VRAM 을 놓았는지 최대 60초 확인한다.Strata 올리기 —
POST /load로 엔진을 다시 올리고/health가loaded가 될 때까지 기다린다. 항상 실행된다. 잡이 실패하거나 취소되거나 클라이언트가 사라져도 4~5단계는finally로 보장된다.결과 기록 — 결과를 배치 파일과
state.json에 쓰고, 기다리던 호출에 돌려준다.
Strata 가 처음부터 응답하지 않으면(GET /health 무응답) 1·5단계를 건너뛰고 배치만 돌린다(strata.server 가 false). 배치 도중 사용자가 LLM 과 대화를 시작해 엔진이 다시 올라오면 경고 한 줄만 남기고 계속 진행하며, 다시 내리지 않는다.
설치
필요한 것: Python 3.10 이상(외부 패키지 없음), Strata(로컬 LLM 서버), ComfyUI 와 그 시작 .bat, 선택으로 VoiceStudio. 검증된 플랫폼은 Windows 이며 POSIX 분기는 있으나 확인하지 못했다.
git clone https://github.com/ssain3d-lgtm/GPU-Gate-MCP GPU-Gate-MCP
cd GPU-Gate-MCP
python gpu_gate_server.py --initpip install . 으로 패키지만 설치했다면 같은 일을 python -m gpu_gate --init 처럼 부른다(진입점 스크립트는 만들어지지 않는다).
설정 만들기 —
--init은 예시config.json을 상태 디렉터리에 만든다. 이미 있으면 덮어쓰지 않는다. 다른 위치의 파일을 쓰려면--config <경로>또는 환경변수GPU_GATE_CONFIG.설정 고치기 — 예시 값은 자리표시자다. 이 PC 의 ComfyUI 폴더와 시작
.bat, VoiceStudio 경로로 바꾼다. 적어 둔 경로는 실제로 있어야 한다. 없으면voicestudio.dir does not exist: ...처럼 키 이름을 대고 실패한다. VoiceStudio 를 쓰지 않으면voicestudio절을 통째로 지운다. 반대로comfyui는 필수라서,voice_batch만 쓰더라도bat이나command중 하나는 있어야 설정이 통과한다.점검 —
python gpu_gate_server.py --selftest는 설정을 읽고, Strata·ComfyUI·VoiceStudio 에 응답이 있는지 물어보고(아무것도 시작하지 않는다), 프로세스 안에서 MCPinitialize/tools/list를 한 번 돌려 본다.config <상태 디렉터리>/config.json home <상태 디렉터리> strata http://127.0.0.1:8080 loaded comfyui http://127.0.0.1:8188 down voicestudio http://127.0.0.1:3900 down mcp protocol 2025-06-18, tools: comfy_batch, voice_batch, gate_status설정이 없으면
--init을 안내하는 한 줄 오류와 함께 종료 코드 1 로 끝난다.클라이언트에 등록 — docs/clients.md (opencode, Qwen Code, Hermes 스니펫과 에이전트 지침).
직접 실행하면(python gpu_gate_server.py) stdin/stdout 으로 MCP 를 말하는 서버가 된다. stdout 에는 프로토콜 줄만 나가고 진단은 모두 stderr 로 간다.
설정
config.json 은 이 기계에 묶인 값을 전부 담는다. 빠진 절과 키는 기본값을 쓰고, 모르는 키는 무시한다. 잘못된 값은 키 이름과 파일 경로를 대고 시작 단계에서 실패한다.
키 | 예시 값 | 설명 |
|
| Strata 주소. |
|
| 있으면 |
|
|
|
|
|
|
|
| ComfyUI 시작 |
|
|
|
|
| 문자열 목록(argv). 있으면 |
|
| ComfyUI 주소. |
|
| 시작 뒤 응답을 기다리는 시간. |
|
| ComfyUI 가 결과를 쓰는 폴더. |
|
| VoiceStudio 작업 폴더. 적으면 실제로 있어야 한다. |
|
| 백엔드를 포그라운드로 띄우는 스크립트. |
|
| 잡을 처리하는 배치 스크립트(voice_batch 참고). 적으면 실제로 있어야 한다. |
|
| VoiceStudio 주소( |
|
| 시작 뒤 응답을 기다리는 시간. |
|
| 잡 하나의 제한 시간(옵션 |
|
| 배치 전체의 제한 시간(옵션 |
|
| 같은 PC 의 다른 로컬 LLM 서버 포트(127.0.0.1). 하나라도 연결되면 배치를 거부한다. |
환경변수는 둘이다.
변수 | 뜻 |
| 상태 디렉터리(기본값은 아래 파일 규약 참고). |
| 설정 파일 경로(기본값은 |
ComfyUI 시작 .bat 은 이렇게 읽는다. set NAME=값 줄들은 환경변수로 모으고(%~dp0, %VAR% 는 풀어서), main.py 로 끝나는 토큰이 있는 첫 줄을 실행 줄로 쓴다. 상대 경로는 .bat 폴더 기준 절대 경로로 바꾸고, --disable-auto-launch 가 없으면 붙인다(브라우저가 열리지 않게). if/call/for/set /a 같은 줄은 해석하지 않고 건너뛰므로, 가상환경을 call ...activate 로 켜는 .bat 이라면 실행 줄에 파이썬 경로를 직접 적거나 comfyui.command 를 쓴다. 게이트가 쓰는 시작 줄(comfyui: starting ...)에는 환경변수의 이름만 남고 값은 남지 않는다(실행 줄로 풀려 들어간 4자 이상의 값은 <이름> 으로 가려진다). 그 뒤에 쌓이는 실행기 자체의 출력은 거르지 않는다.
Strata 에게 바라는 것
게이트는 Strata 에게 아래 HTTP 호출만 한다. 호환되는 서버라면 다른 LLM 서버에도 붙을 수 있다.
호출 | 기대하는 응답 |
| 200 과 JSON 의 불리언 |
| JSON 의 |
| 200 |
| 200. 뒤이어 |
도구
서버는 도구 세 개를 낸다. 호출 결과는 JSON 텍스트(content)와 같은 내용의 structuredContent 로 오고, 도구 오류일 때만 isError 가 참이다. 잡이 실패한 배치도 오류가 아니라 ok: false 인 정상 결과로 돌아온다.
도구 | 하는 일 |
| ComfyUI 잡을 실행한다. 배치가 끝나야 돌아온다. |
| VoiceStudio 잡을 실행한다. 배치가 끝나야 돌아온다. |
| 읽기 전용 현황. 아무것도 바꾸지 않는다. |
인자는 jobs(1개 이상의 객체 배열, 필수)와 options(객체) 뿐이며 다른 이름은 <이름>: unknown argument 로 거절된다.
comfy_batch
jobs 의 항목은 두 종류다.
{"kind": "workflow", "path": "<API 형식 워크플로우 JSON 의 경로>", "name": "선택 이름"}
{"kind": "command", "command": ["python", "gen.py", "--arg"], "cwd": "선택", "timeout_s": 600}워크플로우는 ComfyUI 의 Export (API) 로 저장한 JSON 이어야 한다. 일반 저장(UI 형식)은
not an API-format workflow (save with 'Export (API)')로 그 잡만 실패한다.command는 게이트가 직접 실행하는 프로그램이다(ComfyUI 가 켜져 있는 동안, 앞선 잡이 모두 끝난 뒤). 종료 코드 0 이면done, 아니면error(exited <코드>).cwd가 있으면 존재해야 하고,timeout_s가 없으면job_timeout_s를 쓴다. 출력은 로그에 쌓이고outputs는 비어 있다. 이 도구를 부를 수 있는 누구나 사용자 권한으로 아무 프로그램이나 실행할 수 있다(로컬 에이전트용 도구다).잡 하나가 잘못돼도(파일 없음 등) 그 잡만
error가 되고 나머지는 계속 간다. 단stop_on_error이면 첫 오류 뒤는 건너뛴다.
options (모두 선택):
옵션 | 기본 | 뜻 |
|
| 첫 오류가 나면 나머지를 |
| 설정의 | 잡 하나의 제한 시간. |
| 설정의 | 배치 전체의 제한 시간. 지나면 남은 잡은 |
|
| 배치 끝에 실행기를 끄지 않는다. 게이트가 띄우지 않은(이미 떠 있던) 실행기에만 적용된다. 게이트가 띄운 것은 항상 끈다. |
|
|
|
| 설정의 |
|
이미 떠 있던 ComfyUI 도 배치가 끝나면 꺼진다(그 포트를 잡고 있는 프로세스를 종료). 남기려면 keep_executor 를 쓴다.
완료된 워크플로우의 outputs 는 ComfyUI 기록에 나온 저장 파일(이미지·gif·영상·오디오, 종류가 output 인 것)의 경로다. 임시·입력 파일은 제외한다.
voice_batch
jobs 의 항목은 사용자의 voice_batch.py 가 읽는 jobs.json 항목 그대로다.
{"text": "읽을 문장", "out": "result/line1.wav", "profile_id": "...", "instruct": "...", "speed": 1.0, "language": "ko"}게이트는 잡을 voice_jobs.json 에 쓰고 python <voicestudio.batch_script> <그 파일> 을 voicestudio.dir 에서 한 번 실행한다(게이트를 돌리는 것과 같은 파이썬으로. 배치 폴더 batches/<batch_id>/ 에 voice_jobs.json, voice_batch.log 가 남는다). 스크립트 환경에는 VOICESTUDIO_URL, (dir 가 있으면) VOICESTUDIO_ROOT, PYTHONUTF8=1 이 들어간다. 스크립트는 잡마다 out 의 wav 를 쓰고 끝나면 TTS 모델을 내린 뒤 종료 코드 0 으로 끝나야 한다.
스크립트가 한 번에 모든 잡을 처리하므로 잡별 시간은 따로 재지 않는다(
seconds는 전체 실행 시간). 실행 시간은batch_timeout_s만 제한하고job_timeout_s는 영향이 없다.잡은 종료 코드가 0 이고
out파일이 있어야done이다(상대 경로는 스크립트 작업 폴더인voicestudio.dir기준). 종료 코드가 0 이 아니면 모든 잡이error(batch script exited <코드>), 파일이 없으면 그 잡이error(output missing: <out>).옵션:
batch_timeout_s,keep_executor,force(stop_on_error·comfy_variant는 쓰이지 않는다).voicestudio.start_script/batch_script가 없으면 해당 단계에서voicestudio.start_script is not set처럼 실패한다.
결과 형식
두 배치 도구가 돌려주는 결과다. 이 객체가 배치 파일의 result 와 state.json 의 last_result 에도 그대로 들어간다.
{
"batch_id": "20261017-210500-a3f1",
"started": "2026-10-17T21:05:00+00:00",
"finished": "2026-10-17T21:12:41+00:00",
"ok": true,
"strata": {"server": true, "paused_s": 4.2, "restored": true, "load_s": 38.5},
"executor": {"kind": "comfyui", "started_by_gate": true, "cold_start_s": 21.3, "stopped": true},
"jobs": [
{"index": 0, "kind": "workflow", "name": "portrait.json", "status": "done", "seconds": 52.1,
"outputs": ["C:/ComfyUI/ComfyUI/output/portrait_00001_.png"], "error": null}
],
"warnings": [],
"log": "<상태 디렉터리>/logs/20261017-210500-a3f1.log",
"error": null
}필드 | 뜻 |
| 모든 잡이 |
| Strata 가 응답했는가( |
| LLM 이 내려가 있던 시간 / 다시 올라왔는가 / 올리는 데 걸린 시간. |
|
|
| 게이트가 띄웠는가 / 시작에 걸린 시간 / 끝에 껐는가. |
|
|
| 지정한 이름, 없으면 워크플로우는 파일명, 명령은 프로그램명, 음성은 |
|
|
| 결과 파일 경로 목록 / 실패 이유 한 줄. |
| 예를 들어 |
| 이 배치의 로그 파일. |
| 배치 단위의 실패 이유 한 줄( |
결과와 상태 파일(배치 파일, state.json)에는 경로·숫자·짧은 문자열만 담긴다. 시작 .bat 의 환경변수 값이나 strata.api_key 는 들어가지 않는다. 로그(logs/<id>.log)에는 실행기와 명령의 출력이 거르지 않고 그대로 쌓이며, .bat 에서 set 한 값을 가리는 것은 게이트가 쓰는 시작 줄(comfyui: starting ...)뿐이다.
gate_status
{
"state": "running",
"batch": {"batch_id": "...", "pid": 1234, "started": "...", "kind": "comfyui",
"state": "running", "progress": {"done": 1, "total": 3, "current": "portrait.json"}},
"strata": {"server": true, "loaded": false, "busy": false},
"executor": {"comfyui": "up(gate)", "voicestudio": "down"},
"gpu": [{"pid": 4321, "name": "python", "vram_mb": 21000}],
"warnings": [],
"last_result": null
}state는 상태값 중 하나다. 돌고 있는 배치가 있으면 그 배치의 상태, 없으면state.json의 값(처음에는idle, 배치가 끝난 뒤에는done또는failed). 워커가 죽은 채 남은 lock 이 있으면aborted와 경고를 보인다.batch는 돌고 있는 배치(없으면null).strata의server는 응답 여부,loaded/busy는 Strata 가 답한 값(모르면null).executor값은down,up(gate)(돌고 있는 배치가 쓰고 있는 것. 배치 도중에는 누가 띄웠는지 구분하지 못한다),up(external)(외부에서 띄운 것). 설정을 못 읽으면null.gpu는 VRAM 을 300 MiB 이상 쓰는 프로세스 목록(큰 순서, Windows 의 성능 카운터로 읽음). 못 읽으면null. LLM 이 올라와 있는 동안 다른 프로세스가 300 MiB 이상(데스크톱 창 관리자dwm은 3 GiB 초과) 잡고 있으면 경고를 남긴다.조회가 하나 실패해도 예외 대신
warnings에 적고 나머지를 돌려준다.보고만 한다. 워커가 죽어
aborted로 남은 배치 뒤에 LLM 이 내려가 있어도gate_status는 Strata 를 다시 올리지 않는다(다음 배치 호출이 올린다).
도구 오류
배치를 시작하기 전에 막히면 {"error": "<한 줄>"} 가 isError: true 로 온다.
오류 | 뜻 |
| 다른 배치가 돌고 있다. |
| 설정이 없거나 잘못됐다. 메시지가 키와 파일을 댄다. |
| 워커가 결과를 쓰기 전에 사라졌다. 서버가 배치를 |
| 워커 프로세스를 띄우지 못했다. |
| 워커가 배치를 끝냈다고 표시했지만 결과를 남기지 않았다. 로그를 본다. |
| 인자가 스키마에 맞지 않는다. |
파일 규약
서버, 워커, 외부 도구(예: 설정 UI)는 한 상태 디렉터리의 파일로만 서로 이야기한다. 위치는 GPU_GATE_HOME, 없으면 Windows 는 %LOCALAPPDATA%\gpu-gate, 그 밖에는 ~/.local/share/gpu-gate. 파일은 임시 파일에 쓴 뒤 바꿔치기로 갱신하므로 읽는 쪽이 반쯤 쓰인 파일을 볼 일은 없다.
경로 | 내용 |
| 설정. |
|
|
|
|
| 배치 파일: |
| 파일이 있으면 취소 요청. 외부 도구는 빈 파일을 만들면 된다. |
| 음성 배치의 작업 폴더( |
| 서버·워커 로그, 실행기와 명령의 출력. |
batch_id 는 YYYYMMDD-HHMMSS-<16진수 4자리> (지역 시간) 이다. 오래된 배치 파일과 로그를 지우는 기능은 없다.
상태값: idle, pausing(LLM 내리는 중), starting(실행기 시작), running(잡 실행), cleanup(정리), restoring(LLM 올리는 중), done, failed, aborted. 배치 파일에는 워커가 첫 전환을 하기 전까지 pending 이 보인다. 정상 종료는 done, 결과가 ok: false 이면 failed.
취소
클라이언트가 실행 중인 호출에 대해 notifications/cancelled 를 보내면(에이전트에서 Esc 를 누르거나 클라이언트의 도구 타임아웃이 지났을 때) 서버가 그 배치의 .cancel 파일을 만든다. 워커는 잡을 실행하는 동안 이 파일을 확인하고, 있으면 큐에 남은 프롬프트를 지우고, 실행 중인 것은 중단(/interrupt)하고, 실행기를 끄고, Strata 를 다시 올린다. 외부 도구가 .cancel 파일을 직접 만들어도 같다. LLM 을 내리는 중에 취소하면 실행기를 띄우지 않고(경고 cancelled before the executor started), 밖에서 띄운 실행기가 뜨기를 기다리는 중이면 그 기다림을 바로 멈추며, 게이트가 띄운 실행기가 시작하는 중이면 준비되는 대로 잡을 하나도 돌리지 않고 끈다(경고 cancelled before the jobs started). 어느 경우든 잡은 cancelled 가 되고 Strata 는 다시 올라간다. 취소된 호출에는 응답을 보내지 않으며(MCP 규칙), 결과는 배치 파일과 state.json 에 남는다.
클라이언트를 닫는 것은 취소가 아니다. 서버는 입력이 끊기면 곧(약 1초 안에) 끝나지만 워커는 계속 돌아 잡을 마치고 Strata 를 올린다. 결과는 gate_status 의 last_result 로 볼 수 있다.
알려진 한계
첫 응답이 느리다. LLM 을 내리면 대화의 KV 캐시가 사라진다. 배치가 끝난 뒤 첫 응답은 프롬프트를 처음부터 다시 읽으므로, 컨텍스트가 100K 토큰 이상이면 20~60초가 더 걸린다.
LLM 과 GPU 작업은 동시에 못 돌린다. 한 장의 GPU 에서는 그렇다. 배치 중에는 LLM 이 응답하지 못한다(그 사이 대화를 시작하면 경고만 남고 배치는 계속 간다).
다른 LLM 서버는 막는다.
other_llm_ports의 서버가 응답하면force가 아닌 한 배치를 거부한다. 게이트는 Strata 만 내리고 올린다.한 번에 배치 하나. 다른 클라이언트에서 부르면
busy.진행 알림은 토큰이 있을 때만. 클라이언트가 호출에 progress 토큰(
params._meta.progressToken)을 실어 보내면, 서버는 배치를 기다리는 동안 15초마다(첫 알림은 15초 뒤)notifications/progress를 보낸다.progress는 매번 커지는 알림 번호이고total은 없으며, 상태와 끝난 잡 수/전체 잡 수는message에 있다. 토큰이 없으면 보내지 않는다. 그래도 클라이언트의 도구 타임아웃(그리고 Qwen Code 의 무응답 타이머, Hermes 의 도구 마감 시간)이 배치보다 짧으면 클라이언트가 호출을 끊고 취소를 보낸다. 클라이언트별 설정은 docs/clients.md.Windows 우선. Windows 에서만 검증했다. POSIX 분기(프로세스 종료, 포트 조회)는 있으나 확인하지 않았고, GPU 프로세스별 VRAM 조회는 Windows 성능 카운터에 기댄다.
시작
.bat해석은 단순하다.set줄과main.py실행 줄만 이해한다. 그 이상이 필요하면comfyui.command.voice_batch는 잡별 시간·부분 결과가 없다. 시간 초과나 취소면 일부 파일이 이미 쓰였어도 모든 잡의outputs가 비어 있다.오래된 파일은 쌓인다. 배치 파일과 로그의 자동 정리는 없다.
문제 해결
증상 | 원인과 조치 |
| 다른 배치가 돌고 있다. |
결과 |
|
| 워커가 결과 없이 사라졌다. 로그 파일을 열어 마지막 줄을 본다. LLM 은 서버가 다시 올려 둔다. |
| 설정이 없다. |
| 메시지의 키와 파일을 고친다. 쓰지 않는 VoiceStudio 는 |
결과 |
|
잡 | UI 형식으로 저장한 워크플로우다. ComfyUI 에서 Export (API) 로 다시 저장한다. |
잡 | 경로가 게이트가 도는 PC 에서 존재하지 않는다. 절대 경로를 넘긴다. |
결과 | Strata 가 긴 생성을 하고 있었다. 게이트는 응답이 끝나기를 15분까지 기다린 뒤 포기하며, 이때 LLM 은 건드리지 않았다. 나중에 다시 부른다. |
결과 | ComfyUI 가 제때 뜨지 못했다. 로그에 ComfyUI 의 출력이 있다. 느린 PC 이면 |
결과 | 그 포트를 다른 프로세스가 잡고 있는데 응답하지 않았다(밖에서 띄운 ComfyUI 가 멈췄거나, 다른 프로그램이 포트를 쓴다). 게이트는 자기가 띄우지 않은 그 프로세스를 끄지 않는다. 직접 확인하고 끈 뒤 다시 부른다. |
경고 | 밖에서 막 띄운 실행기가 아직 뜨는 중이라 기다렸다가 썼다. 정상이다. 포트를 아직 잡지 않은 것(ComfyUI 는 시작 뒤 40~60초에야 잡는다)도 프로세스 명령줄( |
경고 | 게이트가 띄운 것과 밖에서 띄운 것이 함께 떴고 밖의 것이 포트를 잡았다. 게이트는 준비 뒤 포트를 잡은 프로세스가 자기 것(또는 그 자식)인지 확인하고, 아니면 자기 것을 끄고 그 실행기를 외부 것으로 다룬다(잡은 거기서 돌고, 배치 뒤 포트로 끈다). |
결과 | 실행기 프로세스가 배치 도중 사라졌다(잡 |
| LLM 이 올라오지 않았다(3번 시도). 로그를 보고 Strata 에 직접 |
에이전트가 도중에 호출을 끊었다 | 클라이언트의 도구 타임아웃이 배치보다 짧다. 정확히 5분(Qwen Code |
개발
python -m pytest -q테스트는 가짜 Strata·ComfyUI·VoiceStudio 서버만 쓰므로 GPU 도 실제 서버도 필요 없다. 실제 환경 확인 절차는 docs/QA.md.
모듈 | 역할 |
| MCP stdio 서버, 도구 세 개, 배치 시작·대기·취소 전달 |
| 분리된 워커: 6단계 순서와 결과 기록 |
| 상태 디렉터리(lock, state.json, 배치 파일, 취소 플래그) |
| 설정 읽기와 검증 |
| 각 서버 어댑터 |
| 프로세스, GPU 조회, HTTP 도우미 |
라이선스
MIT. LICENSE 참고.
Available Tools
3 toolscomfy_batchA
Run ComfyUI jobs on the GPU while the local LLM is unloaded; blocks until all are done and returns per-job status and output file paths. jobs: {"kind": "workflow", "path": "", "name": ""} or {"kind": "command", "command": ["python", "gen.py", ...], "cwd": "", "timeout_s": }. options (all optional): stop_on_error, job_timeout_s, batch_timeout_s, keep_executor (leave an already running ComfyUI up), force (go on although another LLM server answers), comfy_variant (another start .bat in the ComfyUI folder).
| Name | Required | Description | Default |
|---|---|---|---|
| jobs | Yes | ||
| options | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses blocking semantics ('blocks until all are done'), a real side effect (local LLM is unloaded), the return content, and error/executor control via stop_on_error and keep_executor. It does not cover failure-partial-batch behavior or permissions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and return behavior are front-loaded in the first sentence, followed by a compact parameter reference. The dense inline-brace notation is efficient but slightly hard to parse; no sentence is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and no annotations, the description supplies the return format (per-job status and output paths) and the key side effect, which is what an agent needs. Gaps remain around where output files land and what a partially failed batch looks like.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% and the schema is bare (two untyped object properties), so the description must compensate fully — and it does, spelling out both job variants (workflow: kind/path/name; command: kind/command/cwd/timeout_s) and enumerating the options object's keys with inline meaning. This is far more than the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource ('Run ComfyUI jobs on the GPU') plus the notable scoping condition ('while the local LLM is unloaded') and the return shape ('per-job status and output file paths'). An agent can tell this apart from voice_batch on the resource alone, though no sibling is named explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear usage context: this is the path for GPU/ComfyUI work that must coexist with an unloaded local LLM, and the 'force' option signals the guard condition (another LLM server answering). It stops short of explicit when-not guidance or naming voice_batch/gate_status as alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gate_statusARead-only
Read-only snapshot: the gate's state, the running batch's progress, whether the LLM is loaded, whether ComfyUI/VoiceStudio are up, GPU memory per process, warnings and the last batch result.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, so the description carries the rest of the burden, and it does so well by enumerating the full contents of the snapshot, which is effectively the return payload given there is no output schema. It does not mention cost, rate limits, or auth requirements, but for a zero-param read this is largely unnecessary.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single compact sentence that front-loads the read-only nature and then lists the payload contents with no filler or restatement of the tool name.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no input parameters and no output schema, the description's role is to describe what comes back, and it enumerates every returned facet comprehensively, leaving nothing an agent would need missing before calling it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes no parameters, so there is nothing for the description to disambiguate; the baseline for a zero-param tool is 4.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb+resource: a read-only snapshot of the gate's state, and enumerates the exact facets returned (batch progress, LLM loaded, ComfyUI/VoiceStudio status, GPU memory, warnings, last result). It never names or contrasts the sibling tools comfy_batch/voice_batch, so differentiation is only implicit through the read-only framing.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit when-to-use or when-not-to-use statement and no named alternative. Usage is only implied by the 'read-only snapshot' framing, which suggests polling/monitoring as opposed to the action-oriented siblings, but the agent must infer this.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
voice_batchA
Run VoiceStudio speech jobs on the GPU while the local LLM is unloaded; blocks until all are done and returns per-job status and output file paths. jobs: {"text": "...", "out": "<output .wav path>", "profile_id": ..., "instruct": ..., "speed": ..., "language": ...} (the batch script's job format). options (all optional): batch_timeout_s, keep_executor, force.
| Name | Required | Description | Default |
|---|---|---|---|
| jobs | Yes | ||
| options | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations the description carries the full burden, and it discloses meaningful traits: the call blocks until all jobs finish, it returns per-job status and output paths, and it exposes tuning knobs (batch_timeout_s, keep_executor, force). It omits failure semantics — what happens on partial failure or timeout — which keeps it from a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core behavior (run speech jobs on GPU, block until done, return status/paths) before the field details, and every clause carries information. The inline brace-list format is dense but readable; nothing is padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a nested-object, no-output-schema, long-blocking batch tool, the description covers what it does, when it is safe to run, and what comes back, which is close to what an agent needs to call it. Remaining gap is error/partial-failure behavior, which matters for an all-jobs-blocking call.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% and the nested job objects declare no properties at all, so the description is the only source for the job field names (text, out, profile_id, instruct, speed, language) and the option names. It names the options without explaining their effect, so it compensates well but not completely.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Run VoiceStudio speech jobs') plus the key scope (GPU, on a batch of jobs), which is enough to separate it from the unrelated comfy_batch (image ecosystem) and gate_status siblings. It never explicitly names an alternative, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a real usage condition — the jobs run on the GPU 'while the local LLM is unloaded' — which tells the agent when this tool is appropriate versus other GPU work. It does not, however, state exclusions or route to a sibling for the non-batch case, so it is clear context rather than a full when/when-not rule.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v0.1.0- First observed
comfy_batch - First observed
gate_status - First observed
voice_batch
TDQS
Scored across 3 tools
The two batch tools are separated by backend (ComfyUI vs VoiceStudio) and gate_status is a clear read-only counterpart, so boundaries are mostly clear. The shared 'batch while LLM unloaded' framing and the 'gate' theme create mild risk of confusion, but the names and descriptions make the target system explicit.
comfy_batch and voice_batch follow a consistent noun_action pattern with a shared _batch suffix, and gate_status is readable in the same style. The minor deviation (status vs batch) is natural and does not hurt predictability.
Three tools is well-scoped for a GPU gate whose purpose is to run two classes of GPU jobs and report state. It is slightly thin—there is no per-job submission or cancellation tool—but nothing is redundant.
Coverage includes batch execution for both backends plus a status snapshot, which fits the stated purpose. However, there is no way to cancel or abort a long-blocking batch, nor to list or inspect past batches beyond the last result, leaving notable gaps for a blocking-execution server.
Maintenance
Related MCP Connectors
Remote MCP server for supportsheep: run AI interviews and manage support content for your blog.
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
Remote MCP for RunComfy: ComfyUI deployments, hosted models, LoRA training. 31 tools.
Remote MCP server exposing your Node Command fleet (files, shell, processes, browser) to AI hosts.
Related MCP Servers
- AlicenseBqualityCmaintenanceMCP server for AI-controlled GPU VRAM management in ComfyUI, allowing Claude to monitor and control GPU state, manage model offloading, and start/stop ComfyUI.14MIT
- AlicenseBqualityBmaintenanceMCP server that dynamically exposes each enabled ComfyUI workflow as a tool with JSON Schema, supports job submission with wait and idempotency, file uploads, and resource metadata, with both stdio and authenticated Streamable HTTP transports.36MIT
- AlicenseNot gradedqualityBmaintenanceMCP server that wraps ComfyUI for SDXL image generation. It exposes tools for generating images, listing models, and checking ComfyUI health, with presets and GPU resource coordination.1MIT
- AlicenseNot gradedqualityBmaintenanceEnables any MCP client to search and submit tasks across 350+ multimodal image, video, audio, and 3D models, run ComfyUI workflows and AI apps, upload/download files, and chat with LLMs. It supports stdio MCP integration and optional scope trimming for image, video, or audio only.2MIT