Skip to main content
Glama
leejaew

VisitKorea Wellness Tourism MCP Server

by leejaew

VisitKorea Wellness Tourism MCP Server

Python 3.11+ Tests Transport License: MIT

Overview

VisitKorea Wellness Tourism MCP Server is a stateless Model Context Protocol service for the Korea Tourism Organization WellnessTursmService. It exposes nine tools for discovering wellness tourism locations in South Korea and retrieving their details, images, regional codes, and synchronization data.

The server is intended for MCP clients and services that need structured access to KTO wellness tourism data over JSON Streamable HTTP. It does not provide booking, availability, or medical advice.

Related MCP server: mcp-tour

Key Features

  • Nine MCP tools covering catalog, search, synchronization, detail, and image operations

  • Search by administrative area, coordinates, radius, or keyword

  • Seven wellness themes and nine upstream language codes

  • Stateless JSON Streamable HTTP endpoint at /mcp

  • Shared PostgreSQL response cache and rate limit counters

  • PostgreSQL advisory locks to prevent duplicate upstream requests

  • Input validation, bounded pagination, and normalized error responses

  • Host and origin validation, security headers, and secret redaction

  • Developer landing page at /

Tech Stack

Layer

Technology

Language

Python 3.11 or later

MCP framework

MCP Python SDK with FastMCP

HTTP application

Starlette

ASGI server

Uvicorn

Upstream client

HTTPX

Shared state

PostgreSQL through asyncpg

Build backend

setuptools

Tests

Python unittest

Dependency constraints are defined in pyproject.toml and mirrored in requirements.txt.

Architecture

flowchart LR
    Client[MCP client] -->|JSON Streamable HTTP| Transport[Starlette and FastMCP]
    Transport --> Middleware[Security headers and rate limiting]
    Middleware --> Tools[MCP tool registry]
    Tools --> Service[Wellness service]
    Service --> Cache[(PostgreSQL shared state)]
    Service --> KTO[KTO WellnessTursmService]

The application creates one HTTP client and one PostgreSQL shared state dependency at startup. Cache entries and fixed window rate counters are shared across running instances. Advisory locks serialize cache misses for the same upstream request.

The server exposes tools only. It does not expose MCP resources or prompts. See Architecture, Capabilities, and Security for implementation details.

MCP Tools

Tool

Purpose

get_legal_district_codes

List province, city, and district codes

get_wellness_sync_list

Retrieve records for dataset synchronization

search_wellness_by_area

Search by administrative area

search_wellness_by_location

Search within a radius of WGS84 coordinates

search_wellness_by_keyword

Search by text

get_wellness_common_info

Retrieve common venue details

get_wellness_intro_info

Retrieve content type specific details

get_wellness_repeating_info

Retrieve repeating structured details

get_wellness_images

Retrieve image URLs and copyright information

Tool schemas provide argument descriptions, defaults, bounds, and accepted codes directly to MCP clients. Contract tests protect the public tool names and schemas.

Repository Structure

.
├── src/mcp_server/
│   ├── clients/          # KTO client, validation, parsing, and shared state
│   ├── config/           # Environment settings and HTTP configuration
│   ├── errors/           # Application error model
│   ├── observability/    # Logging and secret redaction
│   ├── services/         # Transport independent service layer
│   ├── tools/            # MCP operations and registration
│   ├── transports/       # Streamable HTTP application and middleware
│   ├── main.py           # Dependency composition and process startup
│   └── server.py         # FastMCP server factory
├── tests/                # Unit, integration, contract, and security tests
├── docs/                 # Architecture, deployment, security, and SQL schema
├── static/               # Landing page and favicon
├── main.py               # Compatibility launcher
├── pyproject.toml        # Package metadata and build configuration
└── requirements.txt      # Runtime dependency constraints

Requirements

  • Python 3.11 or later

  • PostgreSQL

  • A URL encoded data.go.kr service key for KTO Service ID 15144030

  • Network access to https://apis.data.go.kr

The psql command line client is optional but useful for applying the included schema.

Environment Variables

Variable

Required

Default

Purpose

WELLNESS_API_KEY_ENCODING

Yes

None

URL encoded data.go.kr service key

DATABASE_URL

Yes

None

PostgreSQL connection string for shared state

PORT

No

8080

HTTP listening port from 1 through 65535

WELLNESS_ALLOWED_HOSTS

No

Localhost entries

Comma separated HTTP host allowlist

WELLNESS_ALLOWED_ORIGINS

No

Local HTTP origins

Comma separated origin allowlist

REPLIT_DOMAINS

No

None

Replit supplied host discovery value

REPLIT_DEV_DOMAIN

No

None

Replit supplied development host

The application does not load .env files. Export variables in the shell or configure them through the deployment platform.

The data.go.kr encoding key may contain escaped characters such as %2B and %2F. Use the provided encoding key without decoding or encoding it again.

Installation

git clone https://github.com/leejaew/visitkorea-wellnesstourism-mcp.git
cd visitkorea-wellnesstourism-mcp
python -m pip install -e .

An editable installation provides the visitkorea-wellness-mcp command and supports package based entry points.

Database Setup

Create the shared cache and rate limit tables before starting the application:

psql "$DATABASE_URL" -f docs/shared_state_schema.sql

The SQL file is idempotent. Application startup verifies that both tables exist, but it does not create or migrate them.

The database stores temporary upstream responses and fixed window request counters. It does not store KTO API keys or end user profiles.

Local Development

Set the required variables:

export WELLNESS_API_KEY_ENCODING="your_url_encoded_data_go_kr_service_key"
export DATABASE_URL="postgresql://user:password@localhost:5432/wellness"
export PORT=8080

Apply the database schema, then start the server:

psql "$DATABASE_URL" -f docs/shared_state_schema.sql
python main.py

Available routes:

URL

Purpose

http://localhost:8080/

Developer landing page

http://localhost:8080/favicon.png

Landing page icon

http://localhost:8080/mcp

MCP Streamable HTTP endpoint

The installed package provides two equivalent entry points:

python -m mcp_server
visitkorea-wellness-mcp

MCP Client Configuration

Point a Streamable HTTP compatible MCP client at the deployed /mcp endpoint:

{
  "mcpServers": {
    "visitkorea-wellnesstourism": {
      "type": "streamable-http",
      "url": "https://your-domain.example/mcp"
    }
  }
}

The endpoint does not issue session IDs and does not require client authentication. Restrict network access or add authentication at the gateway when the service must not be public.

Build and Package

Install the standard Python build frontend, then build the source and wheel distributions:

python -m pip install build
python -m build

Generated packages are written to dist/.

Production Run

A production environment requires the two secrets, the initialized PostgreSQL schema, and an HTTPS proxy or hosting platform in front of Uvicorn.

export WELLNESS_API_KEY_ENCODING="your_url_encoded_data_go_kr_service_key"
export DATABASE_URL="postgresql://user:password@database:5432/wellness"
export PORT=8080
visitkorea-wellness-mcp

The process binds to 0.0.0.0 and reads the port at startup. The service has no background worker or persistent local filesystem requirement.

On Replit, use the managed PostgreSQL database and store the KTO key as a secret. The root python main.py entry point remains compatible with Replit workflows. Replit Publish applies development database schema changes to the production database.

See Deployment for the supported entry points and schema requirements.

Testing

Run the complete test suite:

PYTHONPATH=src python -m unittest discover -s tests -v

Run the compilation check used by CI:

PYTHONPATH=src python -m compileall -q src tests main.py

PostgreSQL integration tests run when DATABASE_URL is available and skip otherwise. HTTP client integration tests use mocked responses. The suite does not call the live KTO API.

Security Notes

  • Never commit WELLNESS_API_KEY_ENCODING, DATABASE_URL, or .env files.

  • Upstream redirects are disabled so the KTO key is not forwarded to another host.

  • Logs redact the configured API key and serviceKey query values.

  • MCP requests are limited to 60 requests per 60 seconds per direct client IP.

  • PostgreSQL counters enforce the same rate limit across all instances.

  • Host and origin validation reduce DNS rebinding exposure.

  • Responses include CSP, frame, content type, and referrer policy headers.

  • TLS and client authentication must be provided by the deployment platform or gateway when required.

Troubleshooting

Startup reports a missing API key

Set WELLNESS_API_KEY_ENCODING to the encoding key from data.go.kr. Do not use the decoded key.

Startup reports a missing database schema

Confirm that DATABASE_URL targets the intended database, then run:

psql "$DATABASE_URL" -f docs/shared_state_schema.sql

Requests fail host or origin validation

Add the public host and origin to the comma separated allowlists:

export WELLNESS_ALLOWED_HOSTS="mcp.example.com"
export WELLNESS_ALLOWED_ORIGINS="https://mcp.example.com"

The upstream API returns an authentication error

Confirm that the KTO service request is approved and that the URL encoded key was not decoded or encoded a second time.

Known Limitations

  • The server exposes read only directory data. It does not provide booking, availability, or transactional operations.

  • Results depend on the KTO service, quota, coverage, and update schedule.

  • Korean data may contain more records or fields than translated datasets.

  • Content type IDs differ between Korean and multilingual responses.

  • The direct ASGI client address is used for rate limiting. Configure trusted proxy behavior at the gateway when deploying behind multiple proxy layers.

  • The public MCP endpoint has no built in client authentication.

  • The landing page loads fonts and client libraries from external CDNs.

Contributing

Open an issue before submitting a substantial change. Run the test and compilation commands before opening a pull request. Do not record live KTO responses containing credentials in fixtures or logs.

License

Licensed under the MIT License.

Tourism data is provided by the Korea Tourism Organization through data.go.kr. Follow the source data terms and the copyright type attached to each record.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Integrates the Korea Tourism Organization's API to provide tourist spot recommendations and detailed information, including attractions, food, and accommodation.
    1
    -
  • A
    license
    A
    quality
    D
    maintenance
    Integrates Korean APIs (Naver, Kakao, TMAP) into LLM applications for search, maps, and directions.
    1
    11
    MIT