@shiftleftpt/sbd-toe-mcp 0.6.2 → 0.7.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/assets/agent-guide.md +22 -19
- package/data/publish/algolia_entities_records_enriched.json +25370 -2
- package/data/publish/canonical_controls.json +1239 -0
- package/data/publish/canonical_requirements_s7.json +1859 -0
- package/data/publish/canonical_roles_s5.json +138 -0
- package/data/publish/lifecycle_user_stories.json +6558 -0
- package/data/publish/mitigated_threats.json +6945 -0
- package/data/publish/practice_assignments.json +16266 -0
- package/data/publish/sbdtoe-ontology.yaml +696 -0
- package/dist/backend/semantic-index-gateway.js +1 -1
- package/dist/index.js +276 -115
- package/dist/index.js.map +1 -1
- package/dist/resources/sbd-toe-resources.js +6 -1
- package/dist/resources/sbd-toe-resources.js.map +1 -1
- package/dist/tools/consult-security-requirements.d.ts +38 -0
- package/dist/tools/consult-security-requirements.js +115 -0
- package/dist/tools/consult-security-requirements.js.map +1 -0
- package/dist/tools/get-guide-by-role.d.ts +38 -0
- package/dist/tools/get-guide-by-role.js +109 -0
- package/dist/tools/get-guide-by-role.js.map +1 -0
- package/dist/tools/get-threat-landscape.d.ts +44 -0
- package/dist/tools/get-threat-landscape.js +116 -0
- package/dist/tools/get-threat-landscape.js.map +1 -0
- package/dist/tools/map-review-scope.js +5 -0
- package/dist/tools/map-review-scope.js.map +1 -1
- package/dist/tools/ontology-loader.d.ts +104 -0
- package/dist/tools/ontology-loader.js +206 -0
- package/dist/tools/ontology-loader.js.map +1 -0
- package/dist/tools/plan-repo-governance.d.ts +25 -38
- package/dist/tools/plan-repo-governance.js +71 -498
- package/dist/tools/plan-repo-governance.js.map +1 -1
- package/dist/tools/resolve-entities.d.ts +26 -0
- package/dist/tools/resolve-entities.js +143 -0
- package/dist/tools/resolve-entities.js.map +1 -0
- package/package.json +4 -1
- package/dist/tools/generate-document.d.ts +0 -22
- package/dist/tools/generate-document.js +0 -392
- package/dist/tools/generate-document.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -5,12 +5,15 @@ import readline from "node:readline";
|
|
|
5
5
|
import { getConfig, resolveAppPath } from "./config.js";
|
|
6
6
|
import { formatSampledAnswerResult, inspectManualRetrieval, prepareManualAnsweringContext, searchManualQuestion } from "./orchestrator/ask-manual.js";
|
|
7
7
|
import { loadSystemPromptTemplate } from "./prompt/system-prompt.js";
|
|
8
|
-
import { getSnapshotCache
|
|
8
|
+
import { getSnapshotCache } from "./backend/semantic-index-gateway.js";
|
|
9
9
|
import { handleGetSbdToeChapterBrief, handleListSbdToeChapters, handleMapSbdToeApplicability, handleQuerySbdToeEntities } from "./tools/structured-tools.js";
|
|
10
|
-
import { handleGenerateDocument } from "./tools/generate-document.js";
|
|
11
10
|
import { handleGenerateSbdToeSkill } from "./tools/generate-sbd-toe-skill.js";
|
|
12
11
|
import { handleMapSbdToeReviewScope } from "./tools/map-review-scope.js";
|
|
13
12
|
import { handlePlanRepoGovernance } from "./tools/plan-repo-governance.js";
|
|
13
|
+
import { handleConsultSecurityRequirements } from "./tools/consult-security-requirements.js";
|
|
14
|
+
import { handleGetThreatLandscape } from "./tools/get-threat-landscape.js";
|
|
15
|
+
import { handleGetGuideByRole } from "./tools/get-guide-by-role.js";
|
|
16
|
+
import { handleResolveEntities } from "./tools/resolve-entities.js";
|
|
14
17
|
import { buildChapterApplicabilityJson, buildSetupAgentPrompt } from "./resources/sbd-toe-resources.js";
|
|
15
18
|
const PROTOCOL_VERSION = "2025-03-26";
|
|
16
19
|
const LOG_LEVELS = [
|
|
@@ -296,23 +299,23 @@ class McpRuntime {
|
|
|
296
299
|
{
|
|
297
300
|
name: "search_sbd_toe_manual",
|
|
298
301
|
title: "Search SbD-ToE Manual",
|
|
299
|
-
description: "
|
|
302
|
+
description: "Retrieves grounded context from the SbD-ToE manual using the embedded local semantic snapshot.",
|
|
300
303
|
inputSchema: {
|
|
301
304
|
type: "object",
|
|
302
305
|
properties: {
|
|
303
306
|
question: {
|
|
304
307
|
type: "string",
|
|
305
|
-
description: "
|
|
308
|
+
description: "Natural-language question about the manual."
|
|
306
309
|
},
|
|
307
310
|
debug: {
|
|
308
311
|
type: "boolean",
|
|
309
|
-
description: "
|
|
312
|
+
description: "When true, appends full retrieval debug information."
|
|
310
313
|
},
|
|
311
314
|
topK: {
|
|
312
315
|
type: "integer",
|
|
313
316
|
minimum: 1,
|
|
314
317
|
maximum: 15,
|
|
315
|
-
description: "
|
|
318
|
+
description: "Maximum number of records used as context."
|
|
316
319
|
}
|
|
317
320
|
},
|
|
318
321
|
required: ["question"],
|
|
@@ -325,23 +328,26 @@ class McpRuntime {
|
|
|
325
328
|
{
|
|
326
329
|
name: "answer_sbd_toe_manual",
|
|
327
330
|
title: "Answer SbD-ToE Manual",
|
|
328
|
-
description: "
|
|
331
|
+
description: "Retrieves SbD-ToE manual context and requests the final answer from the client's model via MCP sampling. " +
|
|
332
|
+
"Requires sampling support from the MCP client. " +
|
|
333
|
+
"Without sampling, falls back to formatted retrieval output (same as search_sbd_toe_manual). " +
|
|
334
|
+
"Prefer search_sbd_toe_manual for clients without sampling support.",
|
|
329
335
|
inputSchema: {
|
|
330
336
|
type: "object",
|
|
331
337
|
properties: {
|
|
332
338
|
question: {
|
|
333
339
|
type: "string",
|
|
334
|
-
description: "
|
|
340
|
+
description: "Natural-language question about the manual."
|
|
335
341
|
},
|
|
336
342
|
debug: {
|
|
337
343
|
type: "boolean",
|
|
338
|
-
description: "
|
|
344
|
+
description: "When true, appends full debug information."
|
|
339
345
|
},
|
|
340
346
|
topK: {
|
|
341
347
|
type: "integer",
|
|
342
348
|
minimum: 1,
|
|
343
349
|
maximum: 15,
|
|
344
|
-
description: "
|
|
350
|
+
description: "Maximum number of records used as context."
|
|
345
351
|
}
|
|
346
352
|
},
|
|
347
353
|
required: ["question"],
|
|
@@ -354,19 +360,19 @@ class McpRuntime {
|
|
|
354
360
|
{
|
|
355
361
|
name: "inspect_sbd_toe_retrieval",
|
|
356
362
|
title: "Inspect SbD-ToE Retrieval",
|
|
357
|
-
description: "
|
|
363
|
+
description: "Inspects retrieval, context selection and final prompt without requesting an answer from the client model.",
|
|
358
364
|
inputSchema: {
|
|
359
365
|
type: "object",
|
|
360
366
|
properties: {
|
|
361
367
|
question: {
|
|
362
368
|
type: "string",
|
|
363
|
-
description: "
|
|
369
|
+
description: "Question to use for the retrieval inspection."
|
|
364
370
|
},
|
|
365
371
|
topK: {
|
|
366
372
|
type: "integer",
|
|
367
373
|
minimum: 1,
|
|
368
374
|
maximum: 15,
|
|
369
|
-
description: "
|
|
375
|
+
description: "Maximum number of records selected for the prompt."
|
|
370
376
|
}
|
|
371
377
|
},
|
|
372
378
|
required: ["question"],
|
|
@@ -379,14 +385,14 @@ class McpRuntime {
|
|
|
379
385
|
{
|
|
380
386
|
name: "list_sbd_toe_chapters",
|
|
381
387
|
title: "List SbD-ToE Chapters",
|
|
382
|
-
description: "
|
|
388
|
+
description: "Lists SbD-ToE manual chapters with id, title and applicability.",
|
|
383
389
|
inputSchema: {
|
|
384
390
|
type: "object",
|
|
385
391
|
properties: {
|
|
386
392
|
riskLevel: {
|
|
387
393
|
type: "string",
|
|
388
394
|
enum: ["L1", "L2", "L3"],
|
|
389
|
-
description: "
|
|
395
|
+
description: "Filter by risk level."
|
|
390
396
|
}
|
|
391
397
|
},
|
|
392
398
|
additionalProperties: false
|
|
@@ -396,7 +402,7 @@ class McpRuntime {
|
|
|
396
402
|
{
|
|
397
403
|
name: "query_sbd_toe_entities",
|
|
398
404
|
title: "Query SbD-ToE Entities",
|
|
399
|
-
description: "
|
|
405
|
+
description: "Queries manual entities by text, entity type, chapter or risk level.",
|
|
400
406
|
inputSchema: {
|
|
401
407
|
type: "object",
|
|
402
408
|
properties: {
|
|
@@ -414,7 +420,7 @@ class McpRuntime {
|
|
|
414
420
|
{
|
|
415
421
|
name: "get_sbd_toe_chapter_brief",
|
|
416
422
|
title: "Get SbD-ToE Chapter Brief",
|
|
417
|
-
description: "
|
|
423
|
+
description: "Returns an operational summary of a chapter: role, phases, artefacts, intent_topics.",
|
|
418
424
|
inputSchema: {
|
|
419
425
|
type: "object",
|
|
420
426
|
properties: {
|
|
@@ -427,66 +433,22 @@ class McpRuntime {
|
|
|
427
433
|
},
|
|
428
434
|
{
|
|
429
435
|
name: "plan_sbd_toe_repo_governance",
|
|
430
|
-
title: "
|
|
431
|
-
description: "
|
|
436
|
+
title: "List SbD-ToE Manual Artefacts",
|
|
437
|
+
description: "Returns the list of artefacts/documents identified in the SbD-ToE manual, " +
|
|
438
|
+
"grouped by chapter, with risk level applicability. " +
|
|
439
|
+
"Optionally filter by riskLevel (L1/L2/L3). " +
|
|
440
|
+
"All data comes from the manual indices — nothing is invented. " +
|
|
441
|
+
"The manual does not provide templates; ask the LLM to generate one if needed.",
|
|
432
442
|
inputSchema: {
|
|
433
443
|
type: "object",
|
|
434
444
|
properties: {
|
|
435
|
-
repoType: {
|
|
436
|
-
type: "string",
|
|
437
|
-
enum: ["library", "service", "webapp", "infrastructure", "pipeline", "monorepo"],
|
|
438
|
-
description: "Tipo de repositório."
|
|
439
|
-
},
|
|
440
|
-
platform: {
|
|
441
|
-
type: "string",
|
|
442
|
-
enum: ["github", "gitlab"],
|
|
443
|
-
description: "Plataforma de hosting do repositório."
|
|
444
|
-
},
|
|
445
|
-
riskLevel: {
|
|
446
|
-
type: "string",
|
|
447
|
-
enum: ["L1", "L2", "L3"],
|
|
448
|
-
description: "Nível de risco do projecto."
|
|
449
|
-
},
|
|
450
|
-
organizationContext: {
|
|
451
|
-
type: "object",
|
|
452
|
-
description: "Contexto organizacional opcional.",
|
|
453
|
-
properties: {
|
|
454
|
-
scale: { type: "string", enum: ["startup", "mid-size", "enterprise"] },
|
|
455
|
-
teamSize: { type: "integer", minimum: 1 },
|
|
456
|
-
enforcementLevel: { type: "string", enum: ["advisory", "enforced", "strict"] }
|
|
457
|
-
},
|
|
458
|
-
additionalProperties: false
|
|
459
|
-
}
|
|
460
|
-
},
|
|
461
|
-
required: ["repoType", "platform", "riskLevel"],
|
|
462
|
-
additionalProperties: false
|
|
463
|
-
},
|
|
464
|
-
annotations: { readOnlyHint: true }
|
|
465
|
-
},
|
|
466
|
-
{
|
|
467
|
-
name: "generate_document",
|
|
468
|
-
title: "Generate SbD-ToE Document",
|
|
469
|
-
description: "Gera o esqueleto estruturado de um documento SbD-ToE (secções, campos obrigatórios, critérios de aceitação) para um tipo e nível de risco.",
|
|
470
|
-
inputSchema: {
|
|
471
|
-
type: "object",
|
|
472
|
-
properties: {
|
|
473
|
-
type: {
|
|
474
|
-
type: "string",
|
|
475
|
-
enum: ["classification-template", "threat-model-template", "checklist", "training-plan", "secure-config"],
|
|
476
|
-
description: "Tipo de documento a gerar."
|
|
477
|
-
},
|
|
478
445
|
riskLevel: {
|
|
479
446
|
type: "string",
|
|
480
447
|
enum: ["L1", "L2", "L3"],
|
|
481
|
-
description: "
|
|
482
|
-
},
|
|
483
|
-
context: {
|
|
484
|
-
type: "object",
|
|
485
|
-
description: "Contexto adicional do projecto (reservado, não usado na estrutura).",
|
|
486
|
-
additionalProperties: true
|
|
448
|
+
description: "Optional. If provided, only artefacts applicable at this risk level are returned."
|
|
487
449
|
}
|
|
488
450
|
},
|
|
489
|
-
required: [
|
|
451
|
+
required: [],
|
|
490
452
|
additionalProperties: false
|
|
491
453
|
},
|
|
492
454
|
annotations: { readOnlyHint: true }
|
|
@@ -511,7 +473,7 @@ class McpRuntime {
|
|
|
511
473
|
{
|
|
512
474
|
name: "map_sbd_toe_review_scope",
|
|
513
475
|
title: "Map SbD-ToE Review Scope",
|
|
514
|
-
description: "
|
|
476
|
+
description: "Given a set of changed files, maps which SbD-ToE knowledge bundles should be reviewed, with explicit reasoning per path.",
|
|
515
477
|
inputSchema: {
|
|
516
478
|
type: "object",
|
|
517
479
|
properties: {
|
|
@@ -519,16 +481,16 @@ class McpRuntime {
|
|
|
519
481
|
type: "array",
|
|
520
482
|
items: { type: "string" },
|
|
521
483
|
minItems: 1,
|
|
522
|
-
description: "
|
|
484
|
+
description: "List of paths relative to the repository root."
|
|
523
485
|
},
|
|
524
486
|
riskLevel: {
|
|
525
487
|
type: "string",
|
|
526
488
|
enum: ["L1", "L2", "L3"],
|
|
527
|
-
description: "
|
|
489
|
+
description: "Project risk level."
|
|
528
490
|
},
|
|
529
491
|
projectContext: {
|
|
530
492
|
type: "object",
|
|
531
|
-
description: "
|
|
493
|
+
description: "Additional project context (optional).",
|
|
532
494
|
properties: {
|
|
533
495
|
repoRole: { type: "string" },
|
|
534
496
|
runtimeModel: { type: "string" },
|
|
@@ -539,7 +501,7 @@ class McpRuntime {
|
|
|
539
501
|
},
|
|
540
502
|
diffSummary: {
|
|
541
503
|
type: "string",
|
|
542
|
-
description: "
|
|
504
|
+
description: "Diff summary (truncated to 500 chars)."
|
|
543
505
|
}
|
|
544
506
|
},
|
|
545
507
|
required: ["changedFiles", "riskLevel"],
|
|
@@ -550,7 +512,7 @@ class McpRuntime {
|
|
|
550
512
|
{
|
|
551
513
|
name: "map_sbd_toe_applicability",
|
|
552
514
|
title: "Map SbD-ToE Applicability",
|
|
553
|
-
description: "
|
|
515
|
+
description: "Maps active, conditional and excluded chapters/controls for a given risk level L1/L2/L3. Supports project context to activate relevant bundles.",
|
|
554
516
|
inputSchema: {
|
|
555
517
|
type: "object",
|
|
556
518
|
properties: {
|
|
@@ -566,26 +528,161 @@ class McpRuntime {
|
|
|
566
528
|
"network-segmentation", "cryptography"
|
|
567
529
|
]
|
|
568
530
|
},
|
|
569
|
-
description: "
|
|
531
|
+
description: "Technologies used in the project."
|
|
570
532
|
},
|
|
571
533
|
hasPersonalData: {
|
|
572
534
|
type: "boolean",
|
|
573
|
-
description: "
|
|
535
|
+
description: "Does the project process personal data?"
|
|
574
536
|
},
|
|
575
537
|
isPublicFacing: {
|
|
576
538
|
type: "boolean",
|
|
577
|
-
description: "
|
|
539
|
+
description: "Does the project have public-facing exposure?"
|
|
578
540
|
},
|
|
579
541
|
projectRole: {
|
|
580
542
|
type: "string",
|
|
581
543
|
enum: ["developer", "architect", "security", "devops", "manager"],
|
|
582
|
-
description: "
|
|
544
|
+
description: "User role in the project."
|
|
583
545
|
}
|
|
584
546
|
},
|
|
585
547
|
required: ["riskLevel"],
|
|
586
548
|
additionalProperties: false
|
|
587
549
|
},
|
|
588
550
|
annotations: { readOnlyHint: true }
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
name: "consult_security_requirements",
|
|
554
|
+
title: "Consult SbD-ToE Security Requirements",
|
|
555
|
+
description: "Deterministic resolution of security requirements and controls for a given application context. " +
|
|
556
|
+
"Filters requirements by risk level, optionally narrows by concern domains (auth, logging, api, etc.), " +
|
|
557
|
+
"then derives active controls via the ontology domain_mapping pipeline. " +
|
|
558
|
+
"All data comes from the SbD-ToE ontology — nothing is invented.",
|
|
559
|
+
inputSchema: {
|
|
560
|
+
type: "object",
|
|
561
|
+
properties: {
|
|
562
|
+
risk_level: {
|
|
563
|
+
type: "string",
|
|
564
|
+
enum: ["L1", "L2", "L3"],
|
|
565
|
+
description: "Application risk level. Controls which requirements are active."
|
|
566
|
+
},
|
|
567
|
+
concerns: {
|
|
568
|
+
type: "array",
|
|
569
|
+
items: {
|
|
570
|
+
type: "string",
|
|
571
|
+
enum: ["auth", "logging", "validation", "api", "config", "integrity", "distribution", "ide", "requirements", "architecture", "iac", "encryption"]
|
|
572
|
+
},
|
|
573
|
+
description: "Optional concern domains to narrow scope (intersects with risk-level filter, does not replace)."
|
|
574
|
+
},
|
|
575
|
+
exposure: {
|
|
576
|
+
type: "string",
|
|
577
|
+
enum: ["local", "internal", "authenticated", "public"],
|
|
578
|
+
description: "Application exposure level (informational — not yet used in filtering)."
|
|
579
|
+
},
|
|
580
|
+
data_sensitivity: {
|
|
581
|
+
type: "string",
|
|
582
|
+
enum: ["low", "personal", "regulated", "secrets"],
|
|
583
|
+
description: "Data sensitivity level (informational — not yet used in filtering)."
|
|
584
|
+
}
|
|
585
|
+
},
|
|
586
|
+
required: ["risk_level"],
|
|
587
|
+
additionalProperties: false
|
|
588
|
+
},
|
|
589
|
+
annotations: { readOnlyHint: true }
|
|
590
|
+
},
|
|
591
|
+
{
|
|
592
|
+
name: "get_threat_landscape",
|
|
593
|
+
title: "Get SbD-ToE Threat Landscape",
|
|
594
|
+
description: "Deterministic threat resolution for an application context using the SbD-ToE ontology threats pipeline. " +
|
|
595
|
+
"Returns threats from mitigated_threats.json relevant to the active source chapters derived from " +
|
|
596
|
+
"the risk-level-filtered requirements. Optionally narrowed by concern domains. " +
|
|
597
|
+
"All data comes from the SbD-ToE ontology — nothing is invented.",
|
|
598
|
+
inputSchema: {
|
|
599
|
+
type: "object",
|
|
600
|
+
properties: {
|
|
601
|
+
risk_level: {
|
|
602
|
+
type: "string",
|
|
603
|
+
enum: ["L1", "L2", "L3"],
|
|
604
|
+
description: "Application risk level."
|
|
605
|
+
},
|
|
606
|
+
concerns: {
|
|
607
|
+
type: "array",
|
|
608
|
+
items: {
|
|
609
|
+
type: "string",
|
|
610
|
+
enum: ["auth", "logging", "validation", "api", "config", "integrity", "distribution", "ide", "requirements", "architecture", "iac", "encryption"]
|
|
611
|
+
},
|
|
612
|
+
description: "Optional concern domains to narrow which chapters are in scope."
|
|
613
|
+
}
|
|
614
|
+
},
|
|
615
|
+
required: ["risk_level"],
|
|
616
|
+
additionalProperties: false
|
|
617
|
+
},
|
|
618
|
+
annotations: { readOnlyHint: true }
|
|
619
|
+
},
|
|
620
|
+
{
|
|
621
|
+
name: "get_guide_by_role",
|
|
622
|
+
title: "Get SbD-ToE Guide by Role",
|
|
623
|
+
description: "Returns practice assignments and user stories from the SbD-ToE manual for a given risk level, " +
|
|
624
|
+
"optionally filtered by role and/or lifecycle phase. " +
|
|
625
|
+
"Roles are resolved via canonical aliases (e.g. 'dev' → 'developer', 'appsec' → 'security-champion'). " +
|
|
626
|
+
"Results grouped by role and phase. All data from the SbD-ToE ontology — nothing is invented.",
|
|
627
|
+
inputSchema: {
|
|
628
|
+
type: "object",
|
|
629
|
+
properties: {
|
|
630
|
+
risk_level: {
|
|
631
|
+
type: "string",
|
|
632
|
+
enum: ["L1", "L2", "L3"],
|
|
633
|
+
description: "Application risk level."
|
|
634
|
+
},
|
|
635
|
+
role: {
|
|
636
|
+
type: "string",
|
|
637
|
+
description: "Role to filter by (supports canonical IDs and aliases, e.g. 'developer', 'security-champion', 'devops', 'appsec')."
|
|
638
|
+
},
|
|
639
|
+
phase: {
|
|
640
|
+
type: "string",
|
|
641
|
+
description: "Lifecycle phase to filter by (e.g. 'design', 'implement', 'test', 'operate')."
|
|
642
|
+
}
|
|
643
|
+
},
|
|
644
|
+
required: ["risk_level"],
|
|
645
|
+
additionalProperties: false
|
|
646
|
+
},
|
|
647
|
+
annotations: { readOnlyHint: true }
|
|
648
|
+
},
|
|
649
|
+
{
|
|
650
|
+
name: "resolve_entities",
|
|
651
|
+
title: "Resolve SbD-ToE Entities",
|
|
652
|
+
description: "Low-level entity resolver over the SbD-ToE enriched index. " +
|
|
653
|
+
"Query any entity type by record_type with optional field filters. " +
|
|
654
|
+
"Supports dot-notation for nested fields (e.g. 'applicable_levels.L2'), " +
|
|
655
|
+
"comparison operators ({gte, lte} for numbers, {in: [...]} for set membership), " +
|
|
656
|
+
"and array membership checks. " +
|
|
657
|
+
"Use this when the high-level tools (consult_security_requirements, get_threat_landscape, " +
|
|
658
|
+
"get_guide_by_role) do not cover your specific query. " +
|
|
659
|
+
"All data from the SbD-ToE enriched entities index — nothing is invented.",
|
|
660
|
+
inputSchema: {
|
|
661
|
+
type: "object",
|
|
662
|
+
properties: {
|
|
663
|
+
record_type: {
|
|
664
|
+
type: "string",
|
|
665
|
+
description: "Entity type to query. Well-known types: requirement, control, practice, threat, " +
|
|
666
|
+
"user_story, assignment, role, phase, maturity_mapping, chapter_bundle. " +
|
|
667
|
+
"Read sbd://toe/ontology to see all entity schemas."
|
|
668
|
+
},
|
|
669
|
+
filters: {
|
|
670
|
+
type: "object",
|
|
671
|
+
description: "Key-value filters on entity fields. " +
|
|
672
|
+
"Dot-notation for nested fields: {\"applicable_levels.L2\": true}. " +
|
|
673
|
+
"Comparison ops: {cvss_score: {gte: 7.0}} or {risk_level: {in: [\"L2\",\"L3\"]}}. " +
|
|
674
|
+
"Array fields: {roles_normalized: \"developer\"} checks membership.",
|
|
675
|
+
additionalProperties: true
|
|
676
|
+
},
|
|
677
|
+
limit: {
|
|
678
|
+
type: "number",
|
|
679
|
+
description: "Max results to return. Default: 50, max: 200."
|
|
680
|
+
}
|
|
681
|
+
},
|
|
682
|
+
required: ["record_type"],
|
|
683
|
+
additionalProperties: false
|
|
684
|
+
},
|
|
685
|
+
annotations: { readOnlyHint: true }
|
|
589
686
|
}
|
|
590
687
|
]
|
|
591
688
|
});
|
|
@@ -594,11 +691,11 @@ class McpRuntime {
|
|
|
594
691
|
return {
|
|
595
692
|
name: "ask_sbd_toe_manual",
|
|
596
693
|
title: "Ask SbD-ToE Manual",
|
|
597
|
-
description: "
|
|
694
|
+
description: "MCP prompt to guide the AI chat to answer questions about the SbD-ToE manual with grounding.",
|
|
598
695
|
arguments: [
|
|
599
696
|
{
|
|
600
697
|
name: "question",
|
|
601
|
-
description: "
|
|
698
|
+
description: "Question about the SbD-ToE manual.",
|
|
602
699
|
required: true
|
|
603
700
|
}
|
|
604
701
|
]
|
|
@@ -611,16 +708,16 @@ class McpRuntime {
|
|
|
611
708
|
{
|
|
612
709
|
name: "setup_sbd_toe_agent",
|
|
613
710
|
title: "Setup SbD-ToE Agent",
|
|
614
|
-
description: "
|
|
711
|
+
description: "MCP prompt to configure an agent with SbD-ToE manual context and rules for a given risk level.",
|
|
615
712
|
arguments: [
|
|
616
713
|
{
|
|
617
714
|
name: "riskLevel",
|
|
618
|
-
description: "
|
|
715
|
+
description: "Project risk level: L1, L2 or L3.",
|
|
619
716
|
required: true
|
|
620
717
|
},
|
|
621
718
|
{
|
|
622
719
|
name: "projectRole",
|
|
623
|
-
description: "
|
|
720
|
+
description: "Project role or description (optional).",
|
|
624
721
|
required: false
|
|
625
722
|
}
|
|
626
723
|
]
|
|
@@ -636,10 +733,10 @@ class McpRuntime {
|
|
|
636
733
|
if (name === "ask_sbd_toe_manual") {
|
|
637
734
|
const question = typeof args.question === "string" ? args.question : "";
|
|
638
735
|
const promptText = `${loadSystemPromptTemplate()}\n\n` +
|
|
639
|
-
"Use
|
|
736
|
+
"Use the `search_sbd_toe_manual` tool before answering.\n" +
|
|
640
737
|
`Question: ${question}`;
|
|
641
738
|
this.sendResponse(request.id, {
|
|
642
|
-
description: "
|
|
739
|
+
description: "Grounded prompt for questions about the SbD-ToE manual.",
|
|
643
740
|
messages: [
|
|
644
741
|
{
|
|
645
742
|
role: "user",
|
|
@@ -655,13 +752,13 @@ class McpRuntime {
|
|
|
655
752
|
if (name === "setup_sbd_toe_agent") {
|
|
656
753
|
const riskLevel = args["riskLevel"];
|
|
657
754
|
if (typeof riskLevel !== "string" || !["L1", "L2", "L3"].includes(riskLevel)) {
|
|
658
|
-
this.sendError(request.id, -32602, '
|
|
755
|
+
this.sendError(request.id, -32602, 'The "riskLevel" argument is required and must be L1, L2 or L3.');
|
|
659
756
|
return;
|
|
660
757
|
}
|
|
661
758
|
const projectRole = typeof args["projectRole"] === "string" ? args["projectRole"] : undefined;
|
|
662
759
|
const promptText = buildSetupAgentPrompt(riskLevel, projectRole);
|
|
663
760
|
this.sendResponse(request.id, {
|
|
664
|
-
description: "Prompt
|
|
761
|
+
description: "Prompt to configure an agent with SbD-ToE context.",
|
|
665
762
|
messages: [
|
|
666
763
|
{
|
|
667
764
|
role: "user",
|
|
@@ -674,7 +771,7 @@ class McpRuntime {
|
|
|
674
771
|
});
|
|
675
772
|
return;
|
|
676
773
|
}
|
|
677
|
-
this.sendError(request.id, -32602, `
|
|
774
|
+
this.sendError(request.id, -32602, `Unknown prompt: ${name}`);
|
|
678
775
|
}
|
|
679
776
|
handleResourcesList(request) {
|
|
680
777
|
this.sendResponse(request.id, {
|
|
@@ -696,6 +793,15 @@ class McpRuntime {
|
|
|
696
793
|
name: "SbD-ToE Index Compact",
|
|
697
794
|
description: "Compact JSON index of the full SbD-ToE manual. Injectable into system prompt to eliminate exploratory discovery.",
|
|
698
795
|
mimeType: "application/json"
|
|
796
|
+
},
|
|
797
|
+
{
|
|
798
|
+
uri: "sbd://toe/ontology",
|
|
799
|
+
name: "SbD-ToE Ontology",
|
|
800
|
+
description: "Full SbD-ToE ontology YAML: domain_mapping (requirement category → control domains), " +
|
|
801
|
+
"8 inference rules with priorities, 4 resolution pipelines (consult/guide/threats/review), " +
|
|
802
|
+
"and entity schemas. Read once per session to understand the deterministic resolution model " +
|
|
803
|
+
"before calling consult_security_requirements, get_threat_landscape or get_guide_by_role.",
|
|
804
|
+
mimeType: "application/yaml"
|
|
699
805
|
}
|
|
700
806
|
]
|
|
701
807
|
});
|
|
@@ -706,7 +812,7 @@ class McpRuntime {
|
|
|
706
812
|
if (applicabilityMatch !== null) {
|
|
707
813
|
const riskLevel = applicabilityMatch[1] ?? "";
|
|
708
814
|
if (!["L1", "L2", "L3"].includes(riskLevel)) {
|
|
709
|
-
this.sendError(request.id, -32602, `riskLevel
|
|
815
|
+
this.sendError(request.id, -32602, `Invalid riskLevel: "${riskLevel}". Allowed values: L1, L2, L3.`);
|
|
710
816
|
return;
|
|
711
817
|
}
|
|
712
818
|
const data = buildChapterApplicabilityJson(riskLevel);
|
|
@@ -722,7 +828,7 @@ class McpRuntime {
|
|
|
722
828
|
indexText = readFileSync(indexPath, "utf-8");
|
|
723
829
|
}
|
|
724
830
|
catch {
|
|
725
|
-
this.sendError(request.id, -32603, "
|
|
831
|
+
this.sendError(request.id, -32603, "Could not read the SbD-ToE compact index.");
|
|
726
832
|
return;
|
|
727
833
|
}
|
|
728
834
|
this.sendResponse(request.id, {
|
|
@@ -745,12 +851,27 @@ class McpRuntime {
|
|
|
745
851
|
});
|
|
746
852
|
return;
|
|
747
853
|
}
|
|
748
|
-
|
|
854
|
+
if (uri === "sbd://toe/ontology") {
|
|
855
|
+
const ontologyPath = resolveAppPath("data/publish/sbdtoe-ontology.yaml");
|
|
856
|
+
let ontologyText;
|
|
857
|
+
try {
|
|
858
|
+
ontologyText = readFileSync(ontologyPath, "utf-8");
|
|
859
|
+
}
|
|
860
|
+
catch {
|
|
861
|
+
this.sendError(request.id, -32603, "Could not read SbD-ToE ontology YAML.");
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
this.sendResponse(request.id, {
|
|
865
|
+
contents: [{ uri, mimeType: "application/yaml", text: ontologyText }]
|
|
866
|
+
});
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
this.sendError(request.id, -32602, `Unknown resource URI: ${uri}`);
|
|
749
870
|
}
|
|
750
871
|
getStringArg(args, key) {
|
|
751
872
|
const value = args[key];
|
|
752
873
|
if (typeof value !== "string" || value.trim().length === 0) {
|
|
753
|
-
throw new Error(`
|
|
874
|
+
throw new Error(`The "${key}" argument is required.`);
|
|
754
875
|
}
|
|
755
876
|
return value;
|
|
756
877
|
}
|
|
@@ -768,7 +889,7 @@ class McpRuntime {
|
|
|
768
889
|
}
|
|
769
890
|
async requestSampling(systemPrompt, userPrompt) {
|
|
770
891
|
if (!this.supportsSampling()) {
|
|
771
|
-
throw new Error("
|
|
892
|
+
throw new Error("The current MCP client has not declared sampling support.");
|
|
772
893
|
}
|
|
773
894
|
const startedAt = Date.now();
|
|
774
895
|
await this.log("debug", {
|
|
@@ -903,15 +1024,13 @@ class McpRuntime {
|
|
|
903
1024
|
const debug = this.getOptionalBooleanArg(args, "debug");
|
|
904
1025
|
const topK = this.getOptionalIntegerArg(args, "topK");
|
|
905
1026
|
if (!this.supportsSampling()) {
|
|
906
|
-
//
|
|
907
|
-
const
|
|
908
|
-
const
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
results: bundle.retrieved
|
|
912
|
-
};
|
|
1027
|
+
// Graceful fallback: delegate to searchManualQuestion (same retrieval, formatted output)
|
|
1028
|
+
const fallback = await searchManualQuestion(question, debug, topK ?? 3);
|
|
1029
|
+
const fallbackText = "**Note: MCP sampling not available in this client — returning formatted retrieval results. " +
|
|
1030
|
+
"For a synthesised answer, use `search_sbd_toe_manual` directly.**\n\n" +
|
|
1031
|
+
fallback.text;
|
|
913
1032
|
this.sendResponse(request.id, {
|
|
914
|
-
content: [{ type: "text", text:
|
|
1033
|
+
content: [{ type: "text", text: fallbackText }]
|
|
915
1034
|
});
|
|
916
1035
|
await this.log("info", {
|
|
917
1036
|
event_type: "tool.call",
|
|
@@ -983,7 +1102,7 @@ class McpRuntime {
|
|
|
983
1102
|
return;
|
|
984
1103
|
}
|
|
985
1104
|
case "plan_sbd_toe_repo_governance": {
|
|
986
|
-
const result = handlePlanRepoGovernance(args);
|
|
1105
|
+
const result = handlePlanRepoGovernance(args, getSnapshotCache());
|
|
987
1106
|
this.sendResponse(request.id, {
|
|
988
1107
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
989
1108
|
});
|
|
@@ -996,8 +1115,8 @@ class McpRuntime {
|
|
|
996
1115
|
});
|
|
997
1116
|
return;
|
|
998
1117
|
}
|
|
999
|
-
case "
|
|
1000
|
-
const result =
|
|
1118
|
+
case "generate_sbd_toe_skill": {
|
|
1119
|
+
const result = handleGenerateSbdToeSkill();
|
|
1001
1120
|
this.sendResponse(request.id, {
|
|
1002
1121
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
1003
1122
|
});
|
|
@@ -1010,8 +1129,8 @@ class McpRuntime {
|
|
|
1010
1129
|
});
|
|
1011
1130
|
return;
|
|
1012
1131
|
}
|
|
1013
|
-
case "
|
|
1014
|
-
const result =
|
|
1132
|
+
case "map_sbd_toe_review_scope": {
|
|
1133
|
+
const result = handleMapSbdToeReviewScope(args);
|
|
1015
1134
|
this.sendResponse(request.id, {
|
|
1016
1135
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
1017
1136
|
});
|
|
@@ -1024,8 +1143,9 @@ class McpRuntime {
|
|
|
1024
1143
|
});
|
|
1025
1144
|
return;
|
|
1026
1145
|
}
|
|
1027
|
-
case "
|
|
1028
|
-
const
|
|
1146
|
+
case "map_sbd_toe_applicability": {
|
|
1147
|
+
const cache = getSnapshotCache();
|
|
1148
|
+
const result = handleMapSbdToeApplicability(args, cache);
|
|
1029
1149
|
this.sendResponse(request.id, {
|
|
1030
1150
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
1031
1151
|
});
|
|
@@ -1038,9 +1158,50 @@ class McpRuntime {
|
|
|
1038
1158
|
});
|
|
1039
1159
|
return;
|
|
1040
1160
|
}
|
|
1041
|
-
case "
|
|
1042
|
-
const
|
|
1043
|
-
|
|
1161
|
+
case "consult_security_requirements": {
|
|
1162
|
+
const result = handleConsultSecurityRequirements(args);
|
|
1163
|
+
this.sendResponse(request.id, {
|
|
1164
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
1165
|
+
});
|
|
1166
|
+
await this.log("info", {
|
|
1167
|
+
event_type: "tool.call",
|
|
1168
|
+
outcome: "succeeded",
|
|
1169
|
+
duration_ms: Date.now() - startedAt,
|
|
1170
|
+
...metadata,
|
|
1171
|
+
message: "Tool invocation completed"
|
|
1172
|
+
});
|
|
1173
|
+
return;
|
|
1174
|
+
}
|
|
1175
|
+
case "get_threat_landscape": {
|
|
1176
|
+
const result = handleGetThreatLandscape(args);
|
|
1177
|
+
this.sendResponse(request.id, {
|
|
1178
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
1179
|
+
});
|
|
1180
|
+
await this.log("info", {
|
|
1181
|
+
event_type: "tool.call",
|
|
1182
|
+
outcome: "succeeded",
|
|
1183
|
+
duration_ms: Date.now() - startedAt,
|
|
1184
|
+
...metadata,
|
|
1185
|
+
message: "Tool invocation completed"
|
|
1186
|
+
});
|
|
1187
|
+
return;
|
|
1188
|
+
}
|
|
1189
|
+
case "get_guide_by_role": {
|
|
1190
|
+
const result = handleGetGuideByRole(args);
|
|
1191
|
+
this.sendResponse(request.id, {
|
|
1192
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
1193
|
+
});
|
|
1194
|
+
await this.log("info", {
|
|
1195
|
+
event_type: "tool.call",
|
|
1196
|
+
outcome: "succeeded",
|
|
1197
|
+
duration_ms: Date.now() - startedAt,
|
|
1198
|
+
...metadata,
|
|
1199
|
+
message: "Tool invocation completed"
|
|
1200
|
+
});
|
|
1201
|
+
return;
|
|
1202
|
+
}
|
|
1203
|
+
case "resolve_entities": {
|
|
1204
|
+
const result = handleResolveEntities(args);
|
|
1044
1205
|
this.sendResponse(request.id, {
|
|
1045
1206
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
1046
1207
|
});
|
|
@@ -1062,11 +1223,11 @@ class McpRuntime {
|
|
|
1062
1223
|
error_code: -32602,
|
|
1063
1224
|
message: "Unknown tool requested"
|
|
1064
1225
|
});
|
|
1065
|
-
this.sendError(request.id, -32602, `
|
|
1226
|
+
this.sendError(request.id, -32602, `Unknown tool: ${name}`);
|
|
1066
1227
|
}
|
|
1067
1228
|
}
|
|
1068
1229
|
catch (error) {
|
|
1069
|
-
//
|
|
1230
|
+
// Errors with rpcError emit JSON-RPC error (e.g. -32602 for invalid input)
|
|
1070
1231
|
if (error instanceof Error &&
|
|
1071
1232
|
"rpcError" in error &&
|
|
1072
1233
|
error.rpcError !== null &&
|
|
@@ -1083,7 +1244,7 @@ class McpRuntime {
|
|
|
1083
1244
|
this.sendError(request.id, rpcError.code, rpcError.message, rpcError.data);
|
|
1084
1245
|
return;
|
|
1085
1246
|
}
|
|
1086
|
-
const message = error instanceof Error ? error.message : "
|
|
1247
|
+
const message = error instanceof Error ? error.message : "Unexpected error.";
|
|
1087
1248
|
await this.log("error", {
|
|
1088
1249
|
event_type: "tool.call",
|
|
1089
1250
|
outcome: "failed",
|