@aborruso/ckan-mcp-server 0.4.13 → 0.4.14
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/CLAUDE.md +7 -7
- package/LOG.md +14 -0
- package/PRD.md +3 -3
- package/README.md +15 -8
- package/dist/index.js +31 -1
- package/dist/worker.js +31 -27
- package/examples/langgraph/01_basic_workflow.py +277 -0
- package/examples/langgraph/02_data_exploration.py +366 -0
- package/examples/langgraph/README.md +719 -0
- package/examples/langgraph/metadata_quality.py +299 -0
- package/examples/langgraph/requirements.txt +12 -0
- package/examples/langgraph/setup.sh +32 -0
- package/examples/langgraph/test_setup.py +106 -0
- package/package.json +1 -1
package/CLAUDE.md
CHANGED
|
@@ -41,7 +41,7 @@ The server exposes MCP tools for:
|
|
|
41
41
|
# Build project (uses esbuild - fast and lightweight)
|
|
42
42
|
npm run build
|
|
43
43
|
|
|
44
|
-
# Run test suite (
|
|
44
|
+
# Run test suite (191 tests - unit + integration)
|
|
45
45
|
npm test
|
|
46
46
|
|
|
47
47
|
# Watch mode for tests during development
|
|
@@ -73,7 +73,7 @@ npm run deploy # Deploy to Cloudflare Workers
|
|
|
73
73
|
The project uses **esbuild** for compilation and **vitest** for testing:
|
|
74
74
|
|
|
75
75
|
- **Build**: Ultra-fast builds (milliseconds instead of minutes)
|
|
76
|
-
- **Tests**:
|
|
76
|
+
- **Tests**: 191 tests (unit + integration) with 100% success rate
|
|
77
77
|
- **Coverage**: ~39% overall (utils: 98%, tools: 15-20%) - available via vitest with v8 coverage engine
|
|
78
78
|
|
|
79
79
|
The `build:tsc` script is available as a fallback but can cause memory issues in some environments (particularly WSL). Always use `npm run build` which uses esbuild.
|
|
@@ -88,12 +88,12 @@ The project has a comprehensive test suite using **Vitest**:
|
|
|
88
88
|
tests/
|
|
89
89
|
├── unit/
|
|
90
90
|
│ ├── formatting.test.ts # Utility functions (19 tests)
|
|
91
|
-
│ ├── http.test.ts # HTTP client (
|
|
91
|
+
│ ├── http.test.ts # HTTP client (11 tests)
|
|
92
92
|
│ └── uri.test.ts # URI parsing (11 tests)
|
|
93
93
|
├── integration/
|
|
94
|
-
│ ├── package.test.ts # Package tools (
|
|
94
|
+
│ ├── package.test.ts # Package tools (31 tests)
|
|
95
95
|
│ ├── organization.test.ts # Organization tools (6 tests)
|
|
96
|
-
│ ├── datastore.test.ts # DataStore tools (
|
|
96
|
+
│ ├── datastore.test.ts # DataStore tools (19 tests)
|
|
97
97
|
│ ├── resources.test.ts # MCP Resources (11 tests)
|
|
98
98
|
│ └── status.test.ts # Status tools (2 tests)
|
|
99
99
|
└── fixtures/
|
|
@@ -101,7 +101,7 @@ tests/
|
|
|
101
101
|
└── errors/ # Error scenario mocks
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
-
**Test Coverage**:
|
|
104
|
+
**Test Coverage**: 191 tests total (117 unit + 74 integration)
|
|
105
105
|
|
|
106
106
|
When making changes:
|
|
107
107
|
1. Run tests before committing: `npm test`
|
|
@@ -341,7 +341,7 @@ To test with Claude Desktop, add the MCP configuration to the config file.
|
|
|
341
341
|
- Direct data access for datasets, resources, organizations
|
|
342
342
|
|
|
343
343
|
**v0.2.0 (2026-01-08)**: Comprehensive test suite
|
|
344
|
-
-
|
|
344
|
+
- 191 tests (unit + integration)
|
|
345
345
|
- ~39% code coverage (utils well-tested, tools improving)
|
|
346
346
|
|
|
347
347
|
**v0.1.0 (2026-01-08)**: Modular refactoring
|
package/LOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# LOG
|
|
2
2
|
|
|
3
|
+
## 2026-01-22
|
|
4
|
+
|
|
5
|
+
### Date Query Auto-Conversion (v0.4.14)
|
|
6
|
+
|
|
7
|
+
- **Feature**: Auto-convert NOW-based date math for `modified` and `issued` fields
|
|
8
|
+
- **Problem**: CKAN Solr supports `NOW-XDAYS` syntax only on `metadata_modified` and `metadata_created` fields
|
|
9
|
+
- **Solution**: New `convertDateMathForUnsupportedFields()` automatically converts queries like `modified:[NOW-30DAYS TO NOW]` to ISO dates `modified:[2025-12-23T... TO 2026-01-22T...]`
|
|
10
|
+
- **Supported fields**: `modified`, `issued` (auto-converted) | `metadata_modified`, `metadata_created` (native NOW support)
|
|
11
|
+
- **Supported units**: DAYS, MONTHS, YEARS (singular and plural forms)
|
|
12
|
+
- **Tests**: +10 unit tests (201 total, all passing)
|
|
13
|
+
- **Documentation**: Updated tool description with NOW syntax limitations and examples
|
|
14
|
+
- **Files**: `src/utils/search.ts`, `src/tools/package.ts`, `tests/unit/search.test.ts`
|
|
15
|
+
- **No breaking changes**: Backward compatible - existing queries work unchanged
|
|
16
|
+
|
|
3
17
|
## 2026-01-19
|
|
4
18
|
|
|
5
19
|
### Search Parser Escaping
|
package/PRD.md
CHANGED
|
@@ -214,7 +214,7 @@ An MCP server that exposes tools to interact with CKAN API v3, enabling AI agent
|
|
|
214
214
|
- `wrangler@^4.58.0` - Cloudflare Workers CLI
|
|
215
215
|
|
|
216
216
|
**Test Framework**:
|
|
217
|
-
- `vitest@^4.0.16` - Test runner (
|
|
217
|
+
- `vitest@^4.0.16` - Test runner (191 tests, 100% passing)
|
|
218
218
|
|
|
219
219
|
### 4.2 Architecture Diagram
|
|
220
220
|
|
|
@@ -825,7 +825,7 @@ ckan_package_search({
|
|
|
825
825
|
### 10.3 Testing & Quality
|
|
826
826
|
|
|
827
827
|
✅ **Current State**:
|
|
828
|
-
-
|
|
828
|
+
- 191 unit and integration tests (100% passing)
|
|
829
829
|
- vitest test runner
|
|
830
830
|
- Coverage for all 13 tools
|
|
831
831
|
- Fixtures for offline testing
|
|
@@ -860,7 +860,7 @@ ckan_package_search({
|
|
|
860
860
|
- **Memory Usage**: < 50MB runtime (Node.js), Workers limits apply
|
|
861
861
|
- **Response Time**: < 30s (CKAN API timeout), < 10s (Workers)
|
|
862
862
|
- **Cold Start**: < 60ms (Cloudflare Workers)
|
|
863
|
-
- **Test Coverage**:
|
|
863
|
+
- **Test Coverage**: 191 tests (100% passing)
|
|
864
864
|
|
|
865
865
|
### 11.2 Distribution Metrics
|
|
866
866
|
|
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ MCP (Model Context Protocol) server for interacting with CKAN-based open data po
|
|
|
17
17
|
- ⚡ Pagination and faceting support
|
|
18
18
|
- 📄 MCP Resource Templates for direct data access
|
|
19
19
|
- 🧭 Guided MCP prompts for common workflows
|
|
20
|
-
- 🧪 Test suite with
|
|
20
|
+
- 🧪 Test suite with 191 tests (100% passing)
|
|
21
21
|
|
|
22
22
|
---
|
|
23
23
|
|
|
@@ -45,7 +45,7 @@ npm install
|
|
|
45
45
|
# Build with esbuild (fast, ~4ms)
|
|
46
46
|
npm run build
|
|
47
47
|
|
|
48
|
-
# Run tests (
|
|
48
|
+
# Run tests (191 tests)
|
|
49
49
|
npm test
|
|
50
50
|
```
|
|
51
51
|
|
|
@@ -117,22 +117,29 @@ Then add to `claude_desktop_config.json`:
|
|
|
117
117
|
}
|
|
118
118
|
```
|
|
119
119
|
|
|
120
|
-
#### Option 2: Local Installation (Optional)
|
|
120
|
+
#### Option 2: Local Project Installation (Optional)
|
|
121
121
|
|
|
122
|
-
If you
|
|
122
|
+
If you want to install the server in a specific project:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
cd your-project
|
|
126
|
+
npm install @aborruso/ckan-mcp-server
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Then add to `claude_desktop_config.json`:
|
|
123
130
|
|
|
124
131
|
```json
|
|
125
132
|
{
|
|
126
133
|
"mcpServers": {
|
|
127
134
|
"ckan": {
|
|
128
|
-
"command": "
|
|
129
|
-
"args": ["/
|
|
135
|
+
"command": "npx",
|
|
136
|
+
"args": ["@aborruso/ckan-mcp-server"]
|
|
130
137
|
}
|
|
131
138
|
}
|
|
132
139
|
}
|
|
133
140
|
```
|
|
134
141
|
|
|
135
|
-
|
|
142
|
+
**Note**: `npx` will use the locally installed package in `node_modules`. Make sure to install the package first.
|
|
136
143
|
|
|
137
144
|
#### Option 3: From Source
|
|
138
145
|
|
|
@@ -559,7 +566,7 @@ ckan-mcp-server/
|
|
|
559
566
|
│ └── transport/
|
|
560
567
|
│ ├── stdio.ts # Stdio transport
|
|
561
568
|
│ └── http.ts # HTTP transport
|
|
562
|
-
├── tests/ # Test suite (
|
|
569
|
+
├── tests/ # Test suite (191 tests)
|
|
563
570
|
├── dist/ # Compiled files (generated)
|
|
564
571
|
├── package.json
|
|
565
572
|
└── README.md
|
package/dist/index.js
CHANGED
|
@@ -168,6 +168,31 @@ function isFieldedQuery(query) {
|
|
|
168
168
|
function escapeSolrQuery(query) {
|
|
169
169
|
return query.replace(SOLR_SPECIAL_CHARS, "\\$&");
|
|
170
170
|
}
|
|
171
|
+
function convertDateMathForUnsupportedFields(query) {
|
|
172
|
+
const now = /* @__PURE__ */ new Date();
|
|
173
|
+
const nowIso = now.toISOString();
|
|
174
|
+
const pattern = /\b(?!metadata_)(modified|issued):\[NOW-(\d+)(DAYS?|MONTHS?|YEARS?)\s+TO\s+NOW\]/gi;
|
|
175
|
+
return query.replace(pattern, (match, field, amount, unit) => {
|
|
176
|
+
const amountNum = parseInt(amount, 10);
|
|
177
|
+
const startDate = new Date(now);
|
|
178
|
+
const normalizedUnit = unit.toLowerCase().replace(/s$/, "");
|
|
179
|
+
switch (normalizedUnit) {
|
|
180
|
+
case "day":
|
|
181
|
+
startDate.setDate(startDate.getDate() - amountNum);
|
|
182
|
+
break;
|
|
183
|
+
case "month":
|
|
184
|
+
startDate.setMonth(startDate.getMonth() - amountNum);
|
|
185
|
+
break;
|
|
186
|
+
case "year":
|
|
187
|
+
startDate.setFullYear(startDate.getFullYear() - amountNum);
|
|
188
|
+
break;
|
|
189
|
+
default:
|
|
190
|
+
return match;
|
|
191
|
+
}
|
|
192
|
+
const startIso = startDate.toISOString();
|
|
193
|
+
return `${field}:[${startIso} TO ${nowIso}]`;
|
|
194
|
+
});
|
|
195
|
+
}
|
|
171
196
|
function resolveSearchQuery(serverUrl, query, parserOverride) {
|
|
172
197
|
const portalSearchConfig = getPortalSearchConfig(serverUrl);
|
|
173
198
|
const portalForce = portalSearchConfig.force_text_field ?? false;
|
|
@@ -180,7 +205,8 @@ function resolveSearchQuery(serverUrl, query, parserOverride) {
|
|
|
180
205
|
const trimmedQuery = query.trim();
|
|
181
206
|
forceTextField = trimmedQuery !== DEFAULT_SEARCH_QUERY && !isFieldedQuery(trimmedQuery);
|
|
182
207
|
}
|
|
183
|
-
|
|
208
|
+
let effectiveQuery = forceTextField ? `text:(${escapeSolrQuery(query)})` : query;
|
|
209
|
+
effectiveQuery = convertDateMathForUnsupportedFields(effectiveQuery);
|
|
184
210
|
return { effectiveQuery, forcedTextField: forceTextField };
|
|
185
211
|
}
|
|
186
212
|
|
|
@@ -333,6 +359,9 @@ Query Syntax (parameter q):
|
|
|
333
359
|
- NOW/DAY, NOW/MONTH (round down)
|
|
334
360
|
- Combined: "metadata_modified:[NOW-2MONTHS TO NOW]"
|
|
335
361
|
- Example: "metadata_created:[NOW-1YEAR TO *]"
|
|
362
|
+
- IMPORTANT: NOW syntax works on metadata_modified and metadata_created fields
|
|
363
|
+
- For 'modified' and 'issued' fields, NOW syntax is auto-converted to ISO dates
|
|
364
|
+
- Manual ISO dates always work: "modified:[2026-01-15T00:00:00Z TO *]"
|
|
336
365
|
|
|
337
366
|
Field existence:
|
|
338
367
|
- Exists: "field:*" or "field:[* TO *]"
|
|
@@ -351,6 +380,7 @@ Examples:
|
|
|
351
380
|
- Proximity: { q: "notes:"open data"~3" }
|
|
352
381
|
- Date range: { q: "metadata_modified:[2024-01-01T00:00:00Z TO 2024-12-31T23:59:59Z]" }
|
|
353
382
|
- Date math: { q: "metadata_modified:[NOW-6MONTHS TO *]" }
|
|
383
|
+
- Date math (auto-converted): { q: "modified:[NOW-30DAYS TO NOW]" }
|
|
354
384
|
- Field exists: { q: "organization:* AND num_resources:[1 TO *]" }
|
|
355
385
|
- Boosting: { q: "title:climate^2 OR notes:climate" }
|
|
356
386
|
- Filter org: { fq: "organization:regione-siciliana" }
|