@aborruso/ckan-mcp-server 0.3.1

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 (43) hide show
  1. package/.claude/commands/openspec/apply.md +23 -0
  2. package/.claude/commands/openspec/archive.md +27 -0
  3. package/.claude/commands/openspec/proposal.md +28 -0
  4. package/.claude/settings.local.json +31 -0
  5. package/.gemini/commands/openspec/apply.toml +21 -0
  6. package/.gemini/commands/openspec/archive.toml +25 -0
  7. package/.gemini/commands/openspec/proposal.toml +26 -0
  8. package/.mcp.json +12 -0
  9. package/.opencode/command/openspec-apply.md +24 -0
  10. package/.opencode/command/openspec-archive.md +27 -0
  11. package/.opencode/command/openspec-proposal.md +29 -0
  12. package/AGENTS.md +18 -0
  13. package/CLAUDE.md +320 -0
  14. package/EXAMPLES.md +707 -0
  15. package/LICENSE.txt +21 -0
  16. package/LOG.md +154 -0
  17. package/PRD.md +912 -0
  18. package/README.md +468 -0
  19. package/REFACTORING.md +237 -0
  20. package/dist/index.js +1277 -0
  21. package/openspec/AGENTS.md +456 -0
  22. package/openspec/changes/archive/2026-01-08-add-mcp-resources/design.md +115 -0
  23. package/openspec/changes/archive/2026-01-08-add-mcp-resources/proposal.md +52 -0
  24. package/openspec/changes/archive/2026-01-08-add-mcp-resources/specs/mcp-resources/spec.md +92 -0
  25. package/openspec/changes/archive/2026-01-08-add-mcp-resources/tasks.md +56 -0
  26. package/openspec/changes/archive/2026-01-08-expand-test-coverage-specs/design.md +355 -0
  27. package/openspec/changes/archive/2026-01-08-expand-test-coverage-specs/proposal.md +161 -0
  28. package/openspec/changes/archive/2026-01-08-expand-test-coverage-specs/tasks.md +162 -0
  29. package/openspec/changes/archive/2026-01-08-translate-project-to-english/proposal.md +115 -0
  30. package/openspec/changes/archive/2026-01-08-translate-project-to-english/specs/documentation-language/spec.md +32 -0
  31. package/openspec/changes/archive/2026-01-08-translate-project-to-english/tasks.md +115 -0
  32. package/openspec/changes/archive/add-automated-tests/design.md +324 -0
  33. package/openspec/changes/archive/add-automated-tests/proposal.md +167 -0
  34. package/openspec/changes/archive/add-automated-tests/specs/automated-testing/spec.md +143 -0
  35. package/openspec/changes/archive/add-automated-tests/tasks.md +132 -0
  36. package/openspec/project.md +113 -0
  37. package/openspec/specs/documentation-language/spec.md +32 -0
  38. package/openspec/specs/mcp-resources/spec.md +94 -0
  39. package/package.json +46 -0
  40. package/spunti.md +19 -0
  41. package/tasks/todo.md +124 -0
  42. package/test-urls.js +18 -0
  43. package/tmp/test-org-search.js +55 -0
package/README.md ADDED
@@ -0,0 +1,468 @@
1
+ # CKAN MCP Server
2
+
3
+ MCP (Model Context Protocol) server for interacting with CKAN-based open data portals.
4
+
5
+ ## Features
6
+
7
+ - ✅ Support for any CKAN server (dati.gov.it, data.gov, demo.ckan.org, etc.)
8
+ - 🔍 Advanced search with Solr syntax
9
+ - 📊 DataStore queries for tabular data analysis
10
+ - 🏢 Organization and group exploration
11
+ - 📦 Complete dataset and resource metadata
12
+ - 🎨 Output in Markdown or JSON format
13
+ - ⚡ Pagination and faceting support
14
+ - 📄 MCP Resource Templates for direct data access
15
+ - 🧪 Comprehensive test suite (101 tests, 100% passing)
16
+
17
+ ## Installation
18
+
19
+ ### From npm (recommended)
20
+
21
+ ```bash
22
+ npm install ckan-mcp-server
23
+ ```
24
+
25
+ ### From source
26
+
27
+ ```bash
28
+ # Clone or copy the project
29
+ cd ckan-mcp-server
30
+
31
+ # Install dependencies
32
+ npm install
33
+
34
+ # Build with esbuild (fast, ~4ms)
35
+ npm run build
36
+
37
+ # Run tests (101 tests)
38
+ npm test
39
+ ```
40
+
41
+ ## Usage
42
+
43
+ ### Start with stdio (for local integration)
44
+
45
+ ```bash
46
+ npm start
47
+ ```
48
+
49
+ ### Start with HTTP (for remote access)
50
+
51
+ ```bash
52
+ TRANSPORT=http PORT=3000 npm start
53
+ ```
54
+
55
+ The server will be available at `http://localhost:3000/mcp`
56
+
57
+ ## Claude Desktop Configuration
58
+
59
+ Add to Claude Desktop configuration file (`claude_desktop_config.json`):
60
+
61
+ ```json
62
+ {
63
+ "mcpServers": {
64
+ "ckan": {
65
+ "command": "node",
66
+ "args": ["/path/to/ckan-mcp-server/dist/index.js"]
67
+ }
68
+ }
69
+ }
70
+ ```
71
+
72
+ Su macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
73
+ Su Windows: `%APPDATA%\Claude\claude_desktop_config.json`
74
+ Su Linux: `~/.config/Claude/claude_desktop_config.json`
75
+
76
+ ## Available Tools
77
+
78
+ ### Search and Discovery
79
+
80
+ - **ckan_package_search**: Search datasets with Solr queries
81
+ - **ckan_package_show**: Complete details of a dataset
82
+ - **ckan_package_list**: List all datasets
83
+
84
+ ### Organizations
85
+
86
+ - **ckan_organization_list**: List all organizations
87
+ - **ckan_organization_show**: Details of an organization
88
+
89
+ ### DataStore
90
+
91
+ - **ckan_datastore_search**: Query tabular data
92
+ - **ckan_datastore_search_sql**: SQL queries (in development)
93
+
94
+ ### Utilities
95
+
96
+ - **ckan_status_show**: Verify server status
97
+
98
+ ## MCP Resource Templates
99
+
100
+ Direct data access via `ckan://` URI scheme:
101
+
102
+ - `ckan://{server}/dataset/{id}` - Dataset metadata
103
+ - `ckan://{server}/resource/{id}` - Resource metadata and download URL
104
+ - `ckan://{server}/organization/{name}` - Organization details
105
+
106
+ Examples:
107
+
108
+ ```
109
+ ckan://dati.gov.it/dataset/vaccini-covid
110
+ ckan://demo.ckan.org/resource/abc-123
111
+ ckan://data.gov/organization/sample-org
112
+ ```
113
+
114
+ ## Usage Examples
115
+
116
+ ### Search datasets on dati.gov.it
117
+
118
+ ```typescript
119
+ ckan_package_search({
120
+ server_url: "https://www.dati.gov.it/opendata",
121
+ q: "popolazione",
122
+ rows: 20
123
+ })
124
+ ```
125
+
126
+ ### Filter by organization
127
+
128
+ ```typescript
129
+ ckan_package_search({
130
+ server_url: "https://www.dati.gov.it/opendata",
131
+ fq: "organization:regione-siciliana",
132
+ sort: "metadata_modified desc"
133
+ })
134
+ ```
135
+
136
+ ### Search organizations with wildcard
137
+
138
+ ```typescript
139
+ // Find all organizations containing "salute" in the name
140
+ ckan_package_search({
141
+ server_url: "https://www.dati.gov.it/opendata",
142
+ q: "organization:*salute*",
143
+ rows: 0,
144
+ facet_field: ["organization"],
145
+ facet_limit: 100
146
+ })
147
+ ```
148
+
149
+ ### Get statistics with faceting
150
+
151
+ ```typescript
152
+ ckan_package_search({
153
+ server_url: "https://www.dati.gov.it/opendata",
154
+ facet_field: ["organization", "tags", "res_format"],
155
+ rows: 0
156
+ })
157
+ ```
158
+
159
+ ### DataStore Query
160
+
161
+ ```typescript
162
+ ckan_datastore_search({
163
+ server_url: "https://www.dati.gov.it/opendata",
164
+ resource_id: "abc-123-def",
165
+ filters: { "regione": "Sicilia", "anno": 2023 },
166
+ sort: "popolazione desc",
167
+ limit: 50
168
+ })
169
+ ```
170
+
171
+ ## Supported CKAN Portals
172
+
173
+ Some of the main compatible portals:
174
+
175
+ - 🇮🇹 **www.dati.gov.it/opendata** - Italy
176
+ - 🇺🇸 **data.gov** - United States
177
+ - 🇨🇦 **open.canada.ca/data** - Canada
178
+ - 🇬🇧 **data.gov.uk** - United Kingdom
179
+ - 🇪🇺 **data.europa.eu** - European Union
180
+ - 🌍 **demo.ckan.org** - CKAN Demo
181
+ - And 500+ more portals worldwide
182
+
183
+ ### Portal View URL Templates
184
+
185
+ 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.
186
+
187
+ When generating a dataset or organization view link, the server:
188
+ - matches the `server_url` against `api_url` and `api_url_aliases` in `src/portals.json`
189
+ - uses the portal-specific `dataset_view_url` / `organization_view_url` template when available
190
+ - falls back to the generic defaults (`{server_url}/dataset/{name}` and `{server_url}/organization/{name}`)
191
+
192
+ You can extend `src/portals.json` by adding new entries under `portals` if a portal uses different web URL patterns.
193
+
194
+ ## Advanced Solr Queries
195
+
196
+ CKAN uses Apache Solr for search. Examples:
197
+
198
+ ```
199
+ # Basic search
200
+ q: "popolazione"
201
+
202
+ # Field search
203
+ q: "title:popolazione"
204
+ q: "notes:sanità"
205
+
206
+ # Boolean operators
207
+ q: "popolazione AND sicilia"
208
+ q: "popolazione OR abitanti"
209
+ q: "popolazione NOT censimento"
210
+
211
+ # Filters (fq)
212
+ fq: "organization:comune-palermo"
213
+ fq: "tags:sanità"
214
+ fq: "res_format:CSV"
215
+
216
+ # Wildcard
217
+ q: "popolaz*"
218
+
219
+ # Date range
220
+ fq: "metadata_modified:[2023-01-01T00:00:00Z TO *]"
221
+ ```
222
+
223
+ ### Advanced Query Examples
224
+
225
+ These real-world examples demonstrate powerful Solr query combinations tested on the Italian open data portal (dati.gov.it):
226
+
227
+ #### 1. Fuzzy Search + Date Math + Boosting
228
+
229
+ Find healthcare datasets (tolerating spelling errors) modified in the last 6 months, prioritizing title matches:
230
+
231
+ ```typescript
232
+ ckan_package_search({
233
+ server_url: "https://www.dati.gov.it/opendata",
234
+ q: "(title:sanità~2^3 OR title:salute~2^3 OR notes:sanità~1) AND metadata_modified:[NOW-6MONTHS TO *]",
235
+ sort: "score desc, metadata_modified desc",
236
+ rows: 30
237
+ })
238
+ ```
239
+
240
+ **Techniques used**:
241
+ - `sanità~2` - Fuzzy search with edit distance 2 (finds "sanita", "sanitá", minor typos)
242
+ - `^3` - Boosts title matches 3x higher in relevance scoring
243
+ - `NOW-6MONTHS` - Dynamic date math for rolling time windows
244
+ - Combined boolean logic with multiple field searches
245
+
246
+ **Results**: 871 datasets including hospital units, healthcare organizations, medical services
247
+
248
+ #### 2. Proximity Search + Complex Boolean
249
+
250
+ Environmental datasets where "inquinamento" and "aria" (air pollution) appear close together, excluding water-related datasets:
251
+
252
+ ```typescript
253
+ ckan_package_search({
254
+ server_url: "https://www.dati.gov.it/opendata",
255
+ q: "(notes:\"inquinamento aria\"~5 OR title:\"qualità aria\"~3) AND NOT (title:acqua OR title:mare)",
256
+ facet_field: ["organization", "res_format"],
257
+ rows: 25
258
+ })
259
+ ```
260
+
261
+ **Techniques used**:
262
+ - `"inquinamento aria"~5` - Proximity search (words within 5 positions)
263
+ - `~3` - Tighter proximity for title matches
264
+ - `NOT (title:acqua OR title:mare)` - Exclude water/sea datasets
265
+ - Faceting for statistical breakdown
266
+
267
+ **Results**: 306 datasets, primarily air quality monitoring from Milan (44) and Palermo (161), formats: XML (150), CSV (124), JSON (76)
268
+
269
+ #### 3. Wildcard + Field Existence + Range Queries
270
+
271
+ Regional datasets with at least 5 resources, published in the last year:
272
+
273
+ ```typescript
274
+ ckan_package_search({
275
+ server_url: "https://www.dati.gov.it/opendata",
276
+ q: "organization:regione* AND num_resources:[5 TO *] AND metadata_created:[NOW-1YEAR TO *] AND res_format:*",
277
+ sort: "num_resources desc, metadata_modified desc",
278
+ facet_field: ["organization"],
279
+ rows: 40
280
+ })
281
+ ```
282
+
283
+ **Techniques used**:
284
+ - `regione*` - Wildcard matches all regional organizations
285
+ - `[5 TO *]` - Inclusive range (5 or more resources)
286
+ - `res_format:*` - Field existence check (has at least one resource format)
287
+ - `NOW-1YEAR` - Rolling 12-month window
288
+
289
+ **Results**: 5,318 datasets, top contributors: Lombardy (3,012), Tuscany (1,151), Puglia (460)
290
+
291
+ #### 4. Date Ranges + Exclusive Bounds
292
+
293
+ ISTAT datasets with moderate resource count (10-50), modified in specific date range:
294
+
295
+ ```typescript
296
+ ckan_package_search({
297
+ server_url: "https://www.dati.gov.it/opendata",
298
+ q: "(title:istat OR organization:*istat*) AND num_resources:{9 TO 51} AND metadata_modified:[2025-07-01T00:00:00Z TO 2025-12-31T23:59:59Z]",
299
+ sort: "metadata_modified desc",
300
+ facet_field: ["res_format", "tags"],
301
+ rows: 30
302
+ })
303
+ ```
304
+
305
+ **Techniques used**:
306
+ - `{9 TO 51}` - Exclusive bounds (10-50 resources, excluding 9 and 51)
307
+ - `[2025-07-01T00:00:00Z TO 2025-12-31T23:59:59Z]` - Explicit date range
308
+ - Combined organization wildcard with title search
309
+ - Multiple facets for content analysis
310
+
311
+ **Note**: This specific query returned 0 results due to the narrow time window, demonstrating how precise constraints work.
312
+
313
+ ### Solr Query Syntax Reference
314
+
315
+ **Boolean Operators**: `AND`, `OR`, `NOT`, `+required`, `-excluded`
316
+ **Wildcards**: `*` (multiple chars), `?` (single char) - Note: left truncation not supported
317
+ **Fuzzy**: `~N` (edit distance), e.g., `health~2`
318
+ **Proximity**: `"phrase"~N` (words within N positions)
319
+ **Boosting**: `^N` (relevance multiplier), e.g., `title:water^2`
320
+ **Ranges**:
321
+ - Inclusive: `[a TO b]`, e.g., `num_resources:[5 TO 10]`
322
+ - Exclusive: `{a TO b}`, e.g., `num_resources:{0 TO 100}`
323
+ - Open-ended: `[2024-01-01T00:00:00Z TO *]`
324
+ **Date Math**: `NOW`, `NOW-1YEAR`, `NOW-6MONTHS`, `NOW-7DAYS`, `NOW/DAY`
325
+ **Field Existence**: `field:*` (field exists), `NOT field:*` (field missing)
326
+
327
+ ## Project Structure
328
+
329
+ ```
330
+ ckan-mcp-server/
331
+ ├── src/
332
+ │ ├── index.ts # Entry point
333
+ │ ├── server.ts # MCP server setup
334
+ │ ├── types.ts # Types & schemas
335
+ │ ├── utils/
336
+ │ │ ├── http.ts # CKAN API client
337
+ │ │ └── formatting.ts # Output formatting
338
+ │ ├── tools/
339
+ │ │ ├── package.ts # Package search/show
340
+ │ │ ├── organization.ts # Organization tools
341
+ │ │ ├── datastore.ts # DataStore queries
342
+ │ │ └── status.ts # Server status
343
+ │ ├── resources/ # MCP Resource Templates
344
+ │ │ ├── index.ts
345
+ │ │ ├── uri.ts # URI parsing
346
+ │ │ ├── dataset.ts
347
+ │ │ ├── resource.ts
348
+ │ │ └── organization.ts
349
+ │ └── transport/
350
+ │ ├── stdio.ts # Stdio transport
351
+ │ └── http.ts # HTTP transport
352
+ ├── tests/ # Test suite (101 tests)
353
+ ├── dist/ # Compiled files (generated)
354
+ ├── package.json
355
+ └── README.md
356
+ ```
357
+
358
+ ## Development
359
+
360
+ ### Testing
361
+
362
+ The project uses **Vitest** for automated testing:
363
+
364
+ ```bash
365
+ # Run all tests
366
+ npm test
367
+
368
+ # Run tests in watch mode
369
+ npm run test:watch
370
+
371
+ # Run tests with coverage report
372
+ npm run test:coverage
373
+ ```
374
+
375
+ Test coverage target is 80%. Current test suite includes:
376
+ - Unit tests for utility functions (formatting, HTTP)
377
+ - Integration tests for MCP tools with mocked CKAN API responses
378
+ - Mock fixtures for CKAN API success and error scenarios
379
+
380
+ See `tests/README.md` for detailed testing guidelines.
381
+
382
+ ### Build
383
+
384
+ The project uses **esbuild** for ultra-fast compilation (~4ms):
385
+
386
+ ```bash
387
+ # Build with esbuild (default)
388
+ npm run build
389
+
390
+ # Watch mode for development
391
+ npm run watch
392
+ ```
393
+
394
+ ### Manual Testing
395
+
396
+ ```bash
397
+ # Start server in HTTP mode
398
+ TRANSPORT=http PORT=3000 npm start
399
+
400
+ # In another terminal, test available tools
401
+ curl -X POST http://localhost:3000/mcp \
402
+ -H 'Content-Type: application/json' \
403
+ -H 'Accept: application/json, text/event-stream' \
404
+ -d '{"jsonrpc":"2.0","method":"tools/list","id":1}'
405
+ ```
406
+
407
+ ## Troubleshooting
408
+
409
+ ### dati.gov.it URL
410
+
411
+ **Important**: The correct URL for the Italian portal is `https://www.dati.gov.it/opendata` (not `https://dati.gov.it`).
412
+
413
+ ### Connection error
414
+
415
+ ```
416
+ Error: Server not found: https://esempio.gov.it
417
+ ```
418
+
419
+ **Solution**: Verify the URL is correct and the server is online. Use `ckan_status_show` to verify.
420
+
421
+ ### No results
422
+
423
+ ```typescript
424
+ // Use a more generic query
425
+ ckan_package_search({
426
+ server_url: "https://www.dati.gov.it/opendata",
427
+ q: "*:*"
428
+ })
429
+
430
+ // Check contents with faceting
431
+ ckan_package_search({
432
+ server_url: "https://www.dati.gov.it/opendata",
433
+ facet_field: ["tags", "organization"],
434
+ rows: 0
435
+ })
436
+ ```
437
+
438
+ ## Contributing
439
+
440
+ Contributions are welcome! Please:
441
+
442
+ 1. Fork the project
443
+ 2. Create a branch for the feature (`git checkout -b feature/AmazingFeature`)
444
+ 3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
445
+ 4. Push to the branch (`git push origin feature/AmazingFeature`)
446
+ 5. Open a Pull Request
447
+
448
+ ## License
449
+
450
+ MIT License - See LICENSE.txt file for complete details.
451
+
452
+ ## Useful Links
453
+
454
+ - **CKAN**: https://ckan.org/
455
+ - **CKAN API Documentation**: https://docs.ckan.org/en/latest/api/
456
+ - **MCP Protocol**: https://modelcontextprotocol.io/
457
+ - **onData**: https://www.ondata.it/
458
+ - **dati.gov.it**: https://www.dati.gov.it/opendata/
459
+
460
+ ## Support
461
+
462
+ For issues or questions:
463
+ - Open an issue on GitHub
464
+ - Contact onData: https://www.ondata.it/
465
+
466
+ ---
467
+
468
+ Created with ❤️ by onData for the open data community
package/REFACTORING.md ADDED
@@ -0,0 +1,237 @@
1
+ # Refactoring Documentation
2
+
3
+ ## Overview
4
+
5
+ Il codebase è stato refactorizzato da un singolo file monolitico di 1021 righe a una struttura modulare di 11 file.
6
+
7
+ ## Motivazione
8
+
9
+ **Problemi del file unico**:
10
+ - 1021 righe difficili da navigare
11
+ - Modifiche rischiose (alta probabilità di errori)
12
+ - Testing complesso
13
+ - Code review difficili
14
+ - Merge conflicts probabili in collaborazione
15
+
16
+ **Vantaggi della struttura modulare**:
17
+ - File più piccoli (max 350 righe)
18
+ - Modifiche localizzate e sicure
19
+ - Testing isolato per tool
20
+ - Manutenzione semplificata
21
+ - Collaborazione efficiente
22
+
23
+ ## Nuova Struttura
24
+
25
+ ```
26
+ src/
27
+ ├── index.ts # Entry point (39 lines)
28
+ ├── server.ts # MCP server setup (12 lines)
29
+ ├── types.ts # Types & schemas (16 lines)
30
+ ├── utils/
31
+ │ ├── http.ts # CKAN API client (51 lines)
32
+ │ └── formatting.ts # Output formatting (37 lines)
33
+ ├── tools/
34
+ │ ├── package.ts # Package tools (350 lines)
35
+ │ ├── organization.ts # Organization tools (341 lines)
36
+ │ ├── datastore.ts # DataStore tools (146 lines)
37
+ │ └── status.ts # Status tools (66 lines)
38
+ └── transport/
39
+ ├── stdio.ts # Stdio transport (12 lines)
40
+ └── http.ts # HTTP transport (27 lines)
41
+ ```
42
+
43
+ **Total**: 1097 lines (vs 1021 original, +76 lines for better organization)
44
+
45
+ ## File Descriptions
46
+
47
+ ### Core Files
48
+
49
+ **`index.ts`** (Entry Point)
50
+ - Importa e registra tutti i tool
51
+ - Sceglie transport (stdio/http)
52
+ - Gestisce startup e error handling
53
+
54
+ **`server.ts`** (Server Configuration)
55
+ - Crea istanza MCP server
56
+ - Configurazione base (name, version)
57
+
58
+ **`types.ts`** (Type Definitions)
59
+ - `ResponseFormat` enum
60
+ - `ResponseFormatSchema` Zod validator
61
+ - `CHARACTER_LIMIT` constant
62
+
63
+ ### Utils
64
+
65
+ **`utils/http.ts`** (HTTP Client)
66
+ - `makeCkanRequest<T>()` - HTTP client per CKAN API
67
+ - Normalizzazione URL
68
+ - Gestione errori (timeout, 404, network)
69
+ - User-Agent header
70
+
71
+ **`utils/formatting.ts`** (Output Formatting)
72
+ - `truncateText()` - Limita output a CHARACTER_LIMIT
73
+ - `formatDate()` - Format date in Italian locale
74
+ - `formatBytes()` - Human-readable file sizes
75
+
76
+ ### Tools
77
+
78
+ **`tools/package.ts`** (Package/Dataset Tools)
79
+ - `ckan_package_search` - Search datasets (182 lines handler)
80
+ - `ckan_package_show` - Dataset details (138 lines handler)
81
+
82
+ **`tools/organization.ts`** (Organization Tools)
83
+ - `ckan_organization_list` - List organizations (118 lines)
84
+ - `ckan_organization_show` - Org details (95 lines)
85
+ - `ckan_organization_search` - Search orgs (102 lines)
86
+
87
+ **`tools/datastore.ts`** (DataStore Tools)
88
+ - `ckan_datastore_search` - Query tabular data (130 lines)
89
+
90
+ **`tools/status.ts`** (Status Tools)
91
+ - `ckan_status_show` - Check server status (51 lines)
92
+
93
+ ### Transport
94
+
95
+ **`transport/stdio.ts`** (Stdio Transport)
96
+ - `runStdio()` - Standard input/output transport
97
+ - For Claude Desktop and local MCP clients
98
+
99
+ **`transport/http.ts`** (HTTP Transport)
100
+ - `runHTTP()` - HTTP server on configurable port
101
+ - For remote access via HTTP POST
102
+
103
+ ## Build Configuration
104
+
105
+ **No changes needed** - esbuild continua a funzionare:
106
+ ```bash
107
+ npm run build # 15ms build time
108
+ ```
109
+
110
+ esbuild automaticamente:
111
+ - Bundle tutti i moduli interni
112
+ - Tree-shake codice non usato
113
+ - Mantiene external dependencies separate
114
+ - Produce singolo file `dist/index.js`
115
+
116
+ ## Testing Results
117
+
118
+ ✅ **Build**: Successful (15ms)
119
+ ✅ **Tool Registration**: All 7 tools listed
120
+ ✅ **Tool Execution**: `ckan_status_show` tested successfully
121
+ ✅ **Backward Compatibility**: 100% - stessa API MCP
122
+
123
+ ## Benefits Achieved
124
+
125
+ ### Maintainability
126
+ - Ogni file < 350 righe (easy to understand)
127
+ - Moduli isolati (modifiche localizzate)
128
+ - Clear separation of concerns
129
+
130
+ ### Testing
131
+ - Tool handlers isolati e testabili
132
+ - Utilities testabili indipendentemente
133
+ - Mock più facili per unit tests
134
+
135
+ ### Collaboration
136
+ - Merge conflicts ridotti
137
+ - Code review più veloci
138
+ - Feature development parallelo possibile
139
+
140
+ ### Performance
141
+ - Build time invariato: ~15ms
142
+ - Bundle size invariato: ~30KB
143
+ - Runtime performance identico
144
+ - Tree-shaking preservato
145
+
146
+ ## Migration Notes
147
+
148
+ ### Old Structure
149
+ ```typescript
150
+ // src/index.ts (1021 lines)
151
+ // Everything in one file
152
+ ```
153
+
154
+ ### New Structure
155
+ ```typescript
156
+ // src/index.ts (39 lines)
157
+ import { createServer } from "./server.js";
158
+ import { registerPackageTools } from "./tools/package.js";
159
+ // ...
160
+
161
+ const server = createServer();
162
+ registerPackageTools(server);
163
+ // ...
164
+ ```
165
+
166
+ ### Backward Compatibility
167
+
168
+ ✅ **Zero breaking changes**:
169
+ - Stessi tool MCP esposti
170
+ - Stessi parametri input
171
+ - Stesso formato output
172
+ - Stesso comportamento
173
+
174
+ ### Old File Preserved
175
+
176
+ `src/index-old.ts` - Backup del file originale (per riferimento)
177
+
178
+ ## Future Enhancements Enabled
179
+
180
+ Con la nuova struttura diventa più facile:
181
+
182
+ 1. **Unit Testing**: Test singoli tool in isolamento
183
+ 2. **New Tools**: Aggiungere tool in file separati
184
+ 3. **Shared Logic**: Utilities riutilizzabili
185
+ 4. **Documentation**: JSDoc per ogni modulo
186
+ 5. **Type Safety**: Types centralizzati
187
+ 6. **Optimization**: Ottimizzare singoli moduli
188
+
189
+ ## Maintenance Guide
190
+
191
+ ### Adding a New Tool
192
+
193
+ 1. Create `src/tools/newtool.ts`:
194
+ ```typescript
195
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
196
+
197
+ export function registerNewTools(server: McpServer) {
198
+ server.registerTool("tool_name", { ... }, async (params) => { ... });
199
+ }
200
+ ```
201
+
202
+ 2. Import in `src/index.ts`:
203
+ ```typescript
204
+ import { registerNewTools } from "./tools/newtool.js";
205
+ registerNewTools(server);
206
+ ```
207
+
208
+ 3. Build and test:
209
+ ```bash
210
+ npm run build
211
+ npm start
212
+ ```
213
+
214
+ ### Modifying a Tool
215
+
216
+ 1. Edit relevant file in `src/tools/`
217
+ 2. Changes are isolated
218
+ 3. Build and test
219
+ 4. No risk to other tools
220
+
221
+ ### Adding Utilities
222
+
223
+ 1. Create in `src/utils/`
224
+ 2. Export function
225
+ 3. Import where needed
226
+ 4. Automatic tree-shaking if unused
227
+
228
+ ## Conclusion
229
+
230
+ Il refactoring è stato completato con successo:
231
+ - ✅ Struttura modulare
232
+ - ✅ Build funzionante
233
+ - ✅ Backward compatible
234
+ - ✅ Testing verificato
235
+ - ✅ Performance preserved
236
+
237
+ Il codice è ora più manutenibile, testabile e scalabile, mantenendo tutta la funzionalità originale.