Ckan Mcp Server

io.github.aborruso由 GitHub 帳號 aborruso 發布v0.4.138更新於 Nov 8, 2026

MCP server for interacting with CKAN open data portals

概覽

AI 產生的概覽

讓助理用自然語言搜尋、瀏覽與查詢 CKAN 開放資料入口網站,包括資料集、機關、群組、標籤與表格式資料。

可以做什麼
  • 搜尋與檢視資料集:Solr 風格檢索、相關性排序、資料集完整詳情、標籤清單
  • 瀏覽機關與群組:列出、檢視詳情、依名稱搜尋
  • 查詢表格式資料:DataStore 記錄篩選與 DataStore 資源的 SQL 查詢
  • 分析目錄:入口網站統計概覽、資料集與結構描述檢查、dati.gov.it 的 MQA 品質分數
  • 探索全球入口網站,並對公開端點執行 SPARQL SELECT 查詢
  • 透過 ckan:// 資源範本直接讀取資料集、資源、機關、群組、標籤與格式的中繼資料
適用情境
適合需要公開開放資料進行研究、新聞查證、政策檢視或資料管線的情境,讓助理不必了解 CKAN API 或 Solr 語法就能找到並摘要資料集。也適合比較各行政機關發布的資料,或在不下載檔案的情況下查詢表格式資源。
執行需求
可透過 npx 或全域 npm 安裝在本機執行(需 Node.js),也可用 Docker 容器;另提供託管 HTTP 端點。不需帳號或 API 金鑰。HTTP 傳輸必須設定 CKAN_ALLOWED_DOMAINS 允許清單才能啟動,並需能連線至目標入口網站的網路。
安裝前請注意
HTTP 傳輸沒有身分驗證,任何能連上它的用戶端都可送出請求;應只綁定本機回環位址或置於具驗證的反向代理之後,並以 CKAN_ALLOWED_DOMAINS 限制可查詢的主機。公開託管實例會記錄工具呼叫參數並以開放資料發布,查詢中不要放入個人資訊。DataStore SQL 與 SPARQL 查詢會送往第三方入口網站。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Ckan Mcp Server,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

[npm version] [GitHub] [Ask DeepWiki] [License: MIT] [Newsletter] [Greptile: The War on Bugs]

CKAN MCP Server

Turn any (CKAN) open data portal into a conversation.

Give your AI assistant direct access to any CKAN open data portal — search datasets, explore organizations, query tabular data, and read metadata, all through natural language.

CKAN is the open-source platform behind most public open data portals worldwide (Italy's dati.gov.it, the US data.gov, Canada's open.canada.ca, and many more). Navigating these portals usually requires knowing their structure, APIs, and search syntax. This MCP server removes that barrier: once connected, your AI tool can do it all for you.

This is possible because of open standards and open source. CKAN exposes a fully documented, public API. Metadata follows DCAT, an open W3C standard for describing datasets. Both are free to use, free to build on, and maintained by open communities. This server stands on that foundation.

Who is this for? Everyone. Journalists looking for data to verify a story. Researchers exploring public datasets. Public servants checking what data their administration publishes. Developers building data pipelines. No CKAN knowledge required.

Adopted by AgID — This project has been reused by AgID, Italy's Agency for Digital Italy, as part of its effort to make public open data more accessible, immediate, and easier to consult through AI.

Two ways to use it — pick the one that suits you:

Option A: Install locallyOption B: No install
Hownpm install -g @aborruso/ckan-mcp-serverPoint your tool to the hosted HTTP endpoint
Best forRuns on your machine, works with any local toolQuick start, zero setup
Request quotaNo shared quota100k requests/day shared quota

Hosted endpoint: https://ckan-mcp-server.andy-pr.workers.dev/mcp

Recommendation: Option B is a great way to get started and try things out without any setup. Once you're familiar with what the server can do, switching to Option A (local install) gives you unlimited usage with no shared quotas.

👉 Want to explore the codebase? The AI-generated DeepWiki is a great starting point.

License: MIT — see LICENSE for complete details. Third-party notices: NOTICE.md.

[CKAN MCP Server demo]


⚖️ Limits

The local and hosted server use the same tool and output caps. The hosted endpoint also has the shared request quota shown above.

AreaDefaultMaximum or configuration
Tool output50,000 charactersFixed server-wide cap
ckan_datastore_search rows10032,000 (0 returns column names only)
ckan_package_search results per page101,000
ckan_find_relevant_datasets results1050
Injected sparql_query rows251,000 when injected; a query that supplies its own LIMIT is not capped
ckan_tag_list results1001,000
ckan_find_portals results1050
HTTP response body32 MiBCKAN_MAX_RESPONSE_BYTES for local Node.js deployments
Decompressed response body64 MiBCKAN_MAX_DECOMPRESSED_BYTES for local Node.js deployments

Text and Markdown responses that exceed the output cap are cut and include a truncation note. JSON responses stay parseable: the server reduces known result arrays and flags the response with _truncated and _original_count, and if a response still cannot fit it is replaced by a small object carrying _truncated and an explanatory _error. The same capped payload is sent on both channels, so a client reading structuredContent sees exactly what the text shows, truncation flags included. Use pagination or a narrower query when you need the complete result set.


🔌 Use it in your favorite tool

ChatGPT | Claude Desktop | Claude Code | Le Chat (Mistral) | Perplexity Pro | Gemini CLI | VS Code | Codex CLI

This server works with any MCP-compatible client. The sections below cover some of the most popular ones — if your tool isn't listed, check its documentation for MCP configuration and use the same endpoint URL or command.

All examples below work with both the local installation and the hosted endpoint. Where both options differ, both are shown.

Using local installation? You need to install the server first — see Run locally.

ChatGPT

Requires a ChatGPT Plus, Team, or Enterprise plan.

  1. Open the profile menu and go to Settings → Apps → Advanced settings
  2. Enable Developer mode
  3. Click Create app (top-right)
  4. Fill in the form:
    • Name: CKAN MCP Server
    • Description: Search datasets on CKAN open data portals
    • MCP Server URL: https://ckan-mcp-server.andy-pr.workers.dev/mcp
    • Authentication: No Auth
    • Check the confirmation box, then click Create
  5. In a new chat, click + → More and select CKAN MCP Server

For a step-by-step walkthrough with screenshots, see the full ChatGPT guide.

Claude Desktop

Using the hosted endpoint (no install) — via connector UI:

  1. Open Claude Desktop and go to Settings → Integrations
  2. Click Add custom integration
  3. Fill in the details:
    • Name: CKAN MCP Server
    • MCP Server URL: https://ckan-mcp-server.andy-pr.workers.dev/mcp
  4. Click Add to save
  5. Open a new chat, click +, select Integrations, and enable CKAN MCP Server
  6. When Claude asks to use a tool, click Allow (or Always allow)

For a detailed walkthrough with screenshots, see the full Claude guide.

Using the hosted endpoint (no install) — via config file:

Configuration file location:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • Linux: ~/.config/Claude/claude_desktop_config.json
json
{  "mcpServers": {    "ckan": {      "url": "https://ckan-mcp-server.andy-pr.workers.dev/mcp"    }  }}

Using local installation:

json
{  "mcpServers": {    "ckan": {      "command": "npx",      "args": ["@aborruso/ckan-mcp-server@latest"]    }  }}

Claude Code

Using the hosted endpoint (no install):

bash
claude mcp add -s user -t http ckan https://ckan-mcp-server.andy-pr.workers.dev/mcp

Using local installation:

bash
claude mcp add -s user ckan npx @aborruso/ckan-mcp-server@latest

--scope user makes the server available globally across all your projects, not just the current one.

To add it only for a specific project, run from the project folder without the --scope user flag:

bash
claude mcp add --transport http ckan https://ckan-mcp-server.andy-pr.workers.dev/mcp

Le Chat (Mistral)

  1. In the left sidebar, click Intelligence, then select Connectors
  2. Click + Add Connector
  3. Select the Custom MCP Connector tab and fill in the details:
    • Name: CKAN
    • Connector Server: https://ckan-mcp-server.andy-pr.workers.dev/mcp
  4. Click Connect to save
  5. Open a new chat, click +, then Connectors, and enable CKAN

For a step-by-step walkthrough with screenshots, see the full Le Chat guide.

Perplexity Pro

Requires a Perplexity Pro account.

  1. Click the "+" (Attach) icon in the message input bar and select Connectors & sources
  2. Click Connect external app
  3. Fill in the details:
    • Name: CKAN MCP Server
    • MCP Server URL: https://ckan-mcp-server.andy-pr.workers.dev/mcp
    • Authorization Type: No Authentication
    • Connection Type: HTTP Streamable
  4. Check the confirmation box and click Save
  5. In a new chat, click + → Connectors & sources and enable ckan_mcp_server

For a step-by-step walkthrough with screenshots, see the full Perplexity guide.

Gemini CLI

bash
gemini mcp add -s user -t http ckan https://ckan-mcp-server.andy-pr.workers.dev/mcp

Or add manually to ~/.gemini/settings.json:

json
{  "mcpServers": {    "ckan": {      "httpUrl": "https://ckan-mcp-server.andy-pr.workers.dev/mcp"    }  }}

VS Code

Add to your User Settings or .vscode/settings.json:

Using the hosted endpoint (no install):

json
{  "mcpServers": {    "ckan": {      "url": "https://ckan-mcp-server.andy-pr.workers.dev/mcp",      "type": "http"    }  }}

Using local installation:

json
{  "mcpServers": {    "ckan": {      "command": "npx",      "args": ["@aborruso/ckan-mcp-server@latest"]    }  }}

Codex CLI

Add to ~/.codex/config.toml:

Using the hosted endpoint (no install):

toml
[mcp_servers.ckan]url = "https://ckan-mcp-server.andy-pr.workers.dev/mcp"

Using local installation:

toml
[mcp_servers.ckan]command = "npx"args = ["-y", "@aborruso/ckan-mcp-server@latest"]

🖥️ Run locally

Option 1 — Install via npm

The quickest way. Install the package globally and it's immediately available as a command:

bash
npm install -g @aborruso/ckan-mcp-server

The server will be available as ckan-mcp-server, or you can run it without installing via:

bash
npx @aborruso/ckan-mcp-server@latest

Option 2 — Clone and build

For development or if you want to run the latest unreleased code:

bash
git clone https://github.com/ondata/ckan-mcp-server.gitcd ckan-mcp-servernpm installnpm run buildnode dist/index.js

Option 3 — Docker

Thanks to @piersoft, you can also run the server via Docker:

bash
git clone https://github.com/ondata/ckan-mcp-server.gitcd ckan-mcp-serverdocker compose up --build -d

The MCP server will be available at http://localhost:3000/mcp. See docker/README.md for full details, including how to connect Claude Desktop to the container.


🛠️ Available Tools

Search and Discovery

  • ckan_package_search: Search datasets with Solr queries
  • ckan_find_relevant_datasets: Rank datasets by relevance score
  • ckan_package_show: Complete details of a dataset. On portals that use ckanext-scheming the schema's other root fields are added as fields, each with its label and the value as stored
  • ckan_tag_list: List tags with counts

Organizations

  • ckan_organization_list: List all organizations
  • ckan_organization_show: Details of an organization
  • ckan_organization_search: Search organizations by name

Groups

  • ckan_group_list: List groups
  • ckan_group_show: Show group details
  • ckan_group_search: Search groups by name

DataStore

  • ckan_datastore_search: Query tabular data
  • ckan_datastore_search_sql: SQL queries on DataStore

Quality Metrics

  • ckan_get_mqa_quality: Get the MQA quality score (methodology v2, 0-7.5 scale with band) for dati.gov.it datasets, with the failing metrics that would raise it most
  • ckan_get_mqa_quality_details: List every failing MQA metric for dati.gov.it datasets, grouped by FAIR dimension, with DCAT-AP property, weight and gain

Portal Discovery

  • ckan_find_portals: Discover CKAN portals worldwide by country, language, or topic (uses datashades.info live registry of ~950 portals)

Catalog Analysis

  • ckan_analyze_datasets: Search datasets and inspect DataStore schemas of queryable resources
  • ckan_catalog_stats: Statistical overview of a portal (totals, breakdown by category, format, organization)

SPARQL

  • sparql_query: Execute SPARQL SELECT queries against any public SPARQL endpoint

Utilities

  • ckan_status_show: Verify server status

📎 MCP Resource Templates

Direct data access via ckan:// URI scheme:

  • ckan://{server}/dataset/{id} - Dataset metadata
  • ckan://{server}/resource/{id} - Resource metadata and download URL
  • ckan://{server}/organization/{name} - Organization details
  • ckan://{server}/group/{name}/datasets - Datasets by group (theme)
  • ckan://{server}/organization/{name}/datasets - Datasets by organization
  • ckan://{server}/tag/{name}/datasets - Datasets by tag
  • ckan://{server}/format/{format}/datasets - Datasets by resource format (res_format + distribution_format)

Examples:

ckan://dati.gov.it/dataset/vaccini-covidckan://demo.ckan.org/resource/abc-123ckan://data.gov/organization/sample-orgckan://dati.gov.it/group/ambiente/datasetsckan://dati.gov.it/organization/regione-toscana/datasetsckan://dati.gov.it/tag/turismo/datasetsckan://dati.gov.it/format/csv/datasets

💡 Usage Examples

A natural language conversation

Once connected, just ask in plain language. No query syntax needed:

"Search dati.gov.it for datasets about air quality in Milan, then summarize what each contains — time coverage, license, and best download format."

The server finds 31 datasets, groups them by structural pattern, and returns a clear summary — including series names, years covered, publisher, and format. No CKAN knowledge required.


The examples below show natural language requests alongside the actual tool call the LLM will generate internally and send to the CKAN portal. You never write these queries yourself — they are shown here to illustrate how your question gets translated under the hood.

Search datasets (natural language: "search for population datasets")

typescript
ckan_package_search({  server_url: "https://www.dati.gov.it/opendata",  q: "popolazione",  rows: 20})

Force text-field parser for long OR queries (natural language: "find hotel or accommodation datasets")

typescript
ckan_package_search({  server_url: "https://www.dati.gov.it/opendata",  q: "hotel OR alberghi OR \"strutture ricettive\" OR ospitalità OR ricettività",  query_parser: "text",  rows: 0  // returns only the total count, no dataset records — useful to check how many results match before fetching them})

Note: when query_parser: "text" is used, Solr special characters in the query are escaped automatically.

Rank datasets by relevance (natural language: "find most relevant datasets about urban mobility")

typescript
ckan_find_relevant_datasets({  server_url: "https://www.dati.gov.it/opendata",  query: "mobilità urbana",  limit: 5})

Filter by organization (natural language: "show recent datasets from Tuscany Region")

typescript
ckan_package_search({  server_url: "https://www.dati.gov.it/opendata",  fq: "organization:regione-toscana",  sort: "metadata_modified desc"})

Get statistics with faceting (natural language: "show statistics by organization, tags and format")

typescript
ckan_package_search({  server_url: "https://www.dati.gov.it/opendata",  facet_field: ["organization", "tags", "res_format"],  rows: 0  // skip dataset records, return only the facet counts})

List tags (natural language: "show top tags about health")

typescript
ckan_tag_list({  server_url: "https://www.dati.gov.it/opendata",  tag_query: "salute",  limit: 25})

Search groups (natural language: "find groups about environment")

typescript
ckan_group_search({  server_url: "https://www.dati.gov.it/opendata",  pattern: "ambiente"})

DataStore Query (natural language: "query tabular data filtering by region and year")

What is DataStore? CKAN DataStore is an optional extension that imports tabular resources (CSV, Excel) into a queryable database. It allows filtering, sorting, and field selection directly on the data — without downloading the file. Not all portals have it enabled, and not all datasets use it even when the portal supports it. Check datastore_active: true on a resource to confirm availability.

typescript
// Ordinanze viabili del Comune di Messina — resource with datastore_active: trueckan_datastore_search({  server_url: "https://dati.comune.messina.it",  resource_id: "17301b8b-2a5b-425f-80b0-5b75bb1793e9",  filters: { "tipo": "lavori" },  sort: "data_pubblicazione desc",  limit: 10})

👏 A shout-out to Comune di Messina and all public administrations that enable the DataStore extension: by doing so, they make their data dramatically easier to query and explore — including through AI tools like this one.

DataStore SQL Query (natural language: "count road orders by type")

typescript
// Count ordinanze viabili by tipo — Comune di Messinackan_datastore_search_sql({  server_url: "https://dati.comune.messina.it",  sql: "SELECT tipo, COUNT(*) AS total FROM \"17301b8b-2a5b-425f-80b0-5b75bb1793e9\" GROUP BY tipo ORDER BY total DESC LIMIT 5"})

🧠 AI Skill for smarter multi-step queries

The MCP server provides the raw tools — the skill teaches your AI assistant how to use them intelligently.

Out of the box, an AI assistant knows each tool individually. The skill adds higher-level reasoning: which portal to query for a given country, what to do when a portal is unreachable, how to fall back to the European open data portal, and how to construct queries that actually return results.

What the skill adds:

  • Country routing — automatically identifies the most authoritative CKAN portal for a country (national > regional > local)
  • Fallback chain — if a portal is unreachable or returns 0 results, tries alternatives and, for European countries, falls back to data.europa.eu with correct country filters
  • Query construction — bilingual queries, parser selection, fq syntax, wildcard handling
  • Correct API patterns — the European portal (data.europa.eu) requires specific facets+facetOperator+facetGroupOperator parameters that are undocumented and easy to get wrong; the skill encodes this correctly

Examples of what the skill enables:

"Find road accident data in Portugal"→ ckan_find_portals(country="Portugal")          # finds 3 regional portals→ ckan_package_search on each → 0 results→ [tells user] "No results on Portuguese CKAN portals. Trying data.europa.eu..."→ curl "https://data.europa.eu/api/hub/search/search?q=acidentes+rodoviarios         &facetOperator=AND&facetGroupOperator=AND&facets={"country":["pt"]}"→ 157 datasets found — reported with source and filter details
"Find French open data about energy"→ [knows data.gouv.fr is NOT CKAN — redirects to data.europa.eu]→ curl "...?q=energie+energy&facets={"country":["fr"]}..."→ Results filtered strictly to France

Install the skill

The skill folder lives at skills/ckan-mcp/ in this repository and is listed on skills.sh. Use the Skills CLI to install it:

bash
# Install globally (available in all your projects)npx skills add -g ondata/ckan-mcp-server --skill ckan-mcp
# Or for a single project (run from your project folder)npx skills add ondata/ckan-mcp-server --skill ckan-mcp

🌍 Supported CKAN Portals

Some examples of supported portals:

catalog.data.gov is no longer CKAN. Data.gov replaced its catalog in 2025 with a different API (details); a call to it now explains this instead of failing with a bare 404.

Discover CKAN portals worldwide

Datashades.info/portals maintains a live registry of ~950 CKAN portals from around the world, with metadata on version, plugins, dataset counts, and geographic coordinates. Thanks to Sara Petti for bringing it to our attention.

The ckan_find_portals tool queries this registry directly. You can filter by country, language, minimum dataset count, or DataStore availability:

ckan_find_portals({ country: "Italy", has_datastore: true, limit: 5 })ckan_find_portals({ language: "fr", min_datasets: 500 })ckan_find_portals({ query: "transport" })

The portal data is also available as a public JSON API — no authentication required:

EndpointDescription
GET https://datashades.info/api/portal/listFull list of portals with CKAN version, plugins, dataset/resource/organization counts, and country coordinates
GET https://datashades.info/api/portal/statsAggregate statistics across all monitored portals
GET https://datashades.info/api/portal/historical/statsHistorical trend data for the monitored portals

🔍 Advanced Solr Queries

CKAN uses Apache Solr as its default search engine. Understanding Solr syntax unlocks the full power of dataset search — from simple keywords to complex boolean expressions, fuzzy matching, proximity searches, and date math.

Basic syntax

# Basic searchq: "popolazione"
# Field searchq: "title:popolazione"q: "notes:sanità"
# Boolean operatorsq: "popolazione AND sicilia"q: "popolazione OR abitanti"q: "popolazione NOT censimento"
# Filters (fq) — single valuefq: "organization:comune-palermo"fq: "tags:sanità"fq: "res_format:CSV"
# Filters (fq) — OR on same field: use field:(val1 OR val2)fq: "res_format:(CSV OR JSON)"fq: "organization:(comune-palermo OR comune-roma)"
# ⚠️ Wrong OR syntax — silently ignored, returns entire catalog:# fq: "res_format:CSV OR res_format:JSON"   ← DO NOT USE
# Filters on CKAN extras fields — use extras_ prefixfq: "extras_hvd_category:\"http://data.europa.eu/bna/c_ac64a52d\""fq: "extras_hvd_category:(\"http://data.europa.eu/bna/c_ac64a52d\" OR \"http://data.europa.eu/bna/c_dd313021\")"
# Wildcardq: "popolaz*"
# Date rangefq: "metadata_modified:[2023-01-01T00:00:00Z TO *]"

Advanced Query Examples

These real-world examples demonstrate powerful Solr query combinations tested on the Italian open data portal (dati.gov.it):

1. Fuzzy Search + Date Math + Boosting (natural language: "find healthcare datasets modified in last 6 months")

Find healthcare datasets (tolerating spelling errors) modified in the last 6 months, prioritizing title matches:

typescript
ckan_package_search({  server_url: "https://www.dati.gov.it/opendata",  q: "(title:sanità~2^3 OR title:salute~2^3 OR notes:sanità~1) AND metadata_modified:[NOW-6MONTHS TO *]",  sort: "score desc, metadata_modified desc",  rows: 30})

Techniques used:

  • sanità~2 - Fuzzy search with edit distance 2 (finds "sanita", "sanitá", minor typos)
  • ^3 - Boosts title matches 3x higher in relevance scoring
  • NOW-6MONTHS - Dynamic date math for rolling time windows
  • Combined boolean logic with multiple field searches

Results: 949 datasets including hospital units, healthcare organizations, medical services

2. Proximity Search + Complex Boolean (natural language: "find air pollution datasets excluding water")

Environmental datasets where "inquinamento" and "aria" (air pollution) appear close together, excluding water-related datasets:

typescript
ckan_package_search({  server_url: "https://www.dati.gov.it/opendata",  q: "(notes:\"inquinamento aria\"~5 OR title:\"qualità aria\"~3) AND NOT (title:acqua OR title:mare)",  facet_field: ["organization", "res_format"],  rows: 25})

Techniques used:

  • "inquinamento aria"~5 - Proximity search (words within 5 positions)
  • ~3 - Tighter proximity for title matches
  • NOT (title:acqua OR title:mare) - Exclude water/sea datasets
  • Faceting for statistical breakdown

Results: 305 datasets

3. Wildcard + Field Existence + Date Math (natural language: "regional datasets with any format from last month")

Regional datasets published in the last month that have at least one resource format declared:

typescript
ckan_package_search({  server_url: "https://www.dati.gov.it/opendata",  q: "organization:regione* AND metadata_created:[NOW-1MONTH TO *] AND res_format:*",  sort: "metadata_modified desc",  facet_field: ["organization"],  rows: 10})

Techniques used:

  • regione* - Wildcard matches all regional organizations
  • res_format:* - Field existence check (has at least one resource format declared)
  • NOW-1MONTH - Rolling 30-day window

Results: 293 datasets

4. Explicit Date Range + Facets (natural language: "Ministry of Labour datasets updated in 2025")

Datasets from the Italian Ministry of Labour modified during 2025, with facets by format and tags:

typescript
ckan_package_search({  server_url: "https://www.dati.gov.it/opendata",  q: "organization:ministero-del-lavoro AND metadata_modified:[2025-01-01T00:00:00Z TO 2025-12-31T23:59:59Z]",  sort: "metadata_modified desc",  facet_field: ["res_format", "tags"],  rows: 10})

Techniques used:

  • [2025-01-01T00:00:00Z TO 2025-12-31T23:59:59Z] - Explicit date range (full year)
  • organization:ministero-del-lavoro - Filter by specific organization
  • Multiple facets for format and topic breakdown

Results: 83 datasets

Solr Query Syntax Reference

Boolean Operators: AND, OR, NOT, +required, -excluded Wildcards: * (multiple chars), ? (single char) - Note: left truncation not supported Fuzzy: ~N (edit distance), e.g., health~2 Proximity: "phrase"~N (words within N positions) Boosting: ^N (relevance multiplier), e.g., title:water^2 Ranges:

  • Inclusive: [a TO b], e.g., num_resources:[5 TO 10]
  • Exclusive: {a TO b}, e.g., num_resources:{0 TO 100}
  • Open-ended: [2024-01-01T00:00:00Z TO *]

Date Math: NOW, NOW-1YEAR, NOW-6MONTHS, NOW-7DAYS, NOW/DAY Field Existence: field:* (field exists), NOT field:* (field missing)


📅 Understanding date fields

CKAN portals can be source catalogs (data published directly by the organization) or harvesting aggregators (data collected from many other portals). This distinction matters a lot when filtering by date.

FieldMeaning on source portalMeaning on aggregator
issuedWhen the publisher released the datasetWhen the publisher released the dataset
metadata_createdWhen the record was first createdWhen the record was first harvested
metadata_modifiedWhen the record was last updatedWhen the record was last re-harvested

On an aggregator like dati.gov.it, metadata_modified is updated every time the portal re-harvests — even if the dataset content hasn't changed. This makes it unsuitable for finding "recently updated content".

Example — same dataset, three different timestamps on dati.gov.it (aggregator):

json
{  "issued": "2024-12-10",  "metadata_created": "2024-12-16",  "metadata_modified": "2026-02-28"}

metadata_modified is February 2026 only because the portal re-harvested it then — not because the data changed.

Which date fields are filterable on dati.gov.it?

All three fields are Solr-indexed and usable in queries:

FieldSolr-indexedWhat queries return
issued✅Datasets by publisher release date — most meaningful, but ~14% of datasets lack it
metadata_created✅Datasets by first harvesting date on dati.gov.it
metadata_modified✅Datasets by last re-harvesting date — often noisy

Query examples (dati.gov.it):

typescript
# Datasets about road accidents published by the original source in 2025ckan_package_search({  server_url: "https://www.dati.gov.it/opendata",  q: "incidenti stradali",  fq: "issued:[2025-01-01T00:00:00Z TO 2025-12-31T23:59:59Z]"})// → ~121 results (only datasets where publisher filled in `issued`)
# Datasets first appearing on dati.gov.it in 2025ckan_package_search({  server_url: "https://www.dati.gov.it/opendata",  q: "incidenti stradali",  fq: "metadata_created:[2025-01-01T00:00:00Z TO 2025-12-31T23:59:59Z]"})// → ~164 results (includes older datasets harvested for the first time in 2025)

Note on issued coverage: ~59,700 of 69,000+ datasets on dati.gov.it have issued populated. Queries on issued are accurate but incomplete — datasets without the field are silently excluded. Prefer issued for content-date queries; use metadata_created only as a fallback for "when did this appear on the portal".

Recommendation: use issued to find datasets by publication date. Use metadata_created to find datasets that appeared on the portal recently.


👩‍💻 Developer Reference

Project Structure

ckan-mcp-server/├── src/│   ├── index.ts            # Entry point│   ├── server.ts           # MCP server setup│   ├── worker.ts           # Cloudflare Workers entry│   ├── types.ts            # Types & schemas│   ├── utils/│   │   ├── http.ts         # CKAN API client│   │   ├── formatting.ts   # Output formatting│   │   └── url-generator.ts│   ├── tools/│   │   ├── package.ts      # Package search/show│   │   ├── organization.ts # Organization tools│   │   ├── datastore.ts    # DataStore queries│   │   ├── status.ts       # Server status│   │   ├── tag.ts          # Tag tools│   │   └── group.ts        # Group tools│   ├── resources/          # MCP Resource Templates│   │   ├── index.ts│   │   ├── uri.ts│   │   ├── dataset.ts│   │   ├── resource.ts│   │   └── organization.ts│   ├── prompts/            # MCP Guided Prompts│   │   ├── index.ts│   │   ├── theme.ts│   │   ├── organization.ts│   │   ├── format.ts│   │   ├── recent.ts│   │   └── dataset-analysis.ts│   └── transport/│       ├── stdio.ts│       └── http.ts├── tests/                  # Test suite├── dist/                   # Compiled output (generated)├── package.json└── README.md

Build & Test

bash
# Build (esbuild, ~4ms)npm run build
# Watch modenpm run watch
# Run all testsnpm test
# Watch mode for testsnpm run test:watch
# Coverage reportnpm run test:coverage

Explore with MCP Inspector

The MCP Inspector lets you browse tools, test calls interactively, and debug responses in a web UI:

bash
npm install -g @modelcontextprotocol/inspectornpm run buildnpx @modelcontextprotocol/inspector node dist/index.js

Opens at http://localhost:5173.

Security: HTTP transport requires a domain allowlist

The HTTP transport (TRANSPORT=http) is unauthenticated: any client that reaches POST /mcp can drive requests through it. Since v0.4.109 it binds to 127.0.0.1 (loopback) by default and enforces DNS-rebinding protection, so it is not exposed on the LAN and cross-origin browser requests are rejected. To prevent SSRF abuse (e.g. a caller pointing server_url at internal hosts or cloud metadata), it also refuses to start unless you set a domain allowlist:

VariableEffect
CKAN_ALLOWED_DOMAINSComma-separated allowlist of hostnames the server may query (default-deny). Required to start the HTTP transport. Exact hostname match, no wildcards or subdomains. Also enforced on every redirect hop: if a portal redirects to another host, list that host too. Example: CKAN_ALLOWED_DOMAINS="www.dati.gov.it,dati.comune.messina.it"
CKAN_HTTP_ALLOW_ALL=trueExplicit opt-out: start the HTTP transport without an allowlist (logs a security warning). Not recommended when network-exposed.
CKAN_HTTP_HOSTInterface to bind (default 127.0.0.1). Set 0.0.0.0 to expose it, ideally behind an authenticating reverse proxy.
CKAN_HTTP_ALLOWED_HOSTSExtra Host header values accepted by the DNS-rebinding guard (comma-separated). Add your public hostname when binding beyond loopback.
CKAN_HTTP_ALLOWED_ORIGINSAllowed Origin header values for browser clients (comma-separated).

The default stdio transport is unaffected — it stays open so you can query any portal locally. Regardless of allowlist, all requests are also validated against private/internal IP ranges, including hostnames that resolve to internal addresses (DNS-based SSRF, fixed in v0.4.108). The official Cloudflare Worker is sandboxed by the platform and does not require this setting.

Manual HTTP Testing

bash
# Start server (HTTP needs an allowlist — see "Security" above)CKAN_ALLOWED_DOMAINS="www.dati.gov.it" TRANSPORT=http PORT=3001 node dist/index.js
# List available toolscurl -s -X POST http://localhost:3001/mcp \  -H 'Content-Type: application/json' \  -H 'Accept: application/json, text/event-stream' \  -d '{"jsonrpc":"2.0","method":"tools/list","id":1}'
# Call a toolcurl -s -X POST http://localhost:3001/mcp \  -H 'Content-Type: application/json' \  -H 'Accept: application/json, text/event-stream' \  -d '{    "jsonrpc":"2.0","method":"tools/call",    "params":{"name":"ckan_package_search","arguments":{"server_url":"https://www.dati.gov.it/opendata","q":"ambiente","rows":3}},    "id":1  }' | jq -r '.result.content[0].text'

Portal View URL Templates

Some CKAN portals expose non-standard web URLs for viewing datasets or organizations. To support those cases, this project ships with src/portals.json, which maps known portal API URLs (and aliases) to custom view URL templates.

When generating a dataset or organization view link, the server:

  • matches the server_url against api_url and api_url_aliases in src/portals.json
  • uses the portal-specific dataset_view_url / organization_view_url template when available
  • falls back to the generic defaults ({server_url}/dataset/{name} and {server_url}/organization/{name})

Troubleshooting

Wrong URL for Italian portal — use https://www.dati.gov.it/opendata (not https://dati.gov.it).

Connection error

Error: Server not found: https://example.gov

Verify the URL is reachable and use ckan_status_show to confirm the portal is responding.

No results — broaden your query or check what's available with facets:

typescript
ckan_package_search({  server_url: "https://www.dati.gov.it/opendata",  q: "*:*",  facet_field: ["tags", "organization"],  rows: 0})

LLM uses external data when no results are found — when a tool returns no results, some LLMs (e.g. ChatGPT) may supplement the answer with information from their training data without warning. This is a known LLM behavior, not a server issue. To avoid it, instruct the model in your system prompt to only use data returned by the MCP tools and not rely on external sources.


🆘 Support

For issues or questions, open an issue on GitHub.


Privacy Policy

A local installation (npm, Claude Desktop extension, stdio or your own HTTP server) sends nothing to us: queries go straight to the CKAN portal you specify, and the only log is an audit line on your machine's standard error. The public demo instance on Cloudflare Workers logs the arguments of each tool call (tool, portal, search text and parameters, datasets returned, outcome), never IP addresses, headers or conversation content; an archive of those fields is published as open data in data/, so do not put personal information in queries sent to it.

See the full Privacy Policy.


Related tools

  • opensituas — Codes and history of every Italian territorial unit, from the CLI. The join key for any ISTAT dataset.
  • opensdmx — Official statistics from Eurostat, ISTAT, OECD, and other SDMX providers — no hallucinations, only published figures.
  • ISTAT MCP Server — Italian statistical data directly in your AI assistant, via the MCP protocol.

🔗 Useful Links


Created with ❤️ by onData for the open data community

來源:README.md,提交 bd1d5a1

工具

20

ckan_find_relevant_datasets

Find Relevant CKAN Datasets

Find and rank datasets by relevance to a query using weighted fields. Use this instead of ckan_package_search when you want relevance-ranked results with explicit scoring across title, notes, tags, and organization fields. Use ckan_package_search instead when you need Solr filter syntax, facets, or pagination. Uses package_search for discovery and applies a local scoring model. Args: - server_url (string): Base URL of CKAN server (e.g., "https://dati.gov.it/opendata") - query (string): Natural language or keyword query (e.g., "mobilità urbana", "air quality") - limit (number): Number of datasets to return (default: 10) - weights (object): Field weights for scoring — higher weight = more influence on rank Default: title=4, tags=3, notes=2, organization=1, holder=4, publisher=2, coverage=4 coverage: bonus for datasets the portal returned with every query term required (Solr mm=100%); these are fetched first, the rest fills in when they are fewer than limit Note on holder vs organization: on federated catalogs (e.g. dati.gov.it), `organization` is the harvesting catalog (e.g. Regione Puglia), while `holder` (DCAT-AP_IT dct:rightsHolder) is the actual data owner (e.g. Comune di Lecce). Queries like "datasets from a specific Comune" match `holder` correctly; matching only `organization` misses datasets harvested via aggregators. `publisher` (dct:publisher) is scored separately at lower weight as it can contain technical roles ("Redazione OD") rather than the institutional owner. - query_parser ('default' | 'text'): Override search parser behavior - response_format ('markdown' | 'json'): Output format Returns: Ranked datasets with relevance scores and per-field score breakdowns Examples: - { server_url: "https://dati.gov.it/opendata", query: "mobilità" } - { server_url: "...", query: "trasporti", limit: 5, weights: { title: 5, notes: 2 } } - { server_url: "...", query: "defibrillatori Comune di Lecce", weights:

輸入參數limitquery必填weightsserver_url必填query_parserresponse_format

ckan_package_show

Show CKAN Dataset Details

Get complete metadata for a specific dataset (package). Returns full details including resources, organization, tags, and all metadata fields. Notes: - metadata_modified is a CKAN record timestamp (publish time on source portals, harvest time on aggregators), not the content date. - issued/modified are content dates when provided by the publisher. - JSON output adds metadata_harvested_at (same as metadata_modified). Args: - server_url (string): Base URL of CKAN server - id (string): Dataset ID or name (machine-readable slug) - include_tracking (boolean): Include view/download statistics (default: false) - response_format ('markdown' | 'json'): Output format On portals that use ckanext-scheming the schema's other root fields are added as "fields" ([{field, label, value}]), each with the label the schema gives it and the value as stored. Portals without scheming are unaffected. Returns (JSON format): id, name, title, notes, organization, tags, state, license_title, metadata_created, metadata_modified, issued, modified, author, maintainer, frequency, language, publisher_name, holder_name, hvd_category, applicable_legislation, temporal_coverage (array of {start, end, start_equals_issued} from dct:temporal; empty if absent; start_equals_issued=true when start = issued and no end: on dcatapit portals an export default, not a data period), resources (id, name, format, url, size, datastore_active, created, last_modified, api_json_url), view_url, api_json_url Examples: - { server_url: "https://dati.gov.it/opendata", id: "dataset-name" } - { server_url: "...", id: "abc-123-def", include_tracking: true } Typical workflow: ckan_package_show → pick a resource with datastore_active=true → ckan_datastore_search (query its data)

輸入參數id必填server_url必填response_formatinclude_tracking

ckan_list_resources

List CKAN Dataset Resources

List all resources in a dataset with a compact summary. Returns a focused table of resources showing format, size, DataStore availability, and download URL. Use this to quickly assess what files a dataset contains before deciding how to access the data. Args: - server_url (string): Base URL of CKAN server - id (string): Dataset ID or name - format_filter (string): Filter resources by format, case-insensitive (e.g., "CSV", "json", "XLSX") - response_format ('markdown' | 'json'): Output format Returns: Compact resource summary with name, ID, format, size, DataStore flag, and URL Examples: - { server_url: "https://dati.gov.it/opendata", id: "dataset-name" } - { server_url: "...", id: "dataset-name", format_filter: "CSV" } Typical workflow: ckan_package_search → ckan_list_resources (assess available files) → ckan_datastore_search (for resources with DataStore=true) When a resource has DataStore=false but its download URL belongs to a different (source) portal, the tool can probe the source portal for DataStore availability and report source_datastore_active and source_portal_url so you can query the data there instead. This probing is OFF by default (it issues extra HTTP requests to hosts taken from the dataset's own resource URLs); set check_source_portal=true to enable it.

輸入參數id必填server_url必填format_filterresponse_formatcheck_source_portal

ckan_organization_list

List CKAN Organizations

List all organizations on a CKAN server. Organizations are entities that publish and manage datasets. Args: - server_url (string): Base URL of CKAN server - all_fields (boolean): Return full objects vs just names (default: false) - sort (string): Sort field (default: "name asc") - limit (number): Maximum results (default: 100). Use 0 to get only the count via faceting - offset (number): Pagination offset (default: 0) - response_format ('markdown' | 'json'): Output format Returns: List of organizations with metadata. When limit=0, returns only the count of organizations with datasets. Typical workflow: ckan_organization_list → ckan_organization_show (inspect one) → ckan_package_search with fq="organization:name" (browse its datasets)

輸入參數sortlimitoffsetall_fieldsserver_url必填response_format

ckan_organization_show

Show CKAN Organization Details

Get details of a specific organization. Args: - server_url (string): Base URL of CKAN server - id (string): Organization ID or name - include_datasets (boolean): Include list of datasets (default: true) - include_users (boolean): Include list of users (default: false) - response_format ('markdown' | 'json'): Output format Returns: Organization details with optional datasets and users Typical workflow: ckan_organization_show → ckan_package_show (inspect a dataset) → ckan_datastore_search (query its data)

輸入參數id必填server_url必填include_usersresponse_formatinclude_datasets

ckan_datastore_search_sql

Search CKAN DataStore with SQL

Run SQL queries on a CKAN DataStore resource. This endpoint is only available on CKAN portals with DataStore enabled and SQL access exposed. Args: - server_url (string): Base URL of CKAN server - sql (string): SQL query (e.g., SELECT * FROM "resource_id" LIMIT 10) - response_format ('markdown' | 'json'): Output format Returns: SQL query results from DataStore Examples: - { server_url: "...", sql: "SELECT * FROM "abc-123" LIMIT 10" } - { server_url: "...", sql: "SELECT COUNT(*) AS total FROM "abc-123"" } Typical workflow: ckan_package_show (get resource_id) → ckan_datastore_search_sql (run SQL on it) Security note: SQL queries are forwarded directly to the CKAN DataStore API. The CKAN server enforces its own access controls and read-only permissions. No local database is exposed. Queries are limited to public DataStore resources on the target portal.

輸入參數sql必填server_url必填response_format

ckan_status_show

Check CKAN Server Status

Check if a CKAN server is available and get version information. Useful to verify server accessibility before making other requests. Also shows the count of High-Value Datasets (HVD) when the portal supports it. Args: - server_url (string): Base URL of CKAN server Returns: Server status, version information, and HVD dataset count (if available) Typical workflow: ckan_status_show (verify server is up) → ckan_package_search (discover datasets)

輸入參數server_url必填

ckan_tag_list

List CKAN Tags

List tags from a CKAN server using faceting. This returns tag names with counts, optionally filtered by dataset query or tag substring. Args: - server_url (string): Base URL of CKAN server - q (string): Dataset search query (default: "*:*") - fq (string): Filter query (optional) - tag_query (string): Filter tags by substring (optional) - limit (number): Max tags to return (default: 100, max: 1000) - response_format ('markdown' | 'json'): Output format Returns: List of tags with counts (from faceting) Typical workflow: ckan_tag_list → ckan_package_search with fq="tags:tag_name" (find datasets by tag) → ckan_package_show

輸入參數qfqlimittag_queryserver_url必填response_format

ckan_group_list

List CKAN Groups

List all groups on a CKAN server. Groups are thematic collections of datasets. Args: - server_url (string): Base URL of CKAN server - all_fields (boolean): Return full objects vs just names (default: false) - sort (string): Sort field (default: "name asc") - limit (number): Maximum results (default: 100). Use 0 to get only the count via faceting - offset (number): Pagination offset (default: 0) - response_format ('markdown' | 'json'): Output format Returns: List of groups with metadata. When limit=0, returns only the count of groups with datasets. Typical workflow: ckan_group_list → ckan_group_show (inspect one) → ckan_package_search with fq="groups:name" (browse its datasets)

輸入參數sortlimitoffsetall_fieldsserver_url必填response_format

ckan_group_show

Show CKAN Group Details

Get details of a specific group. Args: - server_url (string): Base URL of CKAN server - id (string): Group ID or name - include_datasets (boolean): Include list of datasets (default: true) - response_format ('markdown' | 'json'): Output format Returns: Group details with optional datasets Typical workflow: ckan_group_show → ckan_package_show (inspect a dataset) → ckan_datastore_search (query its data)

輸入參數id必填server_url必填response_formatinclude_datasets

ckan_get_mqa_quality

Get MQA Quality Score

Get MQA (Metadata Quality Assessment) quality score for a dataset on dati.gov.it from data.europa.eu. Returns the final score on the 0-7.5 scale of MQA methodology v2 with its band (Sufficient/Good/Excellent), dataset, distribution and data service scores, and the failing metrics with the largest gain. Datasets not yet re-evaluated fall back to the previous methodology (405 scale), labelled as such. Only works with dati.gov.it server. Typical workflow: ckan_package_show (get dataset ID) → ckan_get_mqa_quality → ckan_get_mqa_quality_details (full list of failing metrics)

輸入參數dataset_id必填server_url必填response_format

ckan_get_mqa_quality_details

Get MQA Quality Details

Get detailed MQA (Metadata Quality Assessment) quality reasons for a dataset on dati.gov.it. Lists every failing metric grouped by FAIR dimension, with DCAT-AP property, weight, how many distributions fail it and its gain on the final score, plus the HTTP status of failing URL tests (e.g. 1100 timeout, 404) (methodology v2); previous-methodology datasets get non-max reasons. Only works with dati.gov.it server. Typical workflow: ckan_get_mqa_quality (get overview scores) → ckan_get_mqa_quality_details (inspect failing metrics)

輸入參數dataset_id必填server_url必填response_format

ckan_analyze_datasets

Analyze CKAN Datasets and DataStore Schema

Search datasets and inspect the DataStore schema of queryable resources. For each dataset found, lists all resources. For DataStore-enabled resources, fetches the full field schema (name, type, and label/notes when available) plus total record count — all in one call. Use this before ckan_datastore_search to understand what fields are available and what data to expect. Args: - server_url (string): Base URL of CKAN server - q (string): Solr search query (e.g. "incidenti", "title:ambiente") - rows (number): Max datasets to analyze (default 5, max 20) - response_format ('markdown' | 'json'): Output format Returns: For each dataset: title, ID, organization, and per DataStore resource: field schema with label/notes (when available from DataStore Dictionary) and record count. Typical workflow: ckan_analyze_datasets → ckan_datastore_search (with known field names)

輸入參數q必填rowsserver_url必填response_format

ckan_catalog_stats

Get CKAN Portal Statistics

Get a statistical overview of a CKAN portal: total dataset count and breakdown by category, format, and organization. Single CKAN call (package_search with rows=0 and facets). No query needed. Args: - server_url (string): Base URL of the CKAN server - facet_limit (number): Max entries per facet section (default 20) - response_format ('markdown' | 'json'): Output format Returns: Total dataset count, categories ranked by count, file formats ranked by count, organizations ranked by count. Typical workflow: ckan_catalog_stats (understand the portal) → ckan_package_search (query specific data)

輸入參數server_url必填facet_limitresponse_format

sparql_query

SPARQL Query

Execute a SPARQL SELECT query against any public HTTPS SPARQL endpoint. Useful for querying open data portals and knowledge graphs that expose SPARQL endpoints, including: - data.europa.eu (European open data portal) - publications.europa.eu (EU Publications Office) - DBpedia, Wikidata - Any DCAT-AP compliant data catalog Only HTTPS endpoints are allowed. Queries timeout after 15 seconds. Only SELECT queries are supported (read-only). If the query does not contain a LIMIT clause, one is injected automatically (default: 25, max: 1000). Args: - endpoint_url (string): HTTPS URL of the SPARQL endpoint - query (string): SPARQL SELECT query to execute - limit (number): Max rows to return (default: 25). Ignored if query already contains LIMIT. - response_format ('markdown' | 'json'): Output format Examples: - Count Italian HVD datasets by publisher on data.europa.eu - Query Wikidata for entities related to a dataset topic - Explore EU controlled vocabularies on publications.europa.eu Typical workflow: sparql_query (explore schema) → sparql_query (targeted query) → ckan_package_search (get dataset details)

輸入參數limitquery必填endpoint_url必填response_format

ckan_find_portals

Find CKAN Portals

Search the live datashades.info registry of ~950 CKAN portals worldwide. Use this tool to discover which CKAN portals exist for a country, language, or topic before querying them with other CKAN tools. **IMPORTANT — country parameter**: always pass country name in English. If the user writes in another language (e.g. "Italia", "España", "Brasil"), translate to English ("Italy", "Spain", "Brazil") before calling this tool. Args: - country (string): Country name in English (e.g. "Italy", "Brazil", "France") - query (string): Keyword to match against portal title (e.g. "transport", "health") - min_datasets (number): Minimum number of datasets (e.g. 100) - language (string): Portal default locale code (e.g. "it", "en", "pt_BR", "fr") - has_datastore (boolean): If true, return only portals with DataStore enabled (supports SQL queries) - limit (number): Max results to return (default 10, max 50) Returns: Ranked list of matching portals with URL, country, CKAN version, dataset count, and DataStore status. Typical workflow: ckan_find_portals (discover portal URL) → ckan_status_show (verify) → ckan_package_search (search datasets)

輸入參數limitquerycountrylanguagemin_datasetshas_datastore

版本歷史

10
  1. v0.4.137Nov 7, 2026
  2. v0.4.135Nov 4, 2026
  3. v0.4.134Oct 29, 2026
  4. v0.4.131Oct 22, 2026
  5. v0.4.130Oct 19, 2026
  6. v0.4.129Oct 6, 2026
  7. v0.4.128Sep 28, 2026
  8. v0.4.127Sep 25, 2026
  9. v0.4.126Sep 23, 2026
  10. v0.4.124Sep 16, 2026

評分

已滿足適用檢查項的 50%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分

    請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。

  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具15 分

    請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。

  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分