@aborruso/ckan-mcp-server 0.4.14 โ 0.4.16
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/EXAMPLES.md +18 -0
- package/LOG.md +42 -0
- package/README.md +7 -3
- package/dist/index.js +160 -19
- package/dist/worker.js +40 -37
- package/openspec/changes/add-mqa-quality-tool/proposal.md +21 -0
- package/openspec/changes/add-mqa-quality-tool/specs/ckan-quality/spec.md +71 -0
- package/openspec/changes/add-mqa-quality-tool/tasks.md +29 -0
- package/package.json +1 -1
package/EXAMPLES.md
CHANGED
|
@@ -151,6 +151,24 @@ ckan_package_search({
|
|
|
151
151
|
})
|
|
152
152
|
```
|
|
153
153
|
|
|
154
|
+
### Get MQA quality metrics for a dataset
|
|
155
|
+
```typescript
|
|
156
|
+
ckan_get_mqa_quality({
|
|
157
|
+
server_url: "https://www.dati.gov.it/opendata",
|
|
158
|
+
dataset_id: "332be8b7-89b9-4dfe-a252-7fccd3efda76",
|
|
159
|
+
response_format: "markdown"
|
|
160
|
+
})
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Returns quality score and detailed metrics from data.europa.eu MQA (Metadata Quality Assurance) system:
|
|
164
|
+
- Overall score (max 405 points)
|
|
165
|
+
- Accessibility (URL status, download availability)
|
|
166
|
+
- Reusability (license, contact point, publisher)
|
|
167
|
+
- Interoperability (format, media type)
|
|
168
|
+
- Findability (keywords, category, spatial/temporal coverage)
|
|
169
|
+
|
|
170
|
+
**Note**: Only works with dati.gov.it datasets. Uses the `identifier` field (or falls back to `name`) to query the European MQA API.
|
|
171
|
+
|
|
154
172
|
## USA Examples - data.gov
|
|
155
173
|
|
|
156
174
|
### Search government datasets
|
package/LOG.md
CHANGED
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
# LOG
|
|
2
2
|
|
|
3
|
+
## 2026-01-23
|
|
4
|
+
|
|
5
|
+
### MQA Quality Metrics - Fix identifier format
|
|
6
|
+
|
|
7
|
+
- **Bug fix**: Identifier transformation for data.europa.eu API compatibility
|
|
8
|
+
- **Issue**: CKAN identifiers with colon separator (e.g., `c_f158:224c373e...`) were not recognized by MQA API
|
|
9
|
+
- **Root cause**: data.europa.eu uses hyphen-separated identifiers (`c_f158-224c373e...`)
|
|
10
|
+
- **Solution**: Replace colons with hyphens before API call: `.replace(/:/g, '-')`
|
|
11
|
+
- **Impact**: MQA quality metrics now work for all dati.gov.it datasets, including municipal portals
|
|
12
|
+
- **Example**: Messina air quality dataset now returns score 405/560 (Eccellente)
|
|
13
|
+
- **File modified**: `src/tools/quality.ts` (line 41)
|
|
14
|
+
- **Deployed**: Cloudflare Workers v0.4.16
|
|
15
|
+
|
|
16
|
+
### MQA Quality Metrics Tool
|
|
17
|
+
|
|
18
|
+
- **Feature**: Added `ckan_get_mqa_quality` tool for retrieving quality metrics from data.europa.eu MQA API
|
|
19
|
+
- **Scope**: Only works with dati.gov.it datasets (server validation enforced)
|
|
20
|
+
- **Data source**: Queries https://data.europa.eu/api/mqa/cache/datasets/{identifier}
|
|
21
|
+
- **Identifier logic**: Uses `identifier` field from CKAN metadata, falls back to `name` if identifier is empty
|
|
22
|
+
- **Metrics returned**:
|
|
23
|
+
- Overall score (max 405 points)
|
|
24
|
+
- Accessibility (URL status, download availability)
|
|
25
|
+
- Reusability (license, contact point, publisher)
|
|
26
|
+
- Interoperability (format, media type)
|
|
27
|
+
- Findability (keywords, category, spatial/temporal coverage)
|
|
28
|
+
- **Output formats**: Markdown (default, human-readable) or JSON (structured data)
|
|
29
|
+
- **Error handling**: Dataset not found, MQA API unavailable, invalid server URL
|
|
30
|
+
- **Tests**: +11 integration tests (212 total, all passing)
|
|
31
|
+
- Server validation (www/non-www dati.gov.it URLs)
|
|
32
|
+
- Quality retrieval with identifier
|
|
33
|
+
- Fallback to name field
|
|
34
|
+
- Error scenarios (404, network errors)
|
|
35
|
+
- Markdown formatting (complete/partial data, availability indicators)
|
|
36
|
+
- **Documentation**: README.md (new Quality Metrics section), EXAMPLES.md (usage example with expected metrics)
|
|
37
|
+
- **Files**:
|
|
38
|
+
- `src/tools/quality.ts` (new, 194 lines)
|
|
39
|
+
- `src/server.ts` (register quality tools)
|
|
40
|
+
- `tests/integration/quality.test.ts` (new, 11 tests)
|
|
41
|
+
- `tests/fixtures/responses/mqa-quality-success.json` (new)
|
|
42
|
+
- `tests/fixtures/responses/package-show-{with,without}-identifier.json` (new)
|
|
43
|
+
- **OpenSpec**: Proposal in `openspec/changes/add-mqa-quality-tool/` (4 requirements, 11 scenarios)
|
|
44
|
+
|
|
3
45
|
## 2026-01-22
|
|
4
46
|
|
|
5
47
|
### Date Query Auto-Conversion (v0.4.14)
|
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 212 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 (212 tests)
|
|
49
49
|
npm test
|
|
50
50
|
```
|
|
51
51
|
|
|
@@ -209,6 +209,10 @@ These guides are based on a public demo server, which has a limit of 100,000 cal
|
|
|
209
209
|
- **ckan_group_show**: Show group details
|
|
210
210
|
- **ckan_group_search**: Search groups by name
|
|
211
211
|
|
|
212
|
+
### Quality Metrics
|
|
213
|
+
|
|
214
|
+
- **ckan_get_mqa_quality**: Get MQA quality score and metrics for dati.gov.it datasets (accessibility, reusability, interoperability, findability)
|
|
215
|
+
|
|
212
216
|
### Utilities
|
|
213
217
|
|
|
214
218
|
- **ckan_status_show**: Verify server status
|
|
@@ -566,7 +570,7 @@ ckan-mcp-server/
|
|
|
566
570
|
โ โโโ transport/
|
|
567
571
|
โ โโโ stdio.ts # Stdio transport
|
|
568
572
|
โ โโโ http.ts # HTTP transport
|
|
569
|
-
โโโ tests/ # Test suite (
|
|
573
|
+
โโโ tests/ # Test suite (212 tests)
|
|
570
574
|
โโโ dist/ # Compiled files (generated)
|
|
571
575
|
โโโ package.json
|
|
572
576
|
โโโ README.md
|
package/dist/index.js
CHANGED
|
@@ -2101,6 +2101,146 @@ Returns:
|
|
|
2101
2101
|
);
|
|
2102
2102
|
}
|
|
2103
2103
|
|
|
2104
|
+
// src/tools/quality.ts
|
|
2105
|
+
import { z as z8 } from "zod";
|
|
2106
|
+
import axios2 from "axios";
|
|
2107
|
+
var MQA_API_BASE = "https://data.europa.eu/api/mqa/cache/datasets";
|
|
2108
|
+
var ALLOWED_SERVER_PATTERNS = [
|
|
2109
|
+
/^https?:\/\/(www\.)?dati\.gov\.it/i
|
|
2110
|
+
];
|
|
2111
|
+
function isValidMqaServer(serverUrl) {
|
|
2112
|
+
return ALLOWED_SERVER_PATTERNS.some((pattern) => pattern.test(serverUrl));
|
|
2113
|
+
}
|
|
2114
|
+
async function getMqaQuality(serverUrl, datasetId) {
|
|
2115
|
+
const dataset = await makeCkanRequest(
|
|
2116
|
+
serverUrl,
|
|
2117
|
+
"package_show",
|
|
2118
|
+
{ id: datasetId }
|
|
2119
|
+
);
|
|
2120
|
+
const europeanId = (dataset.identifier || dataset.name).replace(/:/g, "-");
|
|
2121
|
+
const mqaUrl = `${MQA_API_BASE}/${europeanId}`;
|
|
2122
|
+
try {
|
|
2123
|
+
const response = await axios2.get(mqaUrl, {
|
|
2124
|
+
timeout: 3e4,
|
|
2125
|
+
headers: {
|
|
2126
|
+
"User-Agent": "CKAN-MCP-Server/1.0"
|
|
2127
|
+
}
|
|
2128
|
+
});
|
|
2129
|
+
return response.data;
|
|
2130
|
+
} catch (error) {
|
|
2131
|
+
if (axios2.isAxiosError(error)) {
|
|
2132
|
+
if (error.response?.status === 404) {
|
|
2133
|
+
throw new Error(`Quality metrics not found for dataset '${europeanId}' on data.europa.eu`);
|
|
2134
|
+
}
|
|
2135
|
+
throw new Error(`MQA API error: ${error.message}`);
|
|
2136
|
+
}
|
|
2137
|
+
throw error;
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
function formatQualityMarkdown(data, datasetId) {
|
|
2141
|
+
const lines = [];
|
|
2142
|
+
lines.push(`# Quality Metrics for Dataset: ${datasetId}`);
|
|
2143
|
+
lines.push("");
|
|
2144
|
+
if (data.info?.score !== void 0) {
|
|
2145
|
+
lines.push(`**Overall Score**: ${data.info.score}/405`);
|
|
2146
|
+
lines.push("");
|
|
2147
|
+
}
|
|
2148
|
+
if (data.accessibility) {
|
|
2149
|
+
lines.push("## Accessibility");
|
|
2150
|
+
if (data.accessibility.accessUrl !== void 0) {
|
|
2151
|
+
lines.push(`- Access URL: ${data.accessibility.accessUrl.available ? "\u2713" : "\u2717"} Available`);
|
|
2152
|
+
}
|
|
2153
|
+
if (data.accessibility.downloadUrl !== void 0) {
|
|
2154
|
+
lines.push(`- Download URL: ${data.accessibility.downloadUrl.available ? "\u2713" : "\u2717"} Available`);
|
|
2155
|
+
}
|
|
2156
|
+
lines.push("");
|
|
2157
|
+
}
|
|
2158
|
+
if (data.reusability) {
|
|
2159
|
+
lines.push("## Reusability");
|
|
2160
|
+
if (data.reusability.licence !== void 0) {
|
|
2161
|
+
lines.push(`- License: ${data.reusability.licence.available ? "\u2713" : "\u2717"} Available`);
|
|
2162
|
+
}
|
|
2163
|
+
if (data.reusability.contactPoint !== void 0) {
|
|
2164
|
+
lines.push(`- Contact Point: ${data.reusability.contactPoint.available ? "\u2713" : "\u2717"} Available`);
|
|
2165
|
+
}
|
|
2166
|
+
if (data.reusability.publisher !== void 0) {
|
|
2167
|
+
lines.push(`- Publisher: ${data.reusability.publisher.available ? "\u2713" : "\u2717"} Available`);
|
|
2168
|
+
}
|
|
2169
|
+
lines.push("");
|
|
2170
|
+
}
|
|
2171
|
+
if (data.interoperability) {
|
|
2172
|
+
lines.push("## Interoperability");
|
|
2173
|
+
if (data.interoperability.format !== void 0) {
|
|
2174
|
+
lines.push(`- Format: ${data.interoperability.format.available ? "\u2713" : "\u2717"} Available`);
|
|
2175
|
+
}
|
|
2176
|
+
if (data.interoperability.mediaType !== void 0) {
|
|
2177
|
+
lines.push(`- Media Type: ${data.interoperability.mediaType.available ? "\u2713" : "\u2717"} Available`);
|
|
2178
|
+
}
|
|
2179
|
+
lines.push("");
|
|
2180
|
+
}
|
|
2181
|
+
if (data.findability) {
|
|
2182
|
+
lines.push("## Findability");
|
|
2183
|
+
if (data.findability.keyword !== void 0) {
|
|
2184
|
+
lines.push(`- Keywords: ${data.findability.keyword.available ? "\u2713" : "\u2717"} Available`);
|
|
2185
|
+
}
|
|
2186
|
+
if (data.findability.category !== void 0) {
|
|
2187
|
+
lines.push(`- Category: ${data.findability.category.available ? "\u2713" : "\u2717"} Available`);
|
|
2188
|
+
}
|
|
2189
|
+
if (data.findability.spatial !== void 0) {
|
|
2190
|
+
lines.push(`- Spatial: ${data.findability.spatial.available ? "\u2713" : "\u2717"} Available`);
|
|
2191
|
+
}
|
|
2192
|
+
if (data.findability.temporal !== void 0) {
|
|
2193
|
+
lines.push(`- Temporal: ${data.findability.temporal.available ? "\u2713" : "\u2717"} Available`);
|
|
2194
|
+
}
|
|
2195
|
+
lines.push("");
|
|
2196
|
+
}
|
|
2197
|
+
lines.push("---");
|
|
2198
|
+
lines.push(`Source: ${MQA_API_BASE}/${data.id || datasetId}`);
|
|
2199
|
+
return lines.join("\n");
|
|
2200
|
+
}
|
|
2201
|
+
function registerQualityTools(server2) {
|
|
2202
|
+
server2.tool(
|
|
2203
|
+
"ckan_get_mqa_quality",
|
|
2204
|
+
"Get MQA (Metadata Quality Assurance) quality metrics for a dataset on dati.gov.it. Returns quality score and detailed metrics (accessibility, reusability, interoperability, findability) from data.europa.eu. Only works with dati.gov.it server.",
|
|
2205
|
+
{
|
|
2206
|
+
server_url: z8.string().url().describe("Base URL of dati.gov.it (e.g., https://www.dati.gov.it/opendata)"),
|
|
2207
|
+
dataset_id: z8.string().describe("Dataset ID or name"),
|
|
2208
|
+
response_format: ResponseFormatSchema.optional()
|
|
2209
|
+
},
|
|
2210
|
+
async ({ server_url, dataset_id, response_format }) => {
|
|
2211
|
+
if (!isValidMqaServer(server_url)) {
|
|
2212
|
+
return {
|
|
2213
|
+
content: [{
|
|
2214
|
+
type: "text",
|
|
2215
|
+
text: `Error: MQA quality metrics are only available for dati.gov.it datasets. Provided server: ${server_url}
|
|
2216
|
+
|
|
2217
|
+
The MQA (Metadata Quality Assurance) system is operated by data.europa.eu and only evaluates datasets from Italian open data portal.`
|
|
2218
|
+
}]
|
|
2219
|
+
};
|
|
2220
|
+
}
|
|
2221
|
+
try {
|
|
2222
|
+
const qualityData = await getMqaQuality(server_url, dataset_id);
|
|
2223
|
+
const format = response_format || "markdown" /* MARKDOWN */;
|
|
2224
|
+
const output = format === "json" /* JSON */ ? JSON.stringify(qualityData, null, 2) : formatQualityMarkdown(qualityData, dataset_id);
|
|
2225
|
+
return {
|
|
2226
|
+
content: [{
|
|
2227
|
+
type: "text",
|
|
2228
|
+
text: output
|
|
2229
|
+
}]
|
|
2230
|
+
};
|
|
2231
|
+
} catch (error) {
|
|
2232
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2233
|
+
return {
|
|
2234
|
+
content: [{
|
|
2235
|
+
type: "text",
|
|
2236
|
+
text: `Error retrieving quality metrics: ${errorMessage}`
|
|
2237
|
+
}]
|
|
2238
|
+
};
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
);
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2104
2244
|
// src/resources/dataset.ts
|
|
2105
2245
|
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2106
2246
|
|
|
@@ -2370,7 +2510,7 @@ function registerAllResources(server2) {
|
|
|
2370
2510
|
}
|
|
2371
2511
|
|
|
2372
2512
|
// src/prompts/theme.ts
|
|
2373
|
-
import { z as
|
|
2513
|
+
import { z as z9 } from "zod";
|
|
2374
2514
|
|
|
2375
2515
|
// src/prompts/types.ts
|
|
2376
2516
|
var createTextPrompt = (text) => ({
|
|
@@ -2427,9 +2567,9 @@ var registerThemePrompt = (server2) => {
|
|
|
2427
2567
|
title: "Search datasets by theme",
|
|
2428
2568
|
description: "Guided prompt to discover a theme and search datasets under it.",
|
|
2429
2569
|
argsSchema: {
|
|
2430
|
-
server_url:
|
|
2431
|
-
theme:
|
|
2432
|
-
rows:
|
|
2570
|
+
server_url: z9.string().url().describe("Base URL of the CKAN server"),
|
|
2571
|
+
theme: z9.string().min(1).describe("Theme or group name to search"),
|
|
2572
|
+
rows: z9.coerce.number().int().positive().default(10).describe("Max results to return")
|
|
2433
2573
|
}
|
|
2434
2574
|
},
|
|
2435
2575
|
async ({ server_url, theme, rows }) => createTextPrompt(buildThemePromptText(server_url, theme, rows))
|
|
@@ -2437,7 +2577,7 @@ var registerThemePrompt = (server2) => {
|
|
|
2437
2577
|
};
|
|
2438
2578
|
|
|
2439
2579
|
// src/prompts/organization.ts
|
|
2440
|
-
import { z as
|
|
2580
|
+
import { z as z10 } from "zod";
|
|
2441
2581
|
var ORGANIZATION_PROMPT_NAME = "ckan-search-by-organization";
|
|
2442
2582
|
var buildOrganizationPromptText = (serverUrl, organization, rows) => `# Guided search: datasets by organization
|
|
2443
2583
|
|
|
@@ -2468,9 +2608,9 @@ var registerOrganizationPrompt = (server2) => {
|
|
|
2468
2608
|
title: "Search datasets by organization",
|
|
2469
2609
|
description: "Guided prompt to find a publisher and list its datasets.",
|
|
2470
2610
|
argsSchema: {
|
|
2471
|
-
server_url:
|
|
2472
|
-
organization:
|
|
2473
|
-
rows:
|
|
2611
|
+
server_url: z10.string().url().describe("Base URL of the CKAN server"),
|
|
2612
|
+
organization: z10.string().min(1).describe("Organization name or keyword"),
|
|
2613
|
+
rows: z10.coerce.number().int().positive().default(10).describe("Max results to return")
|
|
2474
2614
|
}
|
|
2475
2615
|
},
|
|
2476
2616
|
async ({ server_url, organization, rows }) => createTextPrompt(buildOrganizationPromptText(server_url, organization, rows))
|
|
@@ -2478,7 +2618,7 @@ var registerOrganizationPrompt = (server2) => {
|
|
|
2478
2618
|
};
|
|
2479
2619
|
|
|
2480
2620
|
// src/prompts/format.ts
|
|
2481
|
-
import { z as
|
|
2621
|
+
import { z as z11 } from "zod";
|
|
2482
2622
|
var FORMAT_PROMPT_NAME = "ckan-search-by-format";
|
|
2483
2623
|
var buildFormatPromptText = (serverUrl, format, rows) => `# Guided search: datasets by resource format
|
|
2484
2624
|
|
|
@@ -2499,9 +2639,9 @@ var registerFormatPrompt = (server2) => {
|
|
|
2499
2639
|
title: "Search datasets by resource format",
|
|
2500
2640
|
description: "Guided prompt to find datasets with a given resource format.",
|
|
2501
2641
|
argsSchema: {
|
|
2502
|
-
server_url:
|
|
2503
|
-
format:
|
|
2504
|
-
rows:
|
|
2642
|
+
server_url: z11.string().url().describe("Base URL of the CKAN server"),
|
|
2643
|
+
format: z11.string().min(1).describe("Resource format (e.g., CSV, JSON)"),
|
|
2644
|
+
rows: z11.coerce.number().int().positive().default(10).describe("Max results to return")
|
|
2505
2645
|
}
|
|
2506
2646
|
},
|
|
2507
2647
|
async ({ server_url, format, rows }) => createTextPrompt(buildFormatPromptText(server_url, format, rows))
|
|
@@ -2509,7 +2649,7 @@ var registerFormatPrompt = (server2) => {
|
|
|
2509
2649
|
};
|
|
2510
2650
|
|
|
2511
2651
|
// src/prompts/recent.ts
|
|
2512
|
-
import { z as
|
|
2652
|
+
import { z as z12 } from "zod";
|
|
2513
2653
|
var RECENT_PROMPT_NAME = "ckan-recent-datasets";
|
|
2514
2654
|
var buildRecentPromptText = (serverUrl, rows) => `# Guided search: recent datasets
|
|
2515
2655
|
|
|
@@ -2537,8 +2677,8 @@ var registerRecentPrompt = (server2) => {
|
|
|
2537
2677
|
title: "Find recently updated datasets",
|
|
2538
2678
|
description: "Guided prompt to list recently updated datasets on a CKAN portal.",
|
|
2539
2679
|
argsSchema: {
|
|
2540
|
-
server_url:
|
|
2541
|
-
rows:
|
|
2680
|
+
server_url: z12.string().url().describe("Base URL of the CKAN server"),
|
|
2681
|
+
rows: z12.coerce.number().int().positive().default(10).describe("Max results to return")
|
|
2542
2682
|
}
|
|
2543
2683
|
},
|
|
2544
2684
|
async ({ server_url, rows }) => createTextPrompt(buildRecentPromptText(server_url, rows))
|
|
@@ -2546,7 +2686,7 @@ var registerRecentPrompt = (server2) => {
|
|
|
2546
2686
|
};
|
|
2547
2687
|
|
|
2548
2688
|
// src/prompts/dataset-analysis.ts
|
|
2549
|
-
import { z as
|
|
2689
|
+
import { z as z13 } from "zod";
|
|
2550
2690
|
var DATASET_ANALYSIS_PROMPT_NAME = "ckan-analyze-dataset";
|
|
2551
2691
|
var buildDatasetAnalysisPromptText = (serverUrl, id) => `# Guided analysis: dataset
|
|
2552
2692
|
|
|
@@ -2588,8 +2728,8 @@ var registerDatasetAnalysisPrompt = (server2) => {
|
|
|
2588
2728
|
title: "Analyze a dataset",
|
|
2589
2729
|
description: "Guided prompt to inspect dataset metadata and explore DataStore tables.",
|
|
2590
2730
|
argsSchema: {
|
|
2591
|
-
server_url:
|
|
2592
|
-
id:
|
|
2731
|
+
server_url: z13.string().url().describe("Base URL of the CKAN server"),
|
|
2732
|
+
id: z13.string().min(1).describe("Dataset id or name (CKAN package id)")
|
|
2593
2733
|
}
|
|
2594
2734
|
},
|
|
2595
2735
|
async ({ server_url, id }) => createTextPrompt(buildDatasetAnalysisPromptText(server_url, id))
|
|
@@ -2609,7 +2749,7 @@ var registerAllPrompts = (server2) => {
|
|
|
2609
2749
|
function createServer() {
|
|
2610
2750
|
return new McpServer({
|
|
2611
2751
|
name: "ckan-mcp-server",
|
|
2612
|
-
version: "0.4.
|
|
2752
|
+
version: "0.4.16"
|
|
2613
2753
|
});
|
|
2614
2754
|
}
|
|
2615
2755
|
function registerAll(server2) {
|
|
@@ -2619,6 +2759,7 @@ function registerAll(server2) {
|
|
|
2619
2759
|
registerStatusTools(server2);
|
|
2620
2760
|
registerTagTools(server2);
|
|
2621
2761
|
registerGroupTools(server2);
|
|
2762
|
+
registerQualityTools(server2);
|
|
2622
2763
|
registerAllResources(server2);
|
|
2623
2764
|
registerAllPrompts(server2);
|
|
2624
2765
|
}
|