해당 소스는 Infrastructure Provisioning 자동화를 위한 MCP Server 예제입니다.
Streamable HTTP 프로토콜을 통해 다양한 Client에 연결하여 자연어 기반으로 Infrastructure를 관리할 수 있는 기능을 제공합니다.
Proxmox 환경 기준으로 작성되었으나 Public Cloud 및 Multi Cloud 환경에서도 사용이 가능하도록 설계되었습니다.
WSO2 APIM 등 API Gateway와 연동하여 사용하는 것을 권장합니다.
테스트에 필요한 사전 환경 요구사항은 다음과 같습니다.
- 컨테이너 배포용 환경
- Proxmox 환경
- MCP 프로토콜을 지원하는 Client(Steramable HTTP로 연결해야 합니다.)
MCP Server에 도구를 쉽게 추가/제거하고 코드 종속성을 줄이기 위해 Modular Monolithic Architecture 및 Microkernel Architecture를 적용하였습니다.
Architecture에 대한 세부 정의는 다음과 같습니다.
Resource Provisioner MCP Tools과 같은 비즈니스 로직과 인프라 제어 로직(Terraform/Ansible) 사이의 규격을 저의하는 추상화 인터페이스입니다.
설계 목적
- 인프라 추상화: Client(User, Agent 등)가 Proxmox, AWS 등 특정 플랫폼에 종속되지 않고 명령을 내릴 수 있도록 격리합니다.
- 작업 일관성: 리소스 종류와 관계 없이 동일한 작업 흐름을 보장합니다.
- 확장성: 새로운 인프라 자산 또는 기능이 추가되어도 기존 소스 코드 수정 없이 새 모듈만 구현하면 즉시 통합할 수 있습니다.
Sequence Architecture는 다음과 같습니다.
- 요청 수신: MCP Client가 MCP Tool을 호출하면, MCP Server가 이를 수신한다.
- 리소스 등록: 데이터베이스에 새로운 리소스 정보를 기록하고 상태를
PENDING으로 마킹합니다. - 프로비저너 할당: ProvisionerRegistry(ResoruceProvisioner 인터페이스의 구현체들을 관리하는 클래스)가 리소스 타입을 확인 후, Provisioner 객체를 생성합니다.
- 비동기 실행: Server는 Terraform 프로세스를 비동기 Subprocess로 실행하고 제어권을 반환할 준비를 합니다.
- 상태 스트리밍:
- Terraform 코드가 실행되면서 중간 상태를 POST 요청으로 Terraform 백엔드로 전송합니다.
- Terraform 백엔드는 이를 수신하여 데이터베이스의
tf_state테이블을 실시간으로 갱신합니다.
- 완료 처리: Terraform 프로세스가 종료되면, 서버는 Terraform 반환 결과를 파싱하여 DB에 기록하고 리소스 상태를
RUNNING으로 변경합니다.
Provisioning Workflow는 리소스 생성 시의 Lifecycle을 정의합니다. 데이터베이스의 state 컬럼이 변하는 규칙이며, 시스템의 가시성을 결정합니다.
| 상태 (Status) | 의미 (Meaning) | 전이 조건 (Trigger) |
|---|---|---|
| PENDING | 생성 요청 수신 | Database 레코드 최초 생성 시 |
| PROVISIONING | 인프라 리소스 할당 중 | Terraform 프로세스(apply) 시작 시 |
| CONFIGURING | SW 및 환경 설정 중 | Terraform 프로세스 완료 후 Ansible Playbook 시작 시 |
| RUNNING | 리소스 사용 가능 | 모든 프로비저닝 로직이 성공적으로 종료되었을 때 |
| ERROR | 작업 실패 | 작업 도중 예외 발생 또는 프로세스 에러 반환 시 |
| DESTROYING | 리소스 삭제 | 리소스 삭제 작업 수행 시 |
- 인프라 레이어 (Phase 1): Terraform을 통해 Proxmox 노드에 리소스를 할당합니다.
- 설정 레이어 (Phase 2): 동적으로 Ansible Inventory를 생성하고 Ansible이 동적 Inventory 정보를 이용해 SSH 접속을 시도합니다. 예제에서는 Base Package 설치 및 보안 설정을 수행합니다.
- 데이터 동기화: 각 Phase가 끝날 때마다
infra_state.db의 정보를 갱신하여 사용자가 언제든 진행상황을 확인할 수 있게 합니다.
Terraform 사용 시 PostgreSQL 등 지원하는 Backend를 사용하는 것이 일반적이지만 본 예제에서는 Terraform의 HTTP Backend를 이용하여 SQLite에 저장하도록 구현되었습니다.
이 테이블은 관리 대상인 모든 인프라 자원의 메타데이터와 현재 상태를 추적합니다.
| 컬럼명 | 타입 | 제약 조건 | 설명 |
|---|---|---|---|
| resource_id | TEXT | PK | 고유 식별자 (예: provider-name) |
| name | TEXT | UNIQUE, NOT NULL | 리소스 이름 |
| provider | TEXT | NOT NULL | Cloud Provider (AWS, GCP, Proxmox 등) |
| type | TEXT | NOT NULL | 리소스 타입 (VM, Container, Network 등) |
| state | TEXT | NOT NULL | 리소스 상태 (PENDING, RUNNING 등) |
| metadata | TEXT | NOT NULL | Cloud Provider별 상세 식별 데이터 (JSON 등) |
| created_at | DATETIME | DEFAULT CURRENT_TIMESTAMP | 생성 시간 |
| updated_at | DATETIME | DEFAULT CURRENT_TIMESTAMP | 갱신 시간 |
Terraform의 상태 파일(tfstate)을 관리하며, 동시성 제어를 위한 락(Lock) 정보를 포함합니다. 리소스 단위로 상태관리가 이뤄지게 됩니다.
| 컬럼명 | 타입 | 제약 조건 | 설명 |
|---|---|---|---|
| resource_id | TEXT | PK, FK | 고유 식별자 (resource 테이블 참조) |
| data | TEXT | - | Terraform State 원본 데이터 (JSON 문자열) |
| is_locked | BOOLEAN | DEFAULT 0 | 잠금 여부 (0: 해제, 1: 잠금) |
| lock_info | TEXT | - | Terraform Lock 상세 정보 (JSON) |
| updated_at | DATETIME | DEFAULT CURRENT_TIMESTAMP | 생성 및 최종 갱신 시간 |
docker-compose.yml을 통해 배포하여 관리할 수 있습니다.
services:
mcp-example:
build: .
container_name: mcp-example
ports:
- "8000:8000"
environment:
- TZ=Asia/Seoul
env_file:
- ./secrets/.env
volumes:
- ./data:/app/data
- ./terraform:/app/terraform
- ./ansible:/app/ansible
- ./secrets:/app/secrets
extra_hosts:
- "host.docker.internal:host-gateway"
restart: unless-stopped ##############
# Ansible Envs
##############
PROXMOX_URL="https://<host>:<port>"
PROXMOX_USER="ansible@pve"
PROXMOX_TOKEN_ID="ansible-inventory"
PROXMOX_TOKEN_SECRET="<proxmox-terraform-api-token-sercret>"
PM_VMID_MIN=20000
PM_VMID_MAX=30000
################
# Terraform Envs
################
TF_VAR_pm_api_url="https://<host>:<port>/api2/json"
TF_VAR_pm_api_token_id="terraform@pve!terraform-provider"
TF_VAR_pm_api_token_secret="<proxmox-terraform-api-token-sercret>"
TF_VAR_pool="agentpool"
TF_VAR_target_node="<proxmox node name>"
TF_VAR_template_id=10000
TF_VAR_storage_pool="local-lvm"
TF_VAR_disk_size="32G"
TF_VAR_bridge_name = "vlan50"
TF_VAR_nameserver = "<nameserver>"
TF_VAR_searchdomain = "<dns>"
# User Prompt(VM 생성)
sandbox-01 1대를 생성해줘.
# System
`sandbox-01` VM 생성이 시작되었습니다!
**생성 정보:**
- **VM 이름:** sandbox-01
- **리소스 ID:** pm-sandbox-01
- **사양 (flavor):** small
- **용도 (purpose):** sandbox
VM의 기초 환경 구성이 진행 중입니다. 생성이 완료되면 VM을 사용할 준비가 됩니다.
# User Prompt(VM 목록 조회)
현재 vm 목록을 조회해줘.
# System
현재 Proxmox 노드의 VM 목록은 다음과 같습니다:
## VM 목록 조회 결과
| VM 이름 | 리소스 ID | 상태 | 사양 | VM ID | 생성일 | 업데이트일 |
|--------|----------|------|------|------|--------|-----------|
| **sandbox-01** | pm-sandbox-01 | RUNNING | small | 20000 | 2026-04-22 04:40:00 | 2026-04-22 04:40:55 |
### 요약
- **총 VM 수:** 1 대
- **생성된 VM:** sandbox-01
- **상태:** 정상 동작 중 (RUNNING)
- **리소스 사양:** small
- **용도:** sandbox
VM이 성공적으로 생성되어 현재 실행 중입니다.
# User Prompt(VM 업데이트)
sandbox-01의 사양을 medium으로 변경해줘.
# System
`sandbox-01` VM 의 사양이 `small`에서 `medium`으로 변경되었습니다.
**변경 정보:**
- **VM 이름:** sandbox-01
- **기존 사양:** small
- **새로운 사양:** medium
- **용도:** sandbox (유지)
사양 변경이 완료되었으며, 더 많은 리소스를 사용할 수 있게 되었습니다.
# User Prompt(VM 삭제)
`sandbox-01` VM 삭제 프로세스가 성공적으로 시작되었습니다!
**삭제 정보:**
- **VM 이름:** sandbox-01
- **상태:** 삭제 진행 중
- **결과:** 성공
VM의 데이터와 리소스는 이제 해제가 될 예정입니다. 삭제 작업이 완료되면 더 이상 해당 VM을 사용할 수 없으니 참고하시기 바랍니다./mcp_example
├─ mcp_server/ # MCP/API 소스 코드
│ ├─ main.py # 실행 엔드포인트 (FastAPI + MCP)
│ ├─ database.py # SQLite 초기화 및 CRUD 공통 로직
│ ├─ utils.py # 유틸리티 로직
│ ├─ api/ # 외부 통신 레이어
│ │ ├─ mcp/ # MCP Tool 정의
│ │ │ └─ proxmox.py
│ │ ├─ mcp_router.py # MCP Tool Router
│ │ └─ tf_backend.py # Terraform HTTP Backend
│ ├─ core/ # 프레임워크 코어 로직
│ │ ├─ base.py # 추상 베이스 클래스 집합
│ │ ├─ registry.py # Provisioner 구현체의 생명주기를 관리하는 클래스 집합
│ │ ├─ constants.py # 시스템 전역 상수 및 리소스 상태(Enum) 정의
│ │ └─ executor/ # Ansible, Terraform 등 도구 실행 라이브러리
│ │ ├─ terraform.py
│ │ └─ ansible.py
│ ├─ provisioners/ # 리소스 별 구현체 집합
│ │ └─ proxmox/ # Proxmox Provisioners
│ │ └─ vm.py
│ └─ schemas/ # 스키마 정의
│ ├─ base.py
│ └─ proxmox.py
│
├─ terraform/ # Terraform 코드
│ └─ proxmox/ # Proxmox Provider
│ ├─ main.tf
│ ├─ outputs.tf
│ ├─ provider.tf
│ └─ variables.tf
│
├─ ansible/ # Ansible 코드
│ ├─ inventory/
│ │ └─ group_vars/
│ │ │ └─ all.yml
│ │ └─ sandbox.proxmox.yml
│ ├─ playbooks/
│ │ └─ base.yml
│ └─ ansible.cfg
│
├─ scripts/
│ └─ entrypoint.sh # 초기 셋업용 스크립트
│
├─ secrets/ # .env 및 .ssh 등 프로젝트 내에서 관리되어야 하는 Secret 파일 또는 값의 집합
│ ├─ .env
│ └─ .ssh/
│ ├─ agent_key
│ ├─ agent_key.pub
│ └─ admin_key.pub
│
├─ data/ # 데이터 보관 장소
│ └─ infra_state.db # Infra의 상태를 저장하는 SQLite 파일
│
├─ requirements.txt # 의존성 목록
├─ Dockerfile
├─ docker-compose.yml
├─ .dockerignore
└─ .gitignore

