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.
- khdp-0.1.0/.github/CODEOWNERS +13 -0
- khdp-0.1.0/.github/branch-protection.md +52 -0
- khdp-0.1.0/.github/workflows/ci.yml +34 -0
- khdp-0.1.0/.github/workflows/publish.yml +38 -0
- khdp-0.1.0/.gitignore +42 -0
- khdp-0.1.0/CONTRIBUTING.md +61 -0
- khdp-0.1.0/LICENSE +17 -0
- khdp-0.1.0/PKG-INFO +222 -0
- khdp-0.1.0/PLAN.md +191 -0
- khdp-0.1.0/README.md +185 -0
- khdp-0.1.0/SECURITY.md +60 -0
- khdp-0.1.0/docs/backend-request.md +129 -0
- khdp-0.1.0/docs/example.khdp.local.toml +23 -0
- khdp-0.1.0/pyproject.toml +67 -0
- khdp-0.1.0/src/khdp/__init__.py +18 -0
- khdp-0.1.0/src/khdp/__main__.py +4 -0
- khdp-0.1.0/src/khdp/cli.py +227 -0
- khdp-0.1.0/src/khdp/config.py +106 -0
- khdp-0.1.0/src/khdp/mcp_server.py +231 -0
- khdp-0.1.0/src/khdp/oauth.py +220 -0
- khdp-0.1.0/src/khdp/session.py +127 -0
- khdp-0.1.0/src/khdp/token_store.py +140 -0
- khdp-0.1.0/tests/__init__.py +0 -0
- khdp-0.1.0/tests/test_auth_client.py +114 -0
- khdp-0.1.0/tests/test_config.py +59 -0
- khdp-0.1.0/tests/test_session.py +79 -0
- khdp-0.1.0/tests/test_token_set.py +60 -0
- khdp-0.1.0/tests/test_token_store.py +50 -0
- khdp-0.1.0/wrappers/claude-code/README.md +45 -0
- khdp-0.1.0/wrappers/claude-code/skills/khdp-auth/SKILL.md +79 -0
- khdp-0.1.0/wrappers/codex/AGENTS.md +46 -0
- khdp-0.1.0/wrappers/codex/README.md +36 -0
- khdp-0.1.0/wrappers/codex/config.example.toml +16 -0
- khdp-0.1.0/wrappers/gemini/GEMINI.md +27 -0
- khdp-0.1.0/wrappers/gemini/README.md +30 -0
- khdp-0.1.0/wrappers/gemini/extension.json +12 -0
- 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
|