mcp-server
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-serverlist the tools I have access to"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
MCP Server
범용 MCP(Model Context Protocol) 서버입니다. 내부/외부/OpenAPI 기반 API를 MCP Tool로 등록하고, MCP 클라이언트(예: Codex, Claude 등 MCP 지원 클라이언트)에 Streamable HTTP 전송으로 노출합니다. 관리자 Portal, RBAC/세션 인증, OpenAPI Import, 외부 Credential Service 연동을 통한 Credential 주입, 감사 로그를 제공합니다.
문서 기준: 이 README는 저장소의 실제 소스코드(
app/,alembic/,pyproject.toml,Dockerfile,docker-compose.yml,Jenkinsfile,.env.example/env.template)를 직접 분석해 작성되었습니다. 코드로 확인되지 않은 내용은 "확인 불가"로 표기합니다.
1. 프로젝트 소개
목적: 이질적인 백엔드 API들(수동 등록 / 내부 핸들러 / OpenAPI 문서 Import)을 하나의 MCP 서버로 통합해, MCP 클라이언트가 표준 프로토콜(
tools/list,tools/call)로 도구를 발견·실행할 수 있게 합니다.해결하는 문제: 도구별로 제각각인 인증/노출/정책을 서버가 중앙에서 관리하고, 위험도·Scope·사용자별 선택·확인(confirmation) 정책과 감사 로그를 일관되게 적용합니다.
MCP Server의 역할: 도구 레지스트리 + 정책 게이트 + 실행 오케스트레이터. 업스트림 API로의 HTTP 실행과 감사 로깅을 담당합니다.
Credential Service와의 관계: 실제 자격증명(Secret)은 이 서버가 보관하지 않습니다. 외부 Credential Service(HTTP API)를 호출해 호출자 신원을 확인(
/api/v1/me)하고, 필요 시 단기 토큰 교환 후 Credential을 reveal 받아 업스트림 요청에 주입합니다. MCP Server는 HashiCorp Vault를 직접 호출하지 않습니다(아래 3·6절 참고).
Related MCP server: OpenAPI MCP Server
2. 주요 기능
실제 구현이 확인된 기능만 기재합니다. 다수 실행·인증 기능은 feature flag로 감싸여 있고 코드 기본값은 보수적으로 off입니다(11절 표 참고).
MCP Tool discovery — DB에 등록된 도구를 운영자 노출 정책·사용자별 선택·Scope에 따라
tools/list로 동적 노출 (app/mcp/registry.py,app/mcp/discoverability.py)MCP Tool execution —
tools/call시 다단계 정책 게이트 통과 후 업스트림 HTTP 호출 (app/services/execution/service.py,http_dispatcher.py) — 기본 비활성(MCP_TOOL_EXECUTION_ENABLED=false)OpenAPI Import — OpenAPI 문서(URL/파일)를 가져와 도구를 생성/동기화. 신규 도구는 비활성/비노출로 들어와 관리자가 검토 후 활성화 (
app/api/v1/openapi_sources.py)사용자별 Tool 선택 — 사용자가 자신에게 노출할 도구를 선택 (
user_tool_settings,app/services/user_tool_service.py)관리자 Tool/Provider 관리 — 등록·활성화·MCP 노출·Portal 노출·정책 설정·삭제 (
app/api/v1/tools.py,providers.py)Scope 및 위험도 정책 — 도구별
required_scopes,RiskLevel,requires_confirmation(app/db/models/policy.py,app/domain/scopes.py)Credential 주입 — REQUEST_HEADER_PASSTHROUGH / Credential Service reveal 주입 (
app/services/execution/) — 기본 비활성감사 로그 — 모든
tools/list/tools/call을 RECEIVED→완료로 기록, Secret 마스킹 (app/db/models/audit.py,app/services/execution/audit.py)관리자 Portal / 사용자 Portal — 서버사이드 렌더링 HTML(Jinja2) + 세션 인증 (
app/admin/,app/web/)
3. 전체 아키텍처
flowchart LR
Client[MCP Client]
Server[MCP Server<br/>FastAPI + MCP SDK]
DB[(PostgreSQL<br/>schema: mcp)]
Cred[Credential Service<br/>외부 HTTP API]
Upstream[업스트림 Tool API<br/>HTTP]
Vault[HashiCorp Vault]
Client -- "Streamable HTTP /mcp/" --> Server
Server -- "SQLAlchemy async / asyncpg" --> DB
Server -- "/me, token/exchange, reveal" --> Cred
Server -- "도구 실행(HTTP)" --> Upstream
Cred -. "이 저장소 범위 밖(코드로 확인 불가)" .-> VaultMCP Server는 Credential Service만 호출하며, HashiCorp Vault로의 직접 연결선은 없습니다(코드 전반에서
hvac/VAULT_ADDR/VAULT_TOKEN/hashicorp사용 0건).Credential Service가 내부적으로 Vault를 쓰는지는 이 저장소 코드로 확인할 수 없어 점선·"확인 불가"로 표기했습니다.
계층(레이어)
app/api,app/web,app/admin— HTTP 진입점(REST v1 / 세션 웹 / 관리자 HTML)app/mcp— MCP 전송·서버 핸들러·도구 매핑·발견/정렬app/services— 실행·인증·감사·사용자도구·OpenAPI 등 도메인 서비스app/repositories— DB 접근 계층app/db,alembic— 모델/스키마/마이그레이션app/domain,app/dto,app/core— 열거형·스코프·DTO·설정·로깅·예외
4. 요청 처리 흐름
실제 코드(app/mcp/server.py, app/services/execution/service.py) 기준입니다.
tools/list
MCP 요청 (/mcp/)
→ DB 세션 확인 (없으면 registry_unavailable 오류)
→ (MCP_MCP_CALLER_AUTH_REQUIRED=true일 때) 호출자 인증: API Key 헤더 → Credential Service GET /api/v1/me → status=ACTIVE 확인
→ Principal 생성(McpPrincipal: scopes/roles/email/status)
→ 사용자별 Tool 선택 정책 적용(ADMIN=전체, USER=본인 enable 목록, 매핑 없으면 0개 = fail-closed)
→ 운영자 노출 정책(SQL): provider/tool enabled·미삭제·ACTIVE, tool.mcp_exposed=true, sync_status≠STALE, policy enabled
→ Scope 필터: required_scopes ⊆ caller scopes 인 도구만
→ 입력 스키마 검증 통과분만
→ 페이지네이션(cursor, 상한 MCP_MCP_MAX_DISCOVERABLE_TOOLS) → 목록 반환인증 실패 시 DENIED 감사 로그 기록 후 오류 반환.
tools/call
MCP 요청 (/mcp/)
→ RECEIVED 감사 로그 기록
→ (필요 시) 호출자 인증
→ 전역 실행 플래그 확인(MCP_TOOL_EXECUTION_ENABLED)
→ 도구 조회(노출명) / 삭제·비활성 확인
→ MCP 노출 게이트(enforce_mcp_exposed)
→ 사용자별 선택 게이트(USER는 본인 enable 도구만)
→ Provider/Policy 게이트
→ 실행 타입 게이트(HTTP만 지원)
→ Scope 인가(required_scopes 검사)
→ 인자 검증(OFF/WARN/STRICT)
→ 확인 게이트(requires_confirmation=true & confirm≠true → TOOL_CONFIRMATION_REQUIRED) *Secret 호출 이전*
→ Credential 주입 판단(NONE / REQUEST_HEADER_PASSTHROUGH / CREDENTIAL_SERVICE_CREDENTIAL_INJECTION)
→ 업스트림 HTTP 실행(HttpToolDispatcher)
→ 결과 Secret 마스킹(fail-closed) → 감사 로그 완료 기록 → 결과 반환감사 기록은 fail-open(감사 실패가 응답을 막지 않음), 그 외 정책은 대부분 fail-closed.
구분해야 할 개념: 전역 MCP 호출자 인증(누가 호출했나 — Credential Service
/me) ≠ 도구별 upstream credential 주입(어떤 도구에 자격증명을 어떻게 붙이나).REQUEST_HEADER_PASSTHROUGH(inbound 헤더 변환)와CREDENTIAL_SERVICE_CREDENTIAL_INJECTION(reveal 값 QUERY 주입)은 별개입니다.
5. 인증 및 권한 구조
방식 | 헤더/전송 | 적용 대상 |
Credential Service API Key ( |
| MCP 요청( |
Bearer( |
| REST 관리 API |
세션 쿠키 + CSRF |
| 관리자/사용자 웹 Portal |
API Key prefix:
cs_(app/api/rest_auth.py).cs_로 시작하면 API Key 경로로 처리.JWT: MCP는 JWT를 발급하지 않고 검증만 합니다. 알고리즘 HS256(대칭키) 전용, 발급자/청중은
MCP_JWT_ISSUER/MCP_JWT_AUDIENCE(기본credential-service), 시크릿은MCP_JWT_SECRET(32자 이상 필수). REST 경로는/me재확인으로 JWTsub와 일치하는지도 검증.Principal: Credential Service
/me프로필로 생성(McpPrincipal/RestPrincipal) — scopes/roles/email/status 등 보유.Scope(정확히 7개,
app/domain/scopes.py):resources:read,credentials:reveal,servers.read,ssh.execute,logs.read,status.read,disk.read. 정확 일치(와일드카드/대소문자 무시 없음).Role(
UserRole):USER,ADMIN. REST 관리 API·관리자 페이지는 ADMIN 필요. 마지막 활성 관리자 강등/비활성 및 자기 자신 강등 방지.상태 검사: MCP는
/mestatus=ACTIVE, REST/웹은McpUser.is_active및deleted_at IS NULL.인증 실패 응답: CS 비활성 → 403, 무효/취소/검증불가(타임아웃·5xx 포함) → 401, JWT 설정 불가 → 503, 미등록/비활성 사용자 → 403, DB 미구성 → 503.
Secret 처리 원칙: 원본 자격증명/Authorization/API Key는 로그·감사에 저장하지 않음. 예시 키는 placeholder(
cs_<...>)만 사용.
기본값 주의:
MCP_MCP_CALLER_AUTH_REQUIRED,MCP_WEB_AUTH_ENABLED,MCP_JWT_ENABLED는 모두 기본 false입니다. 운영에서는 명시적으로 활성화해야 합니다.
6. Credential Service 연동
MCP Server와 Credential Service의 책임 경계:
MCP Server: 정책 판단, 도구 실행, 감사. 자격증명 원본을 저장하지 않음.
Credential Service(외부): 사용자 신원(
/api/v1/me), API Key→단기 JWT 교환(/api/v1/auth/token/exchange), Credential reveal(/api/v1/my/resources/{resource_id}/credentials/reveal).
동작:
신원 확인:
GET {base}/api/v1/me—Authorization: ApiKey <cs_...>또는Bearer <JWT>.토큰 교환: 요청의
cs_API Key → 단기 Exchange JWT(Authorization: ApiKey <cs_...>로 요청). TTL 상한 3600초, 재시도 없음.Credential 주입:
CREDENTIAL_SERVICE_CREDENTIAL_INJECTION은 (교환 JWT로) reveal 후 QUERY 파라미터로만 주입.REQUEST_HEADER_PASSTHROUGH는 허용 목록 헤더를 업스트림 허용 헤더로 전달(CR/LF 인젝션 차단).평문 노출 방지: reveal 호출은 단기 Bearer JWT로만(원본
cs_키는 reveal 엔드포인트로 전송하지 않음). reveal 값은 요청 스코프에서 기억되어 외부 반환 경계에서 마스킹(fail-closed).타임아웃/재시도: connect 5.0s / read 10.0s / token-exchange 10.0s, 응답 상한 256KiB, 재시도 없음.
관련 환경변수:
MCP_CREDENTIAL_SERVICE_BASE_URL,MCP_AUTH_BASE_URL(미설정 시 base_url fallback),MCP_CREDENTIAL_SERVICE_API_KEY_HEADER,MCP_CREDENTIAL_SERVICE_TOKEN_EXCHANGE_ENABLED/_PATH,MCP_CREDENTIAL_SERVICE_CREDENTIAL_INJECTION_ENABLED,MCP_MCP_CALLER_AUTH_REQUIRED등(11절 표 참고).
HashiCorp Vault 직접 연결 없음: 이 저장소 코드는 Vault SDK/주소/토큰을 전혀 사용하지 않습니다. 자격증명 접근은 오직 위 3개 Credential Service HTTP 엔드포인트를 통합니다.
7. 데이터베이스 구조
엔진/ORM: PostgreSQL + SQLAlchemy 2.0 비동기(asyncpg). DB 미구성 시 "bootstrap 모드"로 기동(엔진 없음).
전용 스키마:
mcp(MCP_DATABASE_SCHEMA). 모든 테이블이 스키마 한정,search_path도 해당 스키마로 고정(ADR-0004). 스키마명 검증 정규식^[a-z][a-z0-9_]{0,62}$, 예약/공용 스키마 거부.공통 mixin: UUID PK, 소프트 삭제(
deleted_at), 타임스탬프. 활성 유니크 제약은 대개WHERE deleted_at IS NULL부분 유니크.
핵심 엔티티 관계:
erDiagram
mcp_providers ||--o{ mcp_tools : "provider_id (RESTRICT)"
mcp_providers ||--o| mcp_openapi_sources : "provider_id (CASCADE, unique)"
mcp_tools ||--o| mcp_tool_http_configs : "tool_id (CASCADE, 1:1)"
mcp_tools ||--o| mcp_tool_policies : "tool_id (CASCADE, 1:1)"
mcp_users ||--o{ user_tool_settings : "user_id (CASCADE)"
mcp_tools ||--o{ user_tool_settings : "tool_id (CASCADE)"
mcp_users ||--o{ mcp_users : "created_by_user_id (SET NULL)"
mcp_tools ||--o{ mcp_audit_logs : "tool_id (SET NULL)"
mcp_providers ||--o{ mcp_audit_logs : "provider_id (SET NULL)"모델 | 테이블 | 설명 |
|
| 도구 제공자(업스트림). 인증 설정 보유 |
|
| 도구. |
|
| 도구 HTTP 실행 설정(1:1) |
|
| 정책(category/risk/ |
|
| Provider의 OpenAPI Import 소스(0..1) |
|
| 로컬 사용자(USER/ADMIN), Argon2id 해시 |
|
| 사용자별 도구 enable( |
|
| 감사 로그(append-only, 스냅샷 보존, 삭제 시 FK는 SET NULL) |
감사 로그: RECEIVED 행 생성 후 완료 시 상태/결과 UPDATE. 원본 자격증명/응답 본문은 저장하지 않고 마스킹된 인자·요약만 저장. 보존/TTL 정책은 코드에 없음(확인 불가).
정책 저장:
required_scopes(JSONB, 기본[])는 저장·검증하지만 강제는 실행 서비스 게이트에서 수행.requires_confirmation은 저장만 하며, 대화형 elicitation 프로토콜이 아니라 실행 게이트(confirm인자)로 적용.
8. 프로젝트 디렉터리 구조
핵심 경로만 표기합니다.
mcp-server/
├─ app/
│ ├─ main.py # FastAPI 팩토리(create_app), MCP 마운트, 미들웨어/OpenAPI 커스터마이즈
│ ├─ core/ # config(설정), logging(로깅·Secret redact), security, exceptions
│ ├─ api/ # REST 진입점: rest_auth, deps, health, v1/(tools, providers, users, ...)
│ ├─ web/ # 세션 로그인·Portal 라우트·RBAC 가드
│ ├─ admin/ # 관리자 HTML 라우트 + templates/(SSR)
│ ├─ mcp/ # MCP transport(Streamable HTTP)·server 핸들러·registry·tool_mapper·sanitizer
│ ├─ services/ # execution(실행/인증/감사/credential), auth(jwt/principal), user_tool_service, openapi
│ ├─ repositories/ # DB 접근 계층
│ ├─ db/ # base, session, schema, models/(providers/tools/policy/audit/users ...)
│ ├─ domain/ # enums, scopes, provider/credential_binding
│ ├─ dto/ # 요청/응답 DTO
│ └─ scripts/ # seed_initial_users
├─ alembic/ # env.py(스키마 한정 마이그레이션) + versions/(리비전 13개)
├─ tests/ # unit / integration / e2e / fixtures + conftest.py
├─ docs/ # architecture / operations / decisions(ADR) / TODO.md
├─ scripts/ # ci_check.sh, phase 검증 스크립트, update_kustomize_image_tag.sh
├─ Dockerfile # 멀티스테이지(python:3.12-slim, uv)
├─ docker-compose.yml # 로컬 db(postgres:16) + app
├─ Jenkinsfile # CI(빌드/푸시/배포 repo 갱신) — 값은 예시 placeholder
├─ pyproject.toml # 의존성/도구 설정(ruff/mypy/pytest)
└─ uv.lock9. 요구 환경
OS: Linux / WSL(개발), 컨테이너는
python:3.12-slimPython:
>=3.12(pyproject.toml)패키지 매니저:
uv(astral),uv.lock사용PostgreSQL: 실제 DB 기능 사용 시 필요(compose는
postgres:16-alpine)선택적 외부 서비스: Credential Service(자격증명 연동 사용 시)
Docker / Docker Compose: 로컬 실행·빌드 시(선택)
주요 라이브러리: FastAPI, uvicorn, MCP SDK(mcp), SQLAlchemy 2.0(asyncio)+asyncpg, Alembic, pydantic/pydantic-settings, httpx, PyJWT(검증), pwdlib[argon2], itsdangerous, jsonschema, Jinja2.
10. 로컬 실행
명령은 프로젝트 루트에서 실행합니다. 표기 [WSL zsh]는 로컬 셸입니다.
저장소 Clone
# [WSL zsh] git clone <YOUR_REPO_URL> mcp-server && cd mcp-server의존성 설치
# [WSL zsh] uv sync --dev환경변수 준비 (템플릿 복사 후 값 채우기; 실제 Secret은 커밋 금지)
# [WSL zsh] cp .env.example .envDB 준비 (로컬 Postgres 컨테이너)
# [Docker] docker compose up -d db마이그레이션 (DB 접속 환경변수 설정 후)
# [WSL zsh] uv run alembic upgrade head(선택) 초기 사용자 seed —
MCP_SEED_*환경변수 설정 후# [WSL zsh] uv run python -m app.scripts.seed_initial_users서버 실행
# [WSL zsh] uv run uvicorn app.main:app --host 0.0.0.0 --port 8080health 확인
# [WSL zsh] curl http://127.0.0.1:8080/health curl http://127.0.0.1:8080/readyOpenAPI / MCP 확인
# [WSL zsh] curl http://127.0.0.1:8080/openapi.json # Swagger UI: http://127.0.0.1:8080/docs # MCP 엔드포인트(정규 URL): http://127.0.0.1:8080/mcp/ (Streamable HTTP)
⚠ 현재 소스 상태에서는 아래 18절의 알려진 이슈(Enum 길이)로 인해 애플리케이션 import가 실패합니다. 위 실행 명령들은 코드 정의상 유효하지만, 실제 기동을 위해서는 해당 이슈 해결이 선행되어야 합니다.
11. 환경변수
접두사 MCP_ + 대문자 필드명. 값은 app/core/config.py의 Settings 기준(실제 코드 우선). 실제 Secret 값은 표기하지 않습니다. "필수"는 미설정 시 해당 기능이 동작하지 않는 값을 의미합니다.
애플리케이션
변수 | 필수 | 기본값 | 설명 | 민감 |
MCP_APP_NAME | 아니오 | mcp-server | 서비스명 | 아니오 |
MCP_VERSION | 아니오 | 0.1.0 | 버전 | 아니오 |
MCP_ENV | 아니오 | local | local/dev/prod | 아니오 |
MCP_LOG_LEVEL | 아니오 | INFO | 로그 레벨 | 아니오 |
MCP_HOST | 아니오 | 0.0.0.0 | bind host | 아니오 |
MCP_PORT | 아니오 | 8080 | bind port | 아니오 |
MCP_DATABASE_SCHEMA | 아니오 | mcp | 전용 PG 스키마(검증됨) | 아니오 |
데이터베이스
변수 | 필수 | 기본값 | 설명 | 민감 |
MCP_DB_HOST | DB 사용 시 | (없음) | PG 호스트 | 아니오 |
MCP_DB_PORT | 아니오 | 5432 | PG 포트 | 아니오 |
MCP_DB_USER | DB 사용 시 | (없음) | PG 사용자 | 아니오 |
MCP_DB_PASSWORD | DB 사용 시 | (없음) | PG 비밀번호 | 예 |
MCP_DB_NAME | DB 사용 시 | (없음) | PG DB명 | 아니오 |
인증 / JWT / 세션
변수 | 필수 | 기본값 | 설명 | 민감 |
MCP_WEB_AUTH_ENABLED | 아니오 | false | 웹/관리자 인증 활성 | 아니오 |
MCP_SESSION_SECRET | web_auth 시 필수 | (없음) | 세션 서명 시크릿 | 예 |
MCP_SESSION_COOKIE_NAME | 아니오 | mcp_session | 세션 쿠키명 | 아니오 |
MCP_SESSION_TTL_SECONDS | 아니오 | 3600 | 세션 TTL | 아니오 |
MCP_COOKIE_SECURE | 아니오 | false | Secure 쿠키 | 아니오 |
MCP_COOKIE_SAMESITE | 아니오 | lax | SameSite | 아니오 |
MCP_PASSWORD_MIN_LENGTH | 아니오 | 8 | 비밀번호 최소 길이 | 아니오 |
MCP_PASSWORD_MAX_LENGTH | 아니오 | 128 | 비밀번호 최대 길이 | 아니오 |
MCP_JWT_ENABLED | 아니오 | false | JWT 검증 활성 | 아니오 |
MCP_JWT_ALGORITHM | 아니오 | HS256 | HS256만 허용 | 아니오 |
MCP_JWT_SECRET | jwt 시 필수 | (없음) | JWT 검증 시크릿(≥32자) | 예 |
MCP_JWT_ISSUER | 아니오 | credential-service | 발급자 | 아니오 |
MCP_JWT_AUDIENCE | 아니오 | credential-service | 청중 | 아니오 |
MCP
변수 | 필수 | 기본값 | 설명 |
MCP_MCP_ENABLED | 아니오 | true | MCP 전송 마운트 |
MCP_MCP_PATH | 아니오 | /mcp | 마운트 경로(정규 URL |
MCP_MCP_MAX_DISCOVERABLE_TOOLS | 아니오 | 500 | 노출 도구 상한 |
MCP_MCP_PAGE_SIZE | 아니오 | 100 | 페이지 크기 |
MCP_MCP_JSON_RESPONSE | 아니오 | false | 단일 JSON vs SSE |
MCP_MCP_DNS_REBINDING_PROTECTION | 아니오 | false | Host 헤더 보호 |
MCP_MCP_ALLOWED_HOSTS | 아니오 | [] | 허용 Host(콤마 구분) |
MCP_MCP_CALLER_AUTH_REQUIRED | 아니오 | false | MCP 호출자 인증 요구 |
Credential Service
변수 | 필수 | 기본값 | 설명 | 민감 |
MCP_CREDENTIAL_SERVICE_BASE_URL | 연동 시 | (없음) | Credential Service base URL | 아니오 |
MCP_AUTH_BASE_URL | 아니오 | (없음, base_url fallback) | 인증(/me·exchange) base URL | 아니오 |
MCP_CREDENTIAL_SERVICE_API_KEY_HEADER | 아니오 | X-Credential-Service-Api-Key | 요청 API Key 헤더명 | 아니오 |
MCP_CREDENTIAL_SERVICE_CREDENTIAL_INJECTION_ENABLED | 아니오 | false | reveal 주입 활성 | 아니오 |
MCP_CREDENTIAL_SERVICE_TOKEN_EXCHANGE_ENABLED | 아니오 | false | 토큰 교환 활성 | 아니오 |
MCP_CREDENTIAL_SERVICE_TOKEN_EXCHANGE_PATH | 아니오 | /api/v1/auth/token/exchange | 교환 경로 | 아니오 |
MCP_CREDENTIAL_SERVICE_PROFILE_PATH | 아니오 | /api/v1/me | 프로필 경로 | 아니오 |
MCP_CREDENTIAL_SERVICE_CONNECT_TIMEOUT_SECONDS | 아니오 | 5.0 | connect timeout | 아니오 |
MCP_CREDENTIAL_SERVICE_READ_TIMEOUT_SECONDS | 아니오 | 10.0 | read timeout | 아니오 |
MCP_CREDENTIAL_SERVICE_TOKEN_EXCHANGE_TIMEOUT_SECONDS | 아니오 | 10.0 | 교환 timeout | 아니오 |
MCP_CREDENTIAL_SERVICE_MAX_RESPONSE_BYTES | 아니오 | 262144 | 응답 상한 | 아니오 |
MCP_ALLOWED_CREDENTIAL_SERVICE_CREDENTIAL_FIELDS | 아니오 | api_key,token,refresh_token,client_secret,webhook_secret | reveal 허용 필드 | 아니오 |
Tool 정책 / Credential passthrough
변수 | 기본값 | 설명 |
MCP_TOOL_EXECUTION_ENABLED | false | 도구 실행 전역 활성 |
MCP_REQUEST_CREDENTIAL_PASSTHROUGH_ENABLED | false | 헤더 passthrough 활성 |
MCP_ALLOWED_CREDENTIAL_SOURCE_HEADERS | [X-Credential-Service-Api-Key] | 소스 헤더 허용목록 |
MCP_ALLOWED_PASSTHROUGH_TARGET_HEADERS | [Authorization] | 대상 헤더 허용목록 |
MCP_HTTP_EXEC_CONNECT_TIMEOUT_SECONDS | 5.0 | 실행 connect timeout |
MCP_HTTP_EXEC_MAX_RESPONSE_BYTES | 2097152 | 실행 응답 상한 |
감사 로그
변수 | 기본값 | 설명 |
MCP_AUDIT_LOG_ENABLED | true | 감사 로그 활성 |
MCP_AUDIT_MAX_TEXT_LENGTH | 2000 | 텍스트 최대 길이 |
OpenAPI Import
MCP_OPENAPI_FETCH_CONNECT_TIMEOUT_SECONDS(5.0), MCP_OPENAPI_FETCH_READ_TIMEOUT_SECONDS(15.0), MCP_OPENAPI_MAX_DOCUMENT_BYTES(5242880), MCP_OPENAPI_MAX_UPLOAD_BYTES(5242880), MCP_OPENAPI_MAX_REDIRECTS(3), MCP_OPENAPI_ALLOW_PRIVATE_NETWORKS(false), MCP_OPENAPI_MAX_OPERATIONS(500), MCP_OPENAPI_MAX_REF_DEPTH(20), MCP_OPENAPI_MAX_SCHEMA_DEPTH(30).
개발/테스트 (Settings 클래스 밖, seed 스크립트가 직접 사용)
MCP_SEED_ADMIN_USERNAME, MCP_SEED_ADMIN_PASSWORD(민감), MCP_SEED_USER_USERNAME, MCP_SEED_USER_PASSWORD(민감), MCP_SEED_UPDATE_EXISTING(기본 false).
코드·템플릿 불일치:
.env.example/env.template는 위 변수 중 일부(예: 웹 세션 그룹, 일부 Credential Service 세부 변수,MCP_AUTH_BASE_URL,MCP_VERSION,MCP_SEED_*)를 생략합니다. 생략된 변수는 코드 기본값을 따릅니다.
12. 데이터베이스 Migration
도구: Alembic(비동기 엔진).
alembic.ini의sqlalchemy.url은 비워두고alembic/env.py가 앱 설정에서 주입.스키마 한정:
version_table_schema=mcp, autogenerate가mcp스키마만 대상으로 함(다른 서비스 객체 보호). 온라인 실행 시 마이그레이션 전에 스키마를 별도 트랜잭션으로 생성.리비전 수:
alembic/versions/13개. 각 리비전에upgrade()/downgrade()구현되어 있음(스텁 아님).
# [WSL zsh] (DB 접속 환경변수 설정 후)
uv run alembic upgrade head # 최신 스키마 적용
uv run alembic revision --autogenerate -m "메시지" # 리비전 생성(개발)downgrade: 리비전에 구현되어 있으나 프로젝트 문서/CI에서 운영 downgrade 절차는 규정하지 않음. 운영 적용 시 스키마 격리·별도 트랜잭션 생성 특성을 확인하세요.
컨테이너/CI는 마이그레이션을 자동 실행하지 않습니다(Dockerfile·Jenkins에 alembic 실행 없음).
13. 테스트 및 품질 검사
# [WSL zsh]
uv run pytest # 전체 테스트 (testpaths=tests, asyncio_mode=auto)
uv run pytest -m integration # integration 마커만 (PostgreSQL 필요)
uv run pytest tests/unit/test_config.py # 특정 파일
uv run ruff check . # lint
uv run ruff format --check . # 포맷 검사
uv run ruff format . # 포맷 적용
uv run mypy app # 타입 체크(strict)
bash scripts/ci_check.sh # 전체 CI 게이트(포맷→lint→mypy→pytest→phase 검증)커버리지 설정(
[tool.coverage])은 없음.[project.scripts]콘솔 진입점 없음.현재 소스 상태의 실제 실행 결과는 18절 참조(일부 FAIL/BLOCKED).
14. Docker 실행
# [Docker]
docker compose up -d db # 로컬 Postgres만
docker compose up # db + app 함께
docker build -t mcp-server:dev . # 이미지 빌드(멀티스테이지)Dockerfile: 멀티스테이지(
python:3.12-slim), 비루트app사용자,uv sync --frozen --no-dev,EXPOSE 8080,HEALTHCHECK가/health확인,CMD는uvicorn app.main:app --host 0.0.0.0 --port 8080. 컨테이너는 마이그레이션을 실행하지 않음.docker-compose.yml:
db(postgres:16-alpine, 5432, healthcheckpg_isready, 볼륨mcp_pgdata),app(Dockerfile 빌드,dbhealthy 후 기동,MCP_DB_HOST=db, 8080 노출). DB 비밀번호 기본값은 로컬 개발용입니다.
15. Kubernetes 및 배포
이 저장소에는 범용 Kubernetes/Kustomize/Argo CD manifest가 포함되어 있지 않습니다. 실제 배포 manifest는 외부 배포 저장소에 존재하는 것으로 참조만 됩니다.
포함된 것:
Jenkinsfile(빌드→레지스트리 푸시→배포 repo의 이미지 태그 갱신),scripts/update_kustomize_image_tag.sh(kustomization의newTag한 줄만 안전 치환).주의:
Jenkinsfile의 레지스트리/배포 repo/자격증명 ID 등은 실제 값이 아닌 예시 placeholder(registry.example.com:8082,github.com/example-org/...,jenkins@example.com등)입니다. 실제 운영 값으로 교체가 필요합니다.GitHub Actions(
.github/) 없음. Redis/메시지 브로커 없음. HashiCorp Vault 직접 연동 없음.
16. API 및 MCP 사용 예시
placeholder만 사용합니다(유효한 실제 키/Secret 아님).
health:
# [WSL zsh]
curl http://127.0.0.1:8080/health
curl http://127.0.0.1:8080/ready시스템 정보(무인증):
# [WSL zsh]
curl http://127.0.0.1:8080/api/v1/system/info
curl http://127.0.0.1:8080/api/v1/system/mcp관리 REST API(ADMIN, Bearer):
# [WSL zsh]
curl -H "Authorization: Bearer cs_<YOUR_API_KEY>" http://127.0.0.1:8080/api/v1/toolsMCP 클라이언트 연결(개념 — 실제 클라이언트 설정 형식에 맞게):
transport : Streamable HTTP
url : http://127.0.0.1:8080/mcp/
header : X-Credential-Service-Api-Key: cs_<YOUR_API_KEY> # MCP_MCP_CALLER_AUTH_REQUIRED=true 인 경우tools/list/tools/call은 MCP 클라이언트가 위 엔드포인트로 JSON-RPC를 전송하면 서버가 4절 흐름대로 처리합니다.관리자 UI:
http://127.0.0.1:8080/admin· 사용자 Portal:http://127.0.0.1:8080/portal/tools(웹 인증 활성 시 로그인 필요).
17. 보안 주의사항
API Key / JWT Secret:
.env에만 두고 저장소에 커밋하지 마세요.MCP_JWT_SECRET은 32자 이상 필수, placeholder 값은 기동 시 거부됩니다.로그/감사 내 Secret: 로거는 필드명 기반으로 Secret을 마스킹(
***REDACTED***)하고, httpx/httpcore 로그를 WARNING으로 낮춰 쿼리스트링 유출을 억제합니다. 감사 로그는 원본 자격증명/응답 본문을 저장하지 않습니다.Credential injection / reveal: reveal은 단기 Bearer JWT로만 호출하고 원본 API Key를 reveal 엔드포인트로 보내지 않습니다. 반환 경계에서 Secret을 마스킹(fail-closed)합니다.
운영 HTTPS / 쿠키: 운영에서는
MCP_COOKIE_SECURE=true및 TLS 종단(리버스 프록시)을 사용하세요.MCP 전송 보안: MCP 마운트는 네트워크 계층에서 인증되지 않습니다. 네트워크 ACL/프록시로 보호하고, 외부 노출 시
MCP_MCP_DNS_REBINDING_PROTECTION+MCP_MCP_ALLOWED_HOSTS설정을 검토하세요.CORS: 저장소 코드에서 별도 CORS 미들웨어 설정은 확인되지 않았습니다(확인 불가). 필요 시 리버스 프록시/게이트웨이에서 통제하세요.
DB 자격증명:
MCP_DB_PASSWORD는 민감정보입니다. compose 기본 비밀번호는 로컬 전용입니다.HashiCorp Vault 토큰: 이 서버는 Vault 토큰을 사용하지 않습니다(직접 연동 없음).
관리자 기능: 마지막 활성 관리자 보호·자기 강등 방지 등 안전장치가 있으나,
MCP_WEB_AUTH_ENABLED=false(기본)에서는 웹 인증이 우회되므로 운영에서 반드시 활성화하세요.공개 저장소 Secret 관리: 실제 IP/도메인/자격증명을 README·코드·커밋에 포함하지 마세요.
18. 현재 제한 사항
코드 분석과 경량 검증(의존성 설치 후 실제 실행)에서 확인된 사실입니다.
[치명적] 애플리케이션 import 실패 —
AuthType의 값CREDENTIAL_SERVICE_CREDENTIAL_INJECTION(39자)이 DB 컬럼 정의SAEnum(..., length=32)보다 길어 SQLAlchemy가ValueError: length must be larger or equal than the length of the longest enum value. 32 < 39를 발생시킵니다.app/db/models/provider.py·policy.py·tool.py의length=32컬럼들이 영향받으며, 이로 인해 앱 import·OpenAPI 생성·pytest 수집이 모두 실패합니다.[타입/정의 충돌]
app/services/execution/credential_service.py에서CredentialResolver이름이 중복 정의(Protocol vs 구현 클래스)되어mypy가no-redef/Cannot instantiate protocol을 보고합니다.[품질 검사 드리프트]
ruff check(E501 라인 길이 등)·ruff format --check(다수 파일 포맷 차이)·mypy가 현재 통과하지 않습니다.문서·코드 주석 불일치:
app/mcp/의 일부 주석은 "tools/call 미구현(Phase 5)"이라고 되어 있으나, 실제 코드는 플래그 활성 시 업스트림 HTTP 실행·Credential 주입을 수행합니다.로깅 표기: 로깅 모듈 docstring은 "구조적(structured)"이라 하지만 실제는 stdout 평문 포맷입니다.
감사 로그 보존 정책 없음(append-only, TTL/파기 미구현).
외부 의존 검증 불가: 실제 DB/Credential Service 연결이 필요한 동작은 이 문서 작성 범위에서 검증하지 않았습니다.
위 이슈들은 README 작성 범위(문서만 수정)에서 코드를 변경하지 않았습니다. 별도 수정이 필요합니다.
19. 라이선스
저장소에 별도의
LICENSE파일은 없습니다.pyproject.toml에는license = { text = "Proprietary" }로 선언되어 있습니다.
라이선스 정책이 확정되지 않았다면 공개 전에 명시적인 LICENSE 파일 추가를 권장합니다(임의로 라이선스를 지정하지 않았습니다).
This server cannot be deployed
Maintenance
Related MCP Connectors
Governed MCP gateway: one endpoint for your tools, with credential custody and audit log.
MCP server for mandates, delegation, policy-gated execution, credential grants, and audit.
An MCP server that provides an API to LLMs to manage their JumpCloud resources.
MCP server for secureFlows: token-free URL builders and integration-linting tools for AI agents.
Related MCP Servers
- AlicenseAqualityFmaintenanceA universal MCP server that exposes all UTCP-registered tools to MCP clients while providing a web interface for tool management.712 npm203MIT
- AlicenseNot gradedqualityCmaintenanceA generic MCP server that dynamically converts OpenAPI-defined REST APIs into tools for LLMs like Claude. It supports multiple authentication methods and transport protocols, enabling seamless interaction with any OpenAPI-compliant API.21 npmMIT
- AlicenseNot gradedqualityBmaintenanceSelf-hosted MCP proxy and aggregation platform. Register multiple upstream MCP servers and expose them through a single unified endpoint with namespace routing, multi-transport support (HTTP/SSE, stdio, OpenAPI→MCP), per-tool overrides, and a web admin UI.17MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to discover and execute tools via a secure MCP server with JWT authentication, RBAC, rate limiting, and audit logging.1MIT