Command Palette

Search for a command to run...

UnylyUnyly
Весь каталог

Geup Ddong Seoul

БесплатноНе проверен

MCP server for finding nearby public toilets in Seoul, with real-time open status and accessibility filters.

GitHubEmbed

Описание

MCP server for finding nearby public toilets in Seoul, with real-time open status and accessibility filters.

README

급똥 서울 (Geup-Ddong Seoul)

급똥 서울 (geup-ddong-seoul-mcp)

서울시 공중화장실 데이터(스마트서울맵 테마 theme_id=100106)를 조회하는 MCP 서버입니다. 급할 때 내 위치에서 가까운, 지금 열려 있는 화장실을 찾는 것이 핵심 기능입니다.

  • 전송 방식: Streamable HTTP (http://{HOST}:{PORT}/mcp)
  • 데이터 출처: 스마트서울맵 갤러리 (공중화장실, 약 4,500개소)
  • 다운로드는 로그인/인증 불필요 (공개 엔드포인트)

동작 개요

POST https://map.seoul.go.kr/smgis/webs/contents/contents.do
     ?mode=downloadGeomFormatXLSX&down_type=xlsx&lan_type=KOR&conts_type=A&theme_id=100106
  -> contents.zip  ->  contents.xlsx (데이터)  ->  파싱하여 메모리 적재

원본 데이터 구조 (contents.xlsx)

contents.xlsx는 스마트서울맵 테마 업로드 공통 양식으로 77개 컬럼이며, 공중화장실은 약 4,538행입니다. 77컬럼 중 실제로 값이 들어있는 컬럼은 45개이고 나머지는 빈 스타일/예비 컬럼입니다. 헤더 1행은 콘텐츠 ID\n(필수 입력)처럼 안내문구가 붙어 있어 첫 줄만 컬럼명으로 사용합니다. (채움률은 실제 데이터 기준 근삿값)

고정 컬럼

원본 컬럼(첫 줄) 내부 필드 채움률 예시
콘텐츠 ID content_id 100% rest2025_0448
사용유무 in_use (Y→true) 100% Y
콘텐츠명 name 100% 강동구민회관
서브카테고리 명 subcategory 100% 정시 / 상시
구명 district 100% 강동구
새주소[도로명 주소] road_address 92% 서울특별시 강동구 상암로 168
지번주소 jibun_address 99% 서울특별시 강동구 천호동 41
키워드 keyword 99% #공중화장실
좌표[X] longitude (경도) 99% 127.141222548
좌표[Y] latitude (위도) 99% 37.545731457
전화번호 phone 99% 02-2045-7617
웹URL web_url <1% (대부분 비어있음)

상세 속성 (제목/내용 쌍 구조)

상세 정보는 상세 제목N / 상세 내용N 컬럼 으로 저장됩니다. 예를 들어 상세 제목2칸에 개방시간, 상세 내용2칸에 정시(08:00~21:00)이 들어갑니다. 서버는 컬럼 위치(N)가 아니라 제목 텍스트로 매핑하므로 순서가 바뀌어도 안전합니다. 다중값은 |로 구분되며(남자|여자|) 끝의 |는 정리합니다.

상세 제목 내부 필드 타입 채움률 예시
개방주체 open_subject 문자열 ~100% 공공개방
개방시간 open_hours 문자열 ~100% 정시(08:00~21:00)
휴관일 closed_days 리스트 11% ["토요일","일요일"]
화장실구분 toilet_types 리스트 99% ["남자","여자"]
장애인화장실구분 disabled_toilet 리스트 52% ["남자","여자"]
편의시설 amenities 리스트 28% ["기저귀교환대(남)"]
안전시설 safety 리스트 64% ["비상벨(여)"]
건물용도 building_use 문자열 ~100% 공공시설
관리기관 manager 문자열 ~100% 강동구도시관리공단

원문 상세 전체(제목→내용)는 get_toilet 결과의 details에 그대로 담깁니다.

coord.xlsx

zip에 함께 들어오지만 공중화장실은 점(공간객체타입=1) 데이터라 좌표가 contents.xlsx에 모두 있어 사용하지 않습니다.

프로젝트 구조

geup-ddong-seoul-mcp/
├─ seoul_toilet/
│  ├─ __init__.py
│  ├─ data.py        # 다운로드/압축해제/파싱/질의 + ToiletStore(메모리·캐시)
│  └─ server.py      # FastMCP 서버(tool 4종) + /refresh, /health
├─ tests/
│  └─ test_logic.py  # 파싱·개방시간·거리·검색·다운로드(mock)·캐시 검증
├─ data_cache/       # 실행 시 생성: contents.zip, contents.xlsx 캐시
├─ requirements.txt
├─ pyproject.toml
└─ README.md

설치

pip install -r requirements.txt
# 또는 패키지로 설치
pip install -e .

요구사항: Python 3.10+, mcp, requests, openpyxl

실행

python -m seoul_toilet.server
# -> http://127.0.0.1:8000/mcp 에서 MCP 제공

환경변수로 설정합니다.

변수 기본값 설명
SEOUL_TOILET_HOST 127.0.0.1 바인드 호스트
SEOUL_TOILET_PORT 8000 포트
SEOUL_TOILET_CACHE_DIR ./data_cache xlsx/zip 캐시 디렉터리
SEOUL_TOILET_DOWNLOAD_ON_START 1 시작 시 캐시가 없으면 1회 다운로드(0이면 비활성)
SEOUL_TOILET_PUBLIC_HOST (없음) 리버스 프록시 뒤 공개 도메인. 지정 시 MCP /mcp의 Host/Origin 허용 목록에 추가. 쉼표로 여러 개 지정 가능(예: techsummit.asia,foo.playmcp-endpoint.kakaocloud.io). PlayMCP 등 프록시가 보내는 Host도 함께 넣어야 421을 피한다
SEOUL_TOILET_ALLOWED_HOSTS (자동) 허용 Host 헤더 목록(쉼표 구분). 비우면 localhost 계열 + PUBLIC_HOST 자동 구성
SEOUL_TOILET_ALLOWED_ORIGINS (자동) 허용 Origin 목록(쉼표 구분, 브라우저 클라이언트용)
SEOUL_TOILET_DNS_REBINDING_PROTECTION 1 MCP DNS 리바인딩 보호(0이면 비활성)
SEOUL_TOILET_REFRESH_TOKEN (없음) 설정 시 /refresh 호출에 토큰 일치 요구(공개 배포 보호용). 미설정이면 공개

도메인(리버스 프록시) 뒤에서 /mcp를 서비스할 때 SEOUL_TOILET_PUBLIC_HOST를 지정하지 않으면 MCP의 DNS 리바인딩 보호가 외부 Host 헤더를 421 Invalid Host header로 막는다. /health·/refresh는 영향받지 않는다.

시작 시 캐시가 있으면 캐시를 읽고(네트워크 없음), 없으면 1회 다운로드합니다.

MCP 클라이언트 등록

Streamable HTTP를 지원하는 클라이언트에서 아래처럼 URL로 등록합니다.

{
  "mcpServers": {
    "geup-ddong-seoul": {
      "type": "streamable-http",
      "url": "http://127.0.0.1:8000/mcp"
    }
  }
}

노출 Tool (LLM이 호출)

Tool 용도 주요 인자
find_nearest_toilets 내 위치 기준 가까운 화장실(거리순) latitude, longitude, limit, radius_m, open_now, require_disabled
search_toilets 구/이름/주소/키워드 검색 query, district, open_now, require_disabled, limit
get_toilet content_id 상세(원문 details 포함) content_id
dataset_info 건수·갱신시각·자치구 목록 등 메타 (없음)

"지금 개방 중"은 별도 tool 대신 open_now 필터 + 결과의 open_now/open_hours 필드로 통합했습니다. LLM이 거리·개방·시설 조건을 조합해 판단하기 쉽도록, 각 결과에 개방시간(원문)·개방여부· 화장실구분·장애인화장실·편의시설·안전시설·관리기관·전화번호를 함께 담아 반환합니다.

결과 필드 예시

{
  "content_id": "rest2025_0448",
  "name": "강동구민회관",
  "district": "강동구",
  "road_address": "서울특별시 강동구 상암로 168",
  "latitude": 37.545731457, "longitude": 127.141222548,
  "phone": "02-2045-7617",
  "open_hours": "정시(08:00~21:00)", "open_now": true, "is_24h": false,
  "toilet_types": ["남자", "여자"],
  "disabled_toilet": ["남자", "여자"],
  "amenities": ["기저귀교환대(남)", "기저귀교환대(여)"],
  "safety": ["비상벨(여)"],
  "manager": "강동구도시관리공단",
  "distance_m": 12.3
}

반환 필드 레퍼런스

원본 필드(위 데이터 구조 표) 외에 서버가 계산해 넣는 파생 필드입니다.

필드 타입 설명
open_now bool / null 현재(KST) 개방 여부. 형식 해석 불가 시 null
is_24h bool 상시/24시간 개방 여부
distance_m number find_nearest_toilets 한정. 입력 좌표로부터 직선거리(m)
open_hours_note string / null 요일·공휴일 차이 등 자동해석 한계 안내
details object get_toilet 한정. 원문 상세(제목→내용) 전체

빈 값은 단일 필드는 null, 리스트 필드는 []로 반환합니다.

데이터 갱신 (사용자가 직접 호출)

새로고침은 MCP tool로 노출하지 않고 운영용 HTTP 엔드포인트로만 제공합니다.

curl -X POST http://127.0.0.1:8000/refresh   # 원격에서 다시 받아 캐시 갱신
curl http://127.0.0.1:8000/health            # 상태 확인

월 1회 자동화 예시(cron):

0 6 1 * *  curl -fsS -X POST http://127.0.0.1:8000/refresh

공개 배포 등에서 /refresh 남용을 막으려면 SEOUL_TOILET_REFRESH_TOKEN을 설정하고 호출 시 토큰을 함께 보냅니다(미설정이면 공개 — cron이 없는 서버에서 그대로 호출 가능).

export SEOUL_TOILET_REFRESH_TOKEN=$(openssl rand -hex 24)
curl -fsS -X POST -H "X-Refresh-Token: $SEOUL_TOILET_REFRESH_TOKEN" http://127.0.0.1:8000/refresh
# 또는: -H "Authorization: Bearer $TOKEN"  /  "...?token=$TOKEN"

데이터 스냅샷 (오프라인 폴백)

기동 시 원격 다운로드가 실패하거나(네트워크/egress 차단 등) SEOUL_TOILET_DOWNLOAD_ON_START=0 인 경우, 패키지에 포함된 시드 스냅샷 seoul_toilet/seed/contents.xlsx 로 폴백해 데이터가 비지 않습니다. 적재 우선순위는 캐시 → 원격 다운로드 → 시드 입니다(시드는 repo·이미지에 동봉).

스냅샷을 최신화하려면 아래로 갱신 후 커밋합니다.

python scripts/update_snapshot.py        # requests/openpyxl 필요
# 로컬에 의존성이 없으면 컨테이너로:
podman run --rm --user root -v "$PWD/seoul_toilet:/host" geup-ddong-seoul-mcp \
  python -c "from seoul_toilet.data import download_zip,extract_inner_xlsx; import pathlib; \
xb=extract_inner_xlsx(download_zip()); p=pathlib.Path('/host/seed/contents.xlsx'); \
p.parent.mkdir(parents=True,exist_ok=True); p.write_bytes(xb); print(len(xb))"

git add seoul_toilet/seed/contents.xlsx && git commit -m "데이터 스냅샷 갱신"

개방시간 해석 한계

개방시간 원문은 정시(08:00~21:00), 상시(00:00~24:00), 평일(09:00~18:00) 주말휴무 등 형식이 다양합니다. 서버는 시간 구간을 추출해 open_now(KST 기준)를 계산하되, 요일/공휴일별 차이는 완전히 반영하지 못할 수 있어 그런 경우 open_hours_note로 표시하고 원문(open_hours)을 함께 제공합니다. 최종 판단 시 원문을 함께 참고하세요.

왜 FastMCP인가

읽기 전용 조회 서버(다운로드→캐시→질의)라 저수준 SDK의 세밀한 제어가 불필요합니다. 공식 mcp SDK의 FastMCP는 @mcp.tool 데코레이터로 타입힌트 기반 입력 스키마를 자동 생성하고, @mcp.custom_route로 운영용 엔드포인트(/refresh)를 같은 앱에 손쉽게 붙일 수 있어 본 용도에 가장 적합합니다.

테스트

pip install pytest
python -m pytest tests/ -q

실제 스키마(77컬럼, 상세 제목/내용 쌍 구조)를 본뜬 합성 데이터로 파싱·개방시간·거리·검색· 다운로드(mock)·캐시까지 검증합니다.

라이선스/출처 표기

데이터: 서울특별시 스마트서울맵 (이용허락: 저작자표시 BY). 출처를 표기해 사용하세요.

from github.com/Seo-yul/geup-ddong-seoul-mcp

Установка Geup Ddong Seoul

У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.

▸ github.com/Seo-yul/geup-ddong-seoul-mcp

FAQ

Geup Ddong Seoul MCP бесплатный?

Да, Geup Ddong Seoul MCP бесплатный — установка в пару кликов через Unyly без оплаты.

Нужен ли API-ключ для Geup Ddong Seoul?

Нет, Geup Ddong Seoul работает без API-ключей и переменных окружения.

Geup Ddong Seoul — hosted или self-hosted?

Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.

Как установить Geup Ddong Seoul в Claude Desktop, Claude Code или Cursor?

Открой Geup Ddong Seoul на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.

Похожие MCP

Compare Geup Ddong Seoul with

Не уверен что выбрать?

Найди свой стек за 60 секунд

Автор?

Embed-бейдж для README

Похожее

Все в категории development