visitkorea-medicaltourism

visitkorea-medicaltourism

Enables AI agents to search and retrieve information about KTO-certified medical tourism facilities in South Korea, including area-based, location-based, and keyword search, with multilingual support.

Category
Visit Server

README

VisitKorea Medical Tourism MCP Server

Python MCP Transport License: MIT

An MCP (Model Context Protocol) server that wraps the Korea Tourism Organization (KTO) Medical Tourism Open API (MdclTursmService), exposing 8 structured tools that AI agents — including Claude and Manus AI — can call directly via Streamable HTTP.

The underlying data is curated by the Korea Tourism Organization (KTO) and published as an Open API on data.go.kr (Korea's Public Data Portal) under service ID 15143913. It covers KTO-certified medical tourism facilities across South Korea — hospitals, specialist clinics, and wellness centres — with multilingual support for 5 international languages.

Features

  • Area-based search — list facilities by province or city/county
  • Location-based search — find facilities within a GPS radius (up to 20 km), using WGS84 coordinates
  • Keyword search — full-text search across all regions
  • Sync list — full dataset synchronisation list for building and maintaining local databases
  • Detail records — common info, introductory info (hours, parking, capacity), and medical-specific info (specialties, languages, reservation status)
  • 8 MCP tools — one per API operation, with full parameter documentation in docstrings
  • 5 languages — English, Japanese, Simplified Chinese, Korean, Russian
  • TTL response cache — district codes cached 24 h; all other responses cached 5 min (≈6× speedup on cache hits)
  • Rate limiter — 10 upstream calls/min, burst of 5; fast-fail design returns an immediate error when the limit is hit rather than blocking
  • Input validation — all parameters validated before the upstream request; GPS bounds, date format, sort codes, and language codes checked with clear error messages
  • Health endpointGET /healthz for production liveness probes

Prerequisites

  • Python 3.11+
  • A valid API key from data.go.kr (service ID 15143913)
  • Replit account (for deployment)

Installation & Setup

1. Get an API key

  1. Visit https://www.data.go.kr/data/15143913/openapi.do
  2. Sign in or create a 공공데이터포털 account
  3. Click 활용신청 (Request API access) for service MdclTursmService
  4. After approval (~10 minutes), retrieve your key from My Page

Either key variant works — the server normalises both automatically at startup:

Key variant Where to find it Notes
일반 인증키 (Encoding) My Page → 발급받은 키 URL-percent-encoded; the server decodes it once before use
일반 인증키 (Decoding) My Page → 발급받은 키 Raw base64; used as-is

2. Set the Replit Secret

Open the Secrets tab in Replit and add:

Secret name Value
VISITKOREA_API_KEY Your API key (Encoding or Decoding variant — either works)

3. Install dependencies

Replit handles this automatically on first run. To install manually:

pip install -r mcp-server/requirements.txt

requirements.txt:

mcp[cli]
httpx
python-dotenv

4. Run the server

python mcp-server/main.py

The server starts on the PORT environment variable (default 8000).

Endpoint Description
POST /mcp Streamable HTTP MCP endpoint (all tool calls)
GET /healthz Liveness probe — returns {"status":"ok","server":"visitkorea-medicaltourism"}

Connecting an AI Agent

Connector JSON

Paste this into your AI agent's custom connector settings:

{
  "mcpServers": {
    "visitkorea-medicaltourism": {
      "url": "https://<your-replit-url>/mcp"
    }
  }
}

Replace <your-replit-url> with your deployed Replit project domain.

Manus AI

Go to Settings → Connectors → Add Connectors → Custom MCP, click Import by JSON, and paste the JSON above. Do not add a "type" field — Manus AI infers Streamable HTTP from the URL automatically.

Claude Desktop

Add the JSON to your claude_desktop_config.json under the "mcpServers" key.

Tool Reference

All tools follow the same call pattern — they accept a lang_div_cd and return a list of dicts. Pagination defaults to 10 results per page starting at page 1.

Recommended workflows

Goal Sequence
Search by region get_ldong_codeget_area_based_listget_detail_common / get_detail_medical
Search near a location get_location_based_listget_detail_common / get_detail_medical
Search by keyword search_medical_by_keywordget_detail_common / get_detail_medical
Build a local database get_medical_sync_list

Tool 1 — get_ldong_code

Retrieve legal administrative district (법정동) codes for province/city and district filtering.

Upstream endpoint: GET /ldongCode
Cache TTL: 24 hours (codes are static reference data)

Parameter Type Required Description
lang_div_cd string Optional Language code (default ENG)
l_dong_regn_cd string Optional Province code — e.g. 11 = Seoul. Omit to list all provinces.
l_dong_list_yn string Optional N = 시도/시군구 codes only (default); Y = full 법정동 list
num_of_rows int Optional Results per page — clamped to 1–100 (default 10)
page_no int Optional Page number (default 1)

Example response item:

{ "rnum": 1, "code": "11", "name": "Seoul" }

Tool 2 — get_area_based_list

List medical tourism facilities filtered by administrative region.

Upstream endpoint: GET /areaBasedList
Cache TTL: 5 minutes

Parameter Type Required Description
lang_div_cd string Optional Language code
arrange string Optional Sort order: A=title, C=modified, D=created, O/Q/R=image-only variants
l_dong_regn_cd string Optional Province code from get_ldong_code
l_dong_signgu_cd string Optional District code (requires l_dong_regn_cd)
mdfcn_dt string Optional Modified-since date filter in YYYYMMDD format
num_of_rows int Optional Results per page (default 10)
page_no int Optional Page number (default 1)

Tool 3 — get_location_based_list

Find medical tourism facilities within a GPS radius. Coordinates must be within South Korea's WGS84 bounding box (longitude 124–132, latitude 33–39).

Upstream endpoint: GET /locationBasedList
Cache TTL: 5 minutes

Parameter Type Required Description
lang_div_cd string Optional Language code
map_x float Required Longitude in WGS84 — e.g. 126.9780 (Seoul)
map_y float Required Latitude in WGS84 — e.g. 37.5665 (Seoul)
radius int Required Search radius in metres — 1 to 20,000
arrange string Optional Sort: E=distance asc, S=distance desc+image; or standard A/C/D/O/Q/R
l_dong_regn_cd string Optional Optional province filter
l_dong_signgu_cd string Optional Optional district filter (requires l_dong_regn_cd)
mdfcn_dt string Optional Modified-since date filter in YYYYMMDD format
num_of_rows int Optional Results per page (default 10)
page_no int Optional Page number (default 1)

Response items include a dist field (distance in metres from the provided coordinates).


Tool 4 — search_medical_by_keyword

Full-text keyword search across all medical tourism facilities.

Upstream endpoint: GET /searchKeyword
Cache TTL: 5 minutes

Parameter Type Required Description
lang_div_cd string Optional Language code
keyword string Required Search term (automatically URL-encoded)
arrange string Optional Sort order (A/C/D/O/Q/R)
l_dong_regn_cd string Optional Province filter
l_dong_signgu_cd string Optional District filter (requires l_dong_regn_cd)
num_of_rows int Optional Results per page (default 10)
page_no int Optional Page number (default 1)

Tool 5 — get_medical_sync_list

Retrieve the full medical tourism synchronisation list. Use for building or refreshing a local database of all facilities.

Upstream endpoint: GET /mdclTursmSyncList
Cache TTL: 5 minutes

Parameter Type Required Description
lang_div_cd string Optional Language code
showflag string Optional 1 = publicly visible only; 0 = hidden only
old_content_id string Optional Last known content ID — fetch only newer records
mdfcn_dt string Optional Modified-since date in YYYYMMDD format
num_of_rows int Optional Results per page (default 10)
page_no int Optional Page number (default 1)

Tool 6 — get_detail_common

Fetch full common detail for a specific facility: title, address, GPS, phone, homepage, and overview text.

Upstream endpoint: GET /detailCommon
Cache TTL: 5 minutes

Parameter Type Required Description
lang_div_cd string Optional Language code
content_id string Required Content ID returned by any list or search tool
num_of_rows int Optional Results per page (default 1)
page_no int Optional Page number (default 1)

Key response fields: contentId, title, overview, homepage, tel, baseAddr, detailAddr, zipCd, mapX, mapY, orgImage, thumbImage, lDongRegnCd, lDongSignguCd, regDt, mdfcnDt

Note: The upstream API returns GPS fields as lowercase mapx/mapy. This tool normalises them to mapX/mapY for consistency with the list-endpoint field names.


Tool 7 — get_detail_intro

Fetch type-specific introductory details: opening hours, rest days, parking, capacity, and age suitability.

Upstream endpoint: GET /detailIntro
Cache TTL: 5 minutes

Parameter Type Required Description
lang_div_cd string Optional Language code
content_id string Required Content ID
num_of_rows int Optional Results per page (default 1)
page_no int Optional Page number (default 1)

Tool 8 — get_detail_medical

Fetch medical-specific details: specialties, foreign languages served, reservation status, and SNS info.

Upstream endpoint: GET /detailMdclTursm
Cache TTL: 5 minutes

Parameter Type Required Description
lang_div_cd string Optional Language code
content_id string Required Content ID
num_of_rows int Optional Results per page (default 1)
page_no int Optional Page number (default 1)

Key response fields: mainMdclSubjInfo (main specialties), svcLangInfo (supported languages), onlineRsvtPsblYn (online reservation available)


Language Code Reference

Code Language
ENG English
JPN Japanese (日本語)
CHS Simplified Chinese (简体中文)
KOR Korean (한국어)
RUS Russian (Русский)

Error Handling

Upstream API errors

Tool functions surface data.go.kr errors as Python exceptions with descriptive messages. The raw API key is masked ([REDACTED]) in all error strings before they leave the process.

Upstream code Exception type Meaning
00 / 0000 Success; returns results
03 No data; returns []
10 ValueError Invalid request parameter
11 ValueError Missing required parameter
22 RuntimeError Upstream daily quota (1,000 requests/day) exceeded
30 PermissionError Service key not registered
31 PermissionError Service key expired
other RuntimeError Unexpected API error with code and message

Local rate limiter

The server enforces a 10 calls/minute limit (burst of 5) on requests that reach the upstream API. Cache hits bypass the limiter entirely. When the limit is exceeded, the tool returns immediately with:

Rate limit: too many requests to upstream API. Please retry after Xs.
(Limit: 10 calls/min, burst 5)

This is a fast-fail design — no blocking sleep — so the agent receives the retry-after guidance instantly and can back off gracefully.

Project Structure

visitkorea-medicaltourism-mcp/
├── mcp-server/
│   ├── main.py                  # FastMCP entrypoint — Streamable HTTP, /healthz endpoint
│   ├── requirements.txt         # mcp[cli], httpx, python-dotenv
│   ├── README.md
│   ├── tools/
│   │   ├── ldong_code.py        # get_ldong_code
│   │   ├── area_based_list.py   # get_area_based_list
│   │   ├── location_based_list.py # get_location_based_list
│   │   ├── search_keyword.py    # search_medical_by_keyword
│   │   ├── sync_list.py         # get_medical_sync_list
│   │   ├── detail_common.py     # get_detail_common
│   │   ├── detail_intro.py      # get_detail_intro
│   │   └── detail_mdcl_tursm.py # get_detail_medical
│   └── utils/
│       ├── config.py            # API key loading, FIXED_PARAMS, key masking
│       ├── cache.py             # TTL dict cache (24h / 5min by endpoint)
│       ├── rate_limiter.py      # Token bucket — 10/min, burst 5, fast-fail
│       ├── api_client.py        # call_api() — wires cache, limiter, httpx, retry
│       └── validation.py        # Input validation for all parameter types
└── artifacts/
    ├── landing/                 # Developer landing page (React + Vite)
    └── api-server/              # Express proxy (CORS, /api/healthz)

utils/ module responsibilities

Each module has a single, clearly bounded responsibility:

Module LOC Responsibility
config.py 41 Loads VISITKOREA_API_KEY at import time, normalises Encoding/Decoding variant, exposes FIXED_PARAMS and mask_key()
cache.py 49 SHA-256-keyed TTL dict cache; make_key, get, set, ttl_for
rate_limiter.py 60 TokenBucket class; module-level limiter singleton used by call_api
api_client.py 141 call_api(endpoint, params, num_of_rows, page_no) — the only public function; handles the full request lifecycle
validation.py 93 validate_lang, validate_pagination, validate_gps, validate_radius, validate_date, validate_arrange, validate_showflag

Performance

Scenario Typical latency
Cache hit < 5 ms
Cache miss — first get_ldong_code call ~600 ms (upstream API)
Subsequent get_ldong_code calls (24h TTL) < 5 ms
Cache miss — other tools ~600 ms
Subsequent calls within 5 min TTL < 5 ms

The httpx client maintains a persistent TCP connection pool (max_connections=10, max_keepalive_connections=5) to avoid TLS handshake overhead on every request. Total request timeout is 15 s; connection timeout is 5 s.

Environment Variables

Variable Required Description
VISITKOREA_API_KEY Yes API key from data.go.kr (Encoding or Decoding variant)
PORT No Port for uvicorn to listen on (default 8000)

Contributing

Contributions are welcome. Please open an issue before submitting a pull request. Ensure all changes are tested against the live API and that no API keys are committed to the repository.

License

MIT License

Tourism data provided by the Korea Tourism Organization (KTO) via the 공공데이터포털 open API platform (data.go.kr). Data usage is subject to KTO terms — attribution is required for Type1 content; Type3 content additionally prohibits modification.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured