1. 프로젝트 개요

핵심 포지션 및 목적

mcp-kit는 Model Context Protocol(MCP) 서버를 구축하고 배포하기 위한 단일 저장소입니다. 저장소 하나가 배포 패키지 하나(@julong/mcp-kit)에 대응하며, CLI 도구와 MCP 서버 인터페이스를 동시에 제공합니다. 주 목적은 AI 어시스턴트(Claude 등)가 원화 환율 조회, TMDB 영화 조회, 실행 중인 기계의 배터리·메모리·CPU·디스크 상태 조회를 MCP 프로토콜을 통해 직접 호출할 수 있도록 하는 것입니다.

주요 사용자 대상

  • 최종 사용자: Claude Desktop, Cursor 등 MCP 클라이언트를 통해 AI 어시스턴트에 환율·영화·기계 상태 조회 기능을 연결하려는 개발자
  • 개발자: MCP 서버 패키지를 npm으로 설치하거나 npx로 직접 실행하여 사용
  • AI 에이전트: MCP 프로토콜을 통해 도구(tool)를 직접 호출

핵심 기능

이 저장소는 다음 세 가지 인터페이스를 제공합니다:

  • 라이브러리 API: import { tools } from "@julong/mcp-kit" 형태로 Node.js 코드에서 직접 사용
  • MCP 서버: npx @julong/mcp-kit로 stdio 기반 MCP 서버 실행
  • CLI: npx mcp-kit-cli <toolName> [args]로 터미널에서 직접 도구 호출

npx로 MCP 서버가 실행되는 원리 (stdio 전송)

MCP 클라이언트(Claude Desktop, Cursor 등)가 npx @julong/mcp-kit으로 서버를 실행할 때, 서버는 네트워크 포트를 열지 않습니다. 대신 프로세스의 표준 스트림으로 통신합니다. 흐름은 다음과 같습니다:

  1. 프로세스 실행(spawn): 클라이언트가 해당 명령을 자식 프로세스(npx @julong/mcp-kit)로 실행합니다. npx는 npm 레지스트리(또는 로컬 캐시)에서 패키지를 찾아 bin 엔트리를 실행하는데, 이 스크립트는 shebang(#!/usr/bin/env node) 덕분에 Node.js로 바로 구동됩니다.

  2. 파이프 연결: 클라이언트는 자식 프로세스의 stdin, stdout, stderr를 파이프로 연결한 상태로 유지합니다. 이 세 스트림이 곧 전송 채널입니다:

    • stdin (클라이언트 → 서버): 클라이언트가 요청을 씁니다. 서버는 들어오는 메시지를 stdin에서 읽습니다.
    • stdout (서버 → 클라이언트): 서버가 응답/알림을 씁니다. 이 채널은 프로토콜 메시지 전용이며, 다른 것을 stdout에 출력하면 스트림이 손상됩니다.
    • stderr (서버 → 클라이언트, 대역 외): 로깅/진단용입니다. 클라이언트가 캡처할 수는 있지만 프로토콜 데이터로 파싱하지 않습니다. 사람이 읽을 로그는 stdout이 아니라 반드시 여기로 보내야 합니다.
  3. 메시지 프레이밍(JSON-RPC 2.0): MCP는 JSON-RPC 2.0으로 통신합니다. 각 메시지는 한 줄로 직렬화된 JSON 객체이며 개행(\n)으로 끝나는 newline-delimited JSON입니다. 대표적인 교환 예시:

    • 클라이언트 → stdin: {"jsonrpc":"2.0","id":1,"method":"initialize",...}
    • 서버 → stdout: {"jsonrpc":"2.0","id":1,"result":{...}}
    • 이후 tools/list, tools/call 등이 동일한 요청/응답 패턴을 따릅니다.
  4. 라이프사이클: 연결은 자식 프로세스가 살아있는 동안만 유지됩니다. 클라이언트가 stdin을 닫거나(EOF) 프로세스를 종료하면 서버도 종료됩니다. 상시 실행되는 데몬도, 관리할 포트도 없습니다 — 클라이언트가 파이프를 열어 두는 동안에만 서버가 존재합니다.

이 레포에서는 @modelcontextprotocol/sdk의 StdioServerTransport가 이 배관을 처리하므로, 도구 작성자는 stdin/stdout을 직접 다룰 필요 없이 async 도구 핸들러만 등록하면 됩니다. SDK가 표준 스트림 위에서 JSON-RPC 프레임의 직렬화/역직렬화를 대신 수행합니다.

왜 HTTP가 아닌 stdio인가? 포트 할당, 인증 계층, 네트워크 노출이 필요 없기 때문입니다. 클라이언트가 서버의 수명을 완전히 제어하고, OS 파이프는 안전한 로컬 채널입니다. 이것이 이 프로젝트가 stdio 전송만 사용하는 이유입니다(아래 비즈니스 제약 참고).

문서 사이트

저장소 루트에서 Rspress 기반 문서 사이트가 운영됩니다:

  • README 자동 연동: readme-docs-plugin이 손으로 쓴 루트 README.md를 /api 페이지로 렌더링
  • static docs: docs/의 마크다운 파일이 정적 문서 페이지로 제공
  • llms.txt 자동 생성: @rspress/plugin-llms 플러그인으로 LLM 친화적 사이트맵(llms.txt, llms-full.txt) 자동 생성
  • 배포: Netlify (netlify.toml 설정)로 배포

향후 개선 방향

  • 도구 확장: src/tools/에 더 다양한 도구 정의 및 추가
  • 포털·통화 확장: src/exchange/providers/에 조회 대상 추가

비즈니스 제약사항 및 금지 규칙

  • src/common은 내부 공유 모듈로, 빌드 시 번들에 인라인될 뿐 별도 패키지로 배포되지 않음
  • 저장소 루트 패키지 하나가 release-please를 통해 버전 관리 및 배포됨
  • @modelcontextprotocol/sdk와 zod는 핵심 외부 의존성으로, 함부로 버전을 올리거나 제거하지 않음
  • MCP 서버는 stdio 전송 방식만 사용 (HTTP/SSE 아직 미지원)
  • 모든 도구는 비동기 핸들러(async handler)로 작성되어야 함
  • 도구의 inputSchema는 Zod 스키마로만 정의 가능 (json-schema 등 다른 형식 불가)