From a3ba76f2f442e688a1775c6b906ed2a00e33c6ac Mon Sep 17 00:00:00 2001 From: devmrko Date: Tue, 14 Jul 2026 14:19:10 +0900 Subject: [PATCH] Reverse document PoC4 MCP AI Console snapshot --- .../README.md | 122 +++++++++++++++++- 1 file changed, 118 insertions(+), 4 deletions(-) diff --git a/docs/design/654-poc4-mcp-discovery-streamable-http/README.md b/docs/design/654-poc4-mcp-discovery-streamable-http/README.md index 1d65071..cd2ad18 100644 --- a/docs/design/654-poc4-mcp-discovery-streamable-http/README.md +++ b/docs/design/654-poc4-mcp-discovery-streamable-http/README.md @@ -1,9 +1,9 @@ -# 설계서: PoC_4 MCP Discovery UI — KB VPD Streamable HTTP 연동 정비 (#654) +# 설계서: PoC_4 MCP AI Console 소스 스냅샷 역설계 및 KB VPD MCP 연동 정비 (#654) -> **상태**: Draft · source snapshot imported +> **상태**: Implemented snapshot documented · follow-up contract pending > **작성**: [AI] Architect · **최종수정**: 2026-07-14 -> **추적성** — Redmine: #654 · 관련 ADR: 없음 -> · 스냅샷: `poc4_active_source_20260714/` · 원본 archive: `poc4_active_source_20260714/poc4_active_source_20260714.tar.gz` · 목표 구현 파일: `apps/poc4/mcp_discovery_ui.py`, `config/mcp_servers.json`, VPD Backoffice의 `/mcp` endpoint · 테스트: PoC_4 단위 테스트 및 실제 MCP HTTP smoke test +> **추적성** — Redmine: #654 · 관련 ADR: 없음 · 구현 커밋: `5bdd242`, `33399f9` +> · 스냅샷: `poc4_active_source_20260714/` · 원본 archive: `poc4_active_source_20260714/poc4_active_source_20260714.tar.gz` · 현행 구현 파일: `apps/poc4/mcp_discovery_ui.py`, `src/mcp_tool_router.py`, `src/oci_genai_sdk.py`, `src/poc3/model_registry.py`, `config/mcp_servers.json` · 테스트: Python 3.11 `py_compile`, 기존 백오피스 `mvn -q test` ## 1. 목적 (Why) @@ -11,6 +11,89 @@ PoC_4의 MCP Discovery UI가 KB VPD MCP를 사용자별 Bearer 토큰으로 안 현재 UI의 기본 호출 흐름은 동작한다. 다만 `kb_mcp` 설정에는 `endpoint_url`과 `base_url_env`가 함께 있고, UI는 `endpoint_url`을 우선 사용한다. 따라서 `KB_MCP_BASE_URL`을 바꿔도 실제 호출 대상이 바뀌지 않는다. 또한 `custom_python`은 로컬 8500 MCP용 이름이므로 외부 KB VPD MCP의 통신 계약을 설명하지 못한다. +## 1.1 현행 구현 역설계 요약 + +이번 문서는 목표 설계를 먼저 정한 것이 아니라, 배포 서버에서 이미 동작하던 PoC4 MCP AI Console 스냅샷을 저장소로 가져온 뒤 구현을 역으로 읽어 작성했다. 따라서 아래 표가 현재 동작의 기준이다. + +| 영역 | 현행 구현 | +|---|---| +| 저장소 위치 | `poc4_active_source_20260714/` 단일 폴더에 격리 | +| 실행 진입점 | 직접 실행은 `streamlit run apps/poc4/mcp_discovery_ui.py --server.address 0.0.0.0 --server.port 8622` | +| Python 런타임 | Python 3.11 이상. 배포 서버 검증 런타임은 `/home/opc/poc_4/.python-runtime/cpython-3.11.15+20260610/bin/python3.11` | +| Streamlit 화면 | `apps/poc4/mcp_discovery_ui.py` 단일 대형 UI. KB 테마, 포털 로그인, 대화 이력, MCP discovery/call, evidence 수집, 답변 합성을 포함 | +| MCP registry | `config/mcp_servers.json`. `kb_mcp`와 `kb_vector_mcp` 두 서버를 선언 | +| KB 정형 MCP | `https://kb.cloud-handson.com/mcp`, 기본 tool `ords.query.kb_select_ai_vpd` | +| KB 벡터 MCP | `http://127.0.0.1:9978/mcp`, allowlist `hybrid_rerank_search` | +| 토큰 preset | `config/vpd_token_presets.json`. 실제 토큰 원문은 포함하지 않고 placeholder만 둠 | +| 대화 저장소 | 기본 `data/poc4_mcp_chat.sqlite3`, 환경변수 `POC4_CHAT_DB_PATH`로 변경 가능 | +| DB evidence 연결 | 기본 env file `/home/opc/kbmcp/.env`, wallet fallback `/home/opc/wallet/kbaipoc` | +| OCI GenAI | `OCI_AUTH_TYPE=config_file`, `~/.oci/config`, `DEFAULT` profile 기반. model profile은 `config/poc3_model_profiles.json`에서 로드 | +| 보안 원칙 | wallet, DB password, wallet password, 실제 VPD token, 대화 DB는 저장소에 포함하지 않음 | + +현행 데이터 흐름은 다음과 같다. + +```text +Streamlit 사용자 로그인 + ↓ +VPD 사용자 preset 또는 직접 Bearer token 선택 + ↓ +config/mcp_servers.json 로드 + ↓ +각 MCP 서버에 initialize → initialized notification → tools/list + ↓ +질문 유형에 따라 single 또는 agent 실행 계획 선택 + ↓ +tools/call 호출 + - Authorization: Bearer <현재 VPD token> + - JSON-RPC body에는 tool name과 arguments만 포함 + ↓ +정형 MCP / 벡터 MCP 결과 수집 + ↓ +필요 시 /home/opc/kbmcp/.env + /home/opc/wallet/kbaipoc 로 Oracle evidence 조회 + ↓ +OCI GenAI로 최종 답변 합성 + ↓ +SQLite 대화 이력 저장 +``` + +## 1.2 현행 구현 컴포넌트 + +| 파일 | 책임 | +|---|---| +| `apps/poc4/mcp_discovery_ui.py` | Streamlit 화면, 포털 로그인, MCP discovery/call, agent loop, evidence 수집, 답변 합성, 대화 이력 저장 | +| `apps/poc4/ui_theme.py` | UI theme 보조 코드 | +| `src/mcp_tool_router.py` | 발견된 MCP tool descriptor를 기반으로 LLM router가 server/tool을 선택하고 tool arguments를 구성 | +| `src/oci_genai_sdk.py` | OCI Generative AI 호출 경계. MCP/VPD token을 알지 않는 최소 completion client | +| `src/poc3/model_registry.py` | 모델 profile registry 로드, region/endpoint 해석, 환경 override 처리 | +| `src/poc3/questions.py` | 데모 질문 목록 | +| `config/mcp_servers.json` | MCP 서버 registry. 현재는 `endpoint_url`이 있으면 이를 우선 사용 | +| `config/poc3_model_profiles.json` | `gpt55_oci`, `gpt54_mini_oci`, `grok43`, `llama4_maverick`, `llama33_70b` profile | +| `config/vpd_token_presets.json` | 데모 사용자 token preset 구조. 실제 토큰은 배포 환경에서 교체 | +| `scripts/poc4/start_8622_langgraph_tc_ui_nohup.sh` | 원본 PoC4 런처 wrapper. 현재 스냅샷의 직접 entrypoint와는 다르게 `/home/opc/poc_4/scripts/poc4/run_8622_langgraph_tc_ui.sh` 및 `apps/poc4/langgraph_tc_ui.py`를 참조 | + +런처 주의사항: 스냅샷에는 `mcp_discovery_ui.py` 직접 실행에 필요한 소스가 들어 있지만, 포함된 `start_8622...` script는 원본 서버의 공용 runtime wrapper에 의존한다. 이 저장소에서 독립 실행하려면 `SOURCE_README.md`의 직접 `streamlit run` 명령을 사용하거나, 별도 wrapper를 작성해야 한다. + +## 1.3 현행 보안/비밀정보 경계 + +- `VpdTokenPreset.token`은 dataclass에서 `repr=False`이며, UI는 token을 정규화한 뒤 Authorization header에만 넣는다. +- `_NoRedirectHandler`는 redirect 시 Authorization header가 다른 endpoint로 전달되는 것을 막는다. +- `src/mcp_tool_router.py`의 router는 질문과 tool descriptor만 받으며 bearer token 또는 provider credential을 받지 않는다. +- `src/oci_genai_sdk.py`는 `.env`에서 `OCI_AUTH_TYPE`, `OCI_CONFIG_FILE`, `OCI_GENAI_COMPARTMENT_ID`, `OCI_PROFILE`만 읽는다. +- Oracle audit/business evidence 조회는 `/home/opc/kbmcp/.env`에서 `ORACLE_DB_USER`, `ORACLE_DB_PASSWORD`, `ORACLE_DSN`, `ORACLE_WALLET_PASSWORD`, `ORACLE_WALLET_DIR`를 읽는다. +- wallet 기본 fallback은 `/home/opc/wallet/kbaipoc`이다. +- 저장소에는 실제 `.env`, wallet, SQLite 대화 DB, 실제 VPD bearer token 원문을 포함하지 않는다. + +## 1.4 현행 구현과 후속 목표의 차이 + +| 항목 | 현행 구현 | 후속 목표 | +|---|---|---| +| KB MCP provider/transport 명칭 | `provider=custom_python`, `transport=http` | `kb_vpd_streamable_http`, `streamable_http`처럼 외부 KB VPD MCP 계약을 명확히 표현 | +| endpoint 해석 | `endpoint_url`이 있으면 이를 우선 사용하고, 없으면 env 값을 사용 | KB MCP는 `KB_MCP_BASE_URL + /mcp` 단일 계약으로 해석 | +| tool routing | route가 여러 개면 LLM router/agent mode를 사용할 수 있음 | KB 단일 tool 호출에서는 router 없이 direct 선택 | +| 401/403 표시 | 현재 둘 다 “MCP 인증에 실패” 계열 안전 메시지로 축약 | 토큰 없음/만료/권한 부족을 UI에서 명확히 분리 | +| start script | 원본 `/home/opc/poc_4` runtime wrapper 의존 | 스냅샷 폴더 안에서 독립 실행 가능한 wrapper 추가 | +| 회귀 테스트 | 원본 서버 Python 3.11 `py_compile`, Java `mvn -q test` | PoC4 전용 단위 테스트와 실제 MCP HTTP smoke test 추가 | + ## 2. 범위 (Scope) - **포함**: @@ -26,6 +109,8 @@ PoC_4의 MCP Discovery UI가 KB VPD MCP를 사용자별 Bearer 토큰으로 안 ## 3. 인수조건 (Acceptance Criteria) +아래 체크박스는 최종 목표 기준이다. 2026-07-14 스냅샷 반입 상태에서는 일부만 충족한다. + - [ ] KB MCP URL은 `KB_MCP_BASE_URL` 하나에서만 해석되고 `/mcp` path가 안전하게 결합된다. - [ ] `initialize`, `notifications/initialized`, `tools/list`, `tools/call`의 모든 HTTP 요청에 현재 선택된 사용자의 `Authorization: Bearer `만 전송된다. - [ ] Bearer 토큰은 JSON-RPC arguments, SQLite 대화 이력, UI 결과, 애플리케이션 로그에 저장·출력되지 않는다. @@ -35,6 +120,17 @@ PoC_4의 MCP Discovery UI가 KB VPD MCP를 사용자별 Bearer 토큰으로 안 - [ ] 잘못된 Origin의 브라우저 요청은 MCP 서버에서 거부되며, 허용 Origin 및 Origin 없는 네이티브 MCP client 정책이 문서화된다. - [ ] 기존 `kb_vector_mcp` 및 로컬 8500 MCP 회귀 테스트가 통과한다. +| 조건 | 현행 판단 | 근거/메모 | +|---|---|---| +| URL 단일 해석 | 부분 충족 | `_mcp_endpoint()`가 `/mcp` 결합과 URL 검증은 수행하지만 `config/mcp_servers.json`의 `endpoint_url`이 env보다 우선한다. | +| 요청별 Authorization header | 충족 | `_jsonrpc_exchange()`와 `_jsonrpc_notification()`이 `Authorization: Bearer `을 header에 설정한다. | +| JSON-RPC arguments token 미포함 | 충족 | `build_mcp_tool_arguments()`는 `prompt`, `limit`, `query`, `question` 계열만 구성한다. | +| SQLite token 원문 미저장 | 부분 충족 | chat turn에는 선택 사용자/label, question/answer/details를 저장한다. token 원문 필드는 없지만 `details_json`의 evidence payload는 후속 보안 점검 필요. | +| 단일 도구 direct routing | 부분 충족 | route가 1개면 single로 처리하지만, 복수 route에서는 LLM router/agent mode를 사용할 수 있다. | +| 401/403 구분 | 미충족 | 현재 `401`, `403` 모두 안전한 인증 실패 메시지로 축약한다. | +| Origin 검증 | 서버 범위 | UI client는 redirect 차단을 수행한다. Origin 정책은 VPD Backoffice MCP 서버 설정에서 확인해야 한다. | +| 벡터 MCP 회귀 | 미검증 | 소스 반입 시 Java 테스트와 Python 문법 검증만 수행했다. 실제 `kb_vector_mcp` smoke test는 후속이다. | + ## 4. 컨텍스트 & 제약 - KB VPD MCP endpoint: `https://kb.cloud-handson.com/mcp` @@ -213,3 +309,21 @@ Authorization: Bearer - 검증: 배포 서버 원본 경로에서 PoC4 전용 Python `3.11.15`로 `py_compile` 통과. 기존 Java 백오피스 `mvn -q test` 통과. 주의: 이 반입은 소스 스냅샷 보관이다. 아직 본 설계서의 목표 계약인 `kb_vpd_streamable_http`, `KB_MCP_BASE_URL` 단일 endpoint 해석, 단일 도구 direct routing을 구현 완료했다는 의미는 아니다. + +## 14. 2026-07-14 역설계 현행화 + +사용자 요청에 따라 “설계가 먼저 있고 구현을 맞추는 방식”이 아니라, 이미 배포 서버에서 구현·운영 중인 PoC4 MCP AI Console 소스를 기준으로 역설계했다. + +현행화한 내용: + +- `mcp_discovery_ui.py`의 실제 책임 범위를 Streamlit UI, MCP JSON-RPC client, agent loop, evidence collector, answer synthesis, chat store로 분리해 기록했다. +- `mcp_servers.json`의 현재 계약이 목표 계약과 다르다는 점을 명시했다. 특히 현행은 `endpoint_url` 우선이며, `provider=custom_python`, `transport=http`이다. +- `/home/opc/kbmcp/.env`와 `/home/opc/wallet/kbaipoc`를 배포 서버 DB evidence 조회 기준으로 확정했다. +- 포함된 start/status script가 스냅샷 단독 실행용이 아니라 원본 `/home/opc/poc_4` runtime wrapper에 의존한다는 점을 기록했다. +- 인수조건을 최종 목표와 현행 충족 상태로 분리했다. + +검증: + +- 배포 서버 원본 소스 기준 Python 3.11.15 `py_compile` 통과 +- 백오피스 기존 회귀 `mvn -q test` 통과 +- 저장소 문서/스냅샷 커밋 및 `gitea/main` push 완료