@aborruso/ckan-mcp-server 0.4.31 → 0.4.33
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/AGENTS.md +7 -0
- package/LOG.md +10 -0
- package/dist/index.js +61 -4
- package/dist/worker.js +38 -32
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -45,6 +45,13 @@ Keep this managed block so 'openspec update' can refresh the instructions.
|
|
|
45
45
|
|
|
46
46
|
**Single test**: `npm test -- tests/unit/http.test.ts` | `npm test -- -t "testName"`
|
|
47
47
|
|
|
48
|
+
## Local MCP Client Build Test
|
|
49
|
+
|
|
50
|
+
Before deploying, you can test the current dev build by pointing your MCP client at the Node entrypoint in `dist/`:
|
|
51
|
+
|
|
52
|
+
1. Build: `npm run build`
|
|
53
|
+
2. Example absolute path: `/home/aborruso/git/idee/ckan-mcp-server/dist/index.js` (adjust to your local checkout)
|
|
54
|
+
|
|
48
55
|
## GitHub CLI Notes
|
|
49
56
|
|
|
50
57
|
When creating issues with multi-line bodies, avoid literal `\n` in `--body`. Use a here-doc
|
package/LOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
## 2026-02-01
|
|
4
4
|
|
|
5
|
+
### Release v0.4.33
|
|
6
|
+
|
|
7
|
+
- Docs: clarify natural language date-field mapping for package search and document `content_recent` usage with example
|
|
8
|
+
- Files: `src/tools/package.ts`, `src/server.ts`, `src/worker.ts`, `package.json`, `package-lock.json`
|
|
9
|
+
|
|
10
|
+
### Release v0.4.32
|
|
11
|
+
|
|
12
|
+
- Workers: align browser-like headers for fetch path to avoid 403 on dati.gov.it
|
|
13
|
+
- Files: `src/utils/http.ts`, `package.json`, `package-lock.json`
|
|
14
|
+
|
|
5
15
|
### Release v0.4.31
|
|
6
16
|
|
|
7
17
|
- Workers: decode compressed responses via DecompressionStream when available
|
package/dist/index.js
CHANGED
|
@@ -142,12 +142,49 @@ function asBuffer(data) {
|
|
|
142
142
|
}
|
|
143
143
|
return void 0;
|
|
144
144
|
}
|
|
145
|
+
function asArrayBuffer(data) {
|
|
146
|
+
if (!data) {
|
|
147
|
+
return void 0;
|
|
148
|
+
}
|
|
149
|
+
if (data instanceof ArrayBuffer) {
|
|
150
|
+
return data;
|
|
151
|
+
}
|
|
152
|
+
if (ArrayBuffer.isView(data)) {
|
|
153
|
+
return data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
|
|
154
|
+
}
|
|
155
|
+
return void 0;
|
|
156
|
+
}
|
|
157
|
+
async function decodeArrayBufferText(buffer, encoding) {
|
|
158
|
+
if (encoding && typeof DecompressionStream !== "undefined") {
|
|
159
|
+
try {
|
|
160
|
+
const stream = new DecompressionStream(
|
|
161
|
+
encoding.includes("br") ? "br" : encoding.includes("deflate") ? "deflate" : "gzip"
|
|
162
|
+
);
|
|
163
|
+
const decompressed = await new Response(
|
|
164
|
+
new Blob([buffer]).stream().pipeThrough(stream)
|
|
165
|
+
).arrayBuffer();
|
|
166
|
+
return new TextDecoder("utf-8").decode(decompressed).trim();
|
|
167
|
+
} catch {
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return new TextDecoder("utf-8").decode(buffer).trim();
|
|
171
|
+
}
|
|
145
172
|
async function decodePossiblyCompressed(data, headers) {
|
|
146
173
|
if (data === null || data === void 0) {
|
|
147
174
|
return data;
|
|
148
175
|
}
|
|
149
|
-
|
|
150
|
-
|
|
176
|
+
const arrayBuffer = asArrayBuffer(data);
|
|
177
|
+
if (arrayBuffer && typeof Buffer === "undefined") {
|
|
178
|
+
const encoding2 = getHeaderValue(headers, "content-encoding");
|
|
179
|
+
const text2 = await decodeArrayBufferText(arrayBuffer, encoding2);
|
|
180
|
+
if (!text2) {
|
|
181
|
+
return text2;
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
return JSON.parse(text2);
|
|
185
|
+
} catch {
|
|
186
|
+
return text2;
|
|
187
|
+
}
|
|
151
188
|
}
|
|
152
189
|
if (typeof data === "string") {
|
|
153
190
|
try {
|
|
@@ -158,6 +195,9 @@ async function decodePossiblyCompressed(data, headers) {
|
|
|
158
195
|
}
|
|
159
196
|
const buffer = asBuffer(data);
|
|
160
197
|
if (!buffer) {
|
|
198
|
+
if (typeof data === "object") {
|
|
199
|
+
return data;
|
|
200
|
+
}
|
|
161
201
|
return data;
|
|
162
202
|
}
|
|
163
203
|
const encoding = getHeaderValue(headers, "content-encoding");
|
|
@@ -241,7 +281,18 @@ async function makeCkanRequest(serverUrl, action, params = {}) {
|
|
|
241
281
|
method: "GET",
|
|
242
282
|
headers: {
|
|
243
283
|
Accept: "application/json, text/plain, */*",
|
|
244
|
-
"Accept-Language": "en-US,en;q=0.9,it;q=0.8"
|
|
284
|
+
"Accept-Language": "en-US,en;q=0.9,it;q=0.8",
|
|
285
|
+
"Accept-Encoding": "gzip, deflate, br",
|
|
286
|
+
Connection: "keep-alive",
|
|
287
|
+
Referer: `${baseUrl}/`,
|
|
288
|
+
"Sec-Fetch-Site": "same-origin",
|
|
289
|
+
"Sec-Fetch-Mode": "navigate",
|
|
290
|
+
"Sec-Fetch-Dest": "document",
|
|
291
|
+
"Upgrade-Insecure-Requests": "1",
|
|
292
|
+
"Sec-CH-UA": '"Chromium";v="120", "Not?A_Brand";v="24", "Google Chrome";v="120"',
|
|
293
|
+
"Sec-CH-UA-Mobile": "?0",
|
|
294
|
+
"Sec-CH-UA-Platform": '"Linux"',
|
|
295
|
+
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
|
245
296
|
}
|
|
246
297
|
});
|
|
247
298
|
if (!response.ok) {
|
|
@@ -668,6 +719,11 @@ Important - Date field semantics:
|
|
|
668
719
|
- metadata_modified: CKAN record update timestamp (publish time on source portals,
|
|
669
720
|
harvest time on aggregators; use for "updated/modified in last X")
|
|
670
721
|
|
|
722
|
+
Natural language mapping (important for tool callers):
|
|
723
|
+
- "created"/"published" -> prefer issued; fallback to metadata_created
|
|
724
|
+
- "updated"/"modified" -> prefer modified; fallback to metadata_modified
|
|
725
|
+
- For "recent in last X", consider using content_recent (issued with metadata_created fallback)
|
|
726
|
+
|
|
671
727
|
Content-recent helper:
|
|
672
728
|
- content_recent: if true, rewrites the query to use issued with a fallback to
|
|
673
729
|
metadata_created when issued is missing.
|
|
@@ -743,6 +799,7 @@ Examples:
|
|
|
743
799
|
- Date range: { q: "metadata_modified:[2024-01-01T00:00:00Z TO 2024-12-31T23:59:59Z]" }
|
|
744
800
|
- Date math: { q: "metadata_modified:[NOW-6MONTHS TO *]" }
|
|
745
801
|
- Date math (auto-converted): { q: "modified:[NOW-30DAYS TO NOW]" }
|
|
802
|
+
- Recent content (issued w/ fallback): { q: "*:*", content_recent: true, content_recent_days: 180 }
|
|
746
803
|
- Field exists: { q: "organization:* AND num_resources:[1 TO *]" }
|
|
747
804
|
- Boosting: { q: "title:climate^2 OR notes:climate" }
|
|
748
805
|
- Filter org: { fq: "organization:regione-siciliana" }
|
|
@@ -3346,7 +3403,7 @@ var registerAllPrompts = (server2) => {
|
|
|
3346
3403
|
function createServer() {
|
|
3347
3404
|
return new McpServer({
|
|
3348
3405
|
name: "ckan-mcp-server",
|
|
3349
|
-
version: "0.4.
|
|
3406
|
+
version: "0.4.33"
|
|
3350
3407
|
});
|
|
3351
3408
|
}
|
|
3352
3409
|
function registerAll(server2) {
|