@get-technology-inc/jamf-docs-mcp-server 5.8.0 → 5.10.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/README.md +99 -0
  2. package/dist/core/apps/generated/app-html.d.ts +2 -2
  3. package/dist/core/apps/generated/app-html.d.ts.map +1 -1
  4. package/dist/core/apps/generated/app-html.js +2 -2
  5. package/dist/core/apps/generated/app-html.js.map +1 -1
  6. package/dist/core/apps/index.d.ts +1 -1
  7. package/dist/core/apps/index.d.ts.map +1 -1
  8. package/dist/core/apps/index.js +35 -0
  9. package/dist/core/apps/index.js.map +1 -1
  10. package/dist/core/schemas/output.d.ts +5 -0
  11. package/dist/core/schemas/output.d.ts.map +1 -1
  12. package/dist/core/schemas/output.js +15 -0
  13. package/dist/core/schemas/output.js.map +1 -1
  14. package/dist/core/services/article-service.d.ts.map +1 -1
  15. package/dist/core/services/article-service.js +21 -1
  16. package/dist/core/services/article-service.js.map +1 -1
  17. package/dist/core/services/cache-key.d.ts +6 -1
  18. package/dist/core/services/cache-key.d.ts.map +1 -1
  19. package/dist/core/services/cache-key.js +2 -1
  20. package/dist/core/services/cache-key.js.map +1 -1
  21. package/dist/core/services/content-parser.d.ts.map +1 -1
  22. package/dist/core/services/content-parser.js +74 -0
  23. package/dist/core/services/content-parser.js.map +1 -1
  24. package/dist/core/services/ft-internal-link.d.ts +22 -0
  25. package/dist/core/services/ft-internal-link.d.ts.map +1 -1
  26. package/dist/core/services/ft-internal-link.js +132 -4
  27. package/dist/core/services/ft-internal-link.js.map +1 -1
  28. package/dist/core/services/static-search-service.d.ts +40 -0
  29. package/dist/core/services/static-search-service.d.ts.map +1 -0
  30. package/dist/core/services/static-search-service.js +144 -0
  31. package/dist/core/services/static-search-service.js.map +1 -0
  32. package/dist/core/tools/glossary-lookup.d.ts.map +1 -1
  33. package/dist/core/tools/glossary-lookup.js +8 -0
  34. package/dist/core/tools/glossary-lookup.js.map +1 -1
  35. package/dist/core/tools/search.d.ts.map +1 -1
  36. package/dist/core/tools/search.js +79 -9
  37. package/dist/core/tools/search.js.map +1 -1
  38. package/package.json +9 -7
@@ -73,8 +73,39 @@ export function collectInternalLinkMapIds(html) {
73
73
  }
74
74
  return [...mapIds];
75
75
  }
76
- function indexTocNodes(nodes, into, ancestors) {
76
+ function indexTocNodes(nodes, into, ancestors, parent) {
77
77
  for (const node of nodes) {
78
+ // Only a node a reader could actually open joins the navigation tree: it
79
+ // needs an id to key on, a contentId to be addressed by, a URL to go to and
80
+ // a title to be labelled with. A node missing any of those is a grouping
81
+ // heading, and putting one in the tree would mean publishing a link to
82
+ // nothing and counting it among a page's neighbours.
83
+ //
84
+ // Note this is a *stricter* test than the ancestry index below applies. A
85
+ // breadcrumb rung is text, so an unopenable one is harmless and Jamf's own
86
+ // grouping titles belong there; a navigation entry is a destination, and an
87
+ // unopenable one is a dead end. Different requirement, different rule.
88
+ //
89
+ // Measured against the live Jamf Pro map: 0 of 792 nodes are missing any of
90
+ // the four, so in practice nothing takes this branch. It is here because
91
+ // `FtTocNode` is a bare cast over `response.json()` with no validation
92
+ // behind it, and because a future map that does group its topics should
93
+ // lose the grouping, not the topics under it.
94
+ const openable = node.tocId !== '' && node.contentId !== '' && node.prettyUrl !== '' && (node.title ?? '') !== '';
95
+ if (openable) {
96
+ into.nodeByTocId[node.tocId] = {
97
+ title: node.title ?? '',
98
+ url: buildDisplayUrl(node.prettyUrl),
99
+ };
100
+ if (parent === undefined) {
101
+ into.rootTocIds.push(node.tocId);
102
+ }
103
+ else {
104
+ into.parentTocId[node.tocId] = parent;
105
+ (into.childTocIds[parent] ??= []).push(node.tocId);
106
+ }
107
+ into.tocIdByContentId[node.contentId] = node.tocId;
108
+ }
78
109
  // Both fields are declared required, but `FtTocNode` is a bare cast over
79
110
  // `response.json()` with no runtime validation behind it — the same reason
80
111
  // `title` and `children` are optional on that type. An empty value here
@@ -94,16 +125,27 @@ function indexTocNodes(nodes, into, ancestors) {
94
125
  const title = node.title ?? '';
95
126
  const childAncestors = title === '' ? ancestors : [...ancestors, title];
96
127
  // Absent `children` means a leaf, the same as an empty list.
97
- indexTocNodes(node.children ?? [], into, childAncestors);
128
+ // A node that did not join the tree passes its own parent down, so its
129
+ // children attach one rung higher rather than being orphaned under an id
130
+ // nothing can reach.
131
+ indexTocNodes(node.children ?? [], into, childAncestors, openable ? node.tocId : parent);
98
132
  }
99
133
  }
100
134
  async function loadMapTocIndex(cache, mapId, ttl) {
101
- const key = cacheKey('ft-tocindex-v2', { mapId });
135
+ const key = cacheKey('ft-tocindex-v3', { mapId });
102
136
  const cached = await cache.get(key);
103
137
  if (cached !== null) {
104
138
  return cached;
105
139
  }
106
- const index = { urlByTocId: {}, ancestorsByContentId: {} };
140
+ const index = {
141
+ urlByTocId: {},
142
+ ancestorsByContentId: {},
143
+ nodeByTocId: {},
144
+ childTocIds: {},
145
+ parentTocId: {},
146
+ tocIdByContentId: {},
147
+ rootTocIds: [],
148
+ };
107
149
  indexTocNodes(await fetchMapToc(mapId), index, []);
108
150
  await cache.set(key, index, ttl);
109
151
  return index;
@@ -135,6 +177,92 @@ export async function buildInternalLinkResolver(options) {
135
177
  }));
136
178
  return (mapId, tocId) => indexes.get(mapId)?.urlByTocId[tocId];
137
179
  }
180
+ /**
181
+ * How many neighbours a navigation list carries.
182
+ *
183
+ * The counts alongside them are the totals, so a capped list still says how
184
+ * much it is not showing. The cap exists because the sibling set of a
185
+ * top-level page is every top-level page — for Jamf Pro that is twenty-odd
186
+ * links, on the structured channel, on every article fetch.
187
+ */
188
+ const MAX_NAV_LINKS = 8;
189
+ /**
190
+ * Where a topic sits among its neighbours in its map.
191
+ *
192
+ * The complement of {@link fetchTopicAncestors}: that answers "what is above
193
+ * this page", this answers "what is beside and below it". Both read the same
194
+ * cached index, so an article that already resolved a breadcrumb pays nothing
195
+ * for this.
196
+ *
197
+ * It exists because the Fluid Topics API serves one topic per call while the
198
+ * website concatenates a topic and its children into a single page. Nine of
199
+ * the nine `<h2>` sections on the rendered "Computer Configuration Profiles"
200
+ * page are separate topics in the map — measured, not assumed. A reader who
201
+ * opens that page in a viewer gets the parent's introduction and no route to
202
+ * the nine procedures underneath it unless something publishes the tree, and
203
+ * the tree is only in the TOC.
204
+ *
205
+ * Returns `undefined` rather than an empty shape when the topic is not in the
206
+ * index: absent means "this map does not place it", which is different from
207
+ * "it has no neighbours".
208
+ */
209
+ export async function fetchTopicNavigation(options) {
210
+ const { cache, mapId, contentId, ttl, logger } = options;
211
+ let index;
212
+ try {
213
+ index = await loadMapTocIndex(cache, mapId, ttl);
214
+ }
215
+ catch (error) {
216
+ const reason = error instanceof Error ? error.message : String(error);
217
+ logger?.warning(`ft-internal-link: TOC index unavailable for map ${mapId},` +
218
+ ` this article will have no navigation: ${reason}`);
219
+ return undefined;
220
+ }
221
+ const tocId = index.tocIdByContentId[contentId];
222
+ if (tocId === undefined) {
223
+ return undefined;
224
+ }
225
+ const self = index.nodeByTocId[tocId];
226
+ if (self === undefined) {
227
+ return undefined;
228
+ }
229
+ // Constructed field by field, not returned by reference.
230
+ //
231
+ // The index is a cache entry, so what comes back is whatever shape was
232
+ // written when it was stored — including fields a later version of this file
233
+ // dropped. `NavigationLinkSchema` is strict, so one stale extra key fails
234
+ // output validation for the whole tool and the article does not render at
235
+ // all. Naming the two fields makes the published shape independent of how
236
+ // the index happens to be stored, which is the property that actually needs
237
+ // to hold; the namespace version protects against a *missing* field, and
238
+ // cannot protect against an extra one.
239
+ const link = (id) => {
240
+ const node = index.nodeByTocId[id];
241
+ return node === undefined ? undefined : { title: node.title, url: node.url };
242
+ };
243
+ const parentId = index.parentTocId[tocId];
244
+ const parent = parentId !== undefined ? link(parentId) : undefined;
245
+ // A root topic's siblings are the other roots — which is why `rootTocIds` is
246
+ // indexed at all. Without it every top-level page in a product reported no
247
+ // neighbours, which is the opposite of true.
248
+ const siblingIds = (parentId !== undefined ? index.childTocIds[parentId] : index.rootTocIds) ?? [];
249
+ const siblings = siblingIds.filter((id) => id !== tocId).map(link).filter(isLink);
250
+ const children = (index.childTocIds[tocId] ?? []).map(link).filter(isLink);
251
+ return {
252
+ self: { title: self.title, url: self.url },
253
+ ...(parent !== undefined ? { parent } : {}),
254
+ siblings: siblings.slice(0, MAX_NAV_LINKS),
255
+ children: children.slice(0, MAX_NAV_LINKS),
256
+ // The totals, not the array lengths. A truncated list that does not say so
257
+ // is one a reader will treat as exhaustive.
258
+ siblingCount: siblings.length,
259
+ childCount: children.length,
260
+ };
261
+ }
262
+ /** Narrows away an id that is somehow not in the node table. */
263
+ function isLink(value) {
264
+ return value !== undefined;
265
+ }
138
266
  export async function fetchTopicAncestors(options) {
139
267
  const { cache, mapId, contentId, ttl, logger } = options;
140
268
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"ft-internal-link.js","sourceRoot":"","sources":["../../../src/core/services/ft-internal-link.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ft-internal-link.js","sourceRoot":"","sources":["../../../src/core/services/ft-internal-link.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Searching the non-Fluid-Topics sources.
3
+ *
4
+ * These results are kept in their own block rather than merged into the
5
+ * Fluid Topics ranking. `SearchResult` has no score field and Fluid Topics
6
+ * does not return one — `search.ts` says so where it builds a result — so
7
+ * there is nothing on either side to fuse two orderings on. Inventing a
8
+ * comparable number would produce an interleaving that looks authoritative
9
+ * and is not. A labelled second block says exactly what it is: other places
10
+ * this query matched.
11
+ *
12
+ * The index is titles, recovered from each source's sitemap. That is one
13
+ * request per source for 808 support articles and 98 concepts pages, against
14
+ * ~900 page fetches to read the real headings — and a title is what a
15
+ * ranked pointer needs.
16
+ */
17
+ import { type StaticDocSource } from '../constants/sources.js';
18
+ import type { ServerContext } from '../types/context.js';
19
+ /** One page of a static source, as the index holds it. */
20
+ export interface StaticSearchEntry {
21
+ title: string;
22
+ url: string;
23
+ /** Display name of the source it belongs to. */
24
+ source: string;
25
+ }
26
+ /** A hit, with the source that produced it. */
27
+ export interface StaticSearchHit extends StaticSearchEntry {
28
+ /** Fuse's distance, 0 = exact. Comparable within this block only. */
29
+ score: number;
30
+ }
31
+ /** Build one source's title index for a locale. */
32
+ export declare function loadStaticIndex(ctx: ServerContext, source: StaticDocSource, locale: string): Promise<StaticSearchEntry[]>;
33
+ /**
34
+ * Search every static source that publishes the requested locale.
35
+ *
36
+ * Best-effort per source: one unreachable sitemap costs its own hits, not
37
+ * the block, and never the Fluid Topics results this runs alongside.
38
+ */
39
+ export declare function searchStaticSources(ctx: ServerContext, query: string, locale: string, limit?: number): Promise<StaticSearchHit[]>;
40
+ //# sourceMappingURL=static-search-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-search-service.d.ts","sourceRoot":"","sources":["../../../src/core/services/static-search-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH,OAAO,EAAsB,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAEnF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,0DAA0D;AAC1D,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,+CAA+C;AAC/C,MAAM,WAAW,eAAgB,SAAQ,iBAAiB;IACxD,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;CACf;AAsCD,mDAAmD;AACnD,wBAAsB,eAAe,CACnC,GAAG,EAAE,aAAa,EAClB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAc9B;AAyCD;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,aAAa,EAClB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,KAAK,SAAI,GACR,OAAO,CAAC,eAAe,EAAE,CAAC,CAqB5B"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Searching the non-Fluid-Topics sources.
3
+ *
4
+ * These results are kept in their own block rather than merged into the
5
+ * Fluid Topics ranking. `SearchResult` has no score field and Fluid Topics
6
+ * does not return one — `search.ts` says so where it builds a result — so
7
+ * there is nothing on either side to fuse two orderings on. Inventing a
8
+ * comparable number would produce an interleaving that looks authoritative
9
+ * and is not. A labelled second block says exactly what it is: other places
10
+ * this query matched.
11
+ *
12
+ * The index is titles, recovered from each source's sitemap. That is one
13
+ * request per source for 808 support articles and 98 concepts pages, against
14
+ * ~900 page fetches to read the real headings — and a title is what a
15
+ * ranked pointer needs.
16
+ */
17
+ import Fuse from 'fuse.js';
18
+ import { httpGetText } from '../http-client.js';
19
+ import { cacheKey } from './cache-key.js';
20
+ import { titleFromSlug } from './sitemap-service.js';
21
+ import { STATIC_DOC_SOURCES } from '../constants/sources.js';
22
+ /**
23
+ * Path segments that are not articles.
24
+ *
25
+ * `browse` is in concepts.jamf.com's sitemap (ten entries, one per locale)
26
+ * and is a JS-only shell — thirteen characters once tags are stripped. The
27
+ * integration notes claimed these were absent from the sitemap and therefore
28
+ * excluded for free; they are not.
29
+ */
30
+ const NON_ARTICLE_SEGMENTS = new Set(['browse', 'about', 'ecosystem', 'collections']);
31
+ /**
32
+ * Turn a sitemap path into an index entry.
33
+ *
34
+ * Intercom article slugs are prefixed with the numeric id
35
+ * (`10631322-get-started-with-jamf-now`), which is stripped before casing —
36
+ * leaving it in produces "10631322 Get Started With Jamf Now".
37
+ */
38
+ function entryFor(source, url, locale) {
39
+ let segments;
40
+ try {
41
+ segments = new URL(url).pathname.split('/').filter(Boolean);
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ const [entryLocale, section, ...rest] = segments;
47
+ if (entryLocale !== locale) {
48
+ return null;
49
+ }
50
+ if (section === undefined || NON_ARTICLE_SEGMENTS.has(section)) {
51
+ return null;
52
+ }
53
+ // A section index page is a container, not an article.
54
+ if (rest.length === 0) {
55
+ return null;
56
+ }
57
+ const slug = (rest[rest.length - 1] ?? '').replace(/^\d+-/, '');
58
+ if (slug === '') {
59
+ return null;
60
+ }
61
+ return { title: titleFromSlug(slug), url, source: source.name };
62
+ }
63
+ /** Build one source's title index for a locale. */
64
+ export async function loadStaticIndex(ctx, source, locale) {
65
+ const key = cacheKey('static-search-index', { source: source.id, locale });
66
+ const cached = await ctx.cache.get(key);
67
+ if (cached !== null) {
68
+ return cached;
69
+ }
70
+ const xml = await httpGetText(`${source.baseUrl}/sitemap.xml`);
71
+ const entries = [];
72
+ for (const match of xml.matchAll(/<loc>\s*([^<\s]+)\s*<\/loc>/g)) {
73
+ const entry = entryFor(source, match[1] ?? '', locale);
74
+ if (entry !== null) {
75
+ entries.push(entry);
76
+ }
77
+ }
78
+ await ctx.cache.set(key, entries, ctx.config.cacheTtl.products);
79
+ return entries;
80
+ }
81
+ // ─── Fuse index, per server ─────────────────────────────────────
82
+ /**
83
+ * Per-server Fuse indexes, keyed `sourceId:locale`.
84
+ *
85
+ * Same shape as the glossary's: a WeakMap on the CacheProvider so each
86
+ * ServerContext gets its own and it is collected with the context, rather
87
+ * than a module-level map that would outlive a request in a runtime where
88
+ * module scope persists.
89
+ */
90
+ const indexByServer = new WeakMap();
91
+ const FUSE_OPTIONS = {
92
+ keys: [{ name: 'title', weight: 1 }],
93
+ threshold: 0.35,
94
+ includeScore: true,
95
+ ignoreLocation: true,
96
+ minMatchCharLength: 3,
97
+ };
98
+ function fuseFor(ctx, key, entries) {
99
+ let perServer = indexByServer.get(ctx.cache);
100
+ if (perServer === undefined) {
101
+ perServer = new Map();
102
+ indexByServer.set(ctx.cache, perServer);
103
+ }
104
+ const existing = perServer.get(key);
105
+ // Rebuild when the underlying array is a different one — the cache TTL
106
+ // expiring is what replaces it.
107
+ if (existing?.source === entries) {
108
+ return existing.fuse;
109
+ }
110
+ const fuse = new Fuse(entries, FUSE_OPTIONS);
111
+ perServer.set(key, { source: entries, fuse });
112
+ return fuse;
113
+ }
114
+ /**
115
+ * Search every static source that publishes the requested locale.
116
+ *
117
+ * Best-effort per source: one unreachable sitemap costs its own hits, not
118
+ * the block, and never the Fluid Topics results this runs alongside.
119
+ */
120
+ export async function searchStaticSources(ctx, query, locale, limit = 3) {
121
+ const log = ctx.logger.createLogger('static-search');
122
+ const hits = [];
123
+ for (const source of Object.values(STATIC_DOC_SOURCES)) {
124
+ const sourceLocale = source.locales[locale];
125
+ if (sourceLocale === undefined) {
126
+ continue;
127
+ }
128
+ try {
129
+ const entries = await loadStaticIndex(ctx, source, sourceLocale);
130
+ if (entries.length === 0) {
131
+ continue;
132
+ }
133
+ const results = fuseFor(ctx, `${source.id}:${sourceLocale}`, entries).search(query, { limit });
134
+ for (const result of results) {
135
+ hits.push({ ...result.item, score: result.score ?? 1 });
136
+ }
137
+ }
138
+ catch (error) {
139
+ log.warning(`Could not search ${source.name}: ${String(error)}`);
140
+ }
141
+ }
142
+ return hits;
143
+ }
144
+ //# sourceMappingURL=static-search-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-search-service.js","sourceRoot":"","sources":["../../../src/core/services/static-search-service.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"glossary-lookup.d.ts","sourceRoot":"","sources":["../../../src/core/tools/glossary-lookup.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAyFzD,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI,CAsItF"}
1
+ {"version":3,"file":"glossary-lookup.d.ts","sourceRoot":"","sources":["../../../src/core/tools/glossary-lookup.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AA0FzD,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI,CA6ItF"}
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { GlossaryLookupInputSchema } from '../schemas/index.js';
6
6
  import { GlossaryLookupOutputSchema } from '../schemas/output.js';
7
+ import { appToolMeta } from '../apps/index.js';
7
8
  import { ResponseFormat, OutputMode, JAMF_PRODUCTS, TOKEN_CONFIG } from '../constants.js';
8
9
  import { lookupGlossaryTerm } from '../services/glossary.js';
9
10
  import { sanitizeMarkdownText, sanitizeMarkdownUrl, getSafeErrorMessage } from '../utils/sanitize.js';
@@ -85,6 +86,13 @@ export function registerGlossaryLookupTool(server, ctx) {
85
86
  description: TOOL_DESCRIPTION,
86
87
  inputSchema: GlossaryLookupInputSchema,
87
88
  outputSchema: GlossaryLookupOutputSchema,
89
+ // Hosts supporting the MCP Apps extension render this result in the
90
+ // shared viewer; others ignore the metadata and get the markdown. The
91
+ // glossary view reuses the search view's components wholesale — a term
92
+ // is a title, a definition is a snippet — so it was the cheapest way to
93
+ // check that the component set generalises past the three views it was
94
+ // drawn against.
95
+ _meta: appToolMeta(),
88
96
  annotations: {
89
97
  readOnlyHint: true,
90
98
  destructiveHint: false,
@@ -1 +1 @@
1
- {"version":3,"file":"glossary-lookup.js","sourceRoot":"","sources":["../../../src/core/tools/glossary-lookup.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"glossary-lookup.js","sourceRoot":"","sources":["../../../src/core/tools/glossary-lookup.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/core/tools/search.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIzD,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAuB,MAAM,iBAAiB,CAAC;AAkM/E;;;;;;;;GAQG;AACH,UAAU,aAAa;IACrB,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,8BAA8B;IAC9B,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,4BAA4B;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,mDAAmD;IACnD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,eAAe,EAAE,SAAS,aAAa,EAWnD,CAAC;AAkBF,eAAO,MAAM,gBAAgB,QAqDX,CAAC;AA2KnB,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI,CAwK9E"}
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/core/tools/search.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIzD,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAuB,MAAM,iBAAiB,CAAC;AAsM/E;;;;;;;;GAQG;AACH,UAAU,aAAa;IACrB,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,8BAA8B;IAC9B,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,4BAA4B;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,mDAAmD;IACnD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,eAAe,EAAE,SAAS,aAAa,EAWnD,CAAC;AAkBF,eAAO,MAAM,gBAAgB,QAqDX,CAAC;AAuOnB,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,aAAa,GAAG,IAAI,CA0L9E"}
@@ -10,6 +10,7 @@ import { searchDocumentation } from '../services/search-service.js';
10
10
  import { generateSearchSuggestions, formatSearchSuggestions } from '../services/search-suggestions.js';
11
11
  import { sanitizeMarkdownText, sanitizeMarkdownUrl, getSafeErrorMessage } from '../utils/sanitize.js';
12
12
  import { reportProgress } from '../utils/progress.js';
13
+ import { searchStaticSources, } from '../services/static-search-service.js';
13
14
  function formatFiltersLine(filters) {
14
15
  const parts = [];
15
16
  if (filters.product !== undefined) {
@@ -249,6 +250,33 @@ function activeSearchFilters(params) {
249
250
  };
250
251
  return Object.keys(filters).length > 0 ? filters : undefined;
251
252
  }
253
+ /**
254
+ * Render the other-source hits as a labelled trailer.
255
+ *
256
+ * Below the results and clearly separated, because these come from a
257
+ * different ranking that shares no scale with the one above — and because
258
+ * two of the three sources are not product documentation.
259
+ */
260
+ function renderOtherSources(hits) {
261
+ if (hits.length === 0) {
262
+ return '';
263
+ }
264
+ const bySource = new Map();
265
+ for (const hit of hits) {
266
+ bySource.set(hit.source, [...(bySource.get(hit.source) ?? []), hit]);
267
+ }
268
+ let out = '\n---\n\n## Also found outside the product documentation\n\n';
269
+ for (const [source, sourceHits] of bySource) {
270
+ out += `**${source}**\n\n`;
271
+ for (const hit of sourceHits) {
272
+ out += `- [${sanitizeMarkdownText(hit.title)}](${sanitizeMarkdownUrl(hit.url)})\n`;
273
+ }
274
+ out += '\n';
275
+ }
276
+ out += '*Matched on title, ranked separately from the results above — '
277
+ + 'Fluid Topics returns no score to rank them against.*\n';
278
+ return out;
279
+ }
252
280
  function buildSearchStructuredContent(query, results, pagination, extras) {
253
281
  return {
254
282
  query,
@@ -284,7 +312,17 @@ function buildSearchStructuredContent(query, results, pagination, extras) {
284
312
  ...(extras?.filterRelaxation !== undefined ? { filterRelaxation: extras.filterRelaxation } : {}),
285
313
  ...(extras?.versionNote !== undefined ? { versionNote: extras.versionNote } : {}),
286
314
  ...(extras?.paginationNote !== undefined ? { paginationNote: extras.paginationNote } : {}),
287
- ...(extras?.truncatedContent !== undefined ? { truncatedContent: extras.truncatedContent } : {})
315
+ ...(extras?.truncatedContent !== undefined ? { truncatedContent: extras.truncatedContent } : {}),
316
+ // Omitted rather than emitted empty: "nothing matched elsewhere" and
317
+ // "the other sources were not reachable" are different answers, and an
318
+ // empty array would claim the first.
319
+ ...(extras?.otherSources !== undefined && extras.otherSources.length > 0
320
+ ? {
321
+ otherSources: extras.otherSources.map(hit => ({
322
+ title: hit.title, url: hit.url, source: hit.source,
323
+ })),
324
+ }
325
+ : {})
288
326
  };
289
327
  }
290
328
  /**
@@ -292,18 +330,37 @@ function buildSearchStructuredContent(query, results, pagination, extras) {
292
330
  */
293
331
  function buildNoResultsResponse(query, hasProductFilter, hasTopicFilter, locale) {
294
332
  const suggestions = generateSearchSuggestions(query, hasProductFilter, hasTopicFilter);
333
+ /**
334
+ * Queries a client can run, and nothing else.
335
+ *
336
+ * `generateSearchSuggestions` already separates what is runnable
337
+ * (`simplifiedQuery`, `alternativeKeywords`) from what is advice (`tips`,
338
+ * and the locale note below), and this array used to flatten all of it
339
+ * together. A structured client cannot tell the two apart afterwards, so
340
+ * the MCP App rendered "Try removing filters to broaden your search" as a
341
+ * clickable search and, when clicked, searched Jamf for that sentence. The
342
+ * `Try: ` prefix had the same fault one step earlier: it made the one
343
+ * genuinely runnable entry un-runnable, because the prefix went into the
344
+ * query too.
345
+ *
346
+ * Nothing is lost by dropping the prose here. The advice reaches the model
347
+ * through `formatSearchSuggestions` on the text channel below, which is the
348
+ * channel prose belongs on; `structuredContent.suggestions` is read only by
349
+ * clients that are going to *do* something with each entry.
350
+ */
295
351
  const suggestionTexts = [
296
- ...(locale !== undefined && locale !== DEFAULT_LOCALE
297
- ? [`Not all documentation is available in "${locale}". Try searching with language: "${DEFAULT_LOCALE}".`]
298
- : []),
299
- ...(suggestions.simplifiedQuery !== null ? [`Try: ${suggestions.simplifiedQuery}`] : []),
300
- ...suggestions.alternativeKeywords,
301
- ...suggestions.tips
352
+ ...(suggestions.simplifiedQuery !== null ? [suggestions.simplifiedQuery] : []),
353
+ ...suggestions.alternativeKeywords
302
354
  ];
355
+ // The locale caveat is advice, so it rides the text channel with the rest of
356
+ // the advice rather than being mixed into the runnable list above.
357
+ const localeNote = locale !== undefined && locale !== DEFAULT_LOCALE
358
+ ? `\n\nNot all documentation is available in "${locale}". Try searching with language: "${DEFAULT_LOCALE}".`
359
+ : '';
303
360
  return {
304
361
  content: [{
305
362
  type: 'text',
306
- text: formatSearchSuggestions(query, suggestions)
363
+ text: `${formatSearchSuggestions(query, suggestions)}${localeNote}`
307
364
  }],
308
365
  structuredContent: {
309
366
  query,
@@ -403,6 +460,18 @@ export function registerSearchTool(server, ctx) {
403
460
  maxTokens: params.maxTokens ?? TOKEN_CONFIG.DEFAULT_MAX_TOKENS
404
461
  });
405
462
  await reportProgress(extra, { progress: 1, total: 3, message: 'Processing results...' });
463
+ // The non-Fluid-Topics sources, as their own block.
464
+ //
465
+ // Deliberately not merged into the ranking above. Fluid Topics
466
+ // returns no score — see the relevanceNote below, which says so —
467
+ // and neither does this server's SearchResult, so there is nothing
468
+ // on either side to fuse two orderings on. Interleaving them on an
469
+ // invented number would look authoritative and would not be. Never
470
+ // allowed to fail the search it runs beside.
471
+ const otherSources = await searchStaticSources(ctx, params.query, params.language ?? DEFAULT_LOCALE).catch((error) => {
472
+ ctx.logger.createLogger('search').warning(`Other-source search failed: ${String(error)}`);
473
+ return [];
474
+ });
406
475
  const { results, pagination, tokenInfo, filterRelaxation, versionNote, paginationNote, truncatedContent } = searchResult;
407
476
  // Build response
408
477
  const filters = buildFilterSummary(params);
@@ -431,6 +500,7 @@ export function registerSearchTool(server, ctx) {
431
500
  versionNote,
432
501
  paginationNote,
433
502
  truncatedContent,
503
+ otherSources,
434
504
  });
435
505
  if (params.responseFormat === ResponseFormat.JSON) {
436
506
  // Add relevance note only in JSON format.
@@ -463,7 +533,7 @@ export function registerSearchTool(server, ctx) {
463
533
  const formatFn = params.outputMode === OutputMode.COMPACT
464
534
  ? formatSearchResultsAsCompact
465
535
  : formatSearchResultsAsMarkdown;
466
- const markdown = appendMarkdownNotices(formatFn(params.query, results, filters, pagination, tokenInfo), { filterRelaxation, versionNote, paginationNote, truncatedContent });
536
+ const markdown = appendMarkdownNotices(formatFn(params.query, results, filters, pagination, tokenInfo), { filterRelaxation, versionNote, paginationNote, truncatedContent }) + renderOtherSources(otherSources);
467
537
  await reportProgress(extra, { progress: 3, total: 3 });
468
538
  return {
469
539
  content: [{