사내 MCP 서버를 전사에 공개하기 전에 요청 크기와 동시 처리 한도를 확인했다. 큰 위키 페이지를 생성하거나 파일을 첨부할 때 어느 계층에서 제한되는지 파악해야 사용자에게 정확한 허용 범위를 안내할 수 있기 때문이다. 쓰기·읽기 도구를 대상으로 부하 테스트를 수행한 결과, nginx와 MCP 서버에 서로 다른 제한이 있음을 확인했다.

어떻게 테스트했나

별도 MCP 클라이언트를 사용하지 않고 Python에서 JSON-RPC 2.0의 tools/call을 호출했다. ThreadPoolExecutor로 병렬 시나리오를 구성했으며, 쓰기 도구(페이지 생성·수정·댓글·라벨·첨부 업로드·이동)와 읽기 도구(조회·HTML·하위 페이지·댓글·첨부·버전·다운로드·CQL)를 모두 대상으로 삼았다.

그리고 한 가지 변수를 바꿔 가며 두 번 돌렸다. 앞단 nginx의 client_max_body_size를 기본값 1m에서 20m으로 올린 전후를 비교한 것이다.

첫 번째 벽 — nginx client_max_body_size

소규모 호출은 전부 빨랐다(건당 0.1~0.3초). 문제는 큰 본문이었다. 1MB짜리 페이지를 만들려 하자 413이 떨어졌다.

로그에서 RPC 요청 크기가 1,048,582바이트로 1MiB(1,048,576바이트) 한도를 6바이트 초과한 것을 확인했다. 본문 외에 JSON-RPC 구조가 추가되면서 제한을 넘은 것이다. nginx를 20m으로 높인 뒤에는 1MB·5MB·10MB·19MB 본문이 모두 통과했다.

시나리오nginx 1mnginx 20m
1MB 본문 생성❌ 413✅ 1.08s
5MB 본문 생성❌ 불가✅ 5.89s
19MB 본문 생성❌ 불가✅ 8.65s

쓰기 도구의 최대 본문은 1m에서 약 750KB, 20m에서 19~20MB로 약 26배 늘었다. 반대로 라벨·이동처럼 페이로드가 작은 호출은 설정과 무관하게 똑같이 잘 됐다.

두 번째 벽 — base64의 33% 팽창

첨부 업로드에서는 1m 설정에서 786KB 파일이 413 응답으로 차단됐다. 원인은 JSON-RPC에 파일을 포함하기 위해 사용한 base64 인코딩이었다.

첨부파일은 JSON-RPC 안에서 base64로 실려 가는데, base64는 원본보다 약 33% 커진다. 그래서 한도는 이렇게 결정된다.

raw_file_size × 1.33 (base64) + ~200B (JSON wrapper) ≤ nginx client_max_body_size

따라서 실제 업로드할 수 있는 원본 파일의 크기는 nginx에 설정한 요청 한도보다 작다.

nginx 설정RPC 봉투 한도실제 raw 파일 한도
1m~1.0 MiB~766 KB
20m~20 MiB~14.5 MB
50m (가정)~50 MiB~37.5 MB

실제로 20m 설정에서 14.5MB 파일은 통과했지만(RPC 20,272,708B) 15MB 파일은 RPC가 20,971,756B가 되어 20 MiB 한도를 넘고 413이 났다. "20m으로 올렸으니 20MB까지 되겠지"가 아니라 base64 때문에 14.5MB가 실질 상한이었던 것이다.

nginx 너머에 또 다른 한도가 있었다

여기까지는 앞단(nginx) 이야기다. 그런데 읽기 쪽에는 nginx와 무관한 한도가 따로 있었다.

  • 응답 5MB 잘림. 20MB짜리 페이지를 get_page로 읽으면 에러는 안 나지만 응답이 약 5MB에서 잘렸다. nginx가 아니라 MCP 서버 코드의 응답 상한(max_chars 기본값) 때문이다.
  • 다운로드 기본 512KB. download_attachment는 기본적으로 524,288바이트(512KB)에서 잘린다. 이건 버그가 아니라 LLM 토큰 효율을 위한 의도된 기본값이다. max_bytes를 명시하면 10MB까지 받아지는 걸 확인했다.

따라서 큰 페이지나 첨부 응답이 잘릴 때는 nginx뿐 아니라 MCP 서버의 응답 제한도 함께 확인해야 한다.

성능과 동시성

응답 시간은 크기에 비례했다. 소규모는 0.1초 안팎, 10MB 이상은 5~12초가 걸렸다. 그래서 대용량을 다룰 거면 proxy_read_timeout이 넉넉히(예: 300초) 잡혀 있는지 확인이 필요하다.

생성·다운로드·CQL 호출은 5~6개 동시 요청까지 오류 없이 완료됐다. 같은 페이지를 동시에 수정하는 시나리오는 이번 테스트 범위에 포함하지 않았다. 운영 환경에서는 동일 리소스의 동시 변경으로 낙관적 잠금 충돌이 발생할 수 있으므로 별도 검증이 필요하다.

정리하며

부하 테스트에서 확인한 핵심은 요청과 응답의 제한이 여러 계층에 존재한다는 점이다.

  1. 앞단 nginx의 body 한도
  2. base64 인코딩으로 원본보다 요청 크기가 약 33% 증가한다는 점
  3. nginx 너머 서버 코드의 응답·다운로드 기본 제한

세 제한이 함께 적용되므로 nginx 설정만 20m으로 높여도 원본 파일은 약 14.5MB에서 다시 413 응답을 받는다. 공개 전에 계층별 한도를 측정해 사용자 가이드와 운영 기준에 반영했다. 현재 설정(20m)은 대부분의 사용 시나리오를 지원하며, 대용량 첨부가 늘어나면 50m으로 높이는 방안을 검토할 수 있다.

여러 사용자가 사용하는 도구는 정상 동작 여부뿐 아니라 요청·응답 크기와 동시성의 한계를 계층별로 측정해야 한다.


참고