{"id":50187607,"url":"https://github.com/fieldcure/fieldcure-mcp-publicdata","last_synced_at":"2026-05-25T11:01:54.491Z","repository":{"id":349509203,"uuid":"1201954174","full_name":"fieldcure/fieldcure-mcp-publicdata","owner":"fieldcure","description":"MCP server for Korean public data APIs (data.go.kr) — discover, inspect, and call 80,000+ government APIs","archived":false,"fork":false,"pushed_at":"2026-05-21T06:21:31.000Z","size":211,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-21T13:12:00.173Z","etag":null,"topics":["ai","csharp","data-go-kr","dotnet","korea","mcp","mcp-server","open-api","public-data"],"latest_commit_sha":null,"homepage":"https://www.nuget.org/packages/FieldCure.Mcp.PublicData.Kr","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fieldcure.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-05T11:49:54.000Z","updated_at":"2026-05-21T06:21:35.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/fieldcure/fieldcure-mcp-publicdata","commit_stats":null,"previous_names":["fieldcure/fieldcure-mcp-publicdata"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/fieldcure/fieldcure-mcp-publicdata","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fieldcure%2Ffieldcure-mcp-publicdata","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fieldcure%2Ffieldcure-mcp-publicdata/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fieldcure%2Ffieldcure-mcp-publicdata/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fieldcure%2Ffieldcure-mcp-publicdata/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fieldcure","download_url":"https://codeload.github.com/fieldcure/fieldcure-mcp-publicdata/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fieldcure%2Ffieldcure-mcp-publicdata/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33471530,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-25T06:32:55.349Z","status":"ssl_error","status_checked_at":"2026-05-25T06:32:35.322Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","csharp","data-go-kr","dotnet","korea","mcp","mcp-server","open-api","public-data"],"created_at":"2026-05-25T11:01:50.199Z","updated_at":"2026-05-25T11:01:54.484Z","avatar_url":"https://github.com/fieldcure.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"﻿# FieldCure MCP PublicData.Kr\r\n\r\n[![NuGet](https://img.shields.io/nuget/v/FieldCure.Mcp.PublicData.Kr)](https://www.nuget.org/packages/FieldCure.Mcp.PublicData.Kr)\r\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/fieldcure/fieldcure-mcp-publicdata/blob/main/LICENSE)\r\n\r\nKorean public data API gateway. A [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server that lets any MCP client discover, inspect, and call 80,000+ APIs on [data.go.kr](https://www.data.go.kr) — weather, real estate, business registration, air quality, transit, and more. Built with C# and the official [MCP C# SDK](https://github.com/modelcontextprotocol/csharp-sdk).\r\n\r\n## Features\r\n\r\n- **3 tools** — search APIs by keyword, inspect parameters/response fields, call any data.go.kr API\r\n- **Automatic serviceKey injection** — the API key is added to every request; never leaked to the LLM\r\n- **Lazy key resolution** — env var → MCP Elicitation → soft-fail chain (no hard-fail on startup). Hosts that support [MCP Elicitation](https://modelcontextprotocol.io/specification/2025-06-18/server/elicitation) can prompt the user for the key on first use; on upstream `401/403` or `SERVICE_KEY_IS_NOT_REGISTERED` the cached key is invalidated and a re-elicit is attempted (session cap: 2 re-elicits)\r\n- **XML → JSON normalization** — strips the `response/header/body/items` wrapper, returns clean JSON\r\n- **Error code mapping** — translates data.go.kr error codes into Korean guidance messages the LLM can relay directly\r\n- **SSRF protection** — domain whitelist limits calls to approved government hosts\r\n- **EUC-KR support** — legacy encoding from older government APIs is auto-detected and converted\r\n- **Stateless** — no cache, no database, no local files; every call is independent\r\n- **Stdio transport** — standard MCP subprocess model via JSON-RPC over stdin/stdout\r\n\r\n## Installation\r\n\r\n### dotnet tool (recommended)\r\n\r\n```bash\r\ndotnet tool install -g FieldCure.Mcp.PublicData.Kr\r\n```\r\n\r\nAfter installation, the `fieldcure-mcp-publicdata-kr` command is available globally.\r\n\r\n### From source\r\n\r\n```bash\r\ngit clone https://github.com/fieldcure/fieldcure-mcp-publicdata.git\r\ncd fieldcure-mcp-publicdata\r\ndotnet build\r\n```\r\n\r\n## Prerequisites\r\n\r\n1. Sign up at [data.go.kr](https://www.data.go.kr) and get your API key\r\n   (data.go.kr 회원가입 후 인증키 발급)\r\n2. **Subscribe to [목록조회서비스](https://www.data.go.kr/data/15077093/openapi.do)** (Required)\r\n   — `discover_api` and `describe_api` depend on this API\r\n   (discover_api, describe_api 도구가 이 API를 사용합니다)\r\n3. Subscribe to each individual API you want to query\r\n   (조회하려는 개별 API도 각각 활용신청 필요)\r\n\r\n## Requirements\r\n\r\n- [.NET 8.0 Runtime](https://dotnet.microsoft.com/download/dotnet/8.0) or later\r\n\r\n## Authentication\r\n\r\nThis server requires a **data.go.kr API key** (공공데이터포털 인증키). Key resolution is\r\nlazy (on first tool call) and follows the [FieldCure MCP Credential ADR](https://github.com/fieldcure/fieldcure-assiststudio/blob/main/docs/ADR-001-MCP-Credential-Management.md):\r\n\r\n1. **Environment variable** — `DATA_GO_KR_API_KEY` (canonical) or `PUBLICDATA_API_KEY` (legacy alias)\r\n2. **MCP Elicitation** — if no env var is found, the server requests the key interactively\r\n   on the first tool call (requires a client that supports MCP Elicitation — e.g. Claude\r\n   Code ≥ 2.1.76, AssistStudio). The resolved key is cached in process memory for the\r\n   session lifetime and is never written to disk by the server.\r\n3. **Soft-fail** — if both paths fail, `tools/list` still works and tool calls return a\r\n   structured error message asking the user to set the env var.\r\n\r\n`--api-key \u003cvalue\u003e` is also accepted as a CLI arg but is intended for manual testing only,\r\nnot as a supported configuration path.\r\n\r\n### Setup by host\r\n\r\n**Claude Code / Claude Desktop** — add the key to your MCP config:\r\n\r\n```json\r\n{\r\n  \"mcpServers\": {\r\n    \"publicdata-kr\": {\r\n      \"command\": \"fieldcure-mcp-publicdata-kr\",\r\n      \"env\": {\r\n        \"DATA_GO_KR_API_KEY\": \"\u003cyour-key\u003e\"\r\n      }\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nOn Claude Code (≥ 2.1.76), if the env var is omitted the server prompts for the key via\r\nElicitation on first use.\r\n\r\n**AssistStudio** — the key is requested via Elicitation on first use and stored in Windows\r\nPasswordVault for subsequent launches; the host then injects it as an env var when\r\nstarting the server.\r\n\r\n**Docker / CI** — pass the key as a standard environment variable:\r\n\r\n```bash\r\ndocker run -e DATA_GO_KR_API_KEY=\u003cyour-key\u003e ...\r\n```\r\n\r\n### Key validation and re-elicitation\r\n\r\nIf the server receives an HTTP 401/403 or a `resultCode=22` / `SERVICE_KEY_IS_NOT_REGISTERED_ERROR`\r\nbody from data.go.kr, it invalidates the cached key and re-requests via Elicitation\r\n(session cap: 2 re-elicits per `ApiKeyResolver` lifetime). After exhausting retries, the\r\ntool returns a soft-fail error message.\r\n\r\n\u003e **Note:** On data.go.kr an HTTP 401 can mean either an invalid key *or* an API that you\r\n\u003e have not applied for (활용신청). If a re-elicitation prompt appears right after calling\r\n\u003e an API you haven't subscribed to, entering the same key will produce the final error\r\n\u003e envelope with details — at that point visit the API's data.go.kr page and apply for access.\r\n\r\n## Configuration\r\n\r\n### Claude Desktop\r\n\r\nAdd to `claude_desktop_config.json`:\r\n\r\n```json\r\n{\r\n  \"mcpServers\": {\r\n    \"publicdata-kr\": {\r\n      \"command\": \"fieldcure-mcp-publicdata-kr\",\r\n      \"env\": {\r\n        \"DATA_GO_KR_API_KEY\": \"YOUR_DATA_GO_KR_API_KEY\"\r\n      }\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n### Claude Code (v2.1.76+)\r\n\r\n```bash\r\nclaude mcp add publicdata-kr -- fieldcure-mcp-publicdata-kr\r\n```\r\n\r\nClaude Code supports MCP Elicitation, so `DATA_GO_KR_API_KEY` may be omitted — the\r\nserver will prompt for the key on first tool use.\r\n\r\n### VS Code (Copilot)\r\n\r\nAdd to `.vscode/mcp.json`:\r\n\r\n```json\r\n{\r\n  \"servers\": {\r\n    \"publicdata-kr\": {\r\n      \"command\": \"fieldcure-mcp-publicdata-kr\",\r\n      \"env\": {\r\n        \"DATA_GO_KR_API_KEY\": \"YOUR_DATA_GO_KR_API_KEY\"\r\n      }\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n### From source (without dotnet tool)\r\n\r\n```json\r\n{\r\n  \"mcpServers\": {\r\n    \"publicdata-kr\": {\r\n      \"command\": \"dotnet\",\r\n      \"args\": [\r\n        \"run\",\r\n        \"--project\", \"C:\\\\path\\\\to\\\\fieldcure-mcp-publicdata\\\\src\\\\FieldCure.Mcp.PublicData.Kr\"\r\n      ],\r\n      \"env\": {\r\n        \"DATA_GO_KR_API_KEY\": \"YOUR_DATA_GO_KR_API_KEY\"\r\n      }\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n### AssistStudio\r\n\r\n\u003e **Install the dotnet tool first.** AssistStudio does not auto-install external MCP\r\n\u003e servers (only built-in ones are managed via the AssistStudio auto-update path).\r\n\u003e The `fieldcure-mcp-publicdata-kr` command must be on PATH before you add the server,\r\n\u003e otherwise the connection fails with a generic \"server shut down unexpectedly\" message.\r\n\u003e\r\n\u003e ```bash\r\n\u003e dotnet tool install -g FieldCure.Mcp.PublicData.Kr\r\n\u003e # later, to upgrade:\r\n\u003e dotnet tool update -g FieldCure.Mcp.PublicData.Kr\r\n\u003e ```\r\n\r\nThen: Settings \u003e MCP Servers \u003e **Add Server**:\r\n\r\n| Field | Value |\r\n|-------|-------|\r\n| **Name** | `PublicData.Kr` |\r\n| **Command** | `fieldcure-mcp-publicdata-kr` |\r\n| **Arguments** | *(empty)* |\r\n| **Environment** | `DATA_GO_KR_API_KEY` = your data.go.kr API key *(optional — AssistStudio can prompt via Elicitation if unset)* |\r\n| **Description** | *(auto-filled on first connection)* |\r\n\r\n## Tools\r\n\r\n| Tool | Description |\r\n|------|-------------|\r\n| `discover_api` | Search data.go.kr APIs by keyword — returns names, providers, endpoint URLs |\r\n| `describe_api` | Get operations, request parameters, and response fields for a specific API |\r\n| `call_api` | Call any data.go.kr API with automatic serviceKey injection and response normalization |\r\n\r\n### Workflow\r\n\r\n```\r\n1. discover_api(\"미세먼지\")\r\n   → { serviceId: \"15073861\", serviceName: \"한국환경공단_에어코리아_대기오염정보\", ... }\r\n\r\n2. describe_api(\"15073861\")\r\n   → { operations: [{ name: \"getMsrstnAcctoRltmMesureDnsty\", url: \"...\", requestParameters: [...] }] }\r\n\r\n3. call_api(url: \"http://apis.data.go.kr/B552584/ArpltnInforInqireSvc/getMsrstnAcctoRltmMesureDnsty\",\r\n            params: '{\"stationName\": \"종로구\", \"dataTerm\": \"DAILY\", \"returnType\": \"json\"}')\r\n   → { totalCount: 24, items: [{ stationName: \"종로구\", pm10Value: \"45\", ... }] }\r\n```\r\n\r\n### `discover_api`\r\n\r\nSearch Korean public data APIs on data.go.kr by keyword. Results are deduplicated by service — each API appears once even if it has multiple operations.\r\n\r\n| Parameter | Type | Required | Description |\r\n|-----------|------|:--------:|-------------|\r\n| `query` | string | Yes | Search keyword (e.g., `미세먼지`, `부동산`, `사업자`) |\r\n| `page` | int | — | Page number (default: 1) |\r\n| `pageSize` | int | — | Results per page (default: 10, max: 50) |\r\n\r\n### `describe_api`\r\n\r\nGet the request parameters and response fields of a specific API. Use the `serviceId` from `discover_api` results.\r\n\r\n| Parameter | Type | Required | Description |\r\n|-----------|------|:--------:|-------------|\r\n| `serviceId` | string | Yes | Service ID (`list_id`) from `discover_api` |\r\n\r\n### `call_api`\r\n\r\nCall a Korean public data API. The serviceKey is automatically injected — never pass it yourself. If the call fails with ACCESS_DENIED, the user needs to apply for access to that specific API at data.go.kr.\r\n\r\n| Parameter | Type | Required | Description |\r\n|-----------|------|:--------:|-------------|\r\n| `url` | string | Yes | Full endpoint URL from `describe_api` results |\r\n| `params` | string | — | Query parameters as a JSON **string** (not a raw object), e.g. `'{\"stationName\":\"종로구\",\"dataTerm\":\"DAILY\"}'`. Parameter names must come from `describe_api`'s `request_parameters` — do not guess. |\r\n| `maxResults` | int | — | Max items to return (default: 20, prevents context overflow) |\r\n\r\n## Error Code Mapping\r\n\r\nWhen a data.go.kr API returns an error, the server translates it into a Korean guidance message the LLM can relay directly:\r\n\r\n| Code | Meaning | LLM receives |\r\n|------|---------|--------------|\r\n| 12 | NO_OPENAPI_SERVICE | 이 API가 존재하지 않습니다. discover_api로 다시 검색해보세요. |\r\n| 20 | ACCESS_DENIED | 이 API에 대한 활용신청이 필요합니다. (포털 링크 포함) |\r\n| 22 | KEY_NOT_REGISTERED | API 키가 등록되지 않았습니다. |\r\n| 30 | TRAFFIC_EXCEEDED | 일일 호출 한도를 초과했습니다. |\r\n| 31 | UNREGISTERED_IP | 이 IP가 등록되지 않았습니다. |\r\n\r\n## Environment Variables\r\n\r\n| Variable | Required | Default | Description |\r\n|----------|:--------:|---------|-------------|\r\n| `DATA_GO_KR_API_KEY` | — | — | data.go.kr API key (인증키). If unset, the server requests it via MCP Elicitation on first tool call. |\r\n| `PUBLICDATA_API_KEY` | — | — | Legacy alias for `DATA_GO_KR_API_KEY`. Still accepted; prefer the canonical name for new setups. |\r\n| `PUBLICDATA_TIMEOUT_SECONDS` | — | 30 | Per-request timeout |\r\n| `PUBLICDATA_MAX_RESPONSE_LENGTH` | — | 50000 | Maximum response body length in characters |\r\n\r\nCLI args (`--api-key`, `--timeout`, `--max-response-length`) override environment variables\r\nand are intended for manual testing only — `DATA_GO_KR_API_KEY` and Elicitation are the\r\nsupported paths.\r\n\r\n\u003e **Naming note:** the API key follows the external service naming convention\r\n\u003e (`DATA_GO_KR_API_KEY`), while server-local configuration uses the `PUBLICDATA_` prefix.\r\n\u003e This keeps the key aligned with data.go.kr's own documentation so users don't have to\r\n\u003e configure it twice, while local tunables stay grouped under a single package namespace.\r\n\r\n## Security\r\n\r\n- **API key masking** — the serviceKey is replaced with `***` in any error output visible to the LLM\r\n- **Domain whitelist** — `call_api` only allows requests to approved hosts: `api.odcloud.kr`, `apis.data.go.kr`, `api.data.go.kr`, `openapi.data.go.kr`, `www.law.go.kr`, `open.neis.go.kr`\r\n- **Response size limit** — configurable via `PUBLICDATA_MAX_RESPONSE_LENGTH` (default: 50,000 chars)\r\n- **No log leaks** — the API key is never printed to stdout or stderr\r\n\r\n## Project Structure\r\n\r\n```\r\nsrc/FieldCure.Mcp.PublicData.Kr/\r\n├── Program.cs                       # MCP server entry point (stdio); no startup hard-fail\r\n├── Services/\r\n│   ├── ApiKeyResolver.cs            # env var → MCP Elicitation → soft-fail chain + cache + retry cap\r\n│   ├── InvalidApiKeyException.cs    # Signals upstream auth rejection (HTTP 401/403 or body error)\r\n│   ├── KeyedCall.cs                 # Tool-side resolve → run → invalidate → retry helper\r\n│   ├── PublicDataHttpClient.cs      # HTTP proxy with serviceKey injection + auth-error detection\r\n│   ├── DomainWhitelist.cs           # SSRF prevention via host whitelist\r\n│   ├── ResponseNormalizer.cs        # XML→JSON conversion, wrapper removal\r\n│   └── ErrorCodeMapper.cs           # Error code → Korean guidance messages\r\n└── Tools/\r\n    ├── DiscoverApiTool.cs           # discover_api\r\n    ├── DescribeApiTool.cs           # describe_api\r\n    └── CallApiTool.cs               # call_api\r\n```\r\n\r\n## Development\r\n\r\n```bash\r\n# Build\r\ndotnet build\r\n\r\n# Test\r\ndotnet test\r\n\r\n# Pack as dotnet tool\r\ndotnet pack src/FieldCure.Mcp.PublicData.Kr -c Release\r\n```\r\n\r\n## See Also\r\n\r\nPart of the [AssistStudio ecosystem](https://github.com/fieldcure/fieldcure-assiststudio#packages).\r\n\r\n## License\r\n\r\n[MIT](LICENSE)\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffieldcure%2Ffieldcure-mcp-publicdata","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffieldcure%2Ffieldcure-mcp-publicdata","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffieldcure%2Ffieldcure-mcp-publicdata/lists"}