@jrpool/kilotest 60.9.1 → 62.0.0

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/lhm.plugin.json CHANGED
@@ -96,81 +96,48 @@
96
96
  "response content": {
97
97
  "type": "object",
98
98
  "properties": {
99
+ "how to get test results about a page": {
100
+ "type": "object",
101
+ "properties": {
102
+ "method": {
103
+ "type": "string",
104
+ "const": "GET"
105
+ },
106
+ "URL": {
107
+ "type": "string",
108
+ "description": "URL template; replace {identifier} with the identifier of the latest report about the page."
109
+ }
110
+ },
111
+ "required": [
112
+ "method",
113
+ "URL"
114
+ ],
115
+ "additionalProperties": false
116
+ },
117
+ "web users can get test results about a page at": {
118
+ "type": "string",
119
+ "description": "URL template; replace {identifier} with the identifier of the latest report about the page."
120
+ },
99
121
  "basics about all tested pages": {
100
122
  "type": "array",
101
123
  "items": {
102
124
  "type": "object",
103
125
  "properties": {
104
- "tested web page": {
105
- "type": "object",
106
- "properties": {
107
- "description": {
108
- "type": "string"
109
- },
110
- "URL": {
111
- "type": "string"
112
- }
113
- },
114
- "required": [
115
- "description",
116
- "URL"
117
- ],
118
- "additionalProperties": false
119
- },
120
- "number of reports about the page": {
121
- "type": "number"
122
- },
123
- "basics about the latest report": {
124
- "type": "object",
125
- "properties": {
126
- "identifier": {
127
- "type": "string",
128
- "description": "Identifier of the report (example: 260503T0432-x9z)."
129
- },
130
- "completion date and time": {
131
- "type": "string"
132
- },
133
- "days since the report was completed": {
134
- "type": [
135
- "number",
136
- "null"
137
- ]
138
- }
139
- },
140
- "required": [
141
- "identifier",
142
- "completion date and time",
143
- "days since the report was completed"
144
- ],
145
- "additionalProperties": false
146
- },
147
- "how to get details about the latest report": {
148
- "type": "object",
149
- "properties": {
150
- "method": {
151
- "type": "string",
152
- "const": "GET"
153
- },
154
- "URL": {
155
- "type": "string"
156
- }
157
- },
158
- "required": [
159
- "method",
160
- "URL"
161
- ],
162
- "additionalProperties": false
126
+ "description": {
127
+ "type": "string"
163
128
  },
164
- "web users can get details about the latest report at": {
129
+ "URL": {
165
130
  "type": "string"
131
+ },
132
+ "identifier": {
133
+ "type": "string",
134
+ "description": "Identifier of the latest report about the page (example: 260503T0432-x9z)."
166
135
  }
167
136
  },
168
137
  "required": [
169
- "tested web page",
170
- "number of reports about the page",
171
- "basics about the latest report",
172
- "how to get details about the latest report",
173
- "web users can get details about the latest report at"
138
+ "description",
139
+ "URL",
140
+ "identifier"
174
141
  ],
175
142
  "additionalProperties": false
176
143
  }
@@ -231,6 +198,8 @@
231
198
  }
232
199
  },
233
200
  "required": [
201
+ "how to get test results about a page",
202
+ "web users can get test results about a page at",
234
203
  "basics about all tested pages",
235
204
  "how to request that a page with no report be tested",
236
205
  "how a web user can request that the page be tested"
@@ -1272,17 +1241,17 @@
1272
1241
  "how to get details about the element": {
1273
1242
  "type": "object",
1274
1243
  "properties": {
1275
- "URL": {
1276
- "type": "string"
1277
- },
1278
- "request method": {
1244
+ "method": {
1279
1245
  "type": "string",
1280
1246
  "const": "GET"
1247
+ },
1248
+ "URL": {
1249
+ "type": "string"
1281
1250
  }
1282
1251
  },
1283
1252
  "required": [
1284
- "URL",
1285
- "request method"
1253
+ "method",
1254
+ "URL"
1286
1255
  ],
1287
1256
  "additionalProperties": false
1288
1257
  },
@@ -3402,6 +3371,336 @@
3402
3371
  "taskSupport": "forbidden"
3403
3372
  }
3404
3373
  },
3374
+ {
3375
+ "name": "reportDisagreement",
3376
+ "description": "Reports that you disagree with a diagnosis shown by the listDiagnoses tool; queued for manager review. Use this after listDiagnoses when you believe a rule violation was incorrectly diagnosed or classified into an issue, providing the engineID and ruleID shown in the diagnosis and your reason. Returns a confirmation with disposition details.",
3377
+ "inputSchema": {
3378
+ "type": "object",
3379
+ "properties": {
3380
+ "issueID": {
3381
+ "type": "string",
3382
+ "description": "Issue identifier (example: contrastPoor)"
3383
+ },
3384
+ "reportID": {
3385
+ "type": "string",
3386
+ "description": "Identifier of the report (example: 260503T0432-x9z)"
3387
+ },
3388
+ "catalogIndex": {
3389
+ "type": "string",
3390
+ "description": "Identifier of the issue-exhibiting element in the catalog of elements on the page (example: 372)"
3391
+ },
3392
+ "engineID": {
3393
+ "type": "string",
3394
+ "description": "Identifier of the rule engine that produced the disputed diagnosis (example: axe), as shown in the listDiagnoses output"
3395
+ },
3396
+ "ruleID": {
3397
+ "type": "string",
3398
+ "description": "Identifier of the rule whose diagnosis is disputed, as shown in the listDiagnoses output (example: color-contrast); if that output shows null for the rule identifier, use its description of the violation instead"
3399
+ },
3400
+ "reason": {
3401
+ "type": "string",
3402
+ "description": "20- to 1000-character explanation of why the diagnosis is disputed"
3403
+ }
3404
+ },
3405
+ "required": [
3406
+ "issueID",
3407
+ "reportID",
3408
+ "catalogIndex",
3409
+ "engineID",
3410
+ "ruleID",
3411
+ "reason"
3412
+ ],
3413
+ "$schema": "http://json-schema.org/draft-07/schema#"
3414
+ },
3415
+ "outputSchema": {
3416
+ "type": "object",
3417
+ "properties": {
3418
+ "tool collection": {
3419
+ "$ref": "#/definitions/ToolsFacts"
3420
+ },
3421
+ "tool name": {
3422
+ "type": "string"
3423
+ },
3424
+ "this request": {
3425
+ "type": "object",
3426
+ "properties": {
3427
+ "description": {
3428
+ "type": "string"
3429
+ },
3430
+ "method": {
3431
+ "type": "string",
3432
+ "const": "POST"
3433
+ },
3434
+ "URL": {
3435
+ "type": "string"
3436
+ },
3437
+ "body": {
3438
+ "type": "object",
3439
+ "properties": {
3440
+ "engineID": {
3441
+ "type": "string",
3442
+ "description": "Identifier of the rule engine that produced the disputed diagnosis (example: axe), as shown in the listDiagnoses output"
3443
+ },
3444
+ "ruleID": {
3445
+ "type": "string",
3446
+ "description": "Identifier of the rule whose diagnosis is disputed, as shown in the listDiagnoses output (example: color-contrast); if that output shows null for the rule identifier, use its description of the violation instead"
3447
+ },
3448
+ "reason": {
3449
+ "type": "string",
3450
+ "description": "20- to 1000-character explanation of why the diagnosis is disputed"
3451
+ }
3452
+ },
3453
+ "required": [
3454
+ "engineID",
3455
+ "ruleID",
3456
+ "reason"
3457
+ ],
3458
+ "additionalProperties": false
3459
+ },
3460
+ "closest ancestor request": {
3461
+ "anyOf": [
3462
+ {
3463
+ "$ref": "#/definitions/RequestReference"
3464
+ },
3465
+ {
3466
+ "type": "null"
3467
+ }
3468
+ ]
3469
+ }
3470
+ },
3471
+ "required": [
3472
+ "description",
3473
+ "method",
3474
+ "URL",
3475
+ "body",
3476
+ "closest ancestor request"
3477
+ ],
3478
+ "additionalProperties": false
3479
+ },
3480
+ "URLs of similar requests for web users": {
3481
+ "type": "null"
3482
+ },
3483
+ "response metadata": {
3484
+ "$ref": "#/definitions/ResponseMetadata"
3485
+ },
3486
+ "response content": {
3487
+ "type": "object",
3488
+ "properties": {
3489
+ "details about your request": {
3490
+ "anyOf": [
3491
+ {
3492
+ "type": "object",
3493
+ "properties": {
3494
+ "error": {
3495
+ "type": "string"
3496
+ }
3497
+ },
3498
+ "required": [
3499
+ "error"
3500
+ ],
3501
+ "additionalProperties": false
3502
+ },
3503
+ {
3504
+ "type": "object",
3505
+ "properties": {
3506
+ "date and time received": {
3507
+ "type": "string"
3508
+ },
3509
+ "diagnosis you disagree with": {
3510
+ "type": "object",
3511
+ "properties": {
3512
+ "issue identifier": {
3513
+ "type": "string"
3514
+ },
3515
+ "identifier of the rule engine": {
3516
+ "type": "string"
3517
+ },
3518
+ "identifier of the violated rule": {
3519
+ "type": "string"
3520
+ }
3521
+ },
3522
+ "required": [
3523
+ "issue identifier",
3524
+ "identifier of the rule engine",
3525
+ "identifier of the violated rule"
3526
+ ],
3527
+ "additionalProperties": false
3528
+ },
3529
+ "disposition": {
3530
+ "type": "string"
3531
+ }
3532
+ },
3533
+ "required": [
3534
+ "date and time received",
3535
+ "diagnosis you disagree with",
3536
+ "disposition"
3537
+ ],
3538
+ "additionalProperties": false
3539
+ }
3540
+ ]
3541
+ }
3542
+ },
3543
+ "required": [
3544
+ "details about your request"
3545
+ ],
3546
+ "additionalProperties": false
3547
+ }
3548
+ },
3549
+ "required": [
3550
+ "tool collection",
3551
+ "tool name",
3552
+ "this request",
3553
+ "URLs of similar requests for web users",
3554
+ "response metadata",
3555
+ "response content"
3556
+ ],
3557
+ "$schema": "http://json-schema.org/draft-07/schema#",
3558
+ "additionalProperties": false,
3559
+ "definitions": {
3560
+ "ToolsFacts": {
3561
+ "type": "object",
3562
+ "properties": {
3563
+ "name": {
3564
+ "type": "string"
3565
+ },
3566
+ "description": {
3567
+ "type": "object",
3568
+ "properties": {
3569
+ "what Kilotest does": {
3570
+ "type": "string"
3571
+ },
3572
+ "how to retrieve findings": {
3573
+ "type": "object",
3574
+ "properties": {
3575
+ "level 1": {
3576
+ "type": "string"
3577
+ },
3578
+ "level 2": {
3579
+ "type": "string"
3580
+ },
3581
+ "level 3": {
3582
+ "type": "string"
3583
+ },
3584
+ "level 4": {
3585
+ "type": "string"
3586
+ }
3587
+ },
3588
+ "required": [
3589
+ "level 1",
3590
+ "level 2",
3591
+ "level 3",
3592
+ "level 4"
3593
+ ],
3594
+ "additionalProperties": false
3595
+ },
3596
+ "how to generate more findings": {
3597
+ "type": "object",
3598
+ "properties": {
3599
+ "new testing": {
3600
+ "type": "string"
3601
+ },
3602
+ "retesting": {
3603
+ "type": "string"
3604
+ },
3605
+ "latency": {
3606
+ "type": "string"
3607
+ },
3608
+ "confirmation": {
3609
+ "type": "string"
3610
+ }
3611
+ },
3612
+ "required": [
3613
+ "new testing",
3614
+ "retesting",
3615
+ "latency",
3616
+ "confirmation"
3617
+ ],
3618
+ "additionalProperties": false
3619
+ }
3620
+ },
3621
+ "required": [
3622
+ "what Kilotest does",
3623
+ "how to retrieve findings",
3624
+ "how to generate more findings"
3625
+ ],
3626
+ "additionalProperties": false,
3627
+ "description": "Explanation of what Kilotest does and how to use its tools."
3628
+ },
3629
+ "URL": {
3630
+ "type": "string",
3631
+ "description": "URL of the Kilotest MCP server."
3632
+ },
3633
+ "web users can obtain similar functionalities at": {
3634
+ "type": "string"
3635
+ }
3636
+ },
3637
+ "required": [
3638
+ "name",
3639
+ "description",
3640
+ "URL",
3641
+ "web users can obtain similar functionalities at"
3642
+ ],
3643
+ "additionalProperties": false
3644
+ },
3645
+ "RequestReference": {
3646
+ "type": "object",
3647
+ "properties": {
3648
+ "tool name": {
3649
+ "type": "string"
3650
+ },
3651
+ "description": {
3652
+ "type": "string"
3653
+ },
3654
+ "method": {
3655
+ "type": "string",
3656
+ "enum": [
3657
+ "GET",
3658
+ "POST"
3659
+ ]
3660
+ },
3661
+ "URL": {
3662
+ "type": "string"
3663
+ }
3664
+ },
3665
+ "required": [
3666
+ "tool name",
3667
+ "description",
3668
+ "method",
3669
+ "URL"
3670
+ ],
3671
+ "additionalProperties": false
3672
+ },
3673
+ "ResponseMetadata": {
3674
+ "type": "object",
3675
+ "properties": {
3676
+ "identifier": {
3677
+ "type": "string",
3678
+ "description": "Unique identifier of this response (timestamp and random suffix)."
3679
+ },
3680
+ "date and time": {
3681
+ "type": "string",
3682
+ "description": "UTC date and time when the response was generated, in ISO 8601 format."
3683
+ }
3684
+ },
3685
+ "required": [
3686
+ "identifier",
3687
+ "date and time"
3688
+ ],
3689
+ "additionalProperties": false
3690
+ }
3691
+ }
3692
+ },
3693
+ "annotations": {
3694
+ "title": "Report disagreement with a diagnosis",
3695
+ "readOnlyHint": false,
3696
+ "destructiveHint": false,
3697
+ "idempotentHint": false,
3698
+ "openWorldHint": false
3699
+ },
3700
+ "execution": {
3701
+ "taskSupport": "forbidden"
3702
+ }
3703
+ },
3405
3704
  {
3406
3705
  "name": "orderNewTest",
3407
3706
  "description": "Orders testing of a page that has no report yet, with automated approval or rejection and immediate enqueueing if approved. Use this instead of requestNewTest when immediate testing is wanted; testing typically takes 2 to 4 minutes. Returns an order confirmation and disposition details, including, if approved, a report identifier (timestamp and job identifier) and a question about whether to wait for completion with the awaitTest tool.",
@@ -4423,5 +4722,5 @@
4423
4722
  }
4424
4723
  }
4425
4724
  ],
4426
- "version": "60.9.1"
4725
+ "version": "62.0.0"
4427
4726
  }
package/llms-full.txt CHANGED
@@ -74,7 +74,7 @@ Kilotest offers these tools:
74
74
 
75
75
  - `listPages`
76
76
  - method: `GET`
77
- - purpose: list all tested pages, each with its latest report and its number of reports
77
+ - purpose: list all tested pages, each with the identifier of its latest report
78
78
  - path: `/api/listPages`
79
79
  - caveat: Cached results are likely to be stale and should not be used
80
80
  - `listIssues`
@@ -124,6 +124,19 @@ Kilotest offers these tools:
124
124
  - path: `/api/requestFeature`
125
125
  - payload properties
126
126
  - `feature`: description and motivation of the feature improvement or the new feature
127
+ - `reportDisagreement`
128
+ - method: `POST`
129
+ - purpose: report disagreement with a diagnosis shown by `listDiagnoses` of how an element exhibited an issue
130
+ - path: `/api/reportDisagreement/{issueID}/{reportID}/{catalogIndex}`
131
+ - parameters
132
+ - `issueID`: identifier of the issue
133
+ - `reportID`: identifier of the report, with YYMMDDTHHmm format for its initial segment (example: 260503T0432-x9z)
134
+ - `catalogIndex`: index of the catalog entry of the element
135
+ - source of parameters: response to a `listDiagnoses` request
136
+ - payload properties
137
+ - `engineID`: identifier of the rule engine that produced the disputed diagnosis, shown in the `listDiagnoses` response
138
+ - `ruleID`: identifier of the rule whose diagnosis is disputed, shown in the `listDiagnoses` response, or, if it is null, the description of the violation
139
+ - `reason`: 20- to 1000-character explanation of why the diagnosis is disputed
127
140
  - `orderNewTest`
128
141
  - method: `POST`
129
142
  - purpose: order immediate, automatically approved testing of one web page about which no report is available, instead of waiting for manual approval
@@ -163,7 +176,7 @@ When you request a test or a retest:
163
176
  - approval followed by the requested testing
164
177
  - rejection
165
178
  - how to confirm approval
166
- - check test completion by calling `listPages` and looking for the page and the completion date of its latest report in the list
179
+ - check test completion by calling `listPages` and looking for the page in the list
167
180
  - you advise the user to check in approximately 1 day for the test results on the Kilotest website, starting at `https://kilotest.com/listPages.html`
168
181
 
169
182
  For immediate testing without waiting for manual approval, use `orderNewTest` or `orderRetest` instead of `requestNewTest` or `requestRetest`. Each enqueues the job right away and returns a report identifier along with a question about whether to wait for completion. To wait, call `awaitTest` with that identifier; it blocks until the report is ready, the job fails, or a maximum wait time elapses. To check later instead, call `listIssues` with the same identifier.
package/llms.txt CHANGED
@@ -12,6 +12,7 @@ Kilotest integrates an ensemble of 12 rule engines, with about 1,300 rules, to t
12
12
  - Request testing of a web page: `/api/requestNewTest` (`POST`)
13
13
  - Request retesting of a web page: `/api/requestRetest/{reportID}` (`POST`)
14
14
  - Request adding or improving a feature: `/api/requestFeature` (`POST`)
15
+ - Report disagreement with a diagnosis: `/api/reportDisagreement/{issueID}/{reportID}/{catalogIndex}` (`POST`)
15
16
  - Order immediate, automatically approved testing of a web page: `/api/orderNewTest` (`POST`)
16
17
  - Order immediate, automatically approved retesting of a web page: `/api/orderRetest/{reportID}` (`POST`)
17
18
  - Wait for a job ordered via orderNewTest or orderRetest to complete: `/api/awaitTest/{reportID}` (`POST`)
package/mcp.test.ts CHANGED
@@ -37,10 +37,10 @@ test('mcpPath is /mcp', () => {
37
37
  assert.equal(mcpPath, '/mcp');
38
38
  });
39
39
 
40
- test('createMCPServer registers all 12 tools', () => {
40
+ test('createMCPServer registers all 13 tools', () => {
41
41
  const server = createMCPServer();
42
42
  const toolNames = Object.keys((server as any)._registeredTools);
43
- assert.equal(toolNames.length, 12);
43
+ assert.equal(toolNames.length, 13);
44
44
  assert.deepEqual(toolNames, [
45
45
  'getKilotestOverview',
46
46
  'listPages',
@@ -51,6 +51,7 @@ test('createMCPServer registers all 12 tools', () => {
51
51
  'requestNewTest',
52
52
  'requestRetest',
53
53
  'requestFeature',
54
+ 'reportDisagreement',
54
55
  'orderNewTest',
55
56
  'orderRetest',
56
57
  'awaitTest'
@@ -197,6 +198,23 @@ test('requestFeature handler returns content and structuredContent', async () =>
197
198
  assert.equal(getToolCallCount('requestFeature'), countBefore + 1);
198
199
  });
199
200
 
201
+ test('reportDisagreement handler returns content and structuredContent', async () => {
202
+ const server = createMCPServer();
203
+ const countBefore = getToolCallCount('reportDisagreement');
204
+ const result = await (server as any)._registeredTools.reportDisagreement.handler({
205
+ issueID: 'linkNoText',
206
+ reportID: '260101T0000-mix',
207
+ catalogIndex: '0',
208
+ engineID: 'axe',
209
+ ruleID: 'r11',
210
+ reason: 'The element does have an accessible name'
211
+ });
212
+ assert.ok(result.content);
213
+ assert.equal(result.content[0].type, 'text');
214
+ assert.ok(result.structuredContent);
215
+ assert.equal(getToolCallCount('reportDisagreement'), countBefore + 1);
216
+ });
217
+
200
218
  test('orderNewTest handler returns content and structuredContent, and enqueues a job', async () => {
201
219
  const {jobsPath} = await import('./util.ts');
202
220
  const server = createMCPServer();
@@ -349,7 +367,7 @@ test('handleMCP responds to initialize with server info', async () => {
349
367
  }
350
368
  });
351
369
 
352
- test('handleMCP lists all 12 tools via tools/list', async () => {
370
+ test('handleMCP lists all 13 tools via tools/list', async () => {
353
371
  const server = await startMCPServer();
354
372
  try {
355
373
  const port = server.address().port;
@@ -357,7 +375,7 @@ test('handleMCP lists all 12 tools via tools/list', async () => {
357
375
  assert.equal(res.statusCode, 200);
358
376
  const result = parseSSEResult(res.body);
359
377
  const toolNames = result.result.tools.map((t: any) => t.name);
360
- assert.equal(toolNames.length, 12);
378
+ assert.equal(toolNames.length, 13);
361
379
  assert.deepEqual(toolNames, [
362
380
  'getKilotestOverview',
363
381
  'listPages',
@@ -368,6 +386,7 @@ test('handleMCP lists all 12 tools via tools/list', async () => {
368
386
  'requestNewTest',
369
387
  'requestRetest',
370
388
  'requestFeature',
389
+ 'reportDisagreement',
371
390
  'orderNewTest',
372
391
  'orderRetest',
373
392
  'awaitTest'
package/mcp.ts CHANGED
@@ -19,6 +19,7 @@ import * as requestFeatureAPI from './api/requestFeature.ts';
19
19
  import * as orderNewTestAPI from './api/orderNewTest.ts';
20
20
  import * as orderRetestAPI from './api/orderRetest.ts';
21
21
  import * as awaitTestAPI from './api/awaitTest.ts';
22
+ import * as reportDisagreementAPI from './api/reportDisagreement.ts';
22
23
  import {version} from './api/version.ts';
23
24
  import {recordMetric} from './util.ts';
24
25
 
@@ -33,6 +34,7 @@ import {
33
34
  orderNewTestSchema,
34
35
  orderRetestSchema,
35
36
  awaitTestSchema,
37
+ reportDisagreementSchema,
36
38
  listPagesResponseSchema,
37
39
  listIssuesResponseSchema,
38
40
  listViolatorsResponseSchema,
@@ -43,7 +45,8 @@ import {
43
45
  requestFeatureResponseSchema,
44
46
  orderNewTestResponseSchema,
45
47
  orderRetestResponseSchema,
46
- awaitTestResponseSchema
48
+ awaitTestResponseSchema,
49
+ reportDisagreementResponseSchema
47
50
  } from './api/schemas.ts';
48
51
 
49
52
  // CONSTANTS
@@ -257,6 +260,26 @@ export const createMCPServer = (): McpServer => {
257
260
  return {content: [{type: 'text', text: JSON.stringify(result)}], structuredContent: result};
258
261
  }
259
262
  );
263
+ server.registerTool(
264
+ 'reportDisagreement',
265
+ {
266
+ description: 'Reports that you disagree with a diagnosis shown by the listDiagnoses tool; queued for manager review. Use this after listDiagnoses when you believe a rule violation was incorrectly diagnosed or classified into an issue, providing the engineID and ruleID shown in the diagnosis and your reason. Returns a confirmation with disposition details.',
267
+ inputSchema: reportDisagreementSchema,
268
+ outputSchema: reportDisagreementResponseSchema,
269
+ annotations: {
270
+ title: 'Report disagreement with a diagnosis',
271
+ readOnlyHint: false,
272
+ idempotentHint: false,
273
+ destructiveHint: false,
274
+ openWorldHint: false
275
+ }
276
+ },
277
+ async ({issueID, reportID, catalogIndex, engineID, ruleID, reason}) => {
278
+ const result = await reportDisagreementAPI.response([issueID, reportID, catalogIndex, engineID, ruleID, reason]);
279
+ await recordMetric('mcpToolCalls', 'reportDisagreement');
280
+ return {content: [{type: 'text', text: JSON.stringify(result)}], structuredContent: result};
281
+ }
282
+ );
260
283
  server.registerTool(
261
284
  'orderNewTest',
262
285
  {