Claude Desktop MCP — '한 번 더블클릭' 설치자를 만들기까지의 삽질
문제
ZPi Controller 가 MCP 서버를 노출한다. 사용자가 자기 Claude Desktop 에 연결하려면:
- MCP exe 다운로드 (101 MB 자체포함 .NET)
- 적절한 위치에 배치
claude_desktop_config.json에 JSON 항목 추가- Claude Desktop 재시작
이걸 “엔지니어가 아닌 사람”이 하게 만들어야 했다. 시스템 페이지 → [MCP 설치 (PC연동)] 버튼 한 번 → BAT 다운로드 → 더블클릭 → 끝. 이 한 줄 UX 를 위해 의외로 많이 삽질했다.

시도 1: 단순 BAT — 즉시 실패
@echo off
powershell -Command "Invoke-WebRequest http://192.168.0.x:5000/api/mcp/exe -OutFile '%LOCALAPPDATA%\Programs\ZpiController\ZPi.Controller.Mcp.exe'"
... (config 패치)
echo 완료
pause
실패 1: 한국어 메시지에 CP949 인코딩으로 BAT 가 cmd.exe 파서를
깨뜨림. .은(는) 예상되지 않았습니다 에러.
→ BAT 전체를 영어 ASCII 로. 사용자에게 보일 문구만 한글 (config 패치 완료 안내).
실패 2: Download failed: 파일이 다른 프로세스에서 사용 중. Claude
Desktop 이 이미 MCP exe 를 열고 있어서 덮어쓰기 거부.
→ 다운로드 전에 Claude Desktop / MCP 프로세스 종료 단계 추가.
실패 3: taskkill /IM Claude.exe /F 가 Claude Code (CCD) 까지
같이 죽임. 사용자가 CCD 에서 BAT 실행했으면 본인 세션 종료됨.
→ Process Path 보고 분기. claude-code\ 가 들어간 경로는 skip:
Get-Process claude -EA 0 |
Where-Object { $_.Path -and $_.Path -notmatch 'claude-code' } |
Stop-Process -Force
시도 2: PowerShell escape 지옥
BAT 안에서 PowerShell 한 줄로 JSON 패치하는데:
powershell -Command "$exe='%EXE%'; $piHost='{host}'; ...
$entry=[PSCustomObject]@{ command=$exe; args=@('--pi',$piHost) };
if(...) { ... } else { ... }"
PowerShell 안에서 \" 로 큰따옴표 escape, \\\" 로 BAT 안의 큰따옴표.
괄호 안의 명령 (if (...)) 이 BAT 의 for 블록 안에 있으면 괄호
매칭이 깨진다.
증상: PowerShell 출력은 정상인데 그 후에 .은(는) 예상되지 않았습니다
같은 cmd 파서 에러가 뜸. 디버깅하다 보니 — BAT 의 if errorlevel 1 ( echo Pi (192.168.0.x) 에 접속... ). 에서 메시지의 괄호가 if (...)
블록 괄호와 매칭돼서 블록이 일찍 닫히고, 남은 . 가 명령으로 해석됨.
→ 모든 메시지의 괄호 (...) 를 대괄호 [...] 로 변경. if errorlevel 1 (...) 블록은 goto :err 로 치환:
powershell ... -Command "..."
if errorlevel 1 goto :err_download
goto :ok
:err_download
echo *** Download failed.
pause & exit /b 1
:ok
...
시도 3: MS Store Claude Desktop 런치
MCP 설치 후 Claude Desktop 을 자동 재시작해야 한다. 정규 Claude.exe 가
있으면 start "" "%LOCALAPPDATA%\Programs\Claude\Claude.exe" 가 깔끔.
근데 사용자는 MS Store 버전을 쓰고 있었다 (C:\Program Files\WindowsApps\Claude_<버전>_x64__pzs8sxrjxfjjc\app\Claude.exe).
MS Store 앱은 직접 exe 경로로 못 띄운다. AppX 매니페스트의 shell:
URI 가 필요:
shell:AppsFolder\Claude_pzs8sxrjxfjjc!App
이걸 어떻게 BAT 에서 띄우나? 여러 방법:
| 시도 | 결과 |
|---|---|
Start-Process "shell:AppsFolder\..." | ”지정된 파일을 찾을 수 없습니다” 에러 |
Start-Process explorer.exe "shell:AppsFolder\..." | 앱은 뜨는데 AppsFolder 창도 같이 뜸 |
start "" "shell:AppsFolder\..." | ”찾을 수 없습니다” |
ProcessStartInfo.UseShellExecute=true | 잘 동작! 근데 한국어 escape 가 깨짐 |
너무 많이 변형해본 끝에 결론: 자동 launch 자체를 포기. 사용자한테 시작 메뉴에서 Claude 클릭하라고 알리는 게 가장 신뢰성 높았다:
echo [5/5] Finishing up...
echo Please restart Claude Desktop manually:
echo 1. Open Start Menu [Win key]
echo 2. Type Claude and press Enter
echo The MCP entry will be loaded on next startup.
가끔은 자동화 욕심을 버리는 게 정답이다. 수동 한 클릭 < 5가지 환경에서 실패하는 자동화.
토큰 자동 주입
MCP exe 가 ZPi API 를 호출하려면 인증이 필요하다 (운영자 비번을 외울
순 없으니까). 각 Pi 는 첫 부팅 시 32바이트 랜덤 토큰을 자동 생성해
mcp-token.txt 에 저장 (0600 권한). BAT 가 이 토큰을 받아서 Claude
config 의 args 에 박는다:
{
"mcpServers": {
"going-zpi-XXX": {
"command": "C:\\Users\\<you>\\AppData\\Local\\Programs\\ZpiController\\ZPi.Controller.Mcp.exe",
"args": ["--pi", "going-zpi-XXX.local", "--token", "<your-token>"]
}
}
}
MCP exe 는 모든 HTTP 요청에 X-MCP-Token 헤더를 자동 추가하고, Pi 의
auth gate 가 이 토큰을 cookie 없이도 통과시킨다.
SKIP_DOWNLOAD 최적화
BAT 한 번 깔린 PC 에서 사용자가 다시 BAT 실행하면 101 MB 를 또 받는다. 귀찮다. 그래서:
echo [3/5] Installing MCP server...
set "SKIP_DOWNLOAD=0"
if exist "%EXE%" (
for %%I in ("%EXE%") do (
if %%~zI GTR 52428800 set "SKIP_DOWNLOAD=1"
)
)
if "%SKIP_DOWNLOAD%" == "1" (
echo Already installed - skipping download.
goto :download_done
)
echo Downloading [~101 MB]...
... powershell Invoke-WebRequest ...
:download_done
50 MB 넘는 exe 가 이미 있으면 다운로드 skip. 두 번째 실행부터는 토큰 재발급 + config 패치만 하니까 1-2초 안에 끝난다.
다중 디바이스 지원
원래 Claude config 의 MCP key 는 하드코딩 "zpi-controller" 였다. 그
결과 한 PC 에서 BAT 실행 → zpi-controller: --pi 192.168.0.x,
그 다음 같은 PC 에서 다른 ZPi 의 BAT 실행 → 같은 key 덮어쓰기 → 먼저 등록한 게
사라짐.
해결: key 를 호스트명에서 유도. 보드 A (going-zpi-AAA) 가 만든 BAT 은
going-zpi-AAA, 보드 B (going-zpi-BBB) 가 만든 BAT 은 going-zpi-BBB 으로
다른 key. 둘 다 Claude 에 등록되고 도구 이름도 자동으로 prefix 됨
(mcp__going-zpi-AAA__plc_set_output, mcp__going-zpi-BBB__plc_set_output).
// Software/Program.cs - install.bat generator
var entryKey = host.EndsWith(".local")
? host[..^6] // "going-zpi-XXX.local" → "going-zpi-XXX"
: host;
var safeEntryKey = Regex.Replace(entryKey, @"[^a-zA-Z0-9._\-]", "_");
위 호스트명(
going-zpi-AAA/going-zpi-BBB)은 IP 끝자리에서 자동으로 유도되는 예시 패턴일 뿐이다. 실제 보드는 각자 다른 번호를 갖는다.
여러 ZPi 가 있어도 자동으로 모두 인식. 청소도 자동 — 옛 zpi-controller
key 가 있으면 BAT 가 삭제하고 새 호스트별 key 로 교체.
정리 — UX 가 가장 어려운 부분
기능 코드는 며칠이면 짠다. 그런데 “엔지니어 아닌 사람도 한 번 더블클릭으로 설치” 가 되게 만드는 건 인내심 테스트다:
- 한국어 인코딩 (CP949 vs UTF-8 vs ASCII)
- cmd.exe 의 파서 함정 (괄호 매칭,
.명령) - PowerShell ↔ BAT escape 지옥
- Windows 의 다양한 Claude Desktop 설치 변종 (정규 vs MS Store)
- 사용자 vs Claude Code 프로세스 구분
- 토큰 라이프사이클, 호스트명 변경, 다중 디바이스
각 함정을 만났을 때 “이건 더 단순한 방법이 있을 것” 같았는데 결국 없었다. UX 는 누적된 작은 결정의 집합이다.
댓글
로그인 없이 이름만 적고 남기실 수 있어요. 남긴 댓글은 바로 게시됩니다.
댓글을 불러오는 중…