Node.js 생태계의 패키지 저장소이자 설치 도구입니다. Python의 PyPI와 pip를 합친 역할에 가깝습니다.
MCP 학습 노트
PDF Modify MCP를 이해하기 위한 JSON-RPC, npm, npx, MCP 흐름
이 문서는 PDF Modify 웹사이트를 만들며 함께 개발한 @drfirst/pdf-modify-mcp 서버를 소개하고, npm과 npx, JSON-RPC, MCP 클라이언트와 로컬 백엔드가 어떻게 연결되는지 설명합니다.
npm에 올라간 실행 가능한 패키지를 내려받아 바로 실행합니다. 사용자는 저장소를 clone하지 않아도 됩니다.
LLM이 로컬 도구를 표준 방식으로 발견하고 호출할 수 있게 하는 프로토콜입니다.
pdf-master-mcp, 또는 PDF Modify MCP란?
@drfirst/pdf-modify-mcp는 PDF Modify에서 구현한 PDF 작업 기능을 MCP 도구로 쓸 수 있게 만든 로컬 서버입니다. 웹사이트는 브라우저에서 동작하고, MCP 서버는 사용자의 PC에서 Node.js 프로세스로 동작합니다. 둘 다 파일을 외부 서버로 업로드하지 않는다는 철학을 공유합니다.
PDF 파일의 페이지 수 같은 기본 정보를 확인합니다.
여러 PDF를 지정한 순서대로 병합합니다.
1-3, 5 같은 범위로 필요한 페이지만 추출합니다.
한 PDF 또는 여러 PDF의 페이지를 원하는 순서로 재배치합니다.
PDF 좌표를 기준으로 한 페이지의 특정 영역을 잘라냅니다.
DOCX 또는 PPTX 파일의 텍스트를 기반으로 PDF를 생성합니다.
PDF에서 추출 가능한 텍스트를 DOCX로 내보냅니다.
PDF에서 추출 가능한 텍스트를 PPTX 슬라이드로 내보냅니다.
npm publish와 npx 실행의 의미
npm에 패키지를 publish한다는 것은 인터넷 어딘가에 백엔드 서버를 계속 켜둔다는 뜻이 아닙니다. 실행 가능한 프로그램을 npm registry에 올려두는 것입니다. 실제 실행은 사용자의 PC에서 npx가 합니다.
npx -y @drfirst/pdf-modify-mcp
JSON-RPC는 하나의 입구로 여러 작업을 부르는 방식
REST API는 기능마다 endpoint를 나누는 경우가 많습니다. JSON-RPC는 하나의 통신 입구를 두고, 요청 본문의 method로 어떤 작업인지 알려줍니다. MCP는 JSON-RPC 위에서 tools/list, tools/call 같은 규칙을 정한 형태입니다.
POST /api/pdf/merge
POST /api/pdf/split
POST /api/pdf/crop
POST /rpc
{
"method": "pdf_merge",
"params": { ... }
}
MCP의 stdio transport에서는 HTTP endpoint도 없습니다. 대신 실행 중인 프로세스의 stdin/stdout으로 JSON-RPC 메시지가 오갑니다.
MCP에서 실제로 작업이 시작되는 순간
MCP 서버는 먼저 실행되고 대기합니다. 그 후 LLM이 직접 npx에 파일 인자를 붙이는 것이 아니라, MCP 클라이언트가 JSON-RPC 메시지를 서버의 stdin으로 보냅니다.
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "pdf_merge",
"arguments": {
"inputPaths": [
"C:/Users/me/a.pdf",
"C:/Users/me/b.pdf"
],
"outputPath": "C:/Users/me/merged.pdf"
}
}
}
VS Code에서 쓰는 설정
사용자는 MCP 클라이언트 설정에 npm 패키지를 실행하는 명령만 넣으면 됩니다. 그러면 클라이언트가 필요한 순간에 로컬 MCP 서버를 실행합니다.
{
"servers": {
"pdf-modify-mcp": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@drfirst/pdf-modify-mcp"]
}
}
}
이 설정의 args는 PDF 작업 인자가 아니라, MCP 서버를 시작하기 위한 npx 인자입니다. PDF 파일 경로와 결과 경로는 서버가 켜진 뒤 tools/call의 arguments로 전달됩니다.
stdin과 stdout을 아주 쉽게 이해하기
stdin과 stdout은 터미널 화면 자체가 아니라, 실행 중인 프로그램에 연결된 입력과 출력 통로입니다. 사람이 터미널에 직접 입력할 수도 있지만, MCP에서는 MCP 클라이언트가 이 통로를 잡고 JSON-RPC 메시지를 넣고 읽습니다.
python main.py --arg1 input
프로그램을 시작할 때 값을 한 번 넘기는 방식입니다. 이 값은 보통 argv로 읽습니다.
echo '{"method":"hello"}' | python main.py
프로그램이 실행된 뒤 입력 통로로 데이터를 흘려보내는 방식입니다. MCP stdio는 이 방식에 가깝습니다.
LLM이 터미널 화면에 나온 글자를 다시 읽는 것이 아닙니다. MCP 클라이언트가 MCP 서버 프로세스의 stdin과 stdout 파이프를 직접 연결해 JSON 메시지를 주고받습니다.
직접 테스트하고 싶을 때
MCP 클라이언트 없이도 PowerShell에서 JSON lines를 pipe로 보내 간단히 테스트할 수 있습니다.
@'
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"manual-test","version":"1.0.0"}}}
{"jsonrpc":"2.0","method":"notifications/initialized","params":{}}
{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}
'@ | npx -y @drfirst/pdf-modify-mcp
실제 도구 호출은 tools/list 대신 tools/call을 보내면 됩니다.
왜 이 구조가 PDF Modify와 잘 맞는가
PDF Modify의 중요한 방향은 파일을 서버에 업로드하지 않는 것입니다. 웹사이트에서는 브라우저가 작업하고, MCP에서는 사용자의 PC에서 로컬 Node.js 프로세스가 작업합니다. npm은 프로그램을 배포하는 통로일 뿐이고, 실제 PDF 파일 처리는 사용자의 로컬 환경에서 일어납니다.