onbid-mcp

onbid-mcp

Enables LLM clients to ask plain-language questions about Korean public auction property data from the 온비드 OpenAPI, including normalized pricing, location, and failed-sale history.

Category
访问服务器

README

onbid-mcp

한국어 README

An MCP server that lets an LLM query Korean public auction (공매) property data from 온비드 (KAMCO).

Ask "which properties in 강남구 have failed to sell more than three times?" in Claude Desktop and get answers from data you collected yourself — no subscription, no scraping.

Status. Working end to end — the pipeline runs on a schedule, and the four tools are connected and answering in Claude Desktop against live data (6,902 Seoul listings, 99.9% geocoded). Remaining: final acceptance checks (M7) and a week of watching the scheduled batches. See docs/TASKS.md for the exact state.


What you get

Four tools and four resources, over stdio:

Tool What it does
search_auction_items Filter by region, usage, property type, private-contract eligibility, price, discount rate, failure count, deadline, status. Korean names work directly ("강남구", "아파트"). Cursor paginated.
get_auction_detail One property by management number, plus its sibling condition numbers and the original 온비드 link.
get_auction_stats Distributions across six axes, plus winning-bid ratios. Aggregates only — never individual properties.
get_address_geocode Address → coordinates, with a server-side daily cap.
Resource What it holds
onbid://codes/regions Districts and neighborhoods that actually have listings
onbid://codes/usages The three-level usage category tree
onbid://codes/property-types Property type codes
onbid://dataset/status Batch timestamp, counts, geocoding rate — how fresh your data is

Every response carries meta (source, synced_at, is_realtime: false, count, truncated, notice) and query_echo (the filters actually applied, after defaults and clamping).


Before you start

This server queries your own database, not a hosted service. You collect the data, so you need your own credentials:

What Where Notes
온비드 service key 공공데이터포털 Apply for the five 온비드 OpenAPIs. Approval is usually immediate for a development account.
Supabase project supabase.com Free tier is enough — the Seoul dataset is about 7,000 rows. Any PostgreSQL works.
Kakao REST API key Kakao Developers Geocoding. Must be the REST API key, not the JavaScript one.

Also: Python 3.11+ and Claude Desktop (or any MCP client that speaks stdio).

Scope is Seoul, sale-type listings by default. Widening it is a one-line filter change, but the geocoding and quota numbers below assume Seoul.


Setup

git clone https://github.com/daehyub71/onbid-mcp.git
cd onbid-mcp
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt

cp .env.example .env          # fill in the three keys above
python scripts/migrate.py     # create tables (safe to re-run)

Then collect a first dataset. This takes about two minutes and stays well inside the daily API quota:

python scripts/run_batch.py

You should see something like:

── 물건 ──
  ok · 수집 6902 · 적재 6902 · 이력 0 · tombstone 0
── 좌표 ──
  ok · 대상 500 · 좌표 500 (근사 0) · 실패 0 · 호출 133

Run it again with --geocode-budget 1000 until dataset/status reports a geocoding rate you're happy with — the cache absorbs most calls, so the whole 6,902 rows cost roughly 800 Kakao calls in total.


Connecting Claude Desktop

Add the server to claude_desktop_config.json:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
{
  "mcpServers": {
    "onbid": {
      "command": "/absolute/path/to/onbid-mcp/venv/bin/python",
      "args": ["-m", "onbid_mcp.server"],
      "cwd": "/absolute/path/to/onbid-mcp",
      "env": {
        "PYTHONPATH": "/absolute/path/to/onbid-mcp",
        "SUPABASE_DATABASE_URL": "postgresql://...",
        "ONBID_SERVICE_KEY": "...",
        "KAKAO_REST_API_KEY": "..."
      }
    }
  }
}

Four things trip people up here:

  • PYTHONPATH is required — cwd alone is not enough. Claude Desktop does not apply the cwd entry, so python -m onbid_mcp.server cannot find the package and the process dies instantly with ModuleNotFoundError. The app reports that as "Server disconnected", which looks like a connection problem rather than a path one.
  • Use the absolute path to the venv interpreter. Claude Desktop does not inherit your shell PATH, so a bare python picks up a system interpreter with none of the dependencies.
  • Put the keys in env. The app does not read the project's .env file.
  • Logs must never reach stdout. stdout is the JSON-RPC channel; this server logs to stderr for exactly that reason. If you add prints, send them to stderr.

Restart Claude Desktop, then try:

강남구에서 3회 이상 유찰된 물건 중 최저가율 60% 이하인 것 보여줘

If it fails, read ~/Library/Logs/Claude/mcp-server-onbid.log — the actual Python error is in there, while the UI only says "Server disconnected".

To check the connection without Claude Desktop:

python scripts/mcp_smoke.py        # lists tools and calls one over stdio

Keeping the data fresh

Two GitHub Actions workflows are included. Add ONBID_SERVICE_KEY, SUPABASE_DATABASE_URL, and KAKAO_REST_API_KEY to your repository secrets and they run on their own:

Workflow When (KST) What
onbid-daily Mon–Sat 04:00 Changed listings + bid rounds + geocoding
onbid-weekly Sun 04:00 Code tables + full scan — the only run that can mark ended listings

Cron is UTC-only, so 04:00 KST is 19:00 UTC the previous day, which shifts the weekday by one. Check the last week with:

python scripts/batch_health.py

A skipped cron leaves no trace anywhere — GitHub only emails about runs that started and failed — so this counts the days instead.


Design notes worth knowing

These came from measurement, not from the API guide.

Ended listings are marked, never deleted. 온비드 returns in-progress items only, so a listing that disappears is indistinguishable from one that never existed. Rows become 종료추정 instead, and three conditions must all hold first: full-scan mode, matching collection scope, and a completed scan. Getting the scope wrong flipped 6,594 healthy rows in a measured trial.

The primary key is composite. cltrMngNo alone is not unique — one management number carries up to ten pbctCdtnNo values, and the bid-info API returns the same round history under each. Statistics deduplicate by (management number, opening time, round); counting rows made 13 real auction events look like 62.

Ratios are computed, not read. 온비드 ships ratio fields whose measured fill rate is 0%. min_bid_rate is derived, and it legitimately exceeds 1.0 (measured max 150.2%, in 9.8% of rows), so it is never clamped.

Empty results are an error, not an empty list. no_result tells the model to relax the filters; an empty array would let it conclude "there are no such properties".

The winning-bid statistics are biased, and that matters more than the numbers. The only completed auctions visible are ones that were won and then fell through — normally completed sales never appear in the listing API. Every response carries that caveat.


Development

ruff check .
mypy core/ onbid_mcp/ api/ tests/ scripts/
pytest -q            # 595 tests, no network
pytest -m db -q      # 361 tests against your database, inside rolled-back transactions
pytest -m live -q    # real API calls, excluded by default

Database tests run against the real schema inside transactions that always roll back, so they leave no trace — verified by comparing table counts before and after. Pure tests pass with a deliberately broken connection string.

There is also a local HTTP API (api/main.py) bound to loopback only, useful for poking at the data with curl. It is not required for MCP use.


Documentation

Specification-driven; the documents are the source of truth and are written in Korean.

  • docs/SPEC.md — requirements, data model, MCP tool contracts, open questions
  • docs/PLAN.md — architecture, milestones, test strategy, risks
  • docs/TASKS.md — progress dashboard and troubleshooting log
  • docs/API_FINDINGS.md — measured API behavior; takes precedence over the official guides, which were wrong in several places

Security

Keys live in .env (local) or GitHub Secrets / the MCP config env block (deployed), never in code. The 온비드 API requires the service key as a query parameter and httpx logs full request URLs at INFO level, so the client lowers the httpx logger to WARNING at import time — otherwise enabling logging would leak the key. The settings object masks its values in repr for the same reason.

All onbid_* tables have RLS enabled with no policies and revoked grants; access is service_role only, verified by measurement (HTTP 401 for anon on every table). The HTTP API refuses to bind anywhere but loopback.


Limits and non-goals

  • Lookup only. No ranking, scoring, or recommendation — the tools return public data and leave judgement to you. This is deliberate: 공인중개사법 restricts listing-style display and advertisement of properties.
  • No brokerage, no valuation, no legal or investment advice.
  • Seoul, sale-type listings, in-progress by default.
  • Winning-bid statistics come from a biased sample (see above).

License

Not yet chosen. The 온비드 API guide documents are intentionally excluded from this repository; the response structures used here are recorded in docs/API_FINDINGS.md from live measurement.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选