@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.
Files changed (38) hide show
  1. package/assets/agent-guide.md +22 -19
  2. package/data/publish/algolia_entities_records_enriched.json +25370 -2
  3. package/data/publish/canonical_controls.json +1239 -0
  4. package/data/publish/canonical_requirements_s7.json +1859 -0
  5. package/data/publish/canonical_roles_s5.json +138 -0
  6. package/data/publish/lifecycle_user_stories.json +6558 -0
  7. package/data/publish/mitigated_threats.json +6945 -0
  8. package/data/publish/practice_assignments.json +16266 -0
  9. package/data/publish/sbdtoe-ontology.yaml +696 -0
  10. package/dist/backend/semantic-index-gateway.js +1 -1
  11. package/dist/index.js +276 -115
  12. package/dist/index.js.map +1 -1
  13. package/dist/resources/sbd-toe-resources.js +6 -1
  14. package/dist/resources/sbd-toe-resources.js.map +1 -1
  15. package/dist/tools/consult-security-requirements.d.ts +38 -0
  16. package/dist/tools/consult-security-requirements.js +115 -0
  17. package/dist/tools/consult-security-requirements.js.map +1 -0
  18. package/dist/tools/get-guide-by-role.d.ts +38 -0
  19. package/dist/tools/get-guide-by-role.js +109 -0
  20. package/dist/tools/get-guide-by-role.js.map +1 -0
  21. package/dist/tools/get-threat-landscape.d.ts +44 -0
  22. package/dist/tools/get-threat-landscape.js +116 -0
  23. package/dist/tools/get-threat-landscape.js.map +1 -0
  24. package/dist/tools/map-review-scope.js +5 -0
  25. package/dist/tools/map-review-scope.js.map +1 -1
  26. package/dist/tools/ontology-loader.d.ts +104 -0
  27. package/dist/tools/ontology-loader.js +206 -0
  28. package/dist/tools/ontology-loader.js.map +1 -0
  29. package/dist/tools/plan-repo-governance.d.ts +25 -38
  30. package/dist/tools/plan-repo-governance.js +71 -498
  31. package/dist/tools/plan-repo-governance.js.map +1 -1
  32. package/dist/tools/resolve-entities.d.ts +26 -0
  33. package/dist/tools/resolve-entities.js +143 -0
  34. package/dist/tools/resolve-entities.js.map +1 -0
  35. package/package.json +4 -1
  36. package/dist/tools/generate-document.d.ts +0 -22
  37. package/dist/tools/generate-document.js +0 -392
  38. 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, retrievePublishedContext } from "./backend/semantic-index-gateway.js";
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: "Recupera contexto grounded do manual SbD-ToE a partir do snapshot semântico local embutido.",
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: "Pergunta em linguagem natural sobre o manual."
308
+ description: "Natural-language question about the manual."
306
309
  },
307
310
  debug: {
308
311
  type: "boolean",
309
- description: "Quando true, anexa o debug completo do retrieval."
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: "Número máximo de records usados como contexto."
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: "Faz retrieval do manual SbD-ToE e pede a resposta final ao modelo configurado no cliente via sampling MCP.",
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: "Pergunta em linguagem natural sobre o manual."
340
+ description: "Natural-language question about the manual."
335
341
  },
336
342
  debug: {
337
343
  type: "boolean",
338
- description: "Quando true, anexa o debug completo."
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: "Número máximo de records usados como contexto."
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: "Inspeciona retrieval, seleção de contexto e prompt final sem pedir resposta ao modelo do cliente.",
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: "Pergunta a usar na inspeção do retrieval."
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: "Número máximo de records selecionados para o prompt."
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: "Lista os capítulos do manual SbD-ToE com id, título e aplicabilidade.",
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: "Filtrar por nível de risco."
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: "Consulta entidades do manual por query, tipo, capítulo ou nível de risco.",
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: "Devolve resumo operacional de um capítulo: papel, fases, artefactos, intent_topics.",
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: "Plan SbD-ToE Repo Governance",
431
- description: "Dado o tipo de repositório, plataforma e nível de risco, devolve um plano de governança com controlos aplicáveis, checkpoints de baseline, checklist de evidências e recomendações de plataforma.",
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: "Nível de risco do projecto."
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: ["type", "riskLevel"],
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: "Dado um conjunto de ficheiros alterados, mapeia quais knowledge bundles SbD-ToE devem ser revistos, com reasoning explícito por path.",
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: "Lista de paths relativos ao raiz do repositório."
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: "Nível de risco do projecto."
489
+ description: "Project risk level."
528
490
  },
529
491
  projectContext: {
530
492
  type: "object",
531
- description: "Contexto adicional do projecto (opcional).",
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: "Resumo do diff (truncado a 500 chars)."
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: "Mapeia capítulos/controlos activos, condicionais e excluídos para um nível de risco L1/L2/L3. Suporta contexto de projecto para activar bundles relevantes.",
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: "Tecnologias usadas no projecto."
531
+ description: "Technologies used in the project."
570
532
  },
571
533
  hasPersonalData: {
572
534
  type: "boolean",
573
- description: "O projecto processa dados pessoais?"
535
+ description: "Does the project process personal data?"
574
536
  },
575
537
  isPublicFacing: {
576
538
  type: "boolean",
577
- description: "O projecto tem exposição pública?"
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: "Papel do utilizador no projecto."
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: "Prompt MCP para orientar o chat do VS Code a responder perguntas sobre o manual SbD-ToE com grounding.",
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: "Pergunta sobre o manual SbD-ToE.",
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: "Prompt MCP para configurar um agente com o contexto e regras do manual SbD-ToE para um nível de risco.",
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: "Nível de risco do projecto: L1, L2 ou L3.",
715
+ description: "Project risk level: L1, L2 or L3.",
619
716
  required: true
620
717
  },
621
718
  {
622
719
  name: "projectRole",
623
- description: "Papel ou descrição do projecto (opcional).",
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 a ferramenta `search_sbd_toe_manual` antes de responder.\n" +
736
+ "Use the `search_sbd_toe_manual` tool before answering.\n" +
640
737
  `Question: ${question}`;
641
738
  this.sendResponse(request.id, {
642
- description: "Prompt grounded para perguntas sobre o manual SbD-ToE.",
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, 'O argumento "riskLevel" é obrigatório e deve ser L1, L2 ou L3.');
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 para configurar um agente com o contexto SbD-ToE.",
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, `Prompt desconhecida: ${name}`);
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 inválido: "${riskLevel}". Valores permitidos: L1, L2, L3.`);
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, "Não foi possível ler o índice compacto SbD-ToE.");
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
- this.sendError(request.id, -32602, `URI de resource desconhecida: ${uri}`);
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(`O argumento "${key}" é obrigatório.`);
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("O cliente MCP atual não declarou suporte para sampling.");
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
- // Fallback gracioso: devolver top-3 documentos sem sampling
907
- const bundle = await retrievePublishedContext(question, 3);
908
- const fallbackResult = {
909
- sampling_unavailable: true,
910
- note: "Sampling não disponível neste cliente. Apresentando os 3 documentos mais relevantes como contexto.",
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: JSON.stringify(fallbackResult, null, 2) }]
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 "generate_document": {
1000
- const result = handleGenerateDocument(args);
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 "generate_sbd_toe_skill": {
1014
- const result = handleGenerateSbdToeSkill();
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 "map_sbd_toe_review_scope": {
1028
- const result = handleMapSbdToeReviewScope(args);
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 "map_sbd_toe_applicability": {
1042
- const cache = getSnapshotCache();
1043
- const result = handleMapSbdToeApplicability(args, cache);
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, `Tool desconhecida: ${name}`);
1226
+ this.sendError(request.id, -32602, `Unknown tool: ${name}`);
1066
1227
  }
1067
1228
  }
1068
1229
  catch (error) {
1069
- // Erros com rpcError emitem JSON-RPC error (ex: -32602 para input inválido)
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 : "Erro inesperado.";
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",