CLI 클라이언트

CLI 클라이언트 (CLI client)

MCP Inspector를 스크립트로 다루는 방법, 즉 메서드, 출력 형식, 종료 코드, CI 레시피를 다루는 문서예요. 각 CLI 실행은 서버에 연결하고, --method로 이름 붙인 단일 요청을 호출하며, 결과를 출력하고 종료합니다.

출처: 문서

본문

각 CLI 실행은 서버에 연결하고, --method로 이름 붙인 단일 요청을 호출하며, 결과를 출력하고 종료해요. 그래서 서버 변경을 즉시 검증해야 하는 CI 파이프라인, 셸 원라이너, 코딩 에이전트에 잘 맞습니다.

npx @modelcontextprotocol/inspector --cli node build/index.js --method tools/list

아래 예시는 설치된 mcp-inspector 바이너리를 사용해요. 전역 설치가 없다면 위와 같이 각 명령 앞에 npx @modelcontextprotocol/inspector를 붙이세요.

서버 선택

CLI는 위치 인수 명령(stdio), --server-url(HTTP/SSE), 또는 카탈로그·구성 파일에서 이름 붙은 서버를 받아요.

# stdio: everything positional is the command to spawn
mcp-inspector --cli node build/index.js --method tools/list

# HTTP
mcp-inspector --cli https://api.example.com/mcp --transport http --method tools/list

# From a file
mcp-inspector --cli --config ./mcp.json --server myserver --method tools/list

서버가 파일에서 오면 그 서버별 설정(헤더, 타임아웃, OAuth, 프로토콜 시대, roots)이 TUI와 web 클라이언트가 해석하는 것과 정확히 동일하게 연결에 적용돼요. --header 플래그는 그 실행 동안 파일의 헤더를 덮어쓰면서 타임아웃과 OAuth는 그대로 둡니다.

이후 예시는 사용하는 형식 중 어떤 것이든, 그 --transport 또는 --config/--server 플래그와 함께 <server>로 줄여 쓸게요.

구성 파일이 실행에 roots를 주는 유일한 지속적 방법입니다. roots 플래그는 없고, --method roots/set은 그 하나의 단명 연결에만 적용돼요. 서버에 구성된 roots는 연결 시 광고되므로, roots/list를 호출하는 서버(@modelcontextprotocol/server-filesystem이 허용 디렉터리를 배우려고 하는 것처럼)는 그것을 받습니다.

--catalog 대 --config, -- 구분자, 공유 서버 선택 플래그는 구성과 플래그를 참고하세요.

메서드

--method 필수 동반 참고
initialize 없음 연결 전용 프로브: {serverInfo, protocolVersion, capabilities, instructions}.
tools/list 없음
tools/call --tool-name, 그리고 --tool-arg / --tool-args-json
resources/list 없음
resources/read --uri
resources/templates/list 없음
prompts/list 없음
prompts/get --prompt-name, --prompt-args
logging/setLevel --log-level 레거시 시대 전용. 현대 서버는 대신 요청별 옵트인.
servers/list, servers/show 없음 아무것에도 연결하지 않고 카탈로그를 읽음.

스트림·세션 전용 메서드(logging/tail 같은)는 거부돼요. 종료하는 프로세스가 스트림을 열어 둘 수 없기 때문이죠.

인수 전달

--tool-arg는 key=value를 받고 값을 JSON 파싱으로 강제 변환해서, count=1은 숫자가 되고 "012"는 12가 됩니다.

mcp-inspector --cli <server> --method tools/call --tool-name mytool \
  --tool-arg key=value --tool-arg count=1 --tool-arg 'options={"format":"json"}'

--tool-args-json은 전체 인수 객체를 한 번에 받아 강제 변환 없이 그대로 전달해서, "012"는 문자열 012로 유지됩니다. 둘은 상호 배타적이에요.

mcp-inspector --cli <server> --method tools/call --tool-name mytool \
  --tool-args-json '{"zip":"10001"}'

출력

--format text(기본값)는 사람을 위해 예쁘게 출력해요. --format json은 배너 없이 stdout에 단일 JSON 객체를 내보내서, 전체 출력이 깔끔하게 파이프됩니다.

mcp-inspector --cli <server> --method tools/list --format json | jq '.result.tools[].name'

MCP Apps 프로빙

--app-info는 도구를 호출하지 않고 도구가 MCP App UI(ui:// 리소스, CSP, 권한)를 동봉하는지 보고해요. 그래서 파이프라인이 무엇을 호출하기 전에 브라우저가 필요한지 결정할 수 있습니다.

# One tool -> one JSON line
mcp-inspector --cli <server> --method tools/call --tool-name my_tool --app-info
# {"hasApp":true,"toolName":"my_tool","resourceUri":"ui://...","csp":{...},"permissions":{...}}

# Every tool -> NDJSON, one line each, over a single connection
mcp-inspector --cli <server> --method tools/list --app-info | jq -c 'select(.hasApp)'

종료 코드가 결과를 구분해요. 앱이 있는 도구는 0으로, 없는 도구는 2로, 없는 도구는 5로 종료해서 오타가 "앱 없음"으로 오인되지 않게 합니다. 프로브 실패(읽을 수 없는 UI 리소스, 잘못된 resourceUri)는 중단 대신 resourceError 필드로 보고되어, 나쁜 도구 하나가 전체 목록을 죽이지 않아요.

tools/list --app-info는 --format에 관계없이 항상 NDJSON(도구당 한 줄)을 내보냅니다. --format json은 tools/call --app-info의 단일 도구 출력만 재구성해요.

종료 코드와 오류 엔벨로프

모든 0이 아닌 종료는 안정적인 실패 클래스에 매핑되어, 호출자가 산문을 긁지 않고 왜를 기준으로 분기할 수 있어요.

코드 의미
0 성공.
1 사용법 또는 예기치 않은 오류(포괄).
2 도구에서 MCP App을 찾지 못함(--app-info 프로브).
3 서버가 인증을 요구(401/403, WWW-Authenticate, OAuth).
4 서버에 도달 불가(DNS, 연결 거부, 타임아웃, fetch failed).
5 도구 오류: tools/call이 isError: true를 반환했거나 도구를 찾지 못함.

0이 아닌 종료 시 CLI는 stderr에 단일 JSON 줄도 씁니다.

{
  "error": {
    "code": "auth_required",
    "message": "Unauthorized",
    "status": 401,
    "url": "https://api.example/mcp"
  }
}

한 줄이므로 호출자는 2>&1 | tail -1 | jq .error로 파싱할 수 있어요.

isError: true를 반환하는 tools/call은 여전히 페이로드를 출력하지만 5로 종료해서, 실패한 호출에서 && 체인이 진행되지 않습니다.

스크립트에서의 인증

기본적으로 CLI는 TUI와 같은 루프백 OAuth 흐름을 실행해요. 브라우저를 열고 CI 작업이 완료할 수 없는 localhost 콜백을 기다리죠. 두 플래그가 비상호작용 실행을 예측 가능하게 만들어요.

  • --stored-auth-only: 상호작용 OAuth나 스텝업을 시작하지 않고 브라우저를 자동으로 열지 않아요. 공유 저장소의 토큰이 있으면 사용하고, 없으면 즉시 auth_required로 실패해요. CI가 원하는 플래그입니다.
  • --use-stored-auth: web Inspector가 이미 이 머신에서 얻은 토큰을 재사용하고, 리프레시 토큰이 저장되어 있으면 먼저 갱신해요.

둘 다 없고 stdin이나 stderr에 TTY도 없으면, CLI는 아무도 완료하지 않을 콜백에서 15분간 매달리지 않고 auth_required로 빠르게 실패해요.

전체 흐름, web-to-CLI 핸드오프, --print-handoff는 인증을 참고하세요.

레시피

CI에서 서버 검증

set -euo pipefail

# Fail the build if the server can't be reached or doesn't expose the tool
mcp-inspector --cli --config ./ci-servers.json --server my-server \
  --stored-auth-only --method tools/list --format json \
  | jq -e '.result.tools | map(.name) | index("get_weather")' > /dev/null

실패 클래스로 분기

if out=$(mcp-inspector --cli "$URL" --transport http --method tools/list 2>err.json); then
  echo "$out"
else
  case $? in
    3) echo "needs auth: run the web inspector once to sign in" ;;
    4) echo "server unreachable" ;;
    *) jq .error < err.json ;;
  esac
fi

UI가 있는 모든 도구 스모크 테스트

mcp-inspector --cli "$URL" --transport http --method tools/list --app-info \
  | jq -r 'select(.hasApp) | .toolName'

연결하지 않고 카탈로그 검사

mcp-inspector --cli --catalog ~/.mcp-inspector/mcp.json --method servers/list
mcp-inspector --cli --catalog ~/.mcp-inspector/mcp.json --method servers/show --server my-server

servers/show는 비밀을 담은 필드(env 값, 민감한 헤더, OAuth 클라이언트 시크릿)를 편집하지만, 서버 url(userinfo나 쿼리 토큰)이나 stdio args에 내장된 자격 증명은 씻어내지 않아요. 이슈에 붙여넣기 전에 원시 URL과 detail 필드를 민감한 것으로 취급하세요.

프록시

원격 HTTP/SSE 서버로의 연결은 관례적인 프록시 변수를 존중합니다. HTTPS_PROXY/HTTP_PROXY(소문자도)는 프록시를 선택하고 NO_PROXY는 호스트를 면제해요. Inspector 특정 플래그는 필요 없고, 프록시 에이전트는 지연 로드되므로 프록시 없이 실행하는 것은 아무 비용도 들지 않습니다. web 클라이언트의 백엔드에도 동일하게 적용됩니다.

더 알아보기 (Learn more)