mcp-server
Click on "Install 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 installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseAqualityFmaintenanceA universal MCP server that exposes all UTCP-registered tools to MCP clients while providing a web interface for tool management.Last updated738201MIT
- Alicense-qualityCmaintenanceA 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.Last updated17MIT
- Alicense-qualityAmaintenanceSelf-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.Last updated16MIT
- Alicense-qualityCmaintenanceEnables AI agents to discover and execute tools via a secure MCP server with JWT authentication, RBAC, rate limiting, and audit logging.Last updated1MIT
Related MCP Connectors
The official MCP Server from Mia-Platform to interact with Mia-Platform Console
MCP server for interacting with the Supabase platform
MCP server for AI access to SmartBear tools, including BugSnag, Reflect, Swagger, PactFlow, QTM4J.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/gwanghun-choi/mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server