MES(Manufacturing Execution System)의 OpenAPI(Swagger) 스펙을 읽어 모델 컨텍스트 프로토콜(MCP) 서버로 노출하는 Spring Boot 애플리케이션입니다. Infobip OpenAPI MCP 스타터와 Spring AI MCP(WebMVC)를 사용하며, 자연어로 API 도구를 찾는 searchApiTools와 웹 관리 UI를 제공합니다.
STATELESS, 기본 MCP HTTP 경로 /mcp)all-minilm-l6-v2 또는 Ollama)call-history.dbHTTP 서버 포트는 기본 17070 (application.yaml의 server.port).
실행 시 아래 두 값이 비어 있으면 기동 시 검증에서 실패합니다.
| 설정 키 | 환경 변수 | 설명 | 예시 |
|---|---|---|---|
infobip.openapi.mcp.open-api-url | INFOBIP_OPENAPI_MCP_OPEN_API_URL | OpenAPI 문서 URL 또는 클래스패스 | http://localhost:20301/v3/api-docs, classpath:api-v3.json |
infobip.openapi.mcp.api-base-url | INFOBIP_OPENAPI_MCP_API_BASE_URL | 실제 API 호출 시 사용할 베이스 URL | http://localhost:20301 |
OpenAPI 주소 참고
.../v3/api-docs.../v2/api-docs — 애플리케이션 기동 전에 로컬에서 3.x JSON으로 변환한 뒤 임시 파일로 덮어씁니다(Application.convertSpecIfNeeded).classpath:mes-api-v3.json 등 classpath: / file: 는 변환·fetch 없이 그대로 사용합니다.OpenAPI 문서만 Basic 등으로 받을 때(선택): 시스템 프로퍼티 또는 환경 변수 infobip.openapi.mcp.open-api-auth-header / INFOBIP_OPENAPI_MCP_OPEN_API_AUTH_HEADER (예: Bearer ...) — 스펙 HTTP 요청에만 사용됩니다.
swagger.auth)| 설정 키 | 환경 변수 예시 | 설명 |
|---|---|---|
swagger.auth.header-name | SWAGGER_AUTH_HEADER_NAME | 비어 있으면 대상 API 인증 비활성 |
swagger.auth.header-value | SWAGGER_AUTH_HEADER_VALUE | 초기 헤더 값(정적 또는 OAuth 갱신 전) |
swagger.auth.token-url | SWAGGER_AUTH_TOKEN_URL | 설정 시 OAuth2 자동 갱신 활성화 |
swagger.auth.client-id | SWAGGER_AUTH_CLIENT_ID | |
swagger.auth.client-secret | SWAGGER_AUTH_CLIENT_SECRET | |
swagger.auth.token-type | SWAGGER_AUTH_TOKEN_TYPE | 기본 Bearer |
swagger.auth.refresh-before-expiry | SWAGGER_AUTH_REFRESH_BEFORE_EXPIRY | 만료 N초 전 갱신(초 단위) |
런타임 토큰 갱신용 REST(컨테이너 내부 기준):
GET /api/auth/status — 설정·마스킹 값·자동 갱신 여부POST /api/auth/token — JSON {"headerValue":"Bearer ..."} 수동 반영POST /api/auth/refresh — token-url이 있을 때 갱신 즉시 시도app.auth.headers)웹 UI에서 저장한 인증 헤더를 서버 파일(server-auth-headers.json)에 영구 보관합니다.
callApiTool MCP 호출 및 /api/execute REST 호출 시 enabled 상태인 헤더가 자동 주입됩니다.
| 설정 키 | 환경 변수 | 설명 |
|---|---|---|
app.auth.headers.path | SERVER_AUTH_HEADERS_PATH | 저장 파일 경로 (기본 server-auth-headers.json) |
헤더 관리 REST:
GET /api/auth/headers — 저장된 헤더 목록 조회POST /api/auth/headers — 전체 목록 저장(웹 UI 저장 버튼)헤더 주입 우선순위:
swagger.auth정적 설정 → 서버 인증 헤더 → 호출 시 직접 전달 헤더 (후자가 최종 우선)
infobip.openapi.mcp.tools.naming.strategy — 기본 OPERATION_ID (application.yaml 참고)embedding.provider | 설명 | 벡터 차원 |
|---|---|---|
local (기본) | 로컬 ONNX all-minilm-l6-v2, 외부 서버 불필요 | 384 |
ollama | Ollama HTTP API(OllamaEmbeddingModel), 별도 서버 필요 | 모델마다 다름 |
Ollama 사용 시: embedding.ollama.base-url, embedding.ollama.model 추가 설정.
⚠ 임베딩 모델 변경 시 벡터 스토어의
dimension도 함께 변경하고 전체 재인덱싱이 필요합니다.
vector-store.provider)| 값 | 설명 | 재시작 시 재인덱싱 | 사전 조건 |
|---|---|---|---|
memory | JVM 인메모리, 개발·테스트용. 스냅샷 파일로 재시작 재인덱싱 생략 가능 | 스냅샷 없으면 재인덱싱 | 없음 |
chroma (현재 application.yaml 기본값) | ChromaDB HTTP API v1 | 생략 가능 | ChromaDB 서버 |
pgvector | PostgreSQL + pgvector 확장 | 생략 가능 | PostgreSQL + pgvector 확장 |
인메모리 스냅샷 설정:
vector-store:
provider: memory
memory:
store-file: "${EMBEDDING_STORE_PATH:embedding-store.json}"
스펙이 변경된 경우 관리 UI에서 수동 재인덱싱을 실행하세요.
# bash / CMD
docker run -d --name chroma-db -p 8000:8000 chromadb/chroma
# PowerShell
docker run -d --name chroma-db -p 8000:8000 chromadb/chroma
vector-store:
provider: chroma
chroma:
url: "http://localhost:8000" # 로컬 실행 시
# url: "http://host.docker.internal:8000" # Docker 컨테이너 내부에서 실행 시
collection-name: "mcp-tools"
tenant: "swagger_mcp_server"
database: "swagger_mcp_server"
starter.bat을 사용하면 ChromaDB 컨테이너 기동과 앱 실행을 한 번에 처리합니다 (아래 로컬 실행 참고).
# bash
docker run -d --name pgvector-db -p 5432:5432 \
-e POSTGRES_DB=mcp_db \
-e POSTGRES_PASSWORD=<your-password> \
pgvector/pgvector:pg16
# PowerShell
docker run -d --name pgvector-db -p 5432:5432 `
-e POSTGRES_DB=mcp_db `
-e POSTGRES_PASSWORD=<your-password> `
pgvector/pgvector:pg16
vector-store:
provider: pgvector
pgvector:
url: "jdbc:postgresql://localhost:5432/mcp_db"
username: "postgres"
password: "password"
table-name: "tool_embeddings"
dimension: 384 # local 모델 기준, ollama nomic-embed-text 사용 시 768
⚠ pgvector 주의사항
dimension은 사용하는 임베딩 모델의 벡터 차원과 반드시 일치해야 합니다. 불일치 시 INSERT 단계에서 오류가 발생합니다.dimension변경 시:DROP TABLE tool_embeddings;후 재시작하면 새 차원으로 테이블이 자동 재생성됩니다.- 테이블·HNSW 인덱스는 최초 기동 시 자동 생성됩니다 (
CREATE EXTENSION vector포함).- 비밀번호 등 민감 정보는 환경 변수(
VECTOR_STORE_PGVECTOR_PASSWORD)로 주입하세요.
http://<호스트>:17070/mcp
spring.ai.mcp.server.streamable-http.mcp-endpoint 사용.McpToolListFilter: MCP tools/list 응답에는 아래 3개 도구만 클라이언트에 노출합니다.toolIndexStatus, setToolBoost, removeToolBoost)는 목록에서는 숨기고, 필요 시 tools/call로는 호출 가능합니다.| 도구 이름 | 설명 |
|---|---|
searchApiTools | 자연어(한국어 포함) 키워드로 MES API 툴 검색. 쉼표로 다중 키워드 지원. 상위 15개 반환 |
getApiToolDetail | 특정 툴의 파라미터 목록, 타입·위치·필수 여부·설명 조회 |
callApiTool | Swagger API 직접 호출 후 응답 반환. 호출 이력 SQLite 자동 저장 |
| 도구 이름 | 설명 |
|---|---|
toolIndexStatus | 툴 인덱싱 완료 여부 및 총 툴 수 확인 |
setToolBoost | 툴에 추가 설명·부스트 배율·발동 키워드 설정. 변경 후 자동 재인덱싱 |
removeToolBoost | 툴 메타데이터(추가 설명·부스트) 삭제 후 자동 재인덱싱 |
KoreanQueryTranslator)korean-dict.json을 로드하여 한국어 검색어를 영어로 변환합니다.
공백 기준 토큰 분리 후 최장 일치(longest-match, 최대 4-gram) 방식으로 다단어 구문을 우선 매칭하며, 미등록 토큰은 원문 유지합니다.
예) "설비 상태 조회" → "equipment status list search get query"
CorePointService)core_point.json을 로드하여 API URL에 prefix가 포함될 때 검색 점수에 추가 가중치를 부여합니다.
여러 prefix가 매칭되면 가장 큰 값을 적용합니다.
예) "v1/wip" → 0.1 설정 시, GET /v1/wip/lots 툴의 점수에 0.1 추가
웹 UI 또는 외부에서 Swagger API를 HTTP로 직접 호출할 수 있습니다.
| 메서드 | 경로 | 설명 |
|---|---|---|
POST | /api/execute/{toolName} | API 직접 실행. Body: {"params":{...}, "headers":{...}, "rawBody":"..."} |
GET | /api/execute/history | 호출 이력 목록 (page, size, toolName 쿼리 파라미터) |
GET | /api/execute/history/{id} | 호출 이력 단건 상세(요청·응답 전문) |
mvn -DskipTests package
별도 벡터 DB 없이 JVM 인메모리 스토어를 사용합니다. 재시작 시 스냅샷 파일(embedding-store.json)이 있으면 재임베딩을 생략합니다.
rem CMD
java ^
-Dinfobip.openapi.mcp.open-api-url=http://localhost:20301/v3/api-docs ^
-Dinfobip.openapi.mcp.api-base-url=http://localhost:20301 ^
-Dvector-store.provider=memory ^
-jar target/swagger-mcp-server.jar
# PowerShell
java `
-Dinfobip.openapi.mcp.open-api-url=http://localhost:20301/v3/api-docs `
-Dinfobip.openapi.mcp.api-base-url=http://localhost:20301 `
-Dvector-store.provider=memory `
-jar target/swagger-mcp-server.jar
starter.bat 을 사용하면 ChromaDB 컨테이너 기동과 앱 실행을 한 번에 처리합니다.
starter.bat
내부적으로 아래 순서로 동작합니다.
rem [1/2] ChromaDB 컨테이너 기동 (없으면 docker run, 있으면 docker start)
docker run -d --name chroma-db -p 8000:8000 chromadb/chroma
rem [2/2] Spring Boot 앱 실행 — CMD
java ^
-Dinfobip.openapi.mcp.open-api-url=http://localhost:20301/v3/api-docs ^
-Dinfobip.openapi.mcp.api-base-url=http://localhost:20301 ^
-Dvector-store.provider=chroma ^
-Dvector-store.chroma.url=http://localhost:8000 ^
-Dvector-store.chroma.collection-name=mcp-tools ^
-Dvector-store.chroma.tenant=swagger_mcp_server ^
-Dvector-store.chroma.database=swagger_mcp_server ^
-jar target/swagger-mcp-server.jar
# PowerShell
java `
-Dinfobip.openapi.mcp.open-api-url=http://localhost:20301/v3/api-docs `
-Dinfobip.openapi.mcp.api-base-url=http://localhost:20301 `
-Dvector-store.provider=chroma `
-Dvector-store.chroma.url=http://localhost:8000 `
-Dvector-store.chroma.collection-name=mcp-tools `
-Dvector-store.chroma.tenant=swagger_mcp_server `
-Dvector-store.chroma.database=swagger_mcp_server `
-jar target/swagger-mcp-server.jar
http://localhost:17070/ (static/index.html)/api/tools
GET /api/tools 목록/필터/페이지네이션GET /api/tools/{name} 단건 상세GET /api/tools/search?q=... 자연어 검색GET /api/tools/status 인덱스 상태POST /api/tools/{name}/boost 부스트/추가설명/키워드 저장POST /api/tools/{name}/visibility MCP 검색 노출/숨김 처리DELETE /api/tools/{name}/boost 메타데이터 삭제GET /api/tools/metadata/export, POST /api/tools/metadata/import이미지는 실행 단계에서 eclipse-temurin:21-jre(glibc)를 사용합니다. 로컬 ONNX 임베딩은 Alpine JRE와 호환되지 않을 수 있습니다.
Dockerfile 기본값:
INFOBIP_OPENAPI_MCP_OPEN_API_URL = classpath:mes-api-v3.jsonINFOBIP_OPENAPI_MCP_API_BASE_URL = http://localhost:20301ENTRYPOINT가 위 환경 변수를 -Dinfobip.openapi.mcp.* 로 넘기므로, docker run -e 로 덮어쓰면 됩니다.
호스트에서 돌아가는 MES/Swagger에 컨테이너가 붙을 때 컨테이너 안의 localhost는 호스트가 아닙니다. Windows·macOS Docker Desktop에서는 host.docker.internal을 사용하세요.
앱 컨테이너 실행 전에 원하는 벡터 DB를 먼저 기동합니다.
# bash
docker run -d --name chroma-db -p 8000:8000 chromadb/chroma
# PowerShell
docker run -d --name chroma-db -p 8000:8000 chromadb/chroma
# bash
docker run -d --name pgvector-db -p 5432:5432 \
-e POSTGRES_DB=mcp_db \
-e POSTGRES_PASSWORD=<your-password> \
pgvector/pgvector:pg16
# PowerShell
docker run -d --name pgvector-db -p 5432:5432 `
-e POSTGRES_DB=mcp_db `
-e POSTGRES_PASSWORD=<your-password> `
pgvector/pgvector:pg16
docker build -t swagger-mcp-server:latest .
# bash
docker run -d --name swagger-mcp-app -p 17070:17070 \
-e INFOBIP_OPENAPI_MCP_OPEN_API_URL="http://host.docker.internal:20301/v3/api-docs" \
-e INFOBIP_OPENAPI_MCP_API_BASE_URL="http://host.docker.internal:20301" \
-e VECTOR_STORE_PROVIDER=memory \
swagger-mcp-server:latest
# PowerShell
docker run -d --name swagger-mcp-app -p 17070:17070 `
-e INFOBIP_OPENAPI_MCP_OPEN_API_URL="http://host.docker.internal:20301/v3/api-docs" `
-e INFOBIP_OPENAPI_MCP_API_BASE_URL="http://host.docker.internal:20301" `
-e VECTOR_STORE_PROVIDER=memory `
swagger-mcp-server:latest
# bash
docker run -d --name swagger-mcp-app -p 17070:17070 \
-e INFOBIP_OPENAPI_MCP_OPEN_API_URL="http://host.docker.internal:20301/v3/api-docs" \
-e INFOBIP_OPENAPI_MCP_API_BASE_URL="http://host.docker.internal:20301" \
-e VECTOR_STORE_PROVIDER=chroma \
-e VECTOR_STORE_CHROMA_URL="http://host.docker.internal:8000" \
-e VECTOR_STORE_CHROMA_COLLECTION_NAME=mcp-tools \
-e VECTOR_STORE_CHROMA_TENANT=swagger_mcp_server \
-e VECTOR_STORE_CHROMA_DATABASE=swagger_mcp_server \
swagger-mcp-server:latest
# PowerShell
docker run -d --name swagger-mcp-app -p 17070:17070 `
-e INFOBIP_OPENAPI_MCP_OPEN_API_URL="http://host.docker.internal:20301/v3/api-docs" `
-e INFOBIP_OPENAPI_MCP_API_BASE_URL="http://host.docker.internal:20301" `
-e VECTOR_STORE_PROVIDER=chroma `
-e VECTOR_STORE_CHROMA_URL="http://host.docker.internal:8000" `
-e VECTOR_STORE_CHROMA_COLLECTION_NAME=mcp-tools `
-e VECTOR_STORE_CHROMA_TENANT=swagger_mcp_server `
-e VECTOR_STORE_CHROMA_DATABASE=swagger_mcp_server `
swagger-mcp-server:latest
# bash
docker run -d --name swagger-mcp-app -p 17070:17070 \
-e INFOBIP_OPENAPI_MCP_OPEN_API_URL="http://host.docker.internal:20301/v3/api-docs" \
-e INFOBIP_OPENAPI_MCP_API_BASE_URL="http://host.docker.internal:20301" \
-e VECTOR_STORE_PROVIDER=pgvector \
-e VECTOR_STORE_PGVECTOR_URL="jdbc:postgresql://host.docker.internal:5432/mcp_db" \
-e VECTOR_STORE_PGVECTOR_USERNAME=postgres \
-e VECTOR_STORE_PGVECTOR_PASSWORD=<your-password> \
swagger-mcp-server:latest
# PowerShell
docker run -d --name swagger-mcp-app -p 17070:17070 `
-e INFOBIP_OPENAPI_MCP_OPEN_API_URL="http://host.docker.internal:20301/v3/api-docs" `
-e INFOBIP_OPENAPI_MCP_API_BASE_URL="http://host.docker.internal:20301" `
-e VECTOR_STORE_PROVIDER=pgvector `
-e VECTOR_STORE_PGVECTOR_URL="jdbc:postgresql://host.docker.internal:5432/mcp_db" `
-e VECTOR_STORE_PGVECTOR_USERNAME=postgres `
-e VECTOR_STORE_PGVECTOR_PASSWORD=<your-password> `
swagger-mcp-server:latest
Linux(도커 20.10+):
docker run에--add-host=host.docker.internal:host-gateway를 추가하면host.docker.internal을 동일하게 사용할 수 있습니다.
레지스트리로 빌드·푸시할 때는 루트의 docker-build-push.bat 을 사용할 수 있습니다.
docker-build-push.bat
docker-build-push.bat test
latest 태그를 사용합니다.callakrsos/swagger-mcp-server 입니다.docker build 후 같은 태그로 docker push를 수행합니다.서버 URL: http://localhost:17070/mcp (원격이면 호스트·방화벽·TLS에 맞게 조정)
이 서버는 Spring AI HTTP(Streamable) MCP가 기본입니다. 클라이언트가 stdio MCP만 지원하면 연결 방식이 맞지 않을 수 있으니, 해당 제품 문서에서 HTTP/SSE MCP 지원 여부를 확인하세요.
{
"mcpServers": {
"swagger-mcp-server": {
"url": "http://localhost:17070/mcp"
}
}
}
mcp_test_tool.bat 은 MCP Inspector를 띄우기 위한 예시입니다. 필요에 맞게 origin·환경 변수를 조정하세요.
# bash / CMD / PowerShell
mvn test
| 파일 | 역할 |
|---|---|
Application.java | 기동 전 Swagger 2→3 변환, OpenAPI 필터(파라미터 설명 복사, 인증 헤더 주입), RestTemplate 인터셉터 |
ApiUrlService.java | 스펙·베이스 URL, 파라미터 정보, OpenAPI summary 파싱 |
ToolSearchService.java / ToolSearchTool.java | 임베딩·검색, MCP 도구 6종 정의 (searchApiTools, getApiToolDetail, callApiTool, toolIndexStatus, setToolBoost, removeToolBoost) |
KoreanQueryTranslator.java | korean-dict.json 로드 후 한국어 검색어 → 영어 최장일치 번역 |
CorePointService.java | core_point.json 로드 후 API URL prefix 별 검색 점수 추가 가중치 제공 |
ToolMetadataStore.java | 툴별 extraDescription·boost·keywords 관리 (tool-metadata.json) |
OllamaEmbeddingModel.java | Ollama REST API 직접 호출 임베딩 구현체 (HttpURLConnection) |
ChromaVectorStore.java | ChromaDB HTTP API v1 직접 호출 벡터 스토어 |
PgVectorStore.java | PostgreSQL pgvector JDBC 벡터 스토어 |
ApiExecuteController.java / ApiExecutorService.java | Swagger API 직접 실행(/api/execute), 호출 이력 조회, 인증 헤더 우선순위 처리 |
CallHistoryRepository.java | SQLite 호출 이력 저장·조회 |
ServerAuthHeaderController.java / ServerAuthHeaderStore.java | 웹 UI에서 저장한 인증 헤더를 server-auth-headers.json에 영구 보관 (/api/auth/headers) |
AuthRefreshController.java / AuthRefreshService.java / AuthTokenStore.java | swagger.auth 인증 헤더·OAuth 갱신 |
McpToolListFilter.java | tools/list 응답에서 searchApiTools, getApiToolDetail, callApiTool만 클라이언트에 노출 |
WebConfig.java | 전역 CORS 헤더 |
src/main/resources/static/index.html | 툴 목록·부스트·검색·API 실행·호출이력 관리 UI |
Dockerfile | 멀티 스테이지 빌드, JRE 실행 이미지 |
Content type
Image
Digest
sha256:5d307d189…
Size
358.5 MB
Last updated
3 months ago
docker pull callakrsos/swagger-mcp-server