@get-technology-inc/jamf-docs-mcp-server 0.0.1 → 1.1.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/LICENSE +21 -0
- package/README.md +111 -29
- package/dist/constants.d.ts +263 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +308 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/resources/index.d.ts +13 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +45 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/schemas/index.d.ts +61 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +127 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/services/cache.d.ts +47 -0
- package/dist/services/cache.d.ts.map +1 -0
- package/dist/services/cache.js +165 -0
- package/dist/services/cache.js.map +1 -0
- package/dist/services/metadata.d.ts +78 -0
- package/dist/services/metadata.d.ts.map +1 -0
- package/dist/services/metadata.js +349 -0
- package/dist/services/metadata.js.map +1 -0
- package/dist/services/scraper.d.ts +62 -0
- package/dist/services/scraper.d.ts.map +1 -0
- package/dist/services/scraper.js +544 -0
- package/dist/services/scraper.js.map +1 -0
- package/dist/services/search-suggestions.d.ts +27 -0
- package/dist/services/search-suggestions.d.ts.map +1 -0
- package/dist/services/search-suggestions.js +193 -0
- package/dist/services/search-suggestions.js.map +1 -0
- package/dist/services/tokenizer.d.ts +93 -0
- package/dist/services/tokenizer.d.ts.map +1 -0
- package/dist/services/tokenizer.js +330 -0
- package/dist/services/tokenizer.js.map +1 -0
- package/dist/tools/get-article.d.ts +7 -0
- package/dist/tools/get-article.d.ts.map +1 -0
- package/dist/tools/get-article.js +244 -0
- package/dist/tools/get-article.js.map +1 -0
- package/dist/tools/get-toc.d.ts +7 -0
- package/dist/tools/get-toc.d.ts.map +1 -0
- package/dist/tools/get-toc.js +202 -0
- package/dist/tools/get-toc.js.map +1 -0
- package/dist/tools/list-products.d.ts +7 -0
- package/dist/tools/list-products.d.ts.map +1 -0
- package/dist/tools/list-products.js +150 -0
- package/dist/tools/list-products.js.map +1 -0
- package/dist/tools/search.d.ts +7 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +252 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/types.d.ts +188 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +28 -0
- package/dist/types.js.map +1 -0
- package/package.json +68 -6
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* jamf_docs_get_toc tool
|
|
3
|
+
* Get the table of contents for a Jamf product's documentation.
|
|
4
|
+
*/
|
|
5
|
+
import { GetTocInputSchema } from '../schemas/index.js';
|
|
6
|
+
import { ResponseFormat, OutputMode, JAMF_PRODUCTS, TOKEN_CONFIG } from '../constants.js';
|
|
7
|
+
import { fetchTableOfContents } from '../services/scraper.js';
|
|
8
|
+
import { getAvailableVersions } from '../services/metadata.js';
|
|
9
|
+
/**
|
|
10
|
+
* Render a single TOC entry as markdown
|
|
11
|
+
*/
|
|
12
|
+
function renderTocEntry(entry, depth = 0, compact = false) {
|
|
13
|
+
const indent = ' '.repeat(depth);
|
|
14
|
+
let result = `${indent}- [${entry.title}](${entry.url})\n`;
|
|
15
|
+
if (!compact && entry.children !== undefined && entry.children.length > 0) {
|
|
16
|
+
for (const child of entry.children) {
|
|
17
|
+
result += renderTocEntry(child, depth + 1, compact);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Format TOC as compact markdown
|
|
24
|
+
*/
|
|
25
|
+
function formatTocCompact(productName, toc, pagination) {
|
|
26
|
+
let markdown = `## ${productName} TOC (${pagination.totalItems} entries)\n\n`;
|
|
27
|
+
for (const entry of toc) {
|
|
28
|
+
markdown += renderTocEntry(entry, 0, true);
|
|
29
|
+
}
|
|
30
|
+
markdown += `\n---\n*Page ${pagination.page}/${pagination.totalPages}`;
|
|
31
|
+
if (pagination.hasNext) {
|
|
32
|
+
markdown += ` | page=${pagination.page + 1} for more`;
|
|
33
|
+
}
|
|
34
|
+
markdown += '*\n';
|
|
35
|
+
return markdown;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Format TOC as full markdown
|
|
39
|
+
*/
|
|
40
|
+
function formatTocFull(productName, version, toc, pagination, tokenInfo) {
|
|
41
|
+
let markdown = `# ${productName} Documentation\n\n`;
|
|
42
|
+
markdown += `**Version**: ${version} | **Page ${pagination.page} of ${pagination.totalPages}** | ${tokenInfo.tokenCount.toLocaleString()} tokens\n\n`;
|
|
43
|
+
markdown += '---\n\n';
|
|
44
|
+
markdown += '## Table of Contents\n\n';
|
|
45
|
+
for (const entry of toc) {
|
|
46
|
+
markdown += renderTocEntry(entry);
|
|
47
|
+
}
|
|
48
|
+
markdown += '\n---\n\n';
|
|
49
|
+
markdown += `**Page ${pagination.page} of ${pagination.totalPages}** (${tokenInfo.tokenCount.toLocaleString()} tokens, ${pagination.totalItems} total entries)`;
|
|
50
|
+
if (pagination.hasNext) {
|
|
51
|
+
markdown += ` | Use \`page=${pagination.page + 1}\` for more`;
|
|
52
|
+
}
|
|
53
|
+
if (tokenInfo.truncated) {
|
|
54
|
+
markdown += '\n*TOC truncated due to token limit. Use `page` parameter or increase `maxTokens`.*';
|
|
55
|
+
}
|
|
56
|
+
markdown += '\n\n*Use `jamf_docs_get_article` with any URL above to read the full content.*\n';
|
|
57
|
+
return markdown;
|
|
58
|
+
}
|
|
59
|
+
const TOOL_NAME = 'jamf_docs_get_toc';
|
|
60
|
+
const TOOL_DESCRIPTION = `Get the table of contents for a Jamf product's documentation.
|
|
61
|
+
|
|
62
|
+
This tool retrieves the navigation structure for a specific Jamf product,
|
|
63
|
+
allowing you to browse available documentation topics.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
- product (string, required): Product ID - one of: jamf-pro, jamf-school, jamf-connect, jamf-protect
|
|
67
|
+
- version (string, optional): Specific version (defaults to latest)
|
|
68
|
+
- page (number, optional): Page number for pagination 1-100 (default: 1)
|
|
69
|
+
- maxTokens (number, optional): Maximum tokens in response 100-20000 (default: 5000)
|
|
70
|
+
- outputMode ('full' | 'compact'): Output detail level (default: 'full'). Use 'compact' for flat list without nested children
|
|
71
|
+
- responseFormat ('markdown' | 'json'): Output format (default: 'markdown')
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
For JSON format:
|
|
75
|
+
{
|
|
76
|
+
"product": string,
|
|
77
|
+
"version": string,
|
|
78
|
+
"toc": [...],
|
|
79
|
+
"tokenInfo": {
|
|
80
|
+
"tokenCount": number,
|
|
81
|
+
"truncated": boolean,
|
|
82
|
+
"maxTokens": number
|
|
83
|
+
},
|
|
84
|
+
"pagination": {
|
|
85
|
+
"page": number,
|
|
86
|
+
"pageSize": number,
|
|
87
|
+
"totalPages": number,
|
|
88
|
+
"totalItems": number,
|
|
89
|
+
"hasNext": boolean,
|
|
90
|
+
"hasPrev": boolean
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
For Markdown format:
|
|
95
|
+
A hierarchical list of documentation topics with pagination and token info.
|
|
96
|
+
|
|
97
|
+
Examples:
|
|
98
|
+
- Browse Jamf Pro documentation: product="jamf-pro"
|
|
99
|
+
- Get page 2 of TOC: product="jamf-pro", page=2
|
|
100
|
+
- Limit response size: product="jamf-pro", maxTokens=2000
|
|
101
|
+
|
|
102
|
+
Errors:
|
|
103
|
+
- "Invalid product ID" if the product is not recognized
|
|
104
|
+
- "Version not found" if the specified version doesn't exist
|
|
105
|
+
|
|
106
|
+
Note: Use this to discover what topics are available before searching
|
|
107
|
+
or retrieving specific articles. Large TOCs are paginated.`;
|
|
108
|
+
export function registerGetTocTool(server) {
|
|
109
|
+
server.registerTool(TOOL_NAME, {
|
|
110
|
+
title: 'Get Documentation Table of Contents',
|
|
111
|
+
description: TOOL_DESCRIPTION,
|
|
112
|
+
inputSchema: GetTocInputSchema,
|
|
113
|
+
annotations: {
|
|
114
|
+
readOnlyHint: true,
|
|
115
|
+
destructiveHint: false,
|
|
116
|
+
idempotentHint: true,
|
|
117
|
+
openWorldHint: true
|
|
118
|
+
}
|
|
119
|
+
}, async (args) => {
|
|
120
|
+
// Parse and validate input
|
|
121
|
+
const parseResult = GetTocInputSchema.safeParse(args);
|
|
122
|
+
if (!parseResult.success) {
|
|
123
|
+
return {
|
|
124
|
+
isError: true,
|
|
125
|
+
content: [{ type: 'text', text: `Invalid input: ${parseResult.error.message}` }]
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
const params = parseResult.data;
|
|
129
|
+
try {
|
|
130
|
+
// Validate product
|
|
131
|
+
if (!(params.product in JAMF_PRODUCTS)) {
|
|
132
|
+
return {
|
|
133
|
+
isError: true,
|
|
134
|
+
content: [{
|
|
135
|
+
type: 'text',
|
|
136
|
+
text: `Invalid product ID: "${params.product}".\n\nValid options:\n${Object.entries(JAMF_PRODUCTS).map(([id, p]) => `- \`${id}\`: ${p.name}`).join('\n')}`
|
|
137
|
+
}]
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
const productId = params.product;
|
|
141
|
+
const productInfo = JAMF_PRODUCTS[productId];
|
|
142
|
+
// Get available versions dynamically
|
|
143
|
+
const availableVersions = await getAvailableVersions(productId);
|
|
144
|
+
const version = params.version ?? 'current';
|
|
145
|
+
// Validate version if specified
|
|
146
|
+
if (params.version !== undefined && params.version !== '' && params.version !== 'current') {
|
|
147
|
+
if (availableVersions.length > 0 && !availableVersions.includes(params.version)) {
|
|
148
|
+
return {
|
|
149
|
+
isError: true,
|
|
150
|
+
content: [{
|
|
151
|
+
type: 'text',
|
|
152
|
+
text: `Version "${params.version}" not found for ${productInfo.name}.\n\nAvailable versions: ${availableVersions.length > 0 ? availableVersions.join(', ') : 'current'}`
|
|
153
|
+
}]
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const tocResult = await fetchTableOfContents(productId, version, {
|
|
158
|
+
...(params.page !== undefined && { page: params.page }),
|
|
159
|
+
maxTokens: params.maxTokens ?? TOKEN_CONFIG.DEFAULT_MAX_TOKENS
|
|
160
|
+
});
|
|
161
|
+
const { toc, pagination, tokenInfo } = tocResult;
|
|
162
|
+
// Build response
|
|
163
|
+
const response = {
|
|
164
|
+
product: productInfo.name,
|
|
165
|
+
version,
|
|
166
|
+
toc,
|
|
167
|
+
tokenInfo,
|
|
168
|
+
pagination
|
|
169
|
+
};
|
|
170
|
+
// Format output
|
|
171
|
+
if (params.responseFormat === ResponseFormat.JSON) {
|
|
172
|
+
return {
|
|
173
|
+
content: [{
|
|
174
|
+
type: 'text',
|
|
175
|
+
text: JSON.stringify(response, null, 2)
|
|
176
|
+
}]
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
// Format as markdown (compact or full)
|
|
180
|
+
const markdown = params.outputMode === OutputMode.COMPACT
|
|
181
|
+
? formatTocCompact(productInfo.name, toc, pagination)
|
|
182
|
+
: formatTocFull(productInfo.name, version, toc, pagination, tokenInfo);
|
|
183
|
+
return {
|
|
184
|
+
content: [{
|
|
185
|
+
type: 'text',
|
|
186
|
+
text: markdown
|
|
187
|
+
}]
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
192
|
+
return {
|
|
193
|
+
isError: true,
|
|
194
|
+
content: [{
|
|
195
|
+
type: 'text',
|
|
196
|
+
text: `Error fetching table of contents: ${errorMessage}`
|
|
197
|
+
}]
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=get-toc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-toc.js","sourceRoot":"","sources":["../../src/tools/get-toc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* jamf_docs_list_products tool
|
|
3
|
+
* Lists all available Jamf products and their documentation versions.
|
|
4
|
+
*/
|
|
5
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
6
|
+
export declare function registerListProductsTool(server: McpServer): void;
|
|
7
|
+
//# sourceMappingURL=list-products.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-products.d.ts","sourceRoot":"","sources":["../../src/tools/list-products.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAyCzE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA4HhE"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* jamf_docs_list_products tool
|
|
3
|
+
* Lists all available Jamf products and their documentation versions.
|
|
4
|
+
*/
|
|
5
|
+
import { ListProductsInputSchema } from '../schemas/index.js';
|
|
6
|
+
import { JAMF_PRODUCTS, JAMF_TOPICS, ResponseFormat, OutputMode, TOKEN_CONFIG } from '../constants.js';
|
|
7
|
+
import { estimateTokens, createTokenInfo } from '../services/tokenizer.js';
|
|
8
|
+
const TOOL_NAME = 'jamf_docs_list_products';
|
|
9
|
+
const TOOL_DESCRIPTION = `List all available Jamf products, topics, and their documentation versions.
|
|
10
|
+
|
|
11
|
+
This tool returns information about all Jamf products with available documentation,
|
|
12
|
+
including Jamf Pro, Jamf School, Jamf Connect, and Jamf Protect. Also lists available
|
|
13
|
+
topic filters for search.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
- maxTokens (number, optional): Maximum tokens in response 100-20000 (default: 5000)
|
|
17
|
+
- outputMode ('full' | 'compact'): Output detail level (default: 'full'). Use 'compact' for brief list
|
|
18
|
+
- responseFormat ('markdown' | 'json'): Output format (default: 'markdown')
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
For JSON format:
|
|
22
|
+
{
|
|
23
|
+
"products": [...],
|
|
24
|
+
"topics": [...],
|
|
25
|
+
"tokenInfo": {
|
|
26
|
+
"tokenCount": number,
|
|
27
|
+
"truncated": boolean,
|
|
28
|
+
"maxTokens": number
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
For Markdown format:
|
|
33
|
+
A formatted list of products and topics with their details.
|
|
34
|
+
|
|
35
|
+
Examples:
|
|
36
|
+
- "What Jamf products are available?" → use this tool
|
|
37
|
+
- "List all Jamf documentation" → use this tool
|
|
38
|
+
- "What topics can I filter by?" → use this tool
|
|
39
|
+
|
|
40
|
+
Note: This is a read-only operation that does not modify any state.`;
|
|
41
|
+
export function registerListProductsTool(server) {
|
|
42
|
+
server.registerTool(TOOL_NAME, {
|
|
43
|
+
title: 'List Jamf Products',
|
|
44
|
+
description: TOOL_DESCRIPTION,
|
|
45
|
+
inputSchema: ListProductsInputSchema,
|
|
46
|
+
annotations: {
|
|
47
|
+
readOnlyHint: true,
|
|
48
|
+
destructiveHint: false,
|
|
49
|
+
idempotentHint: true,
|
|
50
|
+
openWorldHint: false
|
|
51
|
+
}
|
|
52
|
+
}, (args) => {
|
|
53
|
+
// Parse and validate input
|
|
54
|
+
const parseResult = ListProductsInputSchema.safeParse(args);
|
|
55
|
+
if (!parseResult.success) {
|
|
56
|
+
return {
|
|
57
|
+
isError: true,
|
|
58
|
+
content: [{ type: 'text', text: `Invalid input: ${parseResult.error.message}` }]
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const params = parseResult.data;
|
|
62
|
+
const maxTokens = params.maxTokens ?? TOKEN_CONFIG.DEFAULT_MAX_TOKENS;
|
|
63
|
+
try {
|
|
64
|
+
// Build product list
|
|
65
|
+
const products = Object.values(JAMF_PRODUCTS).map(product => ({
|
|
66
|
+
id: product.id,
|
|
67
|
+
name: product.name,
|
|
68
|
+
description: product.description,
|
|
69
|
+
currentVersion: product.latestVersion,
|
|
70
|
+
availableVersions: [...product.versions]
|
|
71
|
+
}));
|
|
72
|
+
// Build topics list
|
|
73
|
+
const topics = Object.entries(JAMF_TOPICS).map(([id, topic]) => ({
|
|
74
|
+
id,
|
|
75
|
+
name: topic.name,
|
|
76
|
+
keywords: topic.keywords
|
|
77
|
+
}));
|
|
78
|
+
// Format output based on requested format
|
|
79
|
+
if (params.responseFormat === ResponseFormat.JSON) {
|
|
80
|
+
const jsonOutput = JSON.stringify({
|
|
81
|
+
products,
|
|
82
|
+
topics,
|
|
83
|
+
tokenInfo: createTokenInfo(JSON.stringify({ products, topics }), maxTokens)
|
|
84
|
+
}, null, 2);
|
|
85
|
+
return {
|
|
86
|
+
content: [{
|
|
87
|
+
type: 'text',
|
|
88
|
+
text: jsonOutput
|
|
89
|
+
}]
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
// Compact mode: minimal output
|
|
93
|
+
if (params.outputMode === OutputMode.COMPACT) {
|
|
94
|
+
let markdown = '## Products\n';
|
|
95
|
+
for (const product of products) {
|
|
96
|
+
markdown += `- \`${product.id}\`: ${product.name}\n`;
|
|
97
|
+
}
|
|
98
|
+
markdown += '\n## Topics\n';
|
|
99
|
+
for (const topic of topics) {
|
|
100
|
+
markdown += `- \`${topic.id}\`: ${topic.name}\n`;
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
content: [{
|
|
104
|
+
type: 'text',
|
|
105
|
+
text: markdown
|
|
106
|
+
}]
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
// Full markdown format
|
|
110
|
+
let markdown = '# Jamf Documentation Products\n\n';
|
|
111
|
+
for (const product of products) {
|
|
112
|
+
markdown += `## ${product.name}\n\n`;
|
|
113
|
+
markdown += `- **ID**: \`${product.id}\`\n`;
|
|
114
|
+
markdown += `- **Description**: ${product.description}\n`;
|
|
115
|
+
markdown += `- **Current Version**: ${product.currentVersion}\n`;
|
|
116
|
+
markdown += `- **Available Versions**: ${product.availableVersions.join(', ')}\n\n`;
|
|
117
|
+
}
|
|
118
|
+
markdown += '---\n\n';
|
|
119
|
+
markdown += '# Available Topics for Filtering\n\n';
|
|
120
|
+
markdown += 'Use these topic IDs with the `topic` parameter in `jamf_docs_search`:\n\n';
|
|
121
|
+
for (const topic of topics) {
|
|
122
|
+
markdown += `- **\`${topic.id}\`**: ${topic.name}\n`;
|
|
123
|
+
markdown += ` *Keywords: ${topic.keywords.slice(0, 4).join(', ')}${topic.keywords.length > 4 ? '...' : ''}*\n`;
|
|
124
|
+
}
|
|
125
|
+
markdown += '\n---\n\n';
|
|
126
|
+
// Token info
|
|
127
|
+
const tokenCount = estimateTokens(markdown);
|
|
128
|
+
markdown += `*${tokenCount.toLocaleString()} tokens*\n\n`;
|
|
129
|
+
markdown += '*Use `jamf_docs_search` to search within these products, ';
|
|
130
|
+
markdown += 'or `jamf_docs_get_toc` to browse the table of contents.*\n';
|
|
131
|
+
return {
|
|
132
|
+
content: [{
|
|
133
|
+
type: 'text',
|
|
134
|
+
text: markdown
|
|
135
|
+
}]
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
140
|
+
return {
|
|
141
|
+
isError: true,
|
|
142
|
+
content: [{
|
|
143
|
+
type: 'text',
|
|
144
|
+
text: `Error listing products: ${errorMessage}`
|
|
145
|
+
}]
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=list-products.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-products.js","sourceRoot":"","sources":["../../src/tools/list-products.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* jamf_docs_search tool
|
|
3
|
+
* Search Jamf documentation for articles matching a query.
|
|
4
|
+
*/
|
|
5
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
6
|
+
export declare function registerSearchTool(server: McpServer): void;
|
|
7
|
+
//# sourceMappingURL=search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA8KzE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAwI1D"}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* jamf_docs_search tool
|
|
3
|
+
* Search Jamf documentation for articles matching a query.
|
|
4
|
+
*/
|
|
5
|
+
import { SearchInputSchema } from '../schemas/index.js';
|
|
6
|
+
import { ResponseFormat, OutputMode, JAMF_PRODUCTS, JAMF_TOPICS, TOKEN_CONFIG } from '../constants.js';
|
|
7
|
+
import { searchDocumentation } from '../services/scraper.js';
|
|
8
|
+
import { generateSearchSuggestions, formatSearchSuggestions } from '../services/search-suggestions.js';
|
|
9
|
+
function formatFiltersLine(filters) {
|
|
10
|
+
const parts = [];
|
|
11
|
+
if (filters.product !== undefined) {
|
|
12
|
+
parts.push(`product: ${filters.product}`);
|
|
13
|
+
}
|
|
14
|
+
if (filters.topic !== undefined) {
|
|
15
|
+
parts.push(`topic: ${filters.topic}`);
|
|
16
|
+
}
|
|
17
|
+
if (filters.version !== undefined) {
|
|
18
|
+
parts.push(`version: ${filters.version}`);
|
|
19
|
+
}
|
|
20
|
+
return parts.length > 0 ? `\n*Filtered by: ${parts.join(', ')}*` : '';
|
|
21
|
+
}
|
|
22
|
+
function formatSearchResult(result) {
|
|
23
|
+
let output = `### [${result.title}](${result.url})\n\n`;
|
|
24
|
+
output += `> ${result.snippet}\n\n`;
|
|
25
|
+
if (result.product !== '' || result.version !== undefined) {
|
|
26
|
+
const meta = [];
|
|
27
|
+
if (result.product !== '') {
|
|
28
|
+
meta.push(`**Product**: ${result.product}`);
|
|
29
|
+
}
|
|
30
|
+
if (result.version !== undefined) {
|
|
31
|
+
meta.push(`**Version**: ${result.version}`);
|
|
32
|
+
}
|
|
33
|
+
output += `${meta.join(' | ')}\n\n`;
|
|
34
|
+
}
|
|
35
|
+
output += '---\n\n';
|
|
36
|
+
return output;
|
|
37
|
+
}
|
|
38
|
+
function formatPaginationFooter(pagination, tokenInfo, compact = false) {
|
|
39
|
+
if (compact) {
|
|
40
|
+
let footer = `\n---\n*Page ${pagination.page}/${pagination.totalPages}`;
|
|
41
|
+
if (pagination.hasNext) {
|
|
42
|
+
footer += ` | page=${pagination.page + 1} for more`;
|
|
43
|
+
}
|
|
44
|
+
footer += '*\n';
|
|
45
|
+
return footer;
|
|
46
|
+
}
|
|
47
|
+
let footer = `**Page ${pagination.page} of ${pagination.totalPages}** (${tokenInfo.tokenCount.toLocaleString()} tokens)`;
|
|
48
|
+
if (pagination.hasNext) {
|
|
49
|
+
footer += ` | Use \`page=${pagination.page + 1}\` for more results`;
|
|
50
|
+
}
|
|
51
|
+
if (tokenInfo.truncated) {
|
|
52
|
+
footer += '\n*Results truncated due to token limit. Use a smaller `limit` or increase `maxTokens`.*';
|
|
53
|
+
}
|
|
54
|
+
footer += '\n\n*Use `jamf_docs_get_article` with any URL above to read the full article.*\n';
|
|
55
|
+
return footer;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Format search result in compact mode (single line)
|
|
59
|
+
*/
|
|
60
|
+
function formatSearchResultCompact(result, index) {
|
|
61
|
+
// Truncate snippet for compact display
|
|
62
|
+
const snippetPreview = result.snippet.length > 80
|
|
63
|
+
? `${result.snippet.slice(0, 77)}...`
|
|
64
|
+
: result.snippet;
|
|
65
|
+
return `${index}. [${result.title}](${result.url}) - ${snippetPreview}\n`;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Format search results as compact markdown
|
|
69
|
+
*/
|
|
70
|
+
function formatSearchResultsAsCompact(query, results, filters, pagination, tokenInfo) {
|
|
71
|
+
let markdown = `## "${query}" (${pagination.totalItems} results)\n`;
|
|
72
|
+
markdown += formatFiltersLine(filters);
|
|
73
|
+
markdown += '\n\n';
|
|
74
|
+
results.forEach((result, idx) => {
|
|
75
|
+
markdown += formatSearchResultCompact(result, (pagination.page - 1) * pagination.pageSize + idx + 1);
|
|
76
|
+
});
|
|
77
|
+
markdown += formatPaginationFooter(pagination, tokenInfo, true);
|
|
78
|
+
return markdown;
|
|
79
|
+
}
|
|
80
|
+
function formatSearchResultsAsMarkdown(query, results, filters, pagination, tokenInfo) {
|
|
81
|
+
let markdown = `# Search Results for "${query}"\n\n`;
|
|
82
|
+
markdown += `Found ${pagination.totalItems} result(s) | **Page ${pagination.page} of ${pagination.totalPages}** | ${tokenInfo.tokenCount.toLocaleString()} tokens`;
|
|
83
|
+
markdown += formatFiltersLine(filters);
|
|
84
|
+
markdown += '\n\n---\n\n';
|
|
85
|
+
for (const result of results) {
|
|
86
|
+
markdown += formatSearchResult(result);
|
|
87
|
+
}
|
|
88
|
+
markdown += formatPaginationFooter(pagination, tokenInfo);
|
|
89
|
+
return markdown;
|
|
90
|
+
}
|
|
91
|
+
const TOOL_NAME = 'jamf_docs_search';
|
|
92
|
+
const TOOL_DESCRIPTION = `Search Jamf documentation for articles matching your query.
|
|
93
|
+
|
|
94
|
+
This tool searches across all Jamf product documentation including Jamf Pro,
|
|
95
|
+
Jamf School, Jamf Connect, and Jamf Protect. Results include article titles,
|
|
96
|
+
snippets, and direct links.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
- query (string, required): Search keywords (2-200 characters)
|
|
100
|
+
- product (string, optional): Filter by product ID (jamf-pro, jamf-school, jamf-connect, jamf-protect)
|
|
101
|
+
- topic (string, optional): Filter by topic (enrollment, profiles, security, inventory, policies, smart-groups, apps, identity, api, network)
|
|
102
|
+
- version (string, optional): Filter by version (e.g., "11.5.0", "10.x")
|
|
103
|
+
- limit (number, optional): Maximum results per page 1-50 (default: 10)
|
|
104
|
+
- page (number, optional): Page number for pagination 1-100 (default: 1)
|
|
105
|
+
- maxTokens (number, optional): Maximum tokens in response 100-20000 (default: 5000)
|
|
106
|
+
- outputMode ('full' | 'compact'): Output detail level (default: 'full'). Use 'compact' for brief, token-efficient output
|
|
107
|
+
- responseFormat ('markdown' | 'json'): Output format (default: 'markdown')
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
For JSON format:
|
|
111
|
+
{
|
|
112
|
+
"total": number,
|
|
113
|
+
"query": string,
|
|
114
|
+
"results": [...],
|
|
115
|
+
"tokenInfo": {
|
|
116
|
+
"tokenCount": number,
|
|
117
|
+
"truncated": boolean,
|
|
118
|
+
"maxTokens": number
|
|
119
|
+
},
|
|
120
|
+
"pagination": {
|
|
121
|
+
"page": number,
|
|
122
|
+
"pageSize": number,
|
|
123
|
+
"totalPages": number,
|
|
124
|
+
"totalItems": number,
|
|
125
|
+
"hasNext": boolean,
|
|
126
|
+
"hasPrev": boolean
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
For Markdown format:
|
|
131
|
+
A formatted list of search results with pagination and token info.
|
|
132
|
+
|
|
133
|
+
Examples:
|
|
134
|
+
- "How to configure SSO" → query="SSO configuration"
|
|
135
|
+
- "MDM enrollment steps" → query="MDM enrollment", topic="enrollment"
|
|
136
|
+
- "Jamf Pro configuration profiles" → query="configuration profile", product="jamf-pro", topic="profiles"
|
|
137
|
+
- Get page 2 of results → query="policy", page=2
|
|
138
|
+
|
|
139
|
+
Errors:
|
|
140
|
+
- "No results found" if search returns empty
|
|
141
|
+
- "Invalid product ID" if product parameter is not recognized
|
|
142
|
+
|
|
143
|
+
Note: Results are ranked by relevance. Use filters and pagination to navigate large result sets.`;
|
|
144
|
+
export function registerSearchTool(server) {
|
|
145
|
+
server.registerTool(TOOL_NAME, {
|
|
146
|
+
title: 'Search Jamf Documentation',
|
|
147
|
+
description: TOOL_DESCRIPTION,
|
|
148
|
+
inputSchema: SearchInputSchema,
|
|
149
|
+
annotations: {
|
|
150
|
+
readOnlyHint: true,
|
|
151
|
+
destructiveHint: false,
|
|
152
|
+
idempotentHint: true,
|
|
153
|
+
openWorldHint: true
|
|
154
|
+
}
|
|
155
|
+
}, async (args) => {
|
|
156
|
+
// Parse and validate input
|
|
157
|
+
const parseResult = SearchInputSchema.safeParse(args);
|
|
158
|
+
if (!parseResult.success) {
|
|
159
|
+
return {
|
|
160
|
+
isError: true,
|
|
161
|
+
content: [{ type: 'text', text: `Invalid input: ${parseResult.error.message}` }]
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
const params = parseResult.data;
|
|
165
|
+
try {
|
|
166
|
+
// Validate product if provided
|
|
167
|
+
if (params.product !== undefined && !(params.product in JAMF_PRODUCTS)) {
|
|
168
|
+
return {
|
|
169
|
+
isError: true,
|
|
170
|
+
content: [{
|
|
171
|
+
type: 'text',
|
|
172
|
+
text: `Invalid product ID: "${params.product}". Valid options: ${Object.keys(JAMF_PRODUCTS).join(', ')}`
|
|
173
|
+
}]
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
// Validate topic if provided
|
|
177
|
+
if (params.topic !== undefined && !(params.topic in JAMF_TOPICS)) {
|
|
178
|
+
return {
|
|
179
|
+
isError: true,
|
|
180
|
+
content: [{
|
|
181
|
+
type: 'text',
|
|
182
|
+
text: `Invalid topic ID: "${params.topic}". Valid options: ${Object.keys(JAMF_TOPICS).join(', ')}`
|
|
183
|
+
}]
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
// Perform search with new parameters
|
|
187
|
+
const searchResult = await searchDocumentation({
|
|
188
|
+
query: params.query,
|
|
189
|
+
product: params.product,
|
|
190
|
+
topic: params.topic,
|
|
191
|
+
version: params.version,
|
|
192
|
+
limit: params.limit,
|
|
193
|
+
page: params.page,
|
|
194
|
+
maxTokens: params.maxTokens ?? TOKEN_CONFIG.DEFAULT_MAX_TOKENS
|
|
195
|
+
});
|
|
196
|
+
const { results, pagination, tokenInfo } = searchResult;
|
|
197
|
+
// Build response
|
|
198
|
+
const response = {
|
|
199
|
+
total: pagination.totalItems,
|
|
200
|
+
query: params.query,
|
|
201
|
+
results,
|
|
202
|
+
filters: {
|
|
203
|
+
...(params.product !== undefined ? { product: params.product } : {}),
|
|
204
|
+
...(params.version !== undefined ? { version: params.version } : {}),
|
|
205
|
+
...(params.topic !== undefined ? { topic: params.topic } : {})
|
|
206
|
+
},
|
|
207
|
+
tokenInfo,
|
|
208
|
+
pagination
|
|
209
|
+
};
|
|
210
|
+
// Handle no results with suggestions
|
|
211
|
+
if (results.length === 0 && pagination.totalItems === 0) {
|
|
212
|
+
const suggestions = generateSearchSuggestions(params.query, params.product !== undefined, params.topic !== undefined);
|
|
213
|
+
return {
|
|
214
|
+
content: [{
|
|
215
|
+
type: 'text',
|
|
216
|
+
text: formatSearchSuggestions(params.query, suggestions)
|
|
217
|
+
}]
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
// Format output
|
|
221
|
+
if (params.responseFormat === ResponseFormat.JSON) {
|
|
222
|
+
return {
|
|
223
|
+
content: [{
|
|
224
|
+
type: 'text',
|
|
225
|
+
text: JSON.stringify(response, null, 2)
|
|
226
|
+
}]
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
// Markdown format (full or compact)
|
|
230
|
+
const markdown = params.outputMode === OutputMode.COMPACT
|
|
231
|
+
? formatSearchResultsAsCompact(params.query, results, response.filters ?? {}, pagination, tokenInfo)
|
|
232
|
+
: formatSearchResultsAsMarkdown(params.query, results, response.filters ?? {}, pagination, tokenInfo);
|
|
233
|
+
return {
|
|
234
|
+
content: [{
|
|
235
|
+
type: 'text',
|
|
236
|
+
text: markdown
|
|
237
|
+
}]
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
catch (error) {
|
|
241
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
242
|
+
return {
|
|
243
|
+
isError: true,
|
|
244
|
+
content: [{
|
|
245
|
+
type: 'text',
|
|
246
|
+
text: `Search error: ${errorMessage}\n\nPlease try again or use different search terms.`
|
|
247
|
+
}]
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"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"}
|