@aborruso/ckan-mcp-server 0.4.19 → 0.4.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LOG.md +4 -0
- package/dist/worker.js +4 -4
- package/package.json +1 -1
package/LOG.md
CHANGED
package/dist/worker.js
CHANGED
|
@@ -595,7 +595,7 @@ Returns:
|
|
|
595
595
|
`,i+=`| Group | Datasets |
|
|
596
596
|
`,i+=`|-------|----------|
|
|
597
597
|
`;for(let a of o)i+=`| ${a.display_name||a.name} | ${a.count} |
|
|
598
|
-
`}return{content:[{type:"text",text:J(i)}]}}catch(r){return{content:[{type:"text",text:`Error searching groups: ${r instanceof Error?r.message:String(r)}`}],isError:!0}}})}var Tv="https://data.europa.eu/api/mqa/cache/datasets",Ev="https://data.europa.eu/api/hub/repo/datasets",xO=[/^https?:\/\/(www\.)?dati\.gov\.it/i];function wO(t){return xO.some(e=>e.test(t))}function $O(t){return t.trim().replace(/:/g,"-").replace(/-+/g,"-").toLowerCase()}function SO(t){let e=$O(t);if(!e)return[];let r=[e];return e.includes("~~")||r.push(`${e}~~1`,`${e}~~2`),r}var ln={accessibility:100,findability:100,interoperability:110,reusability:75,contextuality:20};function kO(t){if(!t||typeof t!="object")return;let e=t["@value"];if(typeof e=="number")return e;if(typeof e=="string"){let r=Number(e);return Number.isFinite(r)?r:void 0}}function zO(t){let e={};if(!
|
|
598
|
+
`}return{content:[{type:"text",text:J(i)}]}}catch(r){return{content:[{type:"text",text:`Error searching groups: ${r instanceof Error?r.message:String(r)}`}],isError:!0}}})}var Tv="https://data.europa.eu/api/mqa/cache/datasets",Ev="https://data.europa.eu/api/hub/repo/datasets",xO=[/^https?:\/\/(www\.)?dati\.gov\.it/i];function wO(t){return xO.some(e=>e.test(t))}function $O(t){return t.trim().replace(/:/g,"-").replace(/-+/g,"-").toLowerCase()}function SO(t){let e=$O(t);if(!e)return[];let r=[e];return e.includes("~~")||r.push(`${e}~~1`,`${e}~~2`),r}var ln={accessibility:100,findability:100,interoperability:110,reusability:75,contextuality:20};function kO(t){if(!t||typeof t!="object")return;let e=t["@value"];if(typeof e=="number")return e;if(typeof e=="string"){let r=Number(e);return Number.isFinite(r)?r:void 0}}function zO(t){let e={},r=t;if(typeof t=="string")try{r=JSON.parse(t)}catch{return e}if(!r||typeof r!="object")return e;let n=r["@graph"];if(!Array.isArray(n))return e;for(let o of n){if(!o||typeof o!="object")continue;let s=o["dqv:isMeasurementOf"];if(!s)continue;let i=typeof s=="string"?s:s["@id"];if(typeof i!="string")continue;let a=kO(o["dqv:value"]);a!==void 0&&(i.endsWith("#accessibilityScoring")?e.accessibility=a:i.endsWith("#findabilityScoring")?e.findability=a:i.endsWith("#interoperabilityScoring")?e.interoperability=a:i.endsWith("#reusabilityScoring")?e.reusability=a:i.endsWith("#contextualityScoring")?e.contextuality=a:i.endsWith("#scoring")&&(e.total=a))}return e}function TO(t){let e=[];return Object.keys(ln).forEach(r=>{let n=t[r];typeof n=="number"&&n<ln[r]&&e.push(r)}),e}async function EO(t,e){let r=await ne(t,"package_show",{id:e}),n=r.identifier||r.name,o=SO(n);if(o.length===0)throw new Error("Dataset identifier is empty; cannot query MQA API");for(let s of o){let i=`${Tv}/${s}`,a=`${Ev}/${s}/metrics`;try{let c=await Zt.get(i,{timeout:3e4,headers:{"User-Agent":"CKAN-MCP-Server/1.0"}}),u;try{u=await Zt.get(a,{responseType:"json",timeout:3e4,headers:{"User-Agent":"CKAN-MCP-Server/1.0"}})}catch(p){throw Zt.isAxiosError(p)?new Error(`MQA metrics error: ${p.message}`):p}let l=zO(u.data),h=c.data?.result?.results?.[0]?.info?.["dataset-id"]||s,m={scores:l,nonMaxDimensions:TO(l),metricsUrl:a,mqaUrl:i,portalId:h};return{mqa:c.data,breakdown:m}}catch(c){if(Zt.isAxiosError(c)){if(c.response?.status===404)continue;throw new Error(`MQA API error: ${c.message}`)}throw c}}throw new Error(`Quality metrics not found or identifier not aligned on data.europa.eu. Tried: ${o.join(", ")}. Check the dataset quality page on data.europa.eu to confirm the identifier (it may include a '~~1' suffix) or verify alignment on dati.gov.it (quality may be marked as 'Non disponibile o identificativo non allineato').`)}function Cp(t,e){if(Array.isArray(t)){for(let r of t)if(r&&typeof r=="object"&&e in r)return r[e]}}function zv(t){if(!Array.isArray(t))return;let e=new Map;for(let r of t){if(!r||typeof r!="object")continue;let n=r.name,o=r.percentage;typeof n=="string"&&typeof o=="number"&&e.set(n.toLowerCase(),o)}if(e.has("yes"))return(e.get("yes")||0)>0;if(e.size>0){for(let[r,n]of e.entries())if(r.startsWith("2")&&n>0)return!0;return!1}}function dt(t,e){let r=Cp(t,e);if(typeof r=="boolean")return r}function un(t,e,r){let n=Cp(t,e),o=zv(n);if(o!==void 0)return{available:o};if(r){let s=Cp(t,r),i=zv(s);if(i!==void 0)return{available:i}}}function RO(t){let e=t?.mqa??t,r=t?.breakdown,n=e?.result?.results?.[0];return!n||typeof n!="object"?{...t,breakdown:r}:{id:n.info?.["dataset-id"],info:{score:n.info?.score},accessibility:{accessUrl:un(n.accessibility,"accessUrlAvailability","accessUrlStatusCode"),downloadUrl:un(n.accessibility,"downloadUrlAvailability","downloadUrlStatusCode")},reusability:{licence:un(n.reusability,"licenceAvailability"),contactPoint:dt(n.reusability,"contactPointAvailability")!==void 0?{available:dt(n.reusability,"contactPointAvailability")}:void 0,publisher:dt(n.reusability,"publisherAvailability")!==void 0?{available:dt(n.reusability,"publisherAvailability")}:void 0},interoperability:{format:un(n.interoperability,"formatAvailability"),mediaType:un(n.interoperability,"mediaTypeAvailability")},findability:{keyword:dt(n.findability,"keywordAvailability")!==void 0?{available:dt(n.findability,"keywordAvailability")}:void 0,category:dt(n.findability,"categoryAvailability")!==void 0?{available:dt(n.findability,"categoryAvailability")}:void 0,spatial:dt(n.findability,"spatialAvailability")!==void 0?{available:dt(n.findability,"spatialAvailability")}:void 0,temporal:dt(n.findability,"temporalAvailability")!==void 0?{available:dt(n.findability,"temporalAvailability")}:void 0},contextuality:{byteSize:un(n.contextuality,"byteSizeAvailability"),rights:un(n.contextuality,"rightsAvailability")},breakdown:r}}function PO(t,e){let r=RO(t),n=[];if(n.push(`# Quality Metrics for Dataset: ${e}`),n.push(""),r.info?.score!==void 0&&(n.push(`**Overall Score**: ${r.info.score}/450`),n.push("")),r.breakdown?.scores){n.push("## Dimension Scores");let s=r.breakdown.scores,i=[["accessibility","Accessibility",ln.accessibility],["findability","Findability",ln.findability],["interoperability","Interoperability",ln.interoperability],["reusability","Reusability",ln.reusability],["contextuality","Contextuality",ln.contextuality]];for(let[a,c,u]of i){let l=s[a];if(typeof l=="number"){let d=l>=u,h=d?"\u2705":"\u26A0\uFE0F";n.push(`- ${c}: ${l}/${u} ${h}${d?"":` (max ${u})`}`)}}r.breakdown.nonMaxDimensions.length>0?n.push(`- Non-max dimension(s): ${r.breakdown.nonMaxDimensions.join(", ")}`):Object.keys(s).length>0&&n.push("- Non-max dimension(s): none"),n.push("")}r.accessibility&&(n.push("## Accessibility"),r.accessibility.accessUrl!==void 0&&n.push(`- Access URL: ${r.accessibility.accessUrl.available?"\u2713":"\u2717"} Available`),r.accessibility.downloadUrl!==void 0&&n.push(`- Download URL: ${r.accessibility.downloadUrl.available?"\u2713":"\u2717"} Available`),n.push("")),r.reusability&&(n.push("## Reusability"),r.reusability.licence!==void 0&&n.push(`- License: ${r.reusability.licence.available?"\u2713":"\u2717"} Available`),r.reusability.contactPoint!==void 0&&n.push(`- Contact Point: ${r.reusability.contactPoint.available?"\u2713":"\u2717"} Available`),r.reusability.publisher!==void 0&&n.push(`- Publisher: ${r.reusability.publisher.available?"\u2713":"\u2717"} Available`),n.push("")),r.interoperability&&(n.push("## Interoperability"),r.interoperability.format!==void 0&&n.push(`- Format: ${r.interoperability.format.available?"\u2713":"\u2717"} Available`),r.interoperability.mediaType!==void 0&&n.push(`- Media Type: ${r.interoperability.mediaType.available?"\u2713":"\u2717"} Available`),n.push("")),r.findability&&(n.push("## Findability"),r.findability.keyword!==void 0&&n.push(`- Keywords: ${r.findability.keyword.available?"\u2713":"\u2717"} Available`),r.findability.category!==void 0&&n.push(`- Category: ${r.findability.category.available?"\u2713":"\u2717"} Available`),r.findability.spatial!==void 0&&n.push(`- Spatial: ${r.findability.spatial.available?"\u2713":"\u2717"} Available`),r.findability.temporal!==void 0&&n.push(`- Temporal: ${r.findability.temporal.available?"\u2713":"\u2717"} Available`),n.push("")),r.contextuality&&(n.push("## Contextuality"),r.contextuality.byteSize!==void 0&&n.push(`- Byte Size: ${r.contextuality.byteSize.available?"\u2713":"\u2717"} Available`),r.contextuality.rights!==void 0&&n.push(`- Rights: ${r.contextuality.rights.available?"\u2713":"\u2717"} Available`),n.push("")),n.push("---");let o=r.breakdown?.portalId||r.id||e;return n.push(`Portal: https://data.europa.eu/data/datasets/${o}/quality?locale=it`),n.push(`MQA source: ${Tv}/${o}`),n.push(`Metrics endpoint: ${r.breakdown?.metricsUrl||`${Ev}/${o}/metrics`}`),n.join(`
|
|
599
599
|
`)}function Rv(t){t.tool("ckan_get_mqa_quality","Get MQA (Metadata Quality Assurance) quality metrics for a dataset on dati.gov.it. Returns quality score and detailed metrics (accessibility, reusability, interoperability, findability, contextuality) from data.europa.eu. Only works with dati.gov.it server.",{server_url:$.string().url().describe("Base URL of dati.gov.it (e.g., https://www.dati.gov.it/opendata)"),dataset_id:$.string().describe("Dataset ID or name"),response_format:ke.optional()},async({server_url:e,dataset_id:r,response_format:n})=>{if(!wO(e))return{content:[{type:"text",text:`Error: MQA quality metrics are only available for dati.gov.it datasets. Provided server: ${e}
|
|
600
600
|
|
|
601
601
|
The MQA (Metadata Quality Assurance) system is operated by data.europa.eu and only evaluates datasets from Italian open data portal.`}]};try{let o=await EO(e,r);return{content:[{type:"text",text:(n||"markdown")==="json"?JSON.stringify(o,null,2):PO(o,r)}]}}catch(o){return{content:[{type:"text",text:`Error retrieving quality metrics: ${o instanceof Error?o.message:String(o)}`}]}}})}function kr(t){let e=t.hostname;if(!e)throw new Error("Invalid ckan:// URI: missing server hostname");let r=t.pathname.split("/").filter(a=>a.length>0);if(r.length<2)throw new Error(`Invalid ckan:// URI: expected /{type}/{id}, got ${t.pathname}`);let[n,...o]=r,s=o.join("/");if(!n||!s)throw new Error("Invalid ckan:// URI: missing type or id");return{server:hv(e)||`https://${e}`,type:n,id:s}}function Pv(t){t.registerResource("ckan-dataset",new Ct("ckan://{server}/dataset/{id}",{list:void 0}),{title:"CKAN Dataset",description:"Access dataset metadata from any CKAN server. URI format: ckan://{server}/dataset/{id}",mimeType:"application/json"},async(e,r)=>{try{let{server:n}=kr(e),o=r.id,s=await ne(n,"package_show",{id:o}),i=J(JSON.stringify(s,null,2));return{contents:[{uri:e.href,mimeType:"application/json",text:i}]}}catch(n){let o=n instanceof Error?n.message:String(n);return{contents:[{uri:e.href,mimeType:"text/plain",text:`Error fetching dataset: ${o}`}]}}})}function Ov(t){t.registerResource("ckan-resource",new Ct("ckan://{server}/resource/{id}",{list:void 0}),{title:"CKAN Resource",description:"Access resource metadata and download URL from any CKAN server. URI format: ckan://{server}/resource/{id}",mimeType:"application/json"},async(e,r)=>{try{let{server:n}=kr(e),o=r.id,s=await ne(n,"resource_show",{id:o}),i=J(JSON.stringify(s,null,2));return{contents:[{uri:e.href,mimeType:"application/json",text:i}]}}catch(n){let o=n instanceof Error?n.message:String(n);return{contents:[{uri:e.href,mimeType:"text/plain",text:`Error fetching resource: ${o}`}]}}})}function Nv(t){t.registerResource("ckan-organization",new Ct("ckan://{server}/organization/{name}",{list:void 0}),{title:"CKAN Organization",description:"Access organization metadata from any CKAN server. URI format: ckan://{server}/organization/{name}",mimeType:"application/json"},async(e,r)=>{try{let{server:n}=kr(e),o=r.name,s=await ne(n,"organization_show",{id:o,include_datasets:!1}),i=J(JSON.stringify(s,null,2));return{contents:[{uri:e.href,mimeType:"application/json",text:i}]}}catch(n){let o=n instanceof Error?n.message:String(n);return{contents:[{uri:e.href,mimeType:"text/plain",text:`Error fetching organization: ${o}`}]}}})}var ka=t=>t.replace(/["\\]/g,"\\$&"),OO=t=>{let e=t.trim(),r=[e],n=e.toUpperCase();return n!==e&&r.push(n),`(${["res_format","distribution_format"].flatMap(i=>r.map(a=>`${i}:"${ka(a)}"`)).join(" OR ")})`},za=(t,e)=>{t.registerResource(e.name,new Ct(e.template,{list:void 0}),{title:e.title,description:e.description,mimeType:"application/json"},async(r,n)=>{try{let{server:o}=kr(r),s=e.buildFq(n),i=await ne(o,"package_search",{q:"*:*",fq:s}),a=J(JSON.stringify(i,null,2));return{contents:[{uri:r.href,mimeType:"application/json",text:a}]}}catch(o){let s=o instanceof Error?o.message:String(o);return{contents:[{uri:r.href,mimeType:"text/plain",text:`Error fetching datasets: ${s}`}]}}})};function Iv(t){za(t,{name:"ckan-group-datasets",template:"ckan://{server}/group/{name}/datasets",title:"CKAN Group Datasets",description:"List datasets in a CKAN group (theme). URI format: ckan://{server}/group/{name}/datasets",buildFq:e=>`groups:"${ka(e.name)}"`})}function Av(t){za(t,{name:"ckan-organization-datasets",template:"ckan://{server}/organization/{name}/datasets",title:"CKAN Organization Datasets",description:"List datasets for a CKAN organization. URI format: ckan://{server}/organization/{name}/datasets",buildFq:e=>`organization:"${ka(e.name)}"`})}function Cv(t){za(t,{name:"ckan-tag-datasets",template:"ckan://{server}/tag/{name}/datasets",title:"CKAN Tag Datasets",description:"List datasets matching a CKAN tag. URI format: ckan://{server}/tag/{name}/datasets",buildFq:e=>`tags:"${ka(e.name)}"`})}function jv(t){za(t,{name:"ckan-format-datasets",template:"ckan://{server}/format/{format}/datasets",title:"CKAN Format Datasets",description:"List datasets by resource format. URI format: ckan://{server}/format/{format}/datasets",buildFq:e=>OO(e.format)})}function Mv(t){Pv(t),Ov(t),Nv(t),Iv(t),Av(t),Cv(t),jv(t)}var qt=t=>({messages:[{role:"user",content:{type:"text",text:t}}]});var NO="ckan-search-by-theme",IO=(t,e,r)=>`# Guided search: datasets by theme
|
|
@@ -712,7 +712,7 @@ For aggregates, use SQL:
|
|
|
712
712
|
ckan_datastore_search_sql({
|
|
713
713
|
server_url: "${t}",
|
|
714
714
|
sql: "SELECT * FROM "<resource-id>" LIMIT 10"
|
|
715
|
-
})`,Uv=t=>{t.registerPrompt(DO,{title:"Analyze a dataset",description:"Guided prompt to inspect dataset metadata and explore DataStore tables.",argsSchema:{server_url:$.string().url().describe("Base URL of the CKAN server"),id:$.string().min(1).describe("Dataset id or name (CKAN package id)")}},async({server_url:e,id:r})=>qt(LO(e,r)))};var Fv=t=>{Zv(t),qv(t),Dv(t),Lv(t),Uv(t)};function Vv(){return new aa({name:"ckan-mcp-server",version:"0.4.
|
|
715
|
+
})`,Uv=t=>{t.registerPrompt(DO,{title:"Analyze a dataset",description:"Guided prompt to inspect dataset metadata and explore DataStore tables.",argsSchema:{server_url:$.string().url().describe("Base URL of the CKAN server"),id:$.string().min(1).describe("Dataset id or name (CKAN package id)")}},async({server_url:e,id:r})=>qt(LO(e,r)))};var Fv=t=>{Zv(t),qv(t),Dv(t),Lv(t),Uv(t)};function Vv(){return new aa({name:"ckan-mcp-server",version:"0.4.19"})}function Hv(t){vv(t),bv(t),xv(t),wv(t),$v(t),kv(t),Rv(t),Mv(t),Fv(t)}var Ta=class{constructor(e={}){this._started=!1,this._streamMapping=new Map,this._requestToStreamMapping=new Map,this._requestResponseMap=new Map,this._initialized=!1,this._enableJsonResponse=!1,this._standaloneSseStreamId="_GET_stream",this.sessionIdGenerator=e.sessionIdGenerator,this._enableJsonResponse=e.enableJsonResponse??!1,this._eventStore=e.eventStore,this._onsessioninitialized=e.onsessioninitialized,this._onsessionclosed=e.onsessionclosed,this._allowedHosts=e.allowedHosts,this._allowedOrigins=e.allowedOrigins,this._enableDnsRebindingProtection=e.enableDnsRebindingProtection??!1,this._retryInterval=e.retryInterval}async start(){if(this._started)throw new Error("Transport already started");this._started=!0}createJsonErrorResponse(e,r,n,o){let s={code:r,message:n};return o?.data!==void 0&&(s.data=o.data),new Response(JSON.stringify({jsonrpc:"2.0",error:s,id:null}),{status:e,headers:{"Content-Type":"application/json",...o?.headers}})}validateRequestHeaders(e){if(this._enableDnsRebindingProtection){if(this._allowedHosts&&this._allowedHosts.length>0){let r=e.headers.get("host");if(!r||!this._allowedHosts.includes(r)){let n=`Invalid Host header: ${r}`;return this.onerror?.(new Error(n)),this.createJsonErrorResponse(403,-32e3,n)}}if(this._allowedOrigins&&this._allowedOrigins.length>0){let r=e.headers.get("origin");if(r&&!this._allowedOrigins.includes(r)){let n=`Invalid Origin header: ${r}`;return this.onerror?.(new Error(n)),this.createJsonErrorResponse(403,-32e3,n)}}}}async handleRequest(e,r){let n=this.validateRequestHeaders(e);if(n)return n;switch(e.method){case"POST":return this.handlePostRequest(e,r);case"GET":return this.handleGetRequest(e);case"DELETE":return this.handleDeleteRequest(e);default:return this.handleUnsupportedRequest()}}async writePrimingEvent(e,r,n,o){if(!this._eventStore||o<"2025-11-25")return;let s=await this._eventStore.storeEvent(n,{}),i=`id: ${s}
|
|
716
716
|
data:
|
|
717
717
|
|
|
718
718
|
`;this._retryInterval!==void 0&&(i=`id: ${s}
|
|
@@ -895,8 +895,8 @@ data:
|
|
|
895
895
|
<pre><code>curl ${e.origin}/health</code></pre>
|
|
896
896
|
|
|
897
897
|
<div class="footer">
|
|
898
|
-
Version 0.4.
|
|
898
|
+
Version 0.4.19 \u2022 Running on Cloudflare Workers \u2022 <a href="https://github.com/ondata/ckan-mcp-server/blob/main/LICENSE.txt" target="_blank">MIT License</a>
|
|
899
899
|
</div>
|
|
900
900
|
</div>
|
|
901
901
|
</body>
|
|
902
|
-
</html>`,{headers:{"Content-Type":"text/html; charset=utf-8","Access-Control-Allow-Origin":"*"}});if(t.method==="GET"&&e.pathname==="/health")return new Response(JSON.stringify({status:"ok",version:"0.4.
|
|
902
|
+
</html>`,{headers:{"Content-Type":"text/html; charset=utf-8","Access-Control-Allow-Origin":"*"}});if(t.method==="GET"&&e.pathname==="/health")return new Response(JSON.stringify({status:"ok",version:"0.4.19",tools:14,resources:7,prompts:5,runtime:"cloudflare-workers"}),{headers:{"Content-Type":"application/json","Access-Control-Allow-Origin":"*"}});if(e.pathname==="/mcp")try{let r=await Jv.handleRequest(t),n=new Headers(r.headers);return n.set("Access-Control-Allow-Origin","*"),new Response(r.body,{status:r.status,statusText:r.statusText,headers:n})}catch(r){return console.error("Worker error:",r),new Response(JSON.stringify({jsonrpc:"2.0",error:{code:-32603,message:"Internal error",data:r instanceof Error?r.message:String(r)},id:null}),{status:500,headers:{"Content-Type":"application/json","Access-Control-Allow-Origin":"*"}})}return new Response("Not Found",{status:404,headers:{"Access-Control-Allow-Origin":"*"}})}};export{n4 as default};
|