khdp 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. khdp-0.1.0/.github/CODEOWNERS +13 -0
  2. khdp-0.1.0/.github/branch-protection.md +52 -0
  3. khdp-0.1.0/.github/workflows/ci.yml +34 -0
  4. khdp-0.1.0/.github/workflows/publish.yml +38 -0
  5. khdp-0.1.0/.gitignore +42 -0
  6. khdp-0.1.0/CONTRIBUTING.md +61 -0
  7. khdp-0.1.0/LICENSE +17 -0
  8. khdp-0.1.0/PKG-INFO +222 -0
  9. khdp-0.1.0/PLAN.md +191 -0
  10. khdp-0.1.0/README.md +185 -0
  11. khdp-0.1.0/SECURITY.md +60 -0
  12. khdp-0.1.0/docs/backend-request.md +129 -0
  13. khdp-0.1.0/docs/example.khdp.local.toml +23 -0
  14. khdp-0.1.0/pyproject.toml +67 -0
  15. khdp-0.1.0/src/khdp/__init__.py +18 -0
  16. khdp-0.1.0/src/khdp/__main__.py +4 -0
  17. khdp-0.1.0/src/khdp/cli.py +227 -0
  18. khdp-0.1.0/src/khdp/config.py +106 -0
  19. khdp-0.1.0/src/khdp/mcp_server.py +231 -0
  20. khdp-0.1.0/src/khdp/oauth.py +220 -0
  21. khdp-0.1.0/src/khdp/session.py +127 -0
  22. khdp-0.1.0/src/khdp/token_store.py +140 -0
  23. khdp-0.1.0/tests/__init__.py +0 -0
  24. khdp-0.1.0/tests/test_auth_client.py +114 -0
  25. khdp-0.1.0/tests/test_config.py +59 -0
  26. khdp-0.1.0/tests/test_session.py +79 -0
  27. khdp-0.1.0/tests/test_token_set.py +60 -0
  28. khdp-0.1.0/tests/test_token_store.py +50 -0
  29. khdp-0.1.0/wrappers/claude-code/README.md +45 -0
  30. khdp-0.1.0/wrappers/claude-code/skills/khdp-auth/SKILL.md +79 -0
  31. khdp-0.1.0/wrappers/codex/AGENTS.md +46 -0
  32. khdp-0.1.0/wrappers/codex/README.md +36 -0
  33. khdp-0.1.0/wrappers/codex/config.example.toml +16 -0
  34. khdp-0.1.0/wrappers/gemini/GEMINI.md +27 -0
  35. khdp-0.1.0/wrappers/gemini/README.md +30 -0
  36. khdp-0.1.0/wrappers/gemini/extension.json +12 -0
  37. khdp-0.1.0/wrappers/gemini/settings.example.json +16 -0
@@ -0,0 +1,13 @@
1
+ # Default owners for everything in the repo.
2
+ * @KoreaHealthDataPlatform/maintainers
3
+
4
+ # Keep auth code under tighter review — anything that touches token
5
+ # handling or HTTP request building requires a security-aware reviewer.
6
+ /src/khdp/oauth.py @KoreaHealthDataPlatform/security
7
+ /src/khdp/token_store.py @KoreaHealthDataPlatform/security
8
+ /src/khdp/session.py @KoreaHealthDataPlatform/security
9
+ /src/khdp/mcp_server.py @KoreaHealthDataPlatform/security
10
+
11
+ # Wrapper configs are usually safe but should still be reviewed by a
12
+ # wrapper-specific owner before merging.
13
+ /wrappers/ @KoreaHealthDataPlatform/maintainers
@@ -0,0 +1,52 @@
1
+ # Recommended branch-protection settings
2
+
3
+ These settings are GitHub repository configuration, not files. Apply
4
+ them via **Settings → Branches → Add rule** on
5
+ <https://github.com/KoreaHealthDataPlatform/KHDPConnector>.
6
+
7
+ ## `main` branch rule
8
+
9
+ - ✅ **Require a pull request before merging**
10
+ - Require approvals: **1**
11
+ - Dismiss stale pull request approvals when new commits are pushed
12
+ - Require review from Code Owners (uses [`.github/CODEOWNERS`](./CODEOWNERS))
13
+ - ✅ **Require status checks to pass before merging**
14
+ - Require branches to be up to date before merging
15
+ - Required checks: `test (ubuntu-latest, 3.10)`, `test (ubuntu-latest, 3.11)`,
16
+ `test (ubuntu-latest, 3.12)`, `test (macos-latest, 3.12)`,
17
+ `test (windows-latest, 3.12)` (from [`ci.yml`](./workflows/ci.yml))
18
+ - ✅ **Require conversation resolution before merging**
19
+ - ✅ **Require signed commits** *(recommended)*
20
+ - ✅ **Require linear history**
21
+ - ✅ **Restrict who can push to matching branches**
22
+ - Limit to the `KoreaHealthDataPlatform/maintainers` team.
23
+ - ✅ **Do not allow bypassing the above settings**
24
+ - ❌ **Allow force pushes** (off)
25
+ - ❌ **Allow deletions** (off)
26
+
27
+ ## Apply via the GitHub CLI
28
+
29
+ If you have admin scope and `gh` 2.40+:
30
+
31
+ ```bash
32
+ gh api -X PUT repos/KoreaHealthDataPlatform/KHDPConnector/branches/main/protection \
33
+ -F required_status_checks.strict=true \
34
+ -F required_status_checks.contexts[]='test (ubuntu-latest, 3.10)' \
35
+ -F required_status_checks.contexts[]='test (ubuntu-latest, 3.11)' \
36
+ -F required_status_checks.contexts[]='test (ubuntu-latest, 3.12)' \
37
+ -F required_status_checks.contexts[]='test (macos-latest, 3.12)' \
38
+ -F required_status_checks.contexts[]='test (windows-latest, 3.12)' \
39
+ -F enforce_admins=false \
40
+ -F required_pull_request_reviews.required_approving_review_count=1 \
41
+ -F required_pull_request_reviews.require_code_owner_reviews=true \
42
+ -F required_pull_request_reviews.dismiss_stale_reviews=true \
43
+ -F required_linear_history=true \
44
+ -F allow_force_pushes=false \
45
+ -F allow_deletions=false \
46
+ -F restrictions=null
47
+ ```
48
+
49
+ > Replace `null` for `restrictions` with the team JSON if you want to
50
+ > enforce a push allowlist. Read the rest of the
51
+ > [Branches API docs](https://docs.github.com/en/rest/branches/branch-protection)
52
+ > for full options.
@@ -0,0 +1,34 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ${{ matrix.os }}
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ os: [ubuntu-latest, macos-latest, windows-latest]
15
+ python-version: ["3.10", "3.11", "3.12"]
16
+
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - name: Set up Python
21
+ uses: actions/setup-python@v5
22
+ with:
23
+ python-version: ${{ matrix.python-version }}
24
+
25
+ - name: Install
26
+ run: |
27
+ python -m pip install --upgrade pip
28
+ pip install -e '.[dev]'
29
+
30
+ - name: Lint
31
+ run: ruff check src tests
32
+
33
+ - name: Test
34
+ run: pytest -q
@@ -0,0 +1,38 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+
8
+ jobs:
9
+ build:
10
+ name: Build sdist + wheel
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - uses: actions/setup-python@v5
15
+ with:
16
+ python-version: "3.12"
17
+ - run: python -m pip install --upgrade build
18
+ - run: python -m build
19
+ - uses: actions/upload-artifact@v4
20
+ with:
21
+ name: dist
22
+ path: dist/
23
+
24
+ publish:
25
+ name: Publish to PyPI
26
+ needs: build
27
+ runs-on: ubuntu-latest
28
+ environment:
29
+ name: pypi
30
+ url: https://pypi.org/p/khdp
31
+ permissions:
32
+ id-token: write # required for PyPI Trusted Publishing
33
+ steps:
34
+ - uses: actions/download-artifact@v4
35
+ with:
36
+ name: dist
37
+ path: dist/
38
+ - uses: pypa/gh-action-pypi-publish@release/v1
khdp-0.1.0/.gitignore ADDED
@@ -0,0 +1,42 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ dist/
9
+ *.egg-info/
10
+ *.egg
11
+ .eggs/
12
+ .venv/
13
+ venv/
14
+ env/
15
+
16
+ # Tests / coverage
17
+ .pytest_cache/
18
+ .coverage
19
+ htmlcov/
20
+ .tox/
21
+ .mypy_cache/
22
+ .ruff_cache/
23
+
24
+ # Editors
25
+ .vscode/
26
+ .idea/
27
+ *.swp
28
+ *.swo
29
+
30
+ # OS
31
+ .DS_Store
32
+ Thumbs.db
33
+
34
+ # KHDP runtime artifacts (never commit tokens)
35
+ *.token
36
+ *.tokens.json
37
+ .khdp/
38
+ khdp.local.toml
39
+
40
+ # Environment
41
+ .env
42
+ .env.local
@@ -0,0 +1,61 @@
1
+ # Contributing to khdp
2
+
3
+ Thanks for your interest. `khdp` is the official OAuth/MCP connector
4
+ for the Korea Health Data Platform. Most contributions land as small,
5
+ focused PRs.
6
+
7
+ ## Local setup
8
+
9
+ ```bash
10
+ git clone https://github.com/KoreaHealthDataPlatform/KHDPConnector.git
11
+ cd KHDPConnector
12
+ python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
13
+ pip install -e '.[dev,keyring]'
14
+ ```
15
+
16
+ ## Before sending a PR
17
+
18
+ ```bash
19
+ ruff check src tests
20
+ pytest
21
+ ```
22
+
23
+ CI runs the same checks across Linux / macOS / Windows on Python
24
+ 3.10–3.12. If your change adds a new tool or endpoint, please add a
25
+ test under `tests/` that exercises it with `pytest-httpx`.
26
+
27
+ ## What we accept
28
+
29
+ - Bug fixes with a clear repro and a regression test.
30
+ - New MCP tools that map to a stable KHDP backend route (open an
31
+ issue first to align on the tool name and schema).
32
+ - Documentation that improves the onboarding path for an external
33
+ AI coding agent.
34
+ - Wrapper updates for new agent platforms (Cursor, Windsurf, …) under
35
+ `wrappers/`.
36
+
37
+ ## What we don't accept (yet)
38
+
39
+ - Code that bypasses KHDP's auth or audit policies.
40
+ - Tools that surface PHI or patient identifiers in agent context.
41
+ - Vendor-specific tool reimplementations — the wrappers carry config
42
+ and prompts only; the tool surface lives in the MCP server.
43
+
44
+ ## Code style
45
+
46
+ - Type-annotated Python 3.10+. We rely on `from __future__ import
47
+ annotations` for forward references.
48
+ - `ruff` enforces formatting and import order. Keep the existing rule
49
+ set in `pyproject.toml`.
50
+ - Public API additions deserve a short docstring explaining the
51
+ *why*, not the *what*. Don't restate the signature.
52
+
53
+ ## Reporting security issues
54
+
55
+ See [SECURITY.md](./SECURITY.md). Don't open public issues for
56
+ suspected vulnerabilities.
57
+
58
+ ## License
59
+
60
+ By submitting a contribution you agree it will be released under the
61
+ project's [Apache-2.0 License](./LICENSE).
khdp-0.1.0/LICENSE ADDED
@@ -0,0 +1,17 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Copyright 2026 Korea Health Data Platform (KHDP)
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
khdp-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,222 @@
1
+ Metadata-Version: 2.4
2
+ Name: khdp
3
+ Version: 0.1.0
4
+ Summary: KHDP connector. CLI + MCP server for Korea Health Data Platform, with wrappers for Claude Code, OpenAI Codex, and Gemini.
5
+ Project-URL: Homepage, https://github.com/KoreaHealthDataPlatform/KHDPConnector
6
+ Project-URL: Repository, https://github.com/KoreaHealthDataPlatform/KHDPConnector
7
+ Project-URL: Issues, https://github.com/KoreaHealthDataPlatform/KHDPConnector/issues
8
+ Project-URL: Documentation, https://github.com/KoreaHealthDataPlatform/KHDPConnector#readme
9
+ Author-email: Korea Health Data Platform <vital@snu.ac.kr>
10
+ License: Apache-2.0
11
+ License-File: LICENSE
12
+ Keywords: healthcare,khdp,mcp,oauth,omop,vitaldb
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: Healthcare Industry
16
+ Classifier: License :: OSI Approved :: Apache Software License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
23
+ Requires-Python: >=3.10
24
+ Requires-Dist: httpx>=0.27
25
+ Requires-Dist: mcp>=1.0
26
+ Requires-Dist: platformdirs>=4.0
27
+ Requires-Dist: pydantic>=2.0
28
+ Provides-Extra: dev
29
+ Requires-Dist: mypy>=1.10; extra == 'dev'
30
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
31
+ Requires-Dist: pytest-httpx>=0.30; extra == 'dev'
32
+ Requires-Dist: pytest>=8.0; extra == 'dev'
33
+ Requires-Dist: ruff>=0.5; extra == 'dev'
34
+ Provides-Extra: keyring
35
+ Requires-Dist: keyring>=24.0; extra == 'keyring'
36
+ Description-Content-Type: text/markdown
37
+
38
+ # KHDPConnector
39
+
40
+ Auth + MCP connector for the **Korea Health Data Platform (KHDP)**.
41
+
42
+ `khdp-connector` is a CLI-first Python package that handles login
43
+ against the KHDP central auth API and exposes the resulting Bearer
44
+ session through a Model Context Protocol (MCP) server. The same MCP
45
+ server backs thin wrappers for **Claude Code**, **OpenAI Codex CLI**,
46
+ and **Gemini CLI** so KHDP authentication looks the same across every
47
+ coding-agent surface.
48
+
49
+ > **Status:** alpha. APIs and tool names will move during Phase 0–1 of
50
+ > the [PLAN.md](./PLAN.md) roadmap.
51
+
52
+ ## How it talks to KHDP
53
+
54
+ The connector uses KHDP's password-based auth API. It implements two
55
+ endpoints that are safe for headless / CLI use:
56
+
57
+ * `POST /_api/oauth/login {appId, redirectUrl, mail, password}` →
58
+ `{accessToken, refreshToken, expireTime}`
59
+ * `POST /_api/member/refresh-token {refreshToken}` →
60
+ same shape, rotated.
61
+
62
+ All subsequent KHDP API calls go out with `Authorization: Bearer
63
+ <accessToken>`.
64
+
65
+ ```
66
+ ┌────────────────────────────────────────────────────────────┐
67
+ │ Claude Code · Codex CLI · Gemini CLI · … │
68
+ │ │ │ │ │
69
+ │ └──────── MCP (stdio JSON-RPC) ───────┐ │
70
+ │ ▼ │
71
+ │ khdp-connector (this) │
72
+ │ │ │
73
+ │ ▼ │
74
+ │ POST /_api/oauth/login POST /_api/member/... │
75
+ │ (login + refresh) (any KHDP endpoint) │
76
+ │ khdp.net │
77
+ └────────────────────────────────────────────────────────────┘
78
+ ```
79
+
80
+ ## Install
81
+
82
+ ```bash
83
+ pipx install khdp-connector # recommended; isolates from system Python
84
+ # or
85
+ pip install khdp-connector
86
+ # or with OS-keychain support:
87
+ pipx install 'khdp-connector[keyring]'
88
+ ```
89
+
90
+ ## One-time configuration
91
+
92
+ You need a KHDP-registered `app_id` (UUID) and a registered
93
+ `redirect_url`. Drop them into a config file or env vars:
94
+
95
+ ```toml
96
+ # ./khdp.local.toml
97
+ app_id = "00000000-0000-0000-0000-000000000000"
98
+ redirect_url = "https://example.org/khdp-cli"
99
+ api_base = "https://khdp.net/_api" # default; override for staging
100
+ ```
101
+
102
+ …or:
103
+
104
+ ```bash
105
+ export KHDP_APP_ID=00000000-0000-0000-0000-000000000000
106
+ export KHDP_REDIRECT_URL=https://example.org/khdp-cli
107
+ ```
108
+
109
+ > **Don't have an `app_id` yet?** Coordinate with the KHDP team to
110
+ > register a CLI-class app. snuh.ai's public `app_id` won't work for
111
+ > the CLI — its `redirect_url` allowlist excludes anything outside
112
+ > `snuh.ai`.
113
+
114
+ ## CLI usage
115
+
116
+ ```bash
117
+ khdp login # prompts for email + password (or use --email / --password-stdin)
118
+ khdp status # is a token cached? when does it expire?
119
+ khdp refresh # force a refresh-token rotation
120
+ khdp api GET /member/me # authenticated KHDP API call
121
+ khdp logout # delete cached tokens
122
+ khdp config # print resolved configuration
123
+ khdp mcp # run the MCP server on stdio (for agents)
124
+ ```
125
+
126
+ Configuration resolution order (highest first):
127
+
128
+ 1. `KHDP_*` environment variables
129
+ 2. `khdp.local.toml` in the current working directory
130
+ 3. `~/.config/khdp/config.toml` (or platform equivalent)
131
+ 4. Built-in defaults
132
+
133
+ For non-interactive use:
134
+
135
+ ```bash
136
+ KHDP_EMAIL=me@example.com khdp login --password-stdin <<< "$KHDP_PASSWORD"
137
+ ```
138
+
139
+ ## MCP server
140
+
141
+ ```bash
142
+ khdp mcp
143
+ # or
144
+ khdp-mcp
145
+ ```
146
+
147
+ Tools exposed on `stdio`:
148
+
149
+ | Tool | Purpose |
150
+ | --- | --- |
151
+ | `khdp_auth_status` | Is the user logged in? When does the token expire? |
152
+ | `khdp_auth_refresh` | Rotate the refresh token to extend the session. |
153
+ | `khdp_auth_logout` | Delete locally cached tokens. |
154
+ | `khdp_api_request` | Authenticated HTTP passthrough to the KHDP API. |
155
+
156
+ The MCP server **never** accepts a password through tool arguments —
157
+ passwords would otherwise flow through the LLM context window. Login
158
+ is initiated out-of-band via `khdp login` in the user's terminal; the
159
+ MCP server just reads the resulting token cache.
160
+
161
+ Future tools (per [PLAN.md](./PLAN.md)) will add dataset I/O, OMOP
162
+ queries, audit log retrieval, and IRB result-pinning.
163
+
164
+ ## Wrappers
165
+
166
+ The same MCP server backs a thin wrapper per agent platform.
167
+
168
+ ### Claude Code
169
+
170
+ ```bash
171
+ claude mcp add khdp -- khdp mcp
172
+ cp -r wrappers/claude-code/skills/khdp-auth ~/.claude/skills/
173
+ ```
174
+
175
+ ### OpenAI Codex CLI
176
+
177
+ Append `wrappers/codex/config.example.toml` to `~/.codex/config.toml`,
178
+ copy `wrappers/codex/AGENTS.md` to your project root.
179
+
180
+ ### Gemini CLI
181
+
182
+ Merge `wrappers/gemini/settings.example.json` into
183
+ `~/.gemini/settings.json`, or install as a Gemini Extension under
184
+ `.gemini/extensions/khdp/`.
185
+
186
+ ## Development
187
+
188
+ ```bash
189
+ git clone https://github.com/KoreaHealthDataPlatform/KHDPConnector.git
190
+ cd KHDPConnector
191
+ python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
192
+ pip install -e '.[dev,keyring]'
193
+ pytest
194
+ ```
195
+
196
+ ## Security model
197
+
198
+ - **No secret in the binary.** The CLI ships only the user-provided
199
+ `app_id`. There is no embedded client secret.
200
+ - **Password never leaves the local machine** unencrypted; it goes
201
+ only to KHDP's TLS endpoint, never to the LLM, never to the MCP
202
+ context. The MCP tool surface deliberately omits a password
203
+ argument.
204
+ - **Per-app token isolation.** Multiple KHDP apps on one machine are
205
+ kept separate by `app_id`.
206
+ - **Token storage.** OS keychain (Keychain / Credential Manager /
207
+ Secret Service) when the `keyring` extra is installed; otherwise a
208
+ JSON file with `0600` permissions in the platform user-config dir.
209
+ - **No revocation endpoint exposed by KHDP today.** `khdp logout` only
210
+ clears local state. Access tokens expire naturally; refresh tokens
211
+ go invalid the next time the access token is rotated.
212
+
213
+ ## Roadmap
214
+
215
+ See [PLAN.md](./PLAN.md) for the full roadmap. The current
216
+ implementation covers Phase 1 (auth) and a generic API passthrough.
217
+ Dataset I/O, OMOP analysis, and IRB-grade result pinning land in later
218
+ phases.
219
+
220
+ ## License
221
+
222
+ Apache 2.0. See [LICENSE](./LICENSE).
khdp-0.1.0/PLAN.md ADDED
@@ -0,0 +1,191 @@
1
+ # KHDP 커넥터 아키텍처 계획
2
+
3
+ ## 목적
4
+
5
+ KHDP 데이터 및 도구를 외부 AI 코딩 에이전트(Claude Code, Codex CLI, OpenCode, Cursor 등)에서 안전하고 일관되게 사용할 수 있도록 하는 커넥터 레이어를 설계한다. 특정 LLM 벤더에 종속되지 않으면서, KHDP의 인증·감사·접근통제 정책을 클라이언트 환경과 무관하게 서버 측에서 강제하는 것이 목표.
6
+
7
+ ## 설계 원칙
8
+
9
+ 1. **Vendor neutrality**: 의료 데이터 인프라는 다년(5–10년) 단위로 운영되는 반면 LLM 벤더 지형은 1–2년 단위로 변한다. 도구 인터페이스는 벤더 중립 표준(MCP)을 1차로 채택한다.
10
+ 2. **Server-enforced security**: 인증·권한·감사 로그는 클라이언트가 무엇이든(LLM 추론이든 사람이든) 서버 측에서 강제된다. 클라이언트가 보안 프로토콜을 재구현하지 않는다.
11
+ 3. **Reusable across surfaces**: 같은 백엔드를 MCP, CLI, 웹 UI, CI 환경에서 모두 동일하게 사용할 수 있어야 한다.
12
+ 4. **Defense in depth**: manifest 기반 access control, AES-GCM URL 토큰, k-anonymity egress control 등 기존 KHDP 보안 레이어와 정합적으로 통합된다.
13
+ 5. **Auditability over flexibility**: IRB·내부자 위협 모델에 부합하도록, 호출 경로의 자유도보다 감사 가능성을 우선한다.
14
+
15
+ ## 3-tier 구조
16
+
17
+ ```
18
+ ┌─────────────────────────────────────────────────────────────┐
19
+ │ Tier 3: Vendor-specific 자산 (선택적) │
20
+ │ - Anthropic Skills (SKILL.md + 보조 스크립트) │
21
+ │ - GPTs Custom Actions, Gemini Extensions 등 │
22
+ └─────────────────────────────────────────────────────────────┘
23
+ ↓ 참조
24
+ ┌─────────────────────────────────────────────────────────────┐
25
+ │ Tier 2: 벤더 중립 가이드 (KHDP_AGENT_GUIDE.md) │
26
+ │ - 도메인 워크플로우, 도구 사용 순서, 컨벤션 │
27
+ │ - AGENTS.md / CLAUDE.md 형식으로 호환 │
28
+ └─────────────────────────────────────────────────────────────┘
29
+ ↓ 호출
30
+ ┌─────────────────────────────────────────────────────────────┐
31
+ │ Tier 1: KHDP MCP 서버 (1차 산출물) │
32
+ │ - 결정론적 도구 노출 (auth, dataset I/O, OMOP query) │
33
+ │ - 인증/감사/권한 캡슐화 │
34
+ └─────────────────────────────────────────────────────────────┘
35
+ ↓ 호출
36
+ ┌─────────────────────────────────────────────────────────────┐
37
+ │ KHDP Backend (snuh.ai) │
38
+ │ - manifest registry, OMOP CDM, audit log, RID issuer │
39
+ └─────────────────────────────────────────────────────────────┘
40
+ ```
41
+
42
+ ## Tier 1: KHDP MCP 서버
43
+
44
+ ### 노출 도구 (초안)
45
+
46
+ **인증**
47
+ - `khdp_auth_status` — 현재 인증 상태와 사용자 컨텍스트 조회
48
+ - `khdp_auth_login` — OAuth 부트스트랩 (loopback redirect 처리)
49
+ - `khdp_auth_logout` — 토큰 폐기
50
+
51
+ **데이터셋 I/O**
52
+ - `khdp_dataset_list` — 권한 있는 데이터셋 목록 조회 (manifest 기반)
53
+ - `khdp_dataset_describe` — 데이터셋 메타데이터·스키마·라이선스 조회
54
+ - `khdp_dataset_download` — 데이터셋 다운로드 (RID 기반 AES-GCM URL 발급)
55
+ - `khdp_dataset_upload` — 데이터셋 업로드 (PHI 스캔·manifest 등록 포함)
56
+
57
+ **OMOP CDM 분석**
58
+ - `khdp_omop_describe_table` — OMOP 테이블 스키마와 row 수
59
+ - `khdp_omop_find_concept` — concept_id ↔ 명칭 검색 (vocabulary 통합)
60
+ - `khdp_omop_sample_rows` — 테이블 샘플 (egress 정책 적용)
61
+ - `khdp_omop_query` — DuckDB 기반 read-only SQL 실행 (k-anonymity·row limit)
62
+
63
+ **감사·재현성**
64
+ - `khdp_audit_log_query` — 본인의 호출 이력 조회
65
+ - `khdp_result_pin` — IRB 재현성 요건 충족용 결과·쿼리·환경 스냅샷 저장
66
+
67
+ ### 인증 모델
68
+
69
+ - **OAuth 2.0 + PKCE (loopback)** 채택. RFC 8252 권장 패턴.
70
+ - 서버 사이드 배포 시 `https://khdp.net/oauth/callback`, 로컬 MCP는 `http://127.0.0.1:<port>/callback`.
71
+ - Refresh token은 클라이언트 머신에 0600 퍼미션으로 저장, OS keychain 통합 옵션 검토.
72
+ - 모든 토큰은 사용자 단위. 다중 사용자 머신에서는 사용자별 격리.
73
+
74
+ ### 감사 로그 통합
75
+
76
+ - 모든 MCP 도구 호출은 (user_id, tool, params_hash, timestamp, client_ua, result_status) 튜플로 immutable log에 기록.
77
+ - `params_hash`는 PHI를 평문 저장하지 않기 위해 정규화 후 해시.
78
+ - IRB 감사 시 `khdp_result_pin`으로 고정된 결과만 재현성 보장 대상.
79
+
80
+ ### 기술 스택 (잠정)
81
+
82
+ - **언어**: Python 3.12 (KHDP 기존 인프라 호환)
83
+ - **MCP SDK**: 공식 Python SDK (`mcp` 패키지)
84
+ - **데이터 액세스**: DuckDB (read-only concurrent connection), 기존 KHDP storage layer 재사용
85
+ - **배포**: 로컬 모드(stdio)와 원격 모드(HTTP+SSE) 둘 다 지원
86
+ - **컨테이너**: 기존 Firecracker/gVisor 샌드박스 정책과 동일한 격리 수준
87
+
88
+ ## Tier 2: 벤더 중립 가이드 (KHDP_AGENT_GUIDE.md)
89
+
90
+ OpenAI 진영의 `AGENTS.md`, Anthropic 진영의 `CLAUDE.md` 양쪽 모두에서 자연스럽게 참조되도록 작성.
91
+
92
+ ### 포함 내용
93
+
94
+ - KHDP MCP 도구 카탈로그 요약
95
+ - 도메인 워크플로우 (예시)
96
+ - "OMOP 코호트 분석 시: `find_concept` → `describe_table` → `sample_rows` → `query` 순서. 단일 SQL로 끝내려 하지 말고 코딩 에이전트 루프 활용."
97
+ - "데이터셋 업로드 전: 반드시 PHI 스캔 도구로 검증. manifest는 자동 생성됨."
98
+ - "결과를 논문/IRB 보고서에 인용할 경우 `khdp_result_pin` 필수."
99
+ - 안 되는 것 명시 (negative examples)
100
+ - 의료 판단·진단·생성 표현 회피 (UI 카피 정책과 동일)
101
+ - 환자 식별자 평문 출력 금지
102
+ - egress 한도를 우회하려는 다단 쿼리 분해 금지
103
+
104
+ ### 배포 위치
105
+
106
+ - KHDP 공식 문서 사이트 (`docs.khdp.net/agent-guide`)
107
+ - 프로젝트 워크스페이스 루트에 자동 배치되는 옵션 제공 (`khdp init` 시)
108
+
109
+ ## Tier 3: 벤더별 자산 (선택적)
110
+
111
+ ### Anthropic Skill
112
+
113
+ - `khdp-omop-analysis/SKILL.md` — OMOP 분석 워크플로우 자동 트리거
114
+ - `khdp-dataset-management/SKILL.md` — 데이터셋 입출력 워크플로우
115
+ - 보조 스크립트(검증·정규화)를 함께 패키징
116
+ - Claude Code 사용자에게 자동 발견·로드되는 편의 기능
117
+
118
+ ### 기타 (필요 시)
119
+
120
+ - Cursor `.cursorrules`, Windsurf rules 등 IDE별 설정 어댑터
121
+ - OpenAI Custom GPT용 OpenAPI 스펙 (MCP 서버를 HTTP로 노출 시 자동 생성 가능)
122
+
123
+ ## 단계별 로드맵
124
+
125
+ ### Phase 0: 설계 확정 (현재)
126
+ - [ ] 노출 도구 시그니처 확정 (위 초안 검토)
127
+ - [ ] 인증 모델 결정: OAuth scope 정의, refresh token 저장 정책
128
+ - [ ] 감사 로그 스키마 확정 (기존 audit log와 통합)
129
+ - [ ] MCP transport 결정: 로컬 stdio 우선 / 원격 HTTP는 후속
130
+
131
+ ### Phase 1: MVP MCP 서버
132
+ - [ ] 인증 도구 (`auth_status`, `auth_login`, `auth_logout`)
133
+ - [ ] 읽기 전용 도구 (`dataset_list`, `dataset_describe`, `omop_describe_table`)
134
+ - [ ] 단일 사용자, stdio transport, 로컬 실행
135
+ - [ ] 단위 테스트 + audit log smoke test
136
+
137
+ ### Phase 2: 데이터 입출력
138
+ - [ ] `dataset_download` (AES-GCM URL 발급 통합)
139
+ - [ ] `dataset_upload` (PHI 스캔, manifest 자동 생성)
140
+ - [ ] 토큰 갱신 자동화
141
+
142
+ ### Phase 3: OMOP 분석 도구
143
+ - [ ] `omop_find_concept`, `omop_sample_rows`, `omop_query`
144
+ - [ ] k-anonymity egress 정책 통합
145
+ - [ ] DuckDB read-only concurrent 연결 풀
146
+
147
+ ### Phase 4: 재현성 + 다중 사용자
148
+ - [ ] `khdp_result_pin` (결과 스냅샷)
149
+ - [ ] 원격 HTTP transport (다중 사용자 시나리오)
150
+ - [ ] per-user credential 격리 검증
151
+
152
+ ### Phase 5: Tier 2/3 자산
153
+ - [ ] `KHDP_AGENT_GUIDE.md` 작성·배포
154
+ - [ ] Anthropic Skill 패키징
155
+ - [ ] 외부 에이전트 호환성 검증 (Claude Code, Codex CLI, OpenCode, Cursor 각각)
156
+
157
+ ## 결정 필요 항목
158
+
159
+ ### 1. 인증 backend
160
+ - (a) infmedix 자체 OAuth provider 구축 (KCMVP 모듈 OEM 라인 활용)
161
+ - (b) 기존 SNUH SSO 연동
162
+ - (c) 단기적으로 API key + 장기적으로 OAuth 마이그레이션
163
+ - → 1차 의견: (c). MVP 부담을 줄이고, OAuth는 다중 사용자 단계(Phase 4)에서 도입.
164
+
165
+ ### 2. MCP 서버 배포 위치
166
+ - (a) 사용자 로컬 머신 (stdio)
167
+ - (b) snuh.ai 서버 사이드 (HTTP+SSE)
168
+ - (c) 둘 다 지원
169
+ - → 1차 의견: (c). MVP는 (a)로 시작, Phase 4에서 (b) 추가. 로컬은 단일 연구자 자동화에, 원격은 IRB 감사·다중 사용자 환경에.
170
+
171
+ ### 3. 의료 데이터 egress 정책
172
+ - MCP 도구가 반환하는 데이터의 row limit, 컬럼 마스킹, k-anonymity 임계값을 어디서 결정할 것인가
173
+ - → MCP 서버가 아닌 KHDP backend의 기존 egress control layer에서 강제. MCP는 단순 패스스루.
174
+
175
+ ### 4. 외부 호환성 검증 범위
176
+ - 어느 에이전트까지 1차 지원 대상으로 명시할 것인가
177
+ - → 1차 의견: Claude Code, Codex CLI, OpenCode를 우선. Cursor·Windsurf는 best-effort.
178
+
179
+ ## 위험 요소
180
+
181
+ - **MCP 표준 변동성**: 2024–2026년 동안 빠르게 진화 중. transport, auth, 권한 모델이 바뀔 여지. → 추상화 레이어로 격리, SDK 버전 핀.
182
+ - **다중 LLM의 도구 호출 비결정성**: 같은 MCP 도구를 모델마다 다르게 호출. → Tier 2 가이드 + 도구 시그니처 엄격화로 완충.
183
+ - **OAuth 부트스트랩 UX**: 의료 연구자(비개발자)에게 loopback OAuth는 낯섦. → CLI 한 줄 명령(`khdp login`)으로 캡슐화.
184
+ - **Skill vs MCP 중복 유지보수**: Tier 1과 Tier 3가 중복 진화하지 않도록 Tier 3는 워크플로우(가이드)에만 집중하고 도구 자체는 절대 재구현하지 않음.
185
+
186
+ ## 참고
187
+
188
+ - MCP 사양: https://modelcontextprotocol.io
189
+ - RFC 8252 (OAuth for Native Apps), RFC 7636 (PKCE)
190
+ - Anthropic Agent Skills 문서
191
+ - KHDP 기존 설계 문서: AES-GCM URL 스킴, manifest access control, k-anonymity egress