@aborruso/ckan-mcp-server 0.4.5 → 0.4.7

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.
Files changed (32) hide show
  1. package/EXAMPLES.md +19 -0
  2. package/LOG.md +13 -0
  3. package/README.md +47 -37
  4. package/dist/index.js +435 -13
  5. package/dist/worker.js +130 -74
  6. package/openspec/changes/add-ckan-analyze-dataset-structure/proposal.md +17 -0
  7. package/openspec/changes/add-ckan-analyze-dataset-structure/specs/ckan-insights/spec.md +7 -0
  8. package/openspec/changes/add-ckan-analyze-dataset-structure/tasks.md +6 -0
  9. package/openspec/changes/add-ckan-analyze-dataset-updates/proposal.md +17 -0
  10. package/openspec/changes/add-ckan-analyze-dataset-updates/specs/ckan-insights/spec.md +7 -0
  11. package/openspec/changes/add-ckan-analyze-dataset-updates/tasks.md +6 -0
  12. package/openspec/changes/add-ckan-audit-tool/proposal.md +17 -0
  13. package/openspec/changes/add-ckan-audit-tool/specs/ckan-insights/spec.md +7 -0
  14. package/openspec/changes/add-ckan-audit-tool/tasks.md +6 -0
  15. package/openspec/changes/add-ckan-dataset-insights/proposal.md +17 -0
  16. package/openspec/changes/add-ckan-dataset-insights/specs/ckan-insights/spec.md +7 -0
  17. package/openspec/changes/add-ckan-dataset-insights/tasks.md +6 -0
  18. package/openspec/changes/archive/2026-01-10-add-ckan-find-relevant-datasets/proposal.md +17 -0
  19. package/openspec/changes/archive/2026-01-10-add-ckan-find-relevant-datasets/specs/ckan-insights/spec.md +7 -0
  20. package/openspec/changes/archive/2026-01-10-add-ckan-find-relevant-datasets/tasks.md +6 -0
  21. package/openspec/changes/update-search-parser-config/proposal.md +13 -0
  22. package/openspec/changes/update-search-parser-config/specs/ckan-insights/spec.md +11 -0
  23. package/openspec/changes/update-search-parser-config/specs/ckan-search/spec.md +11 -0
  24. package/openspec/changes/update-search-parser-config/tasks.md +6 -0
  25. package/openspec/project.md +9 -7
  26. package/openspec/specs/ckan-insights/spec.md +19 -0
  27. package/openspec/specs/cloudflare-deployment/spec.md +344 -0
  28. package/package.json +1 -1
  29. /package/openspec/changes/{add-cloudflare-workers → archive/2026-01-10-add-cloudflare-workers}/design.md +0 -0
  30. /package/openspec/changes/{add-cloudflare-workers → archive/2026-01-10-add-cloudflare-workers}/proposal.md +0 -0
  31. /package/openspec/changes/{add-cloudflare-workers → archive/2026-01-10-add-cloudflare-workers}/specs/cloudflare-deployment/spec.md +0 -0
  32. /package/openspec/changes/{add-cloudflare-workers → archive/2026-01-10-add-cloudflare-workers}/tasks.md +0 -0
@@ -0,0 +1,17 @@
1
+ # Change: Add ckan_analyze_dataset_structure tool
2
+
3
+ ## Why
4
+ Users need quick schema and quality signals without manual inspection.
5
+
6
+ ## What Changes
7
+ - Add MCP tool `ckan_analyze_dataset_structure` for schema summaries.
8
+ - Use resource schema or DataStore fields for columns and types.
9
+ - Compute null-rate stats when DataStore is available.
10
+
11
+ ## Impact
12
+ - Affected specs: `ckan-insights`
13
+ - Affected code: `src/tools/datastore.ts` and resource utilities
14
+
15
+ ## Open Questions
16
+ - Default `sample_size` for null-rate analysis?
17
+ - How to select resource when only dataset id is provided?
@@ -0,0 +1,7 @@
1
+ ## ADDED Requirements
2
+ ### Requirement: Analyze dataset structure
3
+ The system SHALL provide a `ckan_analyze_dataset_structure` tool that accepts `server_url`, a `resource_id` or `dataset_id`, and optional `sample_size`, returning column names and types; when a DataStore is available it MUST compute per-column null rates from a sampled query.
4
+
5
+ #### Scenario: Schema summary with null rates
6
+ - **WHEN** the tool is invoked for a DataStore-enabled resource
7
+ - **THEN** the system returns columns, types, and null-rate statistics
@@ -0,0 +1,6 @@
1
+ ## 1. Implementation
2
+ - [ ] 1.1 Add tool schema and registration
3
+ - [ ] 1.2 Resolve resource selection (resource_id or dataset)
4
+ - [ ] 1.3 Compute schema summary + null rates
5
+ - [ ] 1.4 Add fixtures + tests
6
+ - [ ] 1.5 Update README/EXAMPLES
@@ -0,0 +1,17 @@
1
+ # Change: Add ckan_analyze_dataset_updates tool
2
+
3
+ ## Why
4
+ Users need quick insight on dataset freshness and update cadence.
5
+
6
+ ## What Changes
7
+ - Add MCP tool `ckan_analyze_dataset_updates` for dataset freshness analysis.
8
+ - Combine `metadata_modified` and resource `last_modified` to estimate cadence.
9
+ - Flag stale datasets based on a configurable threshold.
10
+
11
+ ## Impact
12
+ - Affected specs: `ckan-insights`
13
+ - Affected code: `src/tools/package.ts` and `src/tools/datastore.ts`
14
+
15
+ ## Open Questions
16
+ - Default `stale_days` threshold?
17
+ - How to handle resources without `last_modified`?
@@ -0,0 +1,7 @@
1
+ ## ADDED Requirements
2
+ ### Requirement: Analyze dataset updates
3
+ The system SHALL provide a `ckan_analyze_dataset_updates` tool that accepts `server_url`, `dataset_id`, and optional `stale_days`, and returns update cadence based on `metadata_modified` and resource `last_modified`, including a `stale` flag when the most recent update exceeds the threshold.
4
+
5
+ #### Scenario: Update cadence and stale flag
6
+ - **WHEN** the tool is invoked with a dataset id and stale threshold
7
+ - **THEN** the system returns last update timestamps, cadence summary, and a stale flag
@@ -0,0 +1,6 @@
1
+ ## 1. Implementation
2
+ - [ ] 1.1 Add tool schema and registration
3
+ - [ ] 1.2 Compute update cadence from metadata/resource dates
4
+ - [ ] 1.3 Add stale detection output
5
+ - [ ] 1.4 Add fixtures + tests
6
+ - [ ] 1.5 Update README/EXAMPLES
@@ -0,0 +1,17 @@
1
+ # Change: Add ckan_audit tool
2
+
3
+ ## Why
4
+ Operators need an automated probe to detect datastore/SQL/alias support and capture portal quirks.
5
+
6
+ ## What Changes
7
+ - Add MCP tool `ckan_audit` to probe CKAN API capabilities.
8
+ - Detect DataStore availability, SQL endpoint, and datastore id alias support.
9
+ - Return suggested overrides for portal configuration.
10
+
11
+ ## Impact
12
+ - Affected specs: `ckan-insights`
13
+ - Affected code: `src/tools/status.ts` or new insights module
14
+
15
+ ## Open Questions
16
+ - Should audit run only read-only GET probes?
17
+ - Which overrides format to return (JSON block vs markdown list)?
@@ -0,0 +1,7 @@
1
+ ## ADDED Requirements
2
+ ### Requirement: Audit CKAN portal capabilities
3
+ The system SHALL provide a `ckan_audit` tool that accepts `server_url` and returns detected capabilities for DataStore, SQL endpoint availability, and datastore id alias support, plus suggested portal override values.
4
+
5
+ #### Scenario: Capability probe
6
+ - **WHEN** the tool probes a CKAN portal
7
+ - **THEN** the response includes datastore availability, SQL support, alias support, and recommended overrides
@@ -0,0 +1,6 @@
1
+ ## 1. Implementation
2
+ - [ ] 1.1 Add tool schema and registration
3
+ - [ ] 1.2 Probe datastore_search and datastore_search_sql
4
+ - [ ] 1.3 Detect datastore id alias support
5
+ - [ ] 1.4 Return override suggestions
6
+ - [ ] 1.5 Add fixtures + tests
@@ -0,0 +1,17 @@
1
+ # Change: Add ckan_dataset_insights tool
2
+
3
+ ## Why
4
+ Users want a single call that returns ranked datasets plus freshness and structure insights.
5
+
6
+ ## What Changes
7
+ - Add MCP tool `ckan_dataset_insights` as a wrapper.
8
+ - Combine outputs from `ckan_find_relevant_datasets`, `ckan_analyze_dataset_updates`, and `ckan_analyze_dataset_structure`.
9
+ - Provide compact summary per dataset.
10
+
11
+ ## Impact
12
+ - Affected specs: `ckan-insights`
13
+ - Affected code: new insights module orchestrating existing tools
14
+
15
+ ## Open Questions
16
+ - Default number of datasets to enrich?
17
+ - Should structure analysis be optional for non-DataStore resources?
@@ -0,0 +1,7 @@
1
+ ## ADDED Requirements
2
+ ### Requirement: Dataset insights wrapper
3
+ The system SHALL provide a `ckan_dataset_insights` tool that accepts `server_url`, `query`, `limit`, and optional analysis parameters, and returns per-dataset summaries combining relevance scores, update cadence, and structure metrics.
4
+
5
+ #### Scenario: Combined insights output
6
+ - **WHEN** the tool is invoked with a query and limit
7
+ - **THEN** the system returns the top N datasets with combined relevance, update, and structure insights
@@ -0,0 +1,6 @@
1
+ ## 1. Implementation
2
+ - [ ] 1.1 Add tool schema and registration
3
+ - [ ] 1.2 Orchestrate find/update/structure analyses
4
+ - [ ] 1.3 Define merged output format
5
+ - [ ] 1.4 Add fixtures + tests
6
+ - [ ] 1.5 Update README/EXAMPLES
@@ -0,0 +1,17 @@
1
+ # Change: Add ckan_find_relevant_datasets tool
2
+
3
+ ## Why
4
+ Ranked discovery helps surface the best datasets for a query without manual sorting.
5
+
6
+ ## What Changes
7
+ - Add MCP tool `ckan_find_relevant_datasets` wrapping `package_search`.
8
+ - Score results using weighted fields (title, notes, tags, organization).
9
+ - Return top N datasets with score breakdown.
10
+
11
+ ## Impact
12
+ - Affected specs: `ckan-insights`
13
+ - Affected code: `src/tools/package.ts` (or new insights module)
14
+
15
+ ## Open Questions
16
+ - Default weights for title/notes/tags/organization?
17
+ - Default `limit` when omitted?
@@ -0,0 +1,7 @@
1
+ ## ADDED Requirements
2
+ ### Requirement: Find relevant datasets
3
+ The system SHALL provide a `ckan_find_relevant_datasets` tool that accepts `server_url`, `query`, `limit`, and optional weights for title, notes, tags, and organization, and returns the top N datasets ranked by score with a per-field score breakdown.
4
+
5
+ #### Scenario: Ranked results returned
6
+ - **WHEN** the tool is invoked with a query and limit
7
+ - **THEN** the system uses `package_search` results to return the top N datasets with numeric scores and field contributions
@@ -0,0 +1,6 @@
1
+ ## 1. Implementation
2
+ - [ ] 1.1 Add tool schema and registration
3
+ - [ ] 1.2 Implement weighted scoring + ranking
4
+ - [ ] 1.3 Define markdown/json output shape
5
+ - [ ] 1.4 Add fixtures + tests
6
+ - [ ] 1.5 Update README/EXAMPLES
@@ -0,0 +1,13 @@
1
+ # Change: Update CKAN search parser handling per portal
2
+
3
+ ## Why
4
+ Some CKAN portals (notably dati.gov.it) use a default edismax parser with restrictive `mm` settings that breaks long OR queries. For those portals, the Lucene standard parser on the `text` field yields correct results.
5
+
6
+ ## What Changes
7
+ - Add per-portal search configuration to `src/portals.json` to force `text:(...)` queries where needed.
8
+ - Add an optional tool override to force the text-field parser regardless of portal defaults.
9
+ - Update tool documentation to describe the behavior and override.
10
+
11
+ ## Impact
12
+ - Affected specs: `ckan-insights`, new `ckan-search` capability
13
+ - Affected code: `src/portals.json`, `src/tools/package.ts`, `src/utils/*` (if new helper is added)
@@ -0,0 +1,11 @@
1
+ ## MODIFIED Requirements
2
+ ### Requirement: Find relevant datasets
3
+ The system SHALL provide a `ckan_find_relevant_datasets` tool that accepts `server_url`, `query`, `limit`, optional weights for title, notes, tags, and organization, and an optional search parser override, and returns the top N datasets ranked by score with a per-field score breakdown.
4
+
5
+ #### Scenario: Ranked results returned
6
+ - **WHEN** the tool is invoked with a query and limit
7
+ - **THEN** the system uses `package_search` results to return the top N datasets with numeric scores and field contributions
8
+
9
+ #### Scenario: Search parser override applied
10
+ - **WHEN** the tool is invoked with a search parser override
11
+ - **THEN** the system applies the override to the underlying `package_search` query
@@ -0,0 +1,11 @@
1
+ ## ADDED Requirements
2
+ ### Requirement: Package search parser override
3
+ The system SHALL support a per-portal default and a per-request override to force package search queries through the `text` field when needed.
4
+
5
+ #### Scenario: Portal default applies
6
+ - **WHEN** a portal is configured to force the text-field parser
7
+ - **THEN** `ckan_package_search` uses `text:(...)` for non-fielded queries by default
8
+
9
+ #### Scenario: Request override applies
10
+ - **WHEN** a client explicitly requests the text-field parser
11
+ - **THEN** `ckan_package_search` uses `text:(...)` regardless of portal defaults
@@ -0,0 +1,6 @@
1
+ ## 1. Implementation
2
+ - [x] 1.1 Add per-portal search config for forcing text-field parser
3
+ - [x] 1.2 Add tool override input and apply parser selection in package search
4
+ - [x] 1.3 Apply same override logic in find-relevant datasets
5
+ - [x] 1.4 Update tool docs and examples
6
+ - [x] 1.5 Add/adjust tests if present for query handling
@@ -22,24 +22,25 @@ Exposes MCP tools for:
22
22
 
23
23
  ### Code Style
24
24
  - TypeScript strict mode enabled
25
- - Single-file architecture (src/index.ts)
26
- - Utility functions for reusable operations (makeCkanRequest, truncateText, formatDate, formatBytes)
25
+ - Modular tool files in `src/tools/*`
26
+ - Utility functions for reusable operations (makeCkanRequest, truncateText, formatDate)
27
27
  - Zod schemas for strict input validation (reject extra parameters)
28
28
  - Italian locale for date formatting (it-IT)
29
29
  - Markdown output optimized for human readability; JSON available for programmatic use
30
30
 
31
31
  ### Architecture Patterns
32
- - **Single-file MCP server** - all logic in src/index.ts
33
- - **Tool-based architecture** - 7 registered MCP tools for CKAN operations
34
- - **Dual transport modes**:
32
+ - **Modular MCP server** - registration in `src/server.ts`
33
+ - **Tool-based architecture** - 13 registered MCP tools for CKAN operations
34
+ - **Multiple transport modes**:
35
35
  - stdio (default) - for local MCP client integration
36
36
  - HTTP - for remote access via POST /mcp endpoint
37
+ - Cloudflare Workers - `/mcp` endpoint in `src/worker.ts`
37
38
  - **Read-only operations** - no data modification on CKAN
38
39
  - **No caching** - fresh API calls for each request
39
40
  - **Error handling** - HTTP errors, timeouts, server validation
40
41
 
41
42
  ### Testing Strategy
42
- - **No automated tests currently** (consider adding for critical tools)
43
+ - **Automated tests** with Vitest (integration fixtures)
43
44
  - Manual testing:
44
45
  - stdio mode: direct integration testing with Claude Desktop
45
46
  - HTTP mode: curl-based testing against localhost endpoint
@@ -67,6 +68,7 @@ Exposes MCP tools for:
67
68
  - Output truncated to 50000 characters max (hardcoded)
68
69
  - Dates formatted in Italian locale
69
70
  - File sizes in human-readable format
71
+ - `server_url` for Italy uses `https://dati.gov.it/opendata`
70
72
 
71
73
  ## Important Constraints
72
74
 
@@ -91,7 +93,7 @@ Exposes MCP tools for:
91
93
 
92
94
  ### CKAN Portals
93
95
  Major supported portals:
94
- - 🇮🇹 https://dati.gov.it (Italia)
96
+ - 🇮🇹 https://dati.gov.it/opendata (Italia)
95
97
  - 🇺🇸 https://catalog.data.gov (United States)
96
98
  - 🇨🇦 https://open.canada.ca/data (Canada)
97
99
  - 🇬🇧 https://data.gov.uk (United Kingdom)
@@ -0,0 +1,19 @@
1
+ # ckan-insights Specification
2
+
3
+ ## Purpose
4
+ Describe dataset insight tools (relevance, freshness, structure) once implemented.
5
+ ## Requirements
6
+ ### Requirement: Insights capability reserved
7
+ The system SHALL maintain this specification to document dataset insight tools when they are added.
8
+
9
+ #### Scenario: Insight tools documented
10
+ - **WHEN** new insight tools are implemented
11
+ - **THEN** their requirements are captured in this specification
12
+
13
+ ### Requirement: Find relevant datasets
14
+ The system SHALL provide a `ckan_find_relevant_datasets` tool that accepts `server_url`, `query`, `limit`, and optional weights for title, notes, tags, and organization, and returns the top N datasets ranked by score with a per-field score breakdown.
15
+
16
+ #### Scenario: Ranked results returned
17
+ - **WHEN** the tool is invoked with a query and limit
18
+ - **THEN** the system uses `package_search` results to return the top N datasets with numeric scores and field contributions
19
+
@@ -0,0 +1,344 @@
1
+ # cloudflare-deployment Specification
2
+
3
+ ## Purpose
4
+ TBD - created by archiving change add-cloudflare-workers. Update Purpose after archive.
5
+ ## Requirements
6
+ ### Requirement: Workers Entry Point
7
+
8
+ The system SHALL provide a Cloudflare Workers-compatible entry point that handles HTTP requests using the Workers fetch API.
9
+
10
+ #### Scenario: Health check endpoint
11
+
12
+ - **WHEN** client sends `GET /health` to Workers endpoint
13
+ - **THEN** server returns JSON with status, version, tool count, and resource count
14
+
15
+ #### Scenario: MCP protocol endpoint
16
+
17
+ - **WHEN** client sends `POST /mcp` with JSON-RPC request to Workers endpoint
18
+ - **THEN** server processes MCP request and returns JSON-RPC response
19
+
20
+ #### Scenario: Invalid route
21
+
22
+ - **WHEN** client requests any path other than `/health` or `/mcp`
23
+ - **THEN** server returns 404 Not Found
24
+
25
+ #### Scenario: Invalid method on MCP endpoint
26
+
27
+ - **WHEN** client sends non-POST request to `/mcp`
28
+ - **THEN** server returns 404 Not Found
29
+
30
+ ---
31
+
32
+ ### Requirement: MCP Server Integration
33
+
34
+ The system SHALL initialize MCP server instance on each Workers invocation and register all tools and resources.
35
+
36
+ #### Scenario: Server initialization
37
+
38
+ - **WHEN** Workers receives MCP request
39
+ - **THEN** server creates MCP Server instance with name "ckan-mcp-server" and version "0.4.0"
40
+
41
+ #### Scenario: Tool registration
42
+
43
+ - **WHEN** Workers initializes MCP server
44
+ - **THEN** server registers all 7 CKAN tools (package_search, package_show, organization_list, organization_show, organization_search, datastore_search, status_show)
45
+
46
+ #### Scenario: Resource registration
47
+
48
+ - **WHEN** Workers initializes MCP server
49
+ - **THEN** server registers all 3 resource templates (dataset, resource, organization)
50
+
51
+ #### Scenario: Tools list request
52
+
53
+ - **WHEN** client calls `tools/list` method via Workers endpoint
54
+ - **THEN** response includes all 7 registered CKAN tools with descriptions
55
+
56
+ ---
57
+
58
+ ### Requirement: Web Standards HTTP Client
59
+
60
+ The system SHALL use native Web Fetch API for CKAN API requests instead of Node.js-specific libraries.
61
+
62
+ #### Scenario: CKAN API request with fetch
63
+
64
+ - **WHEN** tool calls `makeCkanRequest()` in Workers runtime
65
+ - **THEN** client uses native `fetch()` with 30-second timeout
66
+
67
+ #### Scenario: Query parameter encoding
68
+
69
+ - **WHEN** CKAN request includes parameters (e.g., `q`, `rows`, `start`)
70
+ - **THEN** client encodes parameters in URL using `URLSearchParams`
71
+
72
+ #### Scenario: Request timeout
73
+
74
+ - **WHEN** CKAN API takes longer than 30 seconds
75
+ - **THEN** client aborts request using `AbortController` and returns timeout error
76
+
77
+ #### Scenario: HTTP error handling
78
+
79
+ - **WHEN** CKAN API returns HTTP error status (4xx, 5xx)
80
+ - **THEN** client throws error with status code and message
81
+
82
+ #### Scenario: CKAN API validation
83
+
84
+ - **WHEN** CKAN API returns 200 OK but `success: false`
85
+ - **THEN** client throws error with CKAN error message
86
+
87
+ ---
88
+
89
+ ### Requirement: Workers Build Configuration
90
+
91
+ The system SHALL provide separate build configuration for Workers deployment targeting browser platform with ESM format.
92
+
93
+ #### Scenario: Workers build script
94
+
95
+ - **WHEN** user runs `npm run build:worker`
96
+ - **THEN** esbuild compiles `src/worker.ts` to `dist/worker.js` in ESM format
97
+
98
+ #### Scenario: Bundle all dependencies
99
+
100
+ - **WHEN** esbuild builds Workers bundle
101
+ - **THEN** all dependencies are bundled (no external modules)
102
+
103
+ #### Scenario: Platform targeting
104
+
105
+ - **WHEN** esbuild builds Workers bundle
106
+ - **THEN** platform is set to `browser` and target is `es2022`
107
+
108
+ #### Scenario: Output format
109
+
110
+ - **WHEN** Workers build completes
111
+ - **THEN** output is ESM format (not CommonJS)
112
+
113
+ #### Scenario: Bundle size validation
114
+
115
+ - **WHEN** Workers build completes
116
+ - **THEN** bundle size is less than 1MB (Workers script size limit)
117
+
118
+ ---
119
+
120
+ ### Requirement: Wrangler Configuration
121
+
122
+ The system SHALL provide Wrangler configuration file for Workers deployment and local development.
123
+
124
+ #### Scenario: Wrangler configuration file
125
+
126
+ - **WHEN** project contains `wrangler.toml` in root directory
127
+ - **THEN** configuration specifies name, main entry point, and compatibility date
128
+
129
+ #### Scenario: Build command
130
+
131
+ - **WHEN** `wrangler deploy` or `wrangler dev` runs
132
+ - **THEN** Wrangler executes `npm run build:worker` before deployment
133
+
134
+ #### Scenario: Local development server
135
+
136
+ - **WHEN** user runs `npm run dev:worker`
137
+ - **THEN** Wrangler starts local Workers server on http://localhost:8787
138
+
139
+ ---
140
+
141
+ ### Requirement: Workers Deployment
142
+
143
+ The system SHALL deploy to Cloudflare Workers and provide public HTTPS endpoint.
144
+
145
+ #### Scenario: Deploy to Workers
146
+
147
+ - **WHEN** user runs `npm run deploy`
148
+ - **THEN** Wrangler builds and uploads worker to Cloudflare
149
+
150
+ #### Scenario: Public endpoint
151
+
152
+ - **WHEN** deployment succeeds
153
+ - **THEN** Workers script is accessible at `https://ckan-mcp-server.<account>.workers.dev`
154
+
155
+ #### Scenario: HTTPS support
156
+
157
+ - **WHEN** client accesses Workers endpoint
158
+ - **THEN** connection uses HTTPS with valid certificate
159
+
160
+ ---
161
+
162
+ ### Requirement: Tool Functionality Preservation
163
+
164
+ The system SHALL maintain identical functionality for all CKAN tools in Workers runtime compared to Node.js runtime.
165
+
166
+ #### Scenario: Package search in Workers
167
+
168
+ - **WHEN** client calls `ckan_package_search` via Workers endpoint
169
+ - **THEN** response is identical to Node.js runtime response
170
+
171
+ #### Scenario: Datastore query in Workers
172
+
173
+ - **WHEN** client calls `ckan_datastore_search` via Workers endpoint
174
+ - **THEN** response is identical to Node.js runtime response
175
+
176
+ #### Scenario: Resource template in Workers
177
+
178
+ - **WHEN** client reads `ckan://{server}/dataset/{id}` via Workers
179
+ - **THEN** response is identical to Node.js runtime response
180
+
181
+ #### Scenario: Error handling in Workers
182
+
183
+ - **WHEN** CKAN API is unreachable in Workers runtime
184
+ - **THEN** error response matches Node.js runtime error format
185
+
186
+ ---
187
+
188
+ ### Requirement: Response Format Compatibility
189
+
190
+ The system SHALL support both markdown and JSON output formats in Workers runtime.
191
+
192
+ #### Scenario: Markdown format
193
+
194
+ - **WHEN** client requests tool with `response_format: "markdown"`
195
+ - **THEN** Workers returns formatted markdown text
196
+
197
+ #### Scenario: JSON format
198
+
199
+ - **WHEN** client requests tool with `response_format: "json"`
200
+ - **THEN** Workers returns raw JSON data
201
+
202
+ #### Scenario: Character limit
203
+
204
+ - **WHEN** response exceeds CHARACTER_LIMIT (50000 characters)
205
+ - **THEN** Workers truncates response identically to Node.js runtime
206
+
207
+ ---
208
+
209
+ ### Requirement: Error Handling
210
+
211
+ The system SHALL handle Workers-specific errors gracefully with JSON-RPC error responses.
212
+
213
+ #### Scenario: Malformed JSON-RPC request
214
+
215
+ - **WHEN** client sends invalid JSON to `/mcp` endpoint
216
+ - **THEN** Workers returns JSON-RPC error with code -32700 (Parse error)
217
+
218
+ #### Scenario: Internal worker error
219
+
220
+ - **WHEN** worker encounters unexpected exception
221
+ - **THEN** Workers returns JSON-RPC error with code -32603 (Internal error)
222
+
223
+ #### Scenario: Method not found
224
+
225
+ - **WHEN** client calls non-existent MCP method
226
+ - **THEN** Workers returns JSON-RPC error with code -32601 (Method not found)
227
+
228
+ ---
229
+
230
+ ### Requirement: CORS Support
231
+
232
+ The system SHALL include CORS headers to enable browser-based MCP clients.
233
+
234
+ #### Scenario: CORS headers on success
235
+
236
+ - **WHEN** Workers returns successful response
237
+ - **THEN** response includes `Access-Control-Allow-Origin: *` header
238
+
239
+ #### Scenario: CORS headers on error
240
+
241
+ - **WHEN** Workers returns error response
242
+ - **THEN** response includes `Access-Control-Allow-Origin: *` header
243
+
244
+ #### Scenario: Preflight request
245
+
246
+ - **WHEN** browser sends OPTIONS request for CORS preflight
247
+ - **THEN** Workers returns allowed methods and headers
248
+
249
+ ---
250
+
251
+ ### Requirement: Deployment Documentation
252
+
253
+ The system SHALL provide comprehensive documentation for deploying to Cloudflare Workers.
254
+
255
+ #### Scenario: Deployment guide
256
+
257
+ - **WHEN** contributor wants to deploy Workers instance
258
+ - **THEN** `docs/DEPLOYMENT.md` provides step-by-step instructions
259
+
260
+ #### Scenario: Prerequisites documentation
261
+
262
+ - **WHEN** contributor reads DEPLOYMENT.md
263
+ - **THEN** document lists all prerequisites (Cloudflare account, wrangler CLI)
264
+
265
+ #### Scenario: Troubleshooting guide
266
+
267
+ - **WHEN** deployment fails
268
+ - **THEN** DEPLOYMENT.md includes common errors and solutions
269
+
270
+ #### Scenario: README update
271
+
272
+ - **WHEN** user reads README.md
273
+ - **THEN** deployment options section includes Cloudflare Workers option
274
+
275
+ ---
276
+
277
+ ### Requirement: Backwards Compatibility
278
+
279
+ The system SHALL maintain all existing deployment modes (stdio, self-hosted HTTP) without breaking changes.
280
+
281
+ #### Scenario: Stdio mode unchanged
282
+
283
+ - **WHEN** user runs `npm start` after Workers implementation
284
+ - **THEN** stdio transport works identically to pre-Workers version
285
+
286
+ #### Scenario: Self-hosted HTTP mode unchanged
287
+
288
+ - **WHEN** user runs `TRANSPORT=http PORT=3000 npm start` after Workers implementation
289
+ - **THEN** HTTP server works identically to pre-Workers version
290
+
291
+ #### Scenario: Existing tests pass
292
+
293
+ - **WHEN** user runs `npm test` after Workers implementation
294
+ - **THEN** all 113 existing tests pass without modification
295
+
296
+ #### Scenario: Node.js bundle unchanged
297
+
298
+ - **WHEN** user runs `npm run build` after Workers implementation
299
+ - **THEN** Node.js bundle (`dist/index.js`) is unchanged
300
+
301
+ ---
302
+
303
+ ### Requirement: Development Workflow
304
+
305
+ The system SHALL support efficient local development and testing of Workers deployment.
306
+
307
+ #### Scenario: Local Workers testing
308
+
309
+ - **WHEN** developer runs `npm run dev:worker`
310
+ - **THEN** wrangler starts local server with hot reload
311
+
312
+ #### Scenario: Quick iteration
313
+
314
+ - **WHEN** developer modifies `src/worker.ts`
315
+ - **THEN** wrangler automatically rebuilds and reloads
316
+
317
+ #### Scenario: curl testing
318
+
319
+ - **WHEN** developer sends curl request to local Workers
320
+ - **THEN** response matches expected MCP protocol format
321
+
322
+ ---
323
+
324
+ ### Requirement: Monitoring and Debugging
325
+
326
+ The system SHALL provide access to Workers logs and metrics for troubleshooting.
327
+
328
+ #### Scenario: Real-time logs
329
+
330
+ - **WHEN** developer runs `wrangler tail`
331
+ - **THEN** console.log output from worker appears in terminal
332
+
333
+ #### Scenario: Error logs
334
+
335
+ - **WHEN** worker throws exception
336
+ - **THEN** stack trace appears in `wrangler tail` output
337
+
338
+ #### Scenario: Cloudflare dashboard
339
+
340
+ - **WHEN** user accesses Cloudflare Workers dashboard
341
+ - **THEN** metrics show request count, error rate, and CPU time
342
+
343
+ ---
344
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aborruso/ckan-mcp-server",
3
- "version": "0.4.5",
3
+ "version": "0.4.7",
4
4
  "description": "MCP server for interacting with CKAN open data portals",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",