Search ISM controls
search_controlsSearch across ISM control labels, titles, statements, and group paths. Use filters for applicability, group, or label prefix.
Instructions
Full-text search across ISM control labels, titles, statements, and group paths. Combine with applicability/group/labelPrefix filters.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | ||
| version | No | ||
| applicability | No | Applicability marking: NC=Non-classified, OS=OFFICIAL: Sensitive, P=PROTECTED, S=SECRET, TS=TOP SECRET. | |
| group | No | ||
| labelPrefix | No | ||
| limit | No | ||
| offset | No | ||
| includeStatement | No | Include the control statement in each result. |
Implementation Reference
- src/index.ts:248-293 (registration)Registration of the 'search_controls' tool on the MCP server via server.registerTool(). Defines the tool name, title, description, input schema (query, version, applicability, group, labelPrefix, limit, offset, includeStatement), and the handler callback.
server.registerTool( "search_controls", { title: "Search ISM controls", description: "Full-text search across ISM control labels, titles, statements, and group paths. Combine with applicability/group/labelPrefix filters.", inputSchema: { query: z.string().min(1), version: z.string().optional(), applicability: ApplicabilitySchema.optional(), group: z.string().optional(), labelPrefix: z.string().optional(), limit: z.number().int().min(1).max(500).optional(), offset: z.number().int().min(0).optional(), includeStatement: z .boolean() .optional() .describe("Include the control statement in each result."), }, }, async (args) => { const v = await resolveVersion(args.version); const flat = await loadFlat(v.tag); const result = searchControls(flat, { query: args.query, applicability: args.applicability as Applicability | undefined, group: args.group, labelPrefix: args.labelPrefix, limit: args.limit, offset: args.offset, }); const items = result.items.map((c) => args.includeStatement ? { ...compactControl(c), statement: c.statement } : compactControl(c), ); return txt({ version: v.id, query: args.query, total: result.total, returned: items.length, offset: args.offset ?? 0, items, }); }, ); - src/store.ts:110-139 (handler)The core searchControls() function that performs full-text, applicability, group, and labelPrefix filtering on the flat control list. Accepts FlatControl[] and SearchOptions, returns SearchResult with total count and paginated items.
export function searchControls( controls: FlatControl[], opts: SearchOptions, ): SearchResult { const q = opts.query?.toLowerCase().trim(); const groupQ = opts.group?.toLowerCase().trim(); const labelPrefix = opts.labelPrefix?.toUpperCase().trim(); const filtered = controls.filter((c) => { if (opts.applicability && !c.applicability.includes(opts.applicability)) return false; if (groupQ && !c.groupPath.some((g) => g.toLowerCase().includes(groupQ))) return false; if (labelPrefix && !c.label.toUpperCase().startsWith(labelPrefix)) return false; if (q) { const hay = `${c.label} ${c.title} ${c.statement} ${c.groupPath.join(" ")}`.toLowerCase(); if (!hay.includes(q)) return false; } return true; }); const offset = Math.max(0, opts.offset ?? 0); const limit = Math.max(1, Math.min(opts.limit ?? 50, 500)); return { total: filtered.length, items: filtered.slice(offset, offset + limit), }; } - src/store.ts:96-103 (schema)Type definitions for the search function: SearchOptions (query, applicability, group, labelPrefix, limit, offset) and SearchResult (total, items).
export interface SearchOptions { query?: string; applicability?: Applicability; group?: string; // case-insensitive substring match against any element of groupPath labelPrefix?: string; // e.g. "GOV", "AC" limit?: number; offset?: number; } - src/store.ts:74-82 (helper)The compactControl helper function used by the handler to produce lightweight control representations (id, label, title, section, applicability) for the search results.
} }; walk(catalog.groups, []); for (const c of catalog.controls ?? []) { out.push(toFlat(c, [])); } return out; } - src/index.ts:19-33 (helper)Import statement for searchControls from ./store.js, which is how the handler file references the core logic.
import { controlToMarkdown, diffControls, flattenCatalog, searchControls, summarizeGroups, type FlatControl, } from "./store.js"; import { APPLICABILITY_LABELS, PROFILE_NAMES, type Applicability, type OscalCatalogDoc, type ProfileName, } from "./types.js";