# HMM MCP endpoint와 토큰 설정

## 인증 수단 구분

HMM 포털 로그인과 MCP 호출은 서로 다른 인증 수단을 사용한다.

| 인증 수단 | 사용 위치 | 전달 방식 | MCP 호출 사용 여부 |
|---|---|---|---|
| `__Host-HMM_PORTAL_SESSION` | `hmm.cloud-handson.com` 포털 로그인 | 브라우저 `Secure; HttpOnly` 쿠키 | 사용 금지 |
| `HMM_MCP_BEARER_TOKEN` | 별도 호환 MCP 서버 접근 | HTTP `Authorization: Bearer` | 포털의 공용 gateway에 사용 |
| HMM 직원별 VPD 토큰 | 백오피스 MCP 사용자 인증·DB context | HTTP `Authorization: Bearer` | Agent Factory 사용자별 연동에 사용 |

포털 쿠키를 복사해 MCP Bearer Token으로 사용하면 안 된다. 브라우저 JavaScript에서도 포털 쿠키를
읽을 수 없도록 `HttpOnly`로 설정한다.

## MCP endpoint 구분

두 주소는 같은 토큰을 받지 않는다.

| 항목 | 값 |
|---|---|
| 사용자별 VPD MCP | `https://hmm-backoffice.cloud-handson.com/mcp` |
| 사용자별 인증 | 백오피스에서 발급한 `vpd_live_*` 토큰 원문 |
| 공용 호환 MCP | `https://hmm-mcp.cloud-handson.com/mcp` |
| 공용 인증 | 운영 `HMM_MCP_BEARER_TOKEN` |
| Transport | Streamable HTTP POST |

허용 도구는 다음 세 개다.

| 도구 | 주요 인자 | 용도 |
|---|---|---|
| `search_hr_data` | `query` | 조직, 직원, 휴가 잔여·신청, 근태 조회 |
| `resolve_hr_term` | `term` | 휴가·근태 표현을 표준 용어와 코드로 변환 |
| `search_hr_policy` | `query` | HR 규정 PDF 지식 검색 |

`tools/list`는 `BACKOFFICE_MCP_TOOLS`의 공개 이름·설명·입력 스키마를 광고한다.
`executionType=AGENT_TOOL`인 항목은 애플리케이션 시작 시 기본 datasource 사용자의
`USER_AI_AGENT_TOOLS`에서 `targetName`이 실제로 존재하고 `STATUS=ENABLED`인지 검증한다.
하나라도 누락되거나 비활성이면 서버는 기동을 실패하며 불완전한 Tool 목록을 광고하지 않는다.
`search_hr_data`처럼 `executionType=SELECT_AI`인 Java 자체 구현 Tool은 이 검증 대상이 아니다.

## 포털의 현재 공용 토큰 조합

`config/vpd_token_presets.json`의 현재 조합은 다음과 같다.

| 데모 사용자 | 역할 | `mcp_token_env` |
|---|---|---|
| E1001 Kim Minseo | HR Team Manager | `HMM_MCP_BEARER_TOKEN` |
| E1002 Lee Jiwon | HR Operations Specialist | `HMM_MCP_BEARER_TOKEN` |
| E1003 Park Dohyun | People Analytics Analyst | `HMM_MCP_BEARER_TOKEN` |
| E1005 Han Seojun | Recruiting Specialist | `HMM_MCP_BEARER_TOKEN` |
| E1007 Kang Minho | HR Coordinator | `HMM_MCP_BEARER_TOKEN` |

현재는 모든 preset이 같은 서버 관리 토큰을 쓴다. preset을 바꾸면 질문에 포함되는 데모 사용자
문맥은 바뀌지만, Bearer Token 자체는 바뀌지 않는다. 따라서 이 조합만으로는 사용자별 VPD
보안 경계를 만들지 못한다.

## 포털 설정

`config/mcp_servers.json`에는 토큰 원문 대신 환경변수 이름만 기록한다.

```json
{
  "id": "hmm_hr_mcp",
  "endpoint_url": "https://hmm-mcp.cloud-handson.com/mcp",
  "auth_token_env": "HMM_MCP_BEARER_TOKEN",
  "tool_allowlist": [
    "search_hr_data",
    "resolve_hr_term",
    "search_hr_policy"
  ]
}
```

운영 서버 `/opt/hmm-poc4/.env`에 실제 값이 있어야 한다.

```dotenv
HMM_MCP_BEARER_TOKEN=<MCP 서버에 등록된 동일한 임의 토큰>
POC3_MCP_TIMEOUT_SECONDS=45
```

토큰 원문은 JSON, Git, 대화 기록, 화면 상세에 저장하지 않는다. 환경 파일은 운영 계정만 읽을
수 있게 제한한다.

## 사용자 VPD MCP 직접 호출 예시

```bash
export HMM_USER_BEARER_TOKEN='<백오피스 발급 화면에서 한 번 표시된 원문>'

curl --fail-with-body \
  -H "Authorization: Bearer ${HMM_USER_BEARER_TOKEN}" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  --data '{
    "jsonrpc": "2.0",
    "id": "tools-list-1",
    "method": "tools/list",
    "params": {}
  }' \
  https://hmm-backoffice.cloud-handson.com/mcp

unset HMM_USER_BEARER_TOKEN
```

MCP 서버가 `initialize`와 session ID를 요구하면 다음 순서를 사용한다.

1. `initialize`
2. 응답의 `Mcp-Session-Id` 보관
3. `notifications/initialized`
4. 같은 session header와 Bearer Token으로 `tools/list`
5. 같은 session header와 Bearer Token으로 `tools/call`

## Oracle AI Database Private Agent Factory 설정

| 입력 항목 | 값 |
|---|---|
| Server name | `hmm-backoffice-mcp` |
| Server URL | `https://hmm-backoffice.cloud-handson.com/mcp` |
| Authentication mode | Bearer Token |
| Token | 백오피스에서 해당 직원에게 발급한 토큰 원문. `Bearer ` 문자열은 붙이지 않음 |
| Allowed tools | 위 세 도구만 선택 |
| Timeout | 45초부터 시작 |

이 endpoint는 OAuth authorization endpoint가 아니다. OAuth client ID, client secret,
authorization URL, token URL은 입력하지 않는다.

## 사용자별 VPD 적용 구조

MCP의 표준 `Authorization` header는 하나이므로 “공통 gateway token + 직원 VPD token” 두 개를
같은 header에 조합하지 않는다. 다음 구조가 권장된다.

1. 백오피스에서 E1001, E1002 등 직원별 opaque token을 각각 발급한다.
2. MCP 서버는 그 직원 token 자체를 Bearer Token으로 검증한다.
3. `ADMIN` 연결은 Select AI `SHOWSQL` 생성까지만 수행한다.
4. `EXEMPT ACCESS POLICY`가 없는 `CB_ORDS` 연결에서
   `CB_ORDS_HANDLER_PKG.SET_VPD_CONTEXT('Bearer ' || :token)`을 호출한다.
5. 같은 `CB_ORDS` DB 세션에서 생성된 읽기 전용 SQL로
   `HMM_LEAVE_BALANCES`, `HMM_LEAVE_REQUESTS`를 조회한다.
6. 실행 전 런타임 사용자가 `ADMIN`이 아니고 `EXEMPT ACCESS POLICY`가 없으며,
   `HMM_ACCESS_CTX.EMPLOYEE_CODE`가 토큰 인증 결과와 일치하는지 확인한다.
7. 하나라도 다르면 조회하지 않고 fail-closed 한다.
8. `finally`에서 `CB_ORDS_HANDLER_PKG.CLEAR_VPD_CONTEXT`와 rollback을 수행한다.
9. 서버 관리용 공통 토큰과 직원별 토큰을 동시에 요구해야 한다면 OAuth/API Gateway에서
   application identity와 user subject를 하나의 검증 가능한 access token으로 합친다.

이 흐름은 2026-07-31 백오피스 MCP `search_hr_data`에 적용됐다. 모든 MCP method가 토큰
해시·만료·회수·재직 상태를 확인한다. `search_hr_data`는
`HMM_HR_DATA_GPT54_PROFILE`로 SQL만 생성하고, 실제 SQL은 위 `CB_ORDS` 세션에서 실행한다.
무토큰·무효·회수 토큰은 HTTP 401이다.

운영 환경에는 다음 값이 필요하다.

```dotenv
BACKOFFICE_SELECT_AI_PROFILE=HMM_HR_DATA_GPT54_PROFILE
BACKOFFICE_SELECT_AI_RUNTIME_DB_URL=<ADB JDBC URL>
BACKOFFICE_SELECT_AI_RUNTIME_DB_USERNAME=CB_ORDS
BACKOFFICE_SELECT_AI_RUNTIME_DB_PASSWORD=<운영 secret>
```

DB 구성 스크립트는 `database/adb/73_hmm_mcp_vpd_runtime.sql`이다. 이 스크립트는 승인된 HMM
HR 객체에 대한 개별 `SELECT`와 handler package 실행 권한만 부여하며
`EXEMPT ACCESS POLICY`는 부여하지 않는다.

포털의 `HMM_MCP_BEARER_TOKEN` 공용 preset은 별도 호환 gateway를 사용하는 기존 UI 라우팅이다.
Agent Factory의 사용자별 권한 검증에는 반드시 백오피스 MCP 주소와 직원 토큰을 사용한다.
