콘텐츠로 이동
Study Notekagent · kmcp

kmcp — MCP 서버 개발과 배포

결론부터
  • kmcp는 MCP 서버용 CLI와 controller다. CLI는 project 생성·로컬 실행·image build·manifest 생성을, controller는 MCPServer 리소스를 Pod로 바꾸는 일을 한다.
  • transportType이 Pod 구조를 정한다. stdio는 gateway 프로세스가 서버를 자식으로 띄우고, http는 서버가 직접 요청을 받는다.
  • HTTP header를 읽어야 하는 서버는 http여야 한다. stdio 서버의 프로세스에는 요청 header가 닿을 길이 없다.
  • 우리 backend API를 감싸는 MCP 서버는 직접 만든 http 서버가 맞는 선택이다.
이 장에서 처음 나오는 말5개
stdio 전송Standard Input/Output Transport
MCP client가 서버를 자식 프로세스로 띄우고 표준 입출력으로 메시지를 주고받는 방식이다. 네트워크 주소가 없다.
http 전송Streamable HTTP Transport
서버가 독립 프로세스로 떠서 HTTP endpoint 하나로 요청을 받는 방식이다.
FastMCP
MCP 서버를 Python으로 만드는 프레임워크다. kmcp init python이 이 구조의 project를 만든다.
MCP Inspector
MCP 서버에 접속해 tool 목록을 보고 직접 실행해 보는 공식 시험 도구다.
agentgateway
MCP·A2A 트래픽용 proxy다. kmcp는 stdio 서버를 HTTP로 노출하는 변환기로 이 binary를 쓴다.

Tool 연결에서 Agent가 MCP 서버를 URL로 부른다는 것을 봤다. 그 서버를 클러스터에 띄우려면 Dockerfile, Deployment, Service, Secret 연결을 서버마다 만들어야 한다. 게다가 공개된 MCP 서버 다수는 npx·uvx로 실행하는 stdio 방식이라 네트워크 주소가 없어서, Agent Pod가 접속할 HTTP endpoint를 따로 만들어 줘야 한다. kmcp가 이 두 가지를 맡는다.

kmcp CLI로 project를 만들고 로컬에서 시험한 뒤 image를 build하고 MCPServer manifest를 만들면 kmcp controller가 Pod를 띄운다
명령하는 일
kmcp init python <이름>FastMCP project를 만든다. src/tools/, Dockerfile, kmcp.yaml이 생긴다. Go는 kmcp init go
kmcp add-tool <이름>tool 파일의 뼈대를 추가한다
kmcp run로컬에서 서버를 띄우고 MCP Inspector를 연다
kmcp build -t <image>project의 container image를 만든다
kmcp deployMCPServer 리소스를 만들어 클러스터에 적용한다. --dry-run·-o <파일>이면 manifest만 만든다
kmcp deploy packageimage 없이 npx·uvx package로 서버를 띄우는 MCPServer를 만든다
kmcp secrets sync <환경>.env 파일을 Kubernetes Secret으로 올린다

설치와 각 명령의 전체 옵션은 kmcp quickstart와 Deploy MCP servers를 따른다. 같은 기능이 kagent mcp 하위 명령으로도 있다(CLI reference).

kagent chart가 kmcp controller를 기본으로 함께 설치하므로, kagent를 쓰는 클러스터에서는 kmcp install을 따로 실행하지 않는다.

MCPServer 하나가 Deployment·Service·ConfigMap·ServiceAccount가 된다. 필드는 kmcp API reference에 있다.

필드뜻
deployment.image서버 image. package 방식이면 생략한다
deployment.cmd · args서버를 시작하는 명령
deployment.portService가 여는 포트. 기본 3000
deployment.env · secretRefs환경 변수와, 환경 변수로 주입할 Secret 이름
deployment.resources · securityContext · replicas일반 Deployment 설정
transportTypestdio 또는 http
httpTransport.targetPort · pathhttp일 때 서버가 듣는 포트와 경로
timeoutclient 연결 timeout. 기본 30s

상태는 네 condition으로 본다 — Accepted(spec 유효), ResolvedRefs(image 등 참조 확인), Programmed(Deployment·Service 생성), Ready(Pod 준비).

터미널 창
kubectl -n agents get mcpserver portal-api-mcp -o jsonpath='{.status.conditions}'

두 전송은 설정 한 줄 차이지만 Pod 안의 모양이 다르다(kmcp v0.4.0 소스에서 확인).

# 공식 문서의 예 — package로 띄우는 fetch 서버
apiVersion: kagent.dev/v1alpha1
kind: MCPServer
metadata:
name: mcp-website-fetcher
namespace: agents
spec:
transportType: stdio
stdioTransport: {}
deployment:
cmd: uvx
args: ["mcp-server-fetch"]
port: 3000

init container가 agentgateway binary를 복사해 두고, main container는 그 binary를 실행한다. agentgateway가 port에서 HTTP 요청을 받고, MCP session마다 cmd·args로 서버 프로세스를 자식으로 띄워 표준 입출력으로 대화한다.

  • 장점: 공개된 stdio 서버를 image 없이 바로 쓸 수 있다.
  • 비용: session마다 프로세스를 새로 띄운다. package cache 상태에 따라 시작에 2~8초가 걸려서 timeout 기본값이 30초다.
  • 한계: 서버 프로세스는 표준 입력으로 MCP 메시지만 받는다. HTTP 요청의 header를 볼 수 없다.
판단 질문stdiohttp
공개 package를 그대로 쓰는가맞다서버가 HTTP를 지원해야 한다
호출한 사용자를 구분해야 하는가불가능가능
호출이 잦은가session마다 시작 비용상주 프로세스

우리 backend를 감싸는 서버는 http로 만든다

섹션 제목: “우리 backend를 감싸는 서버는 http로 만든다”

우리가 만들 MCP 서버의 목적은 backend API를 tool로 노출하는 것이고, backend는 “어느 임직원의 요청인가”를 알아야 한다. 이 정보는 HTTP header로 온다. 따라서 선택지는 정해져 있다.

  • kmcp init python으로 project를 만들고 Streamable HTTP로 서버를 띄운다.
  • tool 함수 안에서 들어온 요청의 header를 읽어 backend 호출에 그대로 싣는다.
  • transportType: http로 배포한다.

FastMCP에서는 fastmcp.server.dependencies의 get_http_request()로 현재 요청의 header를 꺼낸다. 만들고 시험하는 순서는 MCP 서버 로컬 개발 흐름에서, 전체 전파 경로와 backend 쪽 검증은 임직원 토큰 전파에서 이어진다.

MCP 서버가 쓰는 API key 같은 값은 deployment.secretRefs에 Secret 이름을 적어 환경 변수로 받는다. kmcp secrets sync는 로컬 .env 파일을 Secret으로 올려 주는 편의 명령이다 (Manage secrets).

운영에서 이 명령을 개인 PC에서 실행하면 Secret의 출처가 Git에도 secret 저장소에도 남지 않는다. GitOps 배포에서는 Secret 값을 외부 secret 저장소에 두고, manifest에는 secretRefs의 이름만 둔다.

  • uvx로 띄운 stdio 서버가 “호출한 사용자의 토큰으로 API를 부르게” 만들 수 있는가? → 없다. 그 프로세스는 HTTP header를 받지 못한다. Secret으로 넣은 고정 자격만 쓸 수 있으므로 모든 사용자가 같은 권한이 된다.
  • http 서버를 port: 8080으로 배포했는데 Agent의 tool 목록이 비어 있다. 무엇부터 보는가? → MCPServer의 Ready condition, 서버가 실제로 8080의 /mcp에서 응답하는지, 그리고 Agent의 toolNames.