1/18까지 카카오에서 개최한 MCP 개발에 참여하며 제가 만든 MCP를 소개하고 어떻게 만들었는지 알아봅시다!
MCP(Model Context Protocol)은 AI와 외부 시스템을 연결시키는 프로토콜 입니다.
비유하자면
Port와 같습니다.
AI와 외부 시스템을 연결하기 위해서 연동을 위한 별도 코드가 필요합니다.
연동할AI가 많이질 수록 코드가 많아지므로MCP서버 1대를 통해 다양한AI와 연결하기 위해 탄생한 프로토콜입니다.
저도 대회 시작 전에는 존재도 몰랐지만 해당 기술을 직접 사용해보고 개발해보며 개발자를 정말 편하게 해주는 도구임을 깨달았습니다.
현재 카카오에서 개발한 PlayMCP 라는 사이트를 통해 많은 개발자 분들이 만든 MCP를 도구함에 넣은 후 ChatGPT, Claude code, PlayMCP 챗봇에서 이용 가능합니다.

현재 제 서버도 등록하여 ChatGPT에서 사용 가능합니다!
이전부터 에러 로그 및 Spring서버의 상태를 매번 확인하고 모르는 에러를 LLM에게 물어보는 과정이 귀찮았습니다.
이 과정을 저 뿐만 아닌 주변 개발자들도 겪는다는 사실을 알게되고 간단한 모니터링 도구를 만들어보고 싶었습니다.
운영 중인 Spring 서비스의 장애 대응 시간을 줄이기 위해, 로그/메트릭/헬스 데이터를 자동 수집하고 진단 결과를 도구 호출 형태로 제공하는 서버 진단 시스템을 만들었습니다.
시중에 이미 모니터링 도구가 존재하지만 제가 이용하기 힘들었습니다.
높은 가격
DataDog 같은 경우 실제 현업에서 사용하는 만큼 혼자 사용하기 어마어마한 비용이 필요합니다.
적용의 복잡함
돈이 있더라도 모니터링 도구를 적용하기 위해 복잡한 사전 설정이 필요하고 이용 방법 또한 복잡합니다.
저는 기업에서 이용하는 목적보단 간단한 사이드 프로젝트, 초기 스타트업의 간단한 MVP 모델에 특화된 MCP를 고안했습니다.
최대한 적용이 편하고 빨라야함.
그래서 최대한 적용을 쉽게하며 에러 로그와 현 상태를 점검할 수 있는 MCP를 만들었습니다.
가장 큰 위험은 보안입니다.
에러 로그에 JWT 토큰, 회원 정보, 비밀 키 정보, API KEY... 같은 정보가 포함될 수 있습니다.
사용자는 해당 에러 로그가 외부로 노출되며 패킷이 도난당하는 순간 서버에 치명적 공격을 받을 수 있습니다.
또한, 에러 로그와 Health check 정보 확인을 위해 logs파일을 생성하게 하므로 외부에 노출을 막아야합니다.
일단 전체적인 흐름을 다이어그램을 통해 확인합시다.

흐름을 정리하며 다음과 같습니다.
- 유저가 서버를 등록 요청
Docker-compose.yml, application.yml, .env파일에 적용LLM을 통해 서버 상태 및 에러 로그 분석 요청- 요청을 받은
LLM은MCP서버에Tool list에서 적절한 도구를 선택하여 실행MCP서버가 반환 값을LLM에게 return- return 값을
LLM이 분석 후 사용자에게 알려줌
즉, 사용자는 서버 등록 요청 후 파일만 적용하면 바로 사용 가능합니다.
로그, health 정보 를 수집하기 위해 Forwarder가 사용자 서버와 함께 실행됩니다.
사용자가 Docker-compose.yml 설정을 통해 제가 만든 로그 수집기 컨데이너도 함께 실행됩니다.
기존의 모니터링 도구들은 API Endpoint를 이용해 정보를 가져오는 형식입니다.
즉, 모니터링을 위해 Endpoint를 따로 만들어야하는 번거로움이 있습니다.
Endpoint를 통해 가져오는 방식을PULL이라 하고
Forwarder를 통해 주기적으로 정보를 보내는 방식을PUSH라고 합니다.
저는 PUSH 방법을 통해 사용자가 Endpoint를 직접 만들지 않고 Forwarder를 통해 알아서 정보를 수집 후 MCP서버에 보내는 방식을 택했습니다.
Forwarder 방식을 이용한 SideCar 패턴을 이용했습니다.
Q :
SideCar패턴이란?
A : 핵심 비즈니스를 담당하는 컨테이너와 함께 실행되는 보조 컨테이너를 같이 실행시켜 핵심 로직과 분리되며 작동하는 패턴입니다.
왜 이 방식을 택했을까요?
핵심 비즈니스 로직과 명백히 분리되어야합니다.
사용자는 핵심 비즈니스 로직을 수정하지 않고
Forwarder를 붙이는 로직만으로 쉽게 적용 가능해야합니다.
Forwarder 서버가 죽더라도 메인 서버는 잘 작동해야합니다.
Forwarder와 메인 서버가 긴밀한 결합 때문에 의존하게 될 경우Forwarder가 죽을 경우 메인 서버도 죽을 가능성이 높습니다.
명백히 분리해야 안전한 프로그래밍입니다.
역시 보안 문제가 존재합니다.
하지만, 외부에 노출시키지 않으며 Forwarder를 통해 보내면 안전히 보낼 수 있습니다.
# 내 서버 이미지
target:
build: .
image: user-target:latest
container_name: user-target
ports:
- "8085:8085"
volumes:
- logs:/app/logs # 해당 경로에 로그를 작성
environment:
TZ: Asia/Seoul
restart: unless-stopped
# 포워더 이미지
forwarder:
image: ${FORWARDER_IMAGE}
container_name: mcp-forwarder
depends_on: [target]
volumes:
- logs:/logs:ro # 로그 파일을 읽음
environment:
MCP_LOG_INGEST_URL: "${MCP_DOMAIN}/api/servers/${SERVER_NAME}/ingest/logs"
MCP_METRIC_INGEST_URL: "${MCP_DOMAIN}/api/servers/${SERVER_NAME}/ingest/metrics"
MCP_HEALTH_INGEST_URL: "${MCP_DOMAIN}/api/servers/${SERVER_NAME}/ingest/health"
HEALTH_URL: "http://target:9090/actuator/health" # 헬스 체크 대상 URL
MCP_TOKEN: "${INGEST_TOKEN}"
DISCORD_WEBHOOK_URL: "${DISCORD_WEBHOOK_URL}"
LOG_PATH: "/logs/application.log"
# target:9090 을 통해 내 서버의 9090 포트를 이용해 actuator 정보를 가져옴. 외부에는 노출 X(보안에 최적)
ACTUATOR_URL: "http://target:9090/actuator/metrics"
restart: unless-stopped
volumes:
logs:
위의 Docker-compose.yml은 사용자가 적용할 양식입니다.
여기서 forwarder 라는 이미지도 같이 실행시킵니다.
# 로그 남기는 용도
logging:
file:
name: ./app/logs/application.log
# 성능 지표용
management:
server:
port: 9090 # Actuator 서버는 기존 서버와 다른 포트로 연결함.
endpoints:
web:
exposure:
include: "health,metrics,prometheus" # 절대 logfile 은 외부에 노출 X
endpoint:
health:
show-details: when_authorized
위의 application.yml을 설정을 통해 logs 파일을 생성하고 Metrics 정보를 9090 포트로 접근 가능하게 설정합니다.
이 설정을 보면 생기는 의문이 있습니다.
9090 포트에 Metrics를 노출시키면 외부에서 접근 가능하지 않을까?log 정보를 /logs/application.log 경로로 계속 생성하면 외부에서 접근 가능하지 않을까?application.yml 을 보면 logfile은 web에 절대 노출시키지 않으므로 2번 문제는 해결이 됩니다.
하지만, Metrics 정보는 외부에 노출될 위험이 있습니다.

해결을 위해 Metrics 정보는 9090 포트로 내보내며 외부에 9090 포트를 절대 노출시키지 않습니다.
즉, 인스턴스 내부
9090포트는 열려있지만 외부에서9090포트를 막아두면 안전합니다.
어차피Forwarder는 내부 인스턴스에서 작동하므로 외부 포트를 막아도 됩니다.
위 방법을 통해 사용자의 민감한 정보를 외부에 노출시키지 않습니다!
주의 할 점은 사용자가
docker-compose.yml에서9090포트를 외부에 노출시키면 안됩니다.
간단히 흐름만 보겠습니다.
Forwarder는 총 3개가 작동합니다.
(log_forwarder, health_forwarder, metric_forwarder)
모두 python을 통해 작성했습니다.
log_forwarder# 민감 정보 마스킹
REDACT_PATTERNS = [
(re.compile(r"(Authorization:\s*Bearer\s+)[A-Za-z0-9\-\._~\+\/]+=*", re.IGNORECASE), r"\1[REDACTED]"),
(re.compile(r"(Bearer\s+)[A-Za-z0-9\-\._~\+\/]+=*", re.IGNORECASE), r"\1[REDACTED]"),
(re.compile(r"(\b(token|access_token|refresh_token|secret|password)\s*=\s*)[^\s&]+", re.IGNORECASE), r"\1[REDACTED]"),
(re.compile(r'("?(token|access_token|refresh_token|secret|password)"?\s*:\s*)"?[^"\s,}]+', re.IGNORECASE), r'\1"[REDACTED]"'),
]
사용자가 어떤 이름으로 할지 몰라서 일단 대표적인 이름들을 마스킹 합니다.
마스킹을 한 후에 하나의 에러를 체크하는 과정이 있습니다.
Spring서버는 첫 로그의 시작이 시간이므로 시간 정보가 나올 경우 새로운 로그로 인식하게 만들었습니다.
이렇게 에러 로그의 처음과 끝을 구분하여 하나의 에러 로그 덩어리를 만들어 저장 후 일정 시간이 지나면 보내는 형식입니다.
health_forwarder, metric_forwarderhealth, metrics 정보는 내부 인스턴스에서 9090 포트로 접근 가능합니다.Forwarder는 먼저 http://target:9090 으로 접근하여 정보를 가져온 후 MCP 서버에 보내는 양상입니다.제가 데모 서버로 target, demo 라는 서버를 올려놨습니다. 해당 서버 이름의 상태를 알려달라 요청하면 바로 알려줍니다.

demo 라는 이름의 서버는 제가 이미 올렸기 때문에 LLM이 MCP 서버에 접속하여 Tool list를 확인 받아 log, metrics, health 도구를 이용하여 가져온 결과입니다.

에러 로그도 가져왔습니다.

설명을 요청하면 LLM의 역량으로 설명해줍니다.

설정도 간단하고 LLM을 이용한 서버 진단 MCP 를 만들었는데 사이드 프로젝트에서 정말 유용하게 이용할 예정입니다.
또한, 해당 MCP는 AWS 같은 외부 서버에 올리지 않고 내부 컴퓨터에서 실행해도 작동합니다.
즉, 서버 테스트를 위해 적용시킨 후 디버깅 용도로도 사용할 수 있습니다.
서버비가 무서워 앞으로 2주 정도만 더 열어둘 예정입니다.
반응이 좋다면 지속 운영해보겠습니다!
Spring 서버 진단 MCP
많은 관심 부탁드립니다..!
가장 아쉬운 점은 Spring 서버에만 동작 가능한 Forwarder 입니다.
Spring의 application.yml을 통해 log, Metrics를 설정하기 때문입니다.
또한, Spring의 로그 양식을 기준으로 에러를 체크하므로 JS, PY와 같은 로그 양식은 적용이 안될 수 있습니다.
이는 어플 고도화를 통해 JS, PY에 각각 적용 가능하도록 Forwarder를 새로 만들면 해결 가능해보입니다!
Forwarder Github 저장소
위 링크를 통해 코드를 확인할 수 있습니다!
해당 포스팅은 Forwarder, 보안을 위주로 기술했다면 다음 포스팅에서 MCP 서버의 로직에 대해 기술해보겠습니다!