ev-failure-safe-mcp
by kinorossiuk
README.md
# EV Failure Safe MCP
AI가 차량 정보, 충전기 상태, 주행 가능 거리, 경로를 종합하여 충전 실패 가능성이 낮은 충전소를 추천하는 PlayMCP 서버
[](LICENSE)




사용자의 차량, 남은 주행거리, 출발지·목적지, 커넥터 조건을 받아 실제 공공 충전소 데이터와 경로 정보를 기준으로 후보를 정렬합니다. 단순한 거리순 검색보다 **충전 실패 위험을 낮추는 의사결정**에 초점을 둡니다.
## Demo
| 구분 | 링크 | 상태 |
| --- | --- | --- |
| PlayMCP | [EV Failure Safe MCP 사용하기](https://playmcp.kakao.com/mcp/66400934103681548) | 운영 중 |
| GitHub | [현재 저장소](./) | 소스 코드 |
| Web Demo | 추후 추가 예정 | 배포형 데모 사이트 준비 예정 |
### PlayMCP 서비스 화면
<p align="center">
<a href="docs/assets/playmcp-service-overview.jpg">
<img src="docs/assets/playmcp-service-overview.jpg" alt="EV Failure Safe MCP의 PlayMCP 서비스 소개 및 도구 목록 화면" width="900">
</a>
</p>
<p align="center"><sub>온라인 상태, 8개 MCP 도구, 주요 대화 예시를 제공하는 PlayMCP 서비스 화면</sub></p>
### 충전소 추천 결과
<p align="center">
<a href="docs/assets/playmcp-recommendation-result.jpg">
<img src="docs/assets/playmcp-recommendation-result.jpg" alt="강남역에서 잠실로 이동하는 경로의 충전소 추천 결과 화면" width="360">
</a>
</p>
<p align="center"><sub>PlayMCP AI 채팅에서 경로 기반 충전소 추천 결과를 반환한 모바일 화면</sub></p>
## Table of Contents
- [Demo](#demo)
- [Problem & Solution](#problem--solution)
- [Architecture](#architecture)
- [Core MCP Tools](#core-mcp-tools)
- [Quality Engineering](#quality-engineering)
- [Test Strategy](#test-strategy)
- [Performance & Reliability](#performance--reliability)
- [Quick Start](#quick-start)
- [Data Policy](#data-policy)
- [Vehicle Profiles](#vehicle-profiles)
- [Static Charger Master](#static-charger-master)
- [Kakao Cloud Deployment](#kakao-cloud-deployment)
- [Roadmap](#roadmap)
- [Operations](#operations)
- [Sources & License](#sources--license)
## Problem & Solution
### Problem
- 차량 커넥터와 충전기 타입이 맞지 않을 수 있습니다.
- 충전기가 고장 상태일 수 있습니다.
- 도착 시 사용 가능한 충전 포트가 없을 수 있습니다.
- 목적지나 실제 이동 경로에서 지나치게 벗어난 충전소가 추천될 수 있습니다.
- 공공 API가 느리거나 실패하면 추천에 필요한 실데이터를 확보하기 어렵습니다.
### Solution
- 차량 프로필과 명시된 커넥터 조건을 추천에 반영합니다.
- 커넥터 호환성, 운영 상태, 상태 최신성, 사용 가능 포트를 함께 평가합니다.
- 남은 주행거리와 경로 정보를 이용해 도달 가능성과 우회 위험을 고려합니다.
- 공공 API 응답, 최근 캐시, 정적 충전소 마스터 등 확인 가능한 데이터만 사용합니다.
- 데이터가 부족하면 제한 사항을 알리고, 가짜 충전소나 임의 상태값을 생성하지 않습니다.
## Architecture
```text
Vehicle / Request
↓
Recommendation Engine
↓
┌─────────────────────────────────────────────────┐
│ Public EV API │ Kakao Local │ Kakao Mobility │
│ KEPCO (optional) │
└─────────────────────────────────────────────────┘
↓
Failure-risk Ranking
↓
MCP Response
```
추천 엔진은 커넥터 호환성, 도달 가능성, 상태 최신성, 사용 가능 포트, 경로 위험, 참고 비용을 기준으로 후보를 정렬합니다. 외부 API 지연이나 실패 시에는 캐시와 정적 마스터를 활용하고, 확인된 후보가 없으면 빈 결과와 제한 사항을 반환합니다.
## Core MCP Tools
| MCP tool | 역할 |
| --- | --- |
| `ev_failure_safe_recommend` | 차량·커넥터·충전 속도·남은 주행거리·경로를 기준으로 실패 위험이 낮은 후보를 정렬합니다. |
| `ev_charge_stop_plan` | 추천 충전소 한 곳, 카카오맵 길찾기 링크, 예상 비용, 공유 메시지를 하나의 실행 계획으로 만듭니다. |
| `ev_charger_search` | 지역, 커넥터, 급속·완속 조건으로 충전소를 검색합니다. |
| `place_search` | Kakao Local API로 장소를 검색합니다. |
| `meeting_place_recommend` | 여러 출발지를 고려해 약속 장소 후보를 추천합니다. |
| `map_link` | 카카오맵 지도·길찾기 링크를 생성합니다. |
| `share_message` | 카카오톡에 붙여넣기 좋은 공유 메시지를 생성합니다. |
| `service_status` | 서버 상태와 외부 API 키 설정 여부를 확인합니다. |
## Quality Engineering
| 품질 활동 | 현재 구현 | 검증 목적 |
| --- | --- | --- |
| Smoke Test | 서버를 별도 프로세스로 기동한 뒤 `/health`, MCP `initialize`, `tools/list`, `tools/call`을 확인합니다. | 배포 후보의 기본 실행 가능성과 MCP 연결 계약 검증 |
| Stub 기반 성능 테스트 | 외부 EV API 응답과 타임아웃을 stub으로 제어합니다. | 네트워크 변동을 배제한 응답 예산·성능 회귀 검증 |
| API Timeout 제어 | 공공 EV API, Kakao Mobility, KEPCO에 각각 제한 시간을 둡니다. | 느린 외부 의존성이 전체 MCP 응답을 점유하지 않도록 제어 |
| Cache 전략 | fresh·stale 캐시, 영속 EV 캐시, 백그라운드 갱신, 동일 요청 병합을 사용합니다. | 응답 시간과 데이터 가용성의 균형 검증 |
| Failure Recovery | 실시간 조회 실패 시 유효 범위의 실제 캐시 또는 정적 마스터 후보를 사용합니다. | 외부 장애 상황에서도 확인 가능한 데이터로 안전하게 축소 운영 |
| Static Master Data | `data/static-chargers.ndjson` 읽기 전용 마스터를 지원합니다. | 콜드 캐시·공공 API 지연 상황의 후보 가용성 확보 |
| Verification Script | `npm run verify`가 전체 Node.js 테스트 후 smoke test를 순차 실행합니다. | 기능 회귀와 실행 가능성을 한 번에 확인 |
| No Fake Data Policy | API 실패 시 가짜 충전소, 임의 운영 상태, 임의 가용 포트를 만들지 않습니다. | 불확실한 데이터를 사실처럼 노출하는 품질 위험 방지 |
테스트는 정상 흐름뿐 아니라 잘못된 입력, 커넥터 범위, 상태 최신성, 타임아웃, stale cache, 정적 마스터 fallback, 경로, 요금 안내 등 실패 가능성이 높은 경계를 다룹니다.
## Test Strategy
```bash
npm test
npm run perf
npm run smoke
npm run verify
```
| 명령 | 검증 범위 | 외부 API 의존 |
| --- | --- | --- |
| `npm test` | `test/*.test.js`를 순차 실행해 MCP core, 입력 검증, 차량·커넥터 규칙, 추천 안전성, 캐시·타임아웃·fallback, 경로, 요금, UI 계약을 검증합니다. | 테스트 대역 사용 |
| `npm run perf` | 정적 지역 alias, 모호한 위치 입력 차단, upstream timeout 상황의 MCP 응답 예산과 성능 게이트를 검증합니다. | EV API stub 사용 |
| `npm run smoke` | 로컬 서버를 기동하고 health check, MCP 초기화, tool 목록, `service_status` 호출까지 확인합니다. | 키 없이 기본 계약 검증 가능 |
| `npm run verify` | `npm test && npm run smoke`를 순차 실행합니다. | 각 하위 명령과 동일 |
> `npm run verify`에는 `npm run perf`가 포함되지 않습니다. 성능 게이트는 별도로 실행합니다.
## Performance & Reliability
아래 값은 측정 결과를 임의로 작성한 것이 아니라 현재 설정과 성능 스크립트에 정의된 **기본값·상한·테스트 게이트**입니다.
### Runtime Budget
| 항목 | 현재 값 | 의미 |
| --- | ---: | --- |
| MCP tool response budget | `2,900 ms` | `TOOL_RESPONSE_TIMEOUT_MS` 기본값이자 코드상 최대값 |
| Public EV API timeout | `2,000 ms` | 일반·cold 조회 기본 timeout |
| Public EV slow timeout | `2,500 ms` | 완속 조회 기본 timeout |
| Public EV slow page timeout | `2,000 ms` | 완속 페이지 단위 조회 timeout |
| Kakao Mobility timeout | `2,500 ms` | 자동차 길찾기 요청 timeout |
| KEPCO timeout | `2,500 ms` | 선택 연동 시 운영 정보 요청 timeout |
| Static search radius | `3,000 m` | 정적 충전소 기본 탐색 반경 |
### Cache & Recovery
| 항목 | 현재 값 | 의미 |
| --- | ---: | --- |
| EV fresh cache TTL | `10분` | 조회 후 fresh cache로 취급하는 기본 구간 |
| EV stale cache limit | `30분` | 조회 시점부터 stale cache를 허용하는 기본 최대 구간 |
| Kakao directions cache TTL | `15분` | 동일 경로 조회 결과 재사용 |
| Kakao region cache TTL | `24시간` | 지역 해석 결과 재사용 |
| KEPCO fresh / stale cache | `10분 / 30분` | 선택 연동 결과의 fresh·stale 구간 |
| EV API error cooldown | `5분` | 최근 upstream 실패 후 반복 호출 억제 |
| EV API daily safety limit | `96,000회` | 애플리케이션 기본 일일 호출 상한 |
EV·KEPCO·TMAP 캐시 관련 TTL은 코드에서 최대 30분으로 제한됩니다. 공공 EV API의 온라인 재시도 기본값은 `0`이며, 넓은 범위의 갱신은 사용자 응답을 오래 막지 않도록 캐시·백그라운드 경로로 분리합니다.
### Performance Gates
| 게이트 | 통과 기준 |
| --- | ---: |
| Static alias search p99 | `≤ 250 ms` |
| Ambiguous input guard p99 | `≤ 100 ms` |
| Overall average | `≤ 100 ms` |
| Overall p99 | `≤ 3,000 ms` |
| Upstream timeout scenario | MCP tool budget `2,900 ms` 이내 |
이 값들은 `scripts/perf-test.js`의 stub 기반 회귀 기준입니다. 실제 외부 API 응답 속도를 보장하는 수치가 아닙니다.
## Quick Start
### 1. 환경 변수 준비
```bash
cp .env.example .env
```
최소 실행에 필요한 값:
```bash
KAKAO_REST_API_KEY=your_kakao_rest_api_key
EV_API_SERVICE_KEY=your_public_data_decoding_key
```
`KEPCO_API_KEY`가 있으면 Kakao Local 기반 완속 후보를 한국전력공사 충전소 운영 정보로 추가 보강합니다. 키가 없거나 조회에 실패하면 임의 데이터를 대신 만들지 않습니다.
### 2. 로컬 실행
```bash
npm start
```
| 용도 | URL |
| --- | --- |
| 브라우저 데모 | `http://127.0.0.1:3000` |
| MCP endpoint | `POST http://127.0.0.1:3000/mcp` |
| 상태 확인 | `GET http://127.0.0.1:3000/health` |
### 3. JSON-RPC 호출 예시
```bash
curl -s http://127.0.0.1:3000/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"ev_failure_safe_recommend","arguments":{"area":"강남역","destination":"잠실","connector":"dc_combo","speed":"fast","remainingRangeKm":60,"vehicleProfileId":"kia-niro-ev-2025","size":3}}}'
```
## Data Policy
| 데이터 | 사용 방식 |
| --- | --- |
| 충전소 | 한국환경공단 전기자동차 충전소 공공데이터 |
| 장소 | Kakao Local API |
| 경로 | Kakao Mobility 자동차 길찾기와 카카오맵 링크 |
| 선택 운영 정보 | `KEPCO_API_KEY`가 설정된 경우 한국전력공사 API로 완속 후보 보강 |
| 장애 대응 | 공공 API 결과, 최근 실제 캐시, 정적 마스터 중 확인 가능한 데이터 사용 |
| 충전 비용 | 급속·완속 평균 단가 기반 참고 금액 |
### No Fake Data Policy
- API가 실패하면 확인 가능한 후보만 표시합니다.
- 가짜 충전소나 임의 상태값을 생성하지 않습니다.
- 실시간 사업자 요금을 확보하지 못한 경우 평균 단가 기반 참고 금액임을 알립니다.
### 민간 충전사업자별 요금
민간 충전사업자별 실시간 요금 기능은 현재 범위에 포함하지 않습니다. 회원·비회원·로밍·충전 출력·개별 충전소 정책에 따라 요금이 달라지고, 공식 데이터 이용 허가와 지속적인 수집·검수·서버 운영이 필요하기 때문입니다.
현재는 급속·완속 평균 단가로 참고 비용만 계산하며, 실제 결제 요금은 운영사 앱이나 공식 안내에서 확인하도록 안내합니다. 공식 API 또는 데이터 파일과 재표시 권한을 확보하고 운영 비용을 감당할 수 있을 때 별도 기능으로 재검토합니다.
## Vehicle Profiles
`data/vehicle-profiles.ndjson`에는 국내 판매 또는 운용 가능성이 높은 전기차 프로필이 들어 있습니다. 현대, 기아, 제네시스, KGM, 르노, 쉐보레, 테슬라 차량을 포함하며, 차량별 커넥터·배터리·효율·권장 충전 조건을 추천 로직에 사용합니다.
프로필 데이터는 추천 품질을 높이기 위한 보조 데이터입니다. 실제 충전 가능 여부는 충전소 운영 상태, 차량 트림, 연식, 어댑터 사용 여부에 따라 달라질 수 있습니다.
저장소에서 확인되는 범위에는 제조사 사이트를 반복 호출하는 차량 제원 크롤러가 없고, 서비스 실행 중에도 제조사 사이트를 조회하지 않습니다. 현재 101개 프로필은 공개된 제조사 페이지에서 확인한 일부 제원 사실을 정적 파일로 선별·정규화한 것이며, 페이지 원문·이미지·개인정보를 저장하지 않습니다.
단, 각 레코드의 `sourceUrl`과 `sourceCheckedAt`은 출처 이력이지 제조사의 재이용 허가 증명이 아닙니다. 현재 저장소에는 제조사별 서면 허가 또는 데이터 재이용 라이선스 증빙이 없으므로 차량 프로필을 **이용허락이 확인된 데이터**라고 표시하지 않습니다. 상업 운영이나 제3자 재배포 전에는 제조사별 최신 약관과 필요한 허가를 별도로 확인해야 합니다.
자세한 내용은 [차량 프로필 문서](docs/vehicle-profiles.md)를 확인하세요.
## Static Charger Master
`data/static-chargers.ndjson`는 공공 API가 느리거나 실패할 때 활용하는 읽기 전용 충전소 마스터입니다. 현재 데이터는 주요 권역 중심이며, 휴게소·고속도로 충전소는 운영 전 추가 보강 대상입니다.
정적 마스터 수집 대상 확인:
```bash
npm run collect:static-ev -- --profile=major-cities --rows=5000 --dry-run
```
휴게소 후보만 보강:
```bash
npm run collect:static-ev -- --zscodes=47150,47850 --rows=1000 --highway-only=true
```
시도 단위 조회는 응답량이 커서 타임아웃될 수 있습니다. 실패하면 시군구 단위와 작은 `--rows` 값으로 나눠 실행하는 편이 안정적입니다.
## Kakao Cloud Deployment
예선 단계에서는 GitHub private repository를 Kakao Cloud 소스 빌드에 연결하는 흐름을 권장합니다. 이 프로젝트는 Node.js 22 이상 표준 기능 중심으로 구성되어 있으며, `Dockerfile`도 함께 제공합니다.
### 필수 환경 변수
```bash
HOST=0.0.0.0
PORT=<Kakao Cloud assigned port>
KAKAO_REST_API_KEY=<Kakao Developers REST API key>
EV_API_SERVICE_KEY=<공공데이터포털 Decoding 인증키>
ALLOWED_ORIGINS=https://playmcp.kakao.com
```
### 운영 권장 환경 변수
```bash
EV_CACHE_TTL_MS=600000
EV_CACHE_STALE_MS=1800000
TOOL_RESPONSE_TIMEOUT_MS=2900
EV_API_TIMEOUT_MS=2000
EV_API_DAILY_LIMIT=96000
EV_STATIC_FIRST=true
EV_STATIC_SEARCH_RADIUS_METERS=3000
EV_FAST_AVERAGE_PRICE_PER_KWH=347
EV_SLOW_AVERAGE_PRICE_PER_KWH=347
```
### 선택 연동
| 환경 변수 | 용도 |
| --- | --- |
| `KEPCO_API_KEY` | 한국전력공사 충전소 운영 정보 보강 |
| `TMAP_ENABLED=false` | TMAP 조회 비활성화 권장 |
| `TMAP_API_KEY` | TMAP을 명시적으로 사용할 때만 설정 |
| `EV_PRICE_FILE` | 운영사별 단가 JSON 파일 |
등록할 PlayMCP endpoint:
```text
https://<cloud-endpoint>/mcp
```
자세한 배포 점검은 [Kakao Cloud 체크리스트](docs/kakao-cloud-checklist.md)를 확인하세요.
## Roadmap
- [x] MCP Tool 구현
- [x] 한국환경공단 공공 EV API 연동
- [x] Kakao Local 장소 검색
- [x] Kakao Mobility 자동차 길찾기
- [x] Failure-safe Recommendation
- [x] 영속 캐시와 Static Charger Master
- [ ] 휴게소·고속도로 충전소 정적 마스터 추가 보강
- [ ] 공식 데이터와 재표시 권한 확보 후 사업자별 실시간 요금 재검토
## Operations
| 문서 | 내용 |
| --- | --- |
| [Local Release Plan](docs/local-release-plan.md) | 로컬 alpha·beta 및 cloud gate |
| [EV API Performance Strategy](docs/ev-api-performance-strategy.md) | 캐시, prewarm, 응답 예산 전략 |
| [Operator API Priority](docs/operator-api-priority.md) | 운영사 API 연동 우선순위 |
운영 계정 승인 후 캐시 품질을 높일 때:
```bash
npm run prewarm:ev -- --profile=starter
npm run prewarm:ev -- --profile=major-cities --max-jobs=10
```
실제 prewarm은 호출량을 확인한 뒤 `--execute`를 붙여 실행합니다.
## Sources & License
### Sources
- 충전소 데이터: [한국환경공단_전기자동차 충전소 정보](https://www.data.go.kr/data/15076352/openapi.do) — 공공누리 제1유형(출처표시), 제3자 권리 포함
- 차량 프로필: 제조사 공개 제원 페이지의 일부 사실을 선별·정규화한 정적 데이터 — 개별 `sourceUrl` 기록, 별도 재이용 허가 미확인
- 지도·장소·경로: Kakao Local API, Kakao Mobility 자동차 길찾기, 카카오맵 링크
- 프로토콜: [Model Context Protocol Specification](https://modelcontextprotocol.io/specification)
- API 문서: [Kakao Local REST API](https://developers.kakao.com/docs/latest/ko/local/dev-guide)
- 지도 링크: [Kakao Maps URL Scheme](https://apis.map.kakao.com/web/guide/)
### License
별도 표시가 없는 이 프로젝트의 자체 소스 코드와 문서는 [MIT License](LICENSE)로 공개합니다.
공공데이터, 차량 제원 출처, API 제공자 권리, 시각 자산의 적용 범위는 [Third-Party Notices](THIRD_PARTY_NOTICES.md)를 확인하세요.
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues