@get-technology-inc/jamf-docs-mcp-server 0.0.1 → 1.0.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 (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +189 -29
  3. package/dist/constants.d.ts +260 -0
  4. package/dist/constants.d.ts.map +1 -0
  5. package/dist/constants.js +303 -0
  6. package/dist/constants.js.map +1 -0
  7. package/dist/index.d.ts +9 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +36 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/schemas/index.d.ts +98 -0
  12. package/dist/schemas/index.d.ts.map +1 -0
  13. package/dist/schemas/index.js +110 -0
  14. package/dist/schemas/index.js.map +1 -0
  15. package/dist/services/cache.d.ts +56 -0
  16. package/dist/services/cache.d.ts.map +1 -0
  17. package/dist/services/cache.js +189 -0
  18. package/dist/services/cache.js.map +1 -0
  19. package/dist/services/scraper.d.ts +62 -0
  20. package/dist/services/scraper.d.ts.map +1 -0
  21. package/dist/services/scraper.js +568 -0
  22. package/dist/services/scraper.js.map +1 -0
  23. package/dist/services/tokenizer.d.ts +77 -0
  24. package/dist/services/tokenizer.d.ts.map +1 -0
  25. package/dist/services/tokenizer.js +274 -0
  26. package/dist/services/tokenizer.js.map +1 -0
  27. package/dist/tools/get-article.d.ts +7 -0
  28. package/dist/tools/get-article.d.ts.map +1 -0
  29. package/dist/tools/get-article.js +195 -0
  30. package/dist/tools/get-article.js.map +1 -0
  31. package/dist/tools/get-toc.d.ts +7 -0
  32. package/dist/tools/get-toc.d.ts.map +1 -0
  33. package/dist/tools/get-toc.js +172 -0
  34. package/dist/tools/get-toc.js.map +1 -0
  35. package/dist/tools/list-products.d.ts +7 -0
  36. package/dist/tools/list-products.d.ts.map +1 -0
  37. package/dist/tools/list-products.js +132 -0
  38. package/dist/tools/list-products.js.map +1 -0
  39. package/dist/tools/search.d.ts +7 -0
  40. package/dist/tools/search.d.ts.map +1 -0
  41. package/dist/tools/search.js +212 -0
  42. package/dist/tools/search.js.map +1 -0
  43. package/dist/types.d.ts +197 -0
  44. package/dist/types.d.ts.map +1 -0
  45. package/dist/types.js +28 -0
  46. package/dist/types.js.map +1 -0
  47. package/package.json +68 -6
@@ -0,0 +1,172 @@
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, JAMF_PRODUCTS, TOKEN_CONFIG } from '../constants.js';
7
+ import { fetchTableOfContents } from '../services/scraper.js';
8
+ const TOOL_NAME = 'jamf_docs_get_toc';
9
+ const TOOL_DESCRIPTION = `Get the table of contents for a Jamf product's documentation.
10
+
11
+ This tool retrieves the navigation structure for a specific Jamf product,
12
+ allowing you to browse available documentation topics.
13
+
14
+ Args:
15
+ - product (string, required): Product ID - one of: jamf-pro, jamf-school, jamf-connect, jamf-protect
16
+ - version (string, optional): Specific version (defaults to latest)
17
+ - page (number, optional): Page number for pagination 1-100 (default: 1)
18
+ - maxTokens (number, optional): Maximum tokens in response 100-20000 (default: 5000)
19
+ - responseFormat ('markdown' | 'json'): Output format (default: 'markdown')
20
+
21
+ Returns:
22
+ For JSON format:
23
+ {
24
+ "product": string,
25
+ "version": string,
26
+ "toc": [...],
27
+ "tokenInfo": {
28
+ "tokenCount": number,
29
+ "truncated": boolean,
30
+ "maxTokens": number
31
+ },
32
+ "pagination": {
33
+ "page": number,
34
+ "pageSize": number,
35
+ "totalPages": number,
36
+ "totalItems": number,
37
+ "hasNext": boolean,
38
+ "hasPrev": boolean
39
+ }
40
+ }
41
+
42
+ For Markdown format:
43
+ A hierarchical list of documentation topics with pagination and token info.
44
+
45
+ Examples:
46
+ - Browse Jamf Pro documentation: product="jamf-pro"
47
+ - Get page 2 of TOC: product="jamf-pro", page=2
48
+ - Limit response size: product="jamf-pro", maxTokens=2000
49
+
50
+ Errors:
51
+ - "Invalid product ID" if the product is not recognized
52
+ - "Version not found" if the specified version doesn't exist
53
+
54
+ Note: Use this to discover what topics are available before searching
55
+ or retrieving specific articles. Large TOCs are paginated.`;
56
+ export function registerGetTocTool(server) {
57
+ server.registerTool(TOOL_NAME, {
58
+ title: 'Get Documentation Table of Contents',
59
+ description: TOOL_DESCRIPTION,
60
+ inputSchema: GetTocInputSchema,
61
+ annotations: {
62
+ readOnlyHint: true,
63
+ destructiveHint: false,
64
+ idempotentHint: true,
65
+ openWorldHint: true
66
+ }
67
+ }, async (args) => {
68
+ // Parse and validate input
69
+ const parseResult = GetTocInputSchema.safeParse(args);
70
+ if (!parseResult.success) {
71
+ return {
72
+ isError: true,
73
+ content: [{ type: 'text', text: `Invalid input: ${parseResult.error.message}` }]
74
+ };
75
+ }
76
+ const params = parseResult.data;
77
+ try {
78
+ // Validate product
79
+ if (!(params.product in JAMF_PRODUCTS)) {
80
+ return {
81
+ isError: true,
82
+ content: [{
83
+ type: 'text',
84
+ text: `Invalid product ID: "${params.product}".\n\nValid options:\n${Object.entries(JAMF_PRODUCTS).map(([id, p]) => `- \`${id}\`: ${p.name}`).join('\n')}`
85
+ }]
86
+ };
87
+ }
88
+ const productId = params.product;
89
+ const productInfo = JAMF_PRODUCTS[productId];
90
+ const version = params.version ?? productInfo.latestVersion;
91
+ // Validate version
92
+ if (params.version && !productInfo.versions.includes(params.version)) {
93
+ return {
94
+ isError: true,
95
+ content: [{
96
+ type: 'text',
97
+ text: `Version "${params.version}" not found for ${productInfo.name}.\n\nAvailable versions: ${productInfo.versions.join(', ')}`
98
+ }]
99
+ };
100
+ }
101
+ // Fetch TOC with pagination and token options
102
+ const tocResult = await fetchTableOfContents(productId, version, {
103
+ ...(params.page !== undefined && { page: params.page }),
104
+ maxTokens: params.maxTokens ?? TOKEN_CONFIG.DEFAULT_MAX_TOKENS
105
+ });
106
+ const { toc, pagination, tokenInfo } = tocResult;
107
+ // Build response
108
+ const response = {
109
+ product: productInfo.name,
110
+ version,
111
+ toc,
112
+ tokenInfo,
113
+ pagination
114
+ };
115
+ // Format output
116
+ if (params.responseFormat === ResponseFormat.JSON) {
117
+ return {
118
+ content: [{
119
+ type: 'text',
120
+ text: JSON.stringify(response, null, 2)
121
+ }]
122
+ };
123
+ }
124
+ // Markdown format with Context7 style
125
+ let markdown = `# ${productInfo.name} Documentation\n\n`;
126
+ markdown += `**Version**: ${version} | **Page ${pagination.page} of ${pagination.totalPages}** | ${tokenInfo.tokenCount.toLocaleString()} tokens\n\n`;
127
+ markdown += '---\n\n';
128
+ markdown += '## Table of Contents\n\n';
129
+ // Recursive function to render TOC
130
+ function renderTocEntry(entry, depth = 0) {
131
+ const indent = ' '.repeat(depth);
132
+ let result = `${indent}- [${entry.title}](${entry.url})\n`;
133
+ if (entry.children && entry.children.length > 0) {
134
+ for (const child of entry.children) {
135
+ result += renderTocEntry(child, depth + 1);
136
+ }
137
+ }
138
+ return result;
139
+ }
140
+ for (const entry of toc) {
141
+ markdown += renderTocEntry(entry);
142
+ }
143
+ // Pagination footer
144
+ markdown += '\n---\n\n';
145
+ markdown += `**Page ${pagination.page} of ${pagination.totalPages}** (${tokenInfo.tokenCount.toLocaleString()} tokens, ${pagination.totalItems} total entries)`;
146
+ if (pagination.hasNext) {
147
+ markdown += ` | Use \`page=${pagination.page + 1}\` for more`;
148
+ }
149
+ if (tokenInfo.truncated) {
150
+ markdown += '\n*TOC truncated due to token limit. Use `page` parameter or increase `maxTokens`.*';
151
+ }
152
+ markdown += '\n\n*Use `jamf_docs_get_article` with any URL above to read the full content.*\n';
153
+ return {
154
+ content: [{
155
+ type: 'text',
156
+ text: markdown
157
+ }]
158
+ };
159
+ }
160
+ catch (error) {
161
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
162
+ return {
163
+ isError: true,
164
+ content: [{
165
+ type: 'text',
166
+ text: `Error fetching table of contents: ${errorMessage}`
167
+ }]
168
+ };
169
+ }
170
+ });
171
+ }
172
+ //# sourceMappingURL=get-toc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-toc.js","sourceRoot":"","sources":["../../src/tools/get-toc.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,MAAM,SAAS,GAAG,mBAAmB,CAAC;AAEtC,MAAM,gBAAgB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2DA8CkC,CAAC;AAE5D,MAAM,UAAU,kBAAkB,CAAC,MAAiB;IAClD,MAAM,CAAC,YAAY,CACjB,SAAS,EACT;QACE,KAAK,EAAE,qCAAqC;QAC5C,WAAW,EAAE,gBAAgB;QAC7B,WAAW,EAAE,iBAAiB;QAC9B,WAAW,EAAE;YACX,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,IAAI;SACpB;KACF,EACD,KAAK,EAAE,IAAI,EAAuB,EAAE;QAClC,2BAA2B;QAC3B,MAAM,WAAW,GAAG,iBAAiB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACtD,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;YACzB,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,WAAW,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;aACjF,CAAC;QACJ,CAAC;QACD,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC;QAEhC,IAAI,CAAC;YACH,mBAAmB;YACnB,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,IAAI,aAAa,CAAC,EAAE,CAAC;gBACvC,OAAO;oBACL,OAAO,EAAE,IAAI;oBACb,OAAO,EAAE,CAAC;4BACR,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,wBAAwB,MAAM,CAAC,OAAO,yBAAyB,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;yBAC3J,CAAC;iBACH,CAAC;YACJ,CAAC;YAED,MAAM,SAAS,GAAG,MAAM,CAAC,OAAoB,CAAC;YAC9C,MAAM,WAAW,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;YAC7C,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,WAAW,CAAC,aAAa,CAAC;YAE5D,mBAAmB;YACnB,IAAI,MAAM,CAAC,OAAO,IAAI,CAAE,WAAW,CAAC,QAA8B,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC5F,OAAO;oBACL,OAAO,EAAE,IAAI;oBACb,OAAO,EAAE,CAAC;4BACR,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,YAAY,MAAM,CAAC,OAAO,mBAAmB,WAAW,CAAC,IAAI,4BAA4B,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;yBACjI,CAAC;iBACH,CAAC;YACJ,CAAC;YAED,8CAA8C;YAC9C,MAAM,SAAS,GAAG,MAAM,oBAAoB,CAAC,SAAS,EAAE,OAAO,EAAE;gBAC/D,GAAG,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;gBACvD,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,YAAY,CAAC,kBAAkB;aAC/D,CAAC,CAAC;YAEH,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,SAAS,CAAC;YAEjD,iBAAiB;YACjB,MAAM,QAAQ,GAAgB;gBAC5B,OAAO,EAAE,WAAW,CAAC,IAAI;gBACzB,OAAO;gBACP,GAAG;gBACH,SAAS;gBACT,UAAU;aACX,CAAC;YAEF,gBAAgB;YAChB,IAAI,MAAM,CAAC,cAAc,KAAK,cAAc,CAAC,IAAI,EAAE,CAAC;gBAClD,OAAO;oBACL,OAAO,EAAE,CAAC;4BACR,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;yBACxC,CAAC;iBACH,CAAC;YACJ,CAAC;YAED,sCAAsC;YACtC,IAAI,QAAQ,GAAG,KAAK,WAAW,CAAC,IAAI,oBAAoB,CAAC;YACzD,QAAQ,IAAI,gBAAgB,OAAO,aAAa,UAAU,CAAC,IAAI,OAAO,UAAU,CAAC,UAAU,QAAQ,SAAS,CAAC,UAAU,CAAC,cAAc,EAAE,aAAa,CAAC;YACtJ,QAAQ,IAAI,SAAS,CAAC;YACtB,QAAQ,IAAI,0BAA0B,CAAC;YAEvC,mCAAmC;YACnC,SAAS,cAAc,CAAC,KAAoB,EAAE,QAAgB,CAAC;gBAC7D,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAClC,IAAI,MAAM,GAAG,GAAG,MAAM,MAAM,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,GAAG,KAAK,CAAC;gBAE3D,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAChD,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;wBACnC,MAAM,IAAI,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;oBAC7C,CAAC;gBACH,CAAC;gBAED,OAAO,MAAM,CAAC;YAChB,CAAC;YAED,KAAK,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;gBACxB,QAAQ,IAAI,cAAc,CAAC,KAAK,CAAC,CAAC;YACpC,CAAC;YAED,oBAAoB;YACpB,QAAQ,IAAI,WAAW,CAAC;YACxB,QAAQ,IAAI,UAAU,UAAU,CAAC,IAAI,OAAO,UAAU,CAAC,UAAU,OAAO,SAAS,CAAC,UAAU,CAAC,cAAc,EAAE,YAAY,UAAU,CAAC,UAAU,iBAAiB,CAAC;YAChK,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;gBACvB,QAAQ,IAAI,iBAAiB,UAAU,CAAC,IAAI,GAAG,CAAC,aAAa,CAAC;YAChE,CAAC;YACD,IAAI,SAAS,CAAC,SAAS,EAAE,CAAC;gBACxB,QAAQ,IAAI,qFAAqF,CAAC;YACpG,CAAC;YAED,QAAQ,IAAI,kFAAkF,CAAC;YAE/F,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,QAAQ;qBACf,CAAC;aACH,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,CAAC;YACvF,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,qCAAqC,YAAY,EAAE;qBAC1D,CAAC;aACH,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * jamf_docs_list_products tool
3
+ * Lists all available Jamf products and their documentation versions.
4
+ */
5
+ import { 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,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAwCpE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA0GhE"}
@@ -0,0 +1,132 @@
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, 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
+ - responseFormat ('markdown' | 'json'): Output format (default: 'markdown')
18
+
19
+ Returns:
20
+ For JSON format:
21
+ {
22
+ "products": [...],
23
+ "topics": [...],
24
+ "tokenInfo": {
25
+ "tokenCount": number,
26
+ "truncated": boolean,
27
+ "maxTokens": number
28
+ }
29
+ }
30
+
31
+ For Markdown format:
32
+ A formatted list of products and topics with their details.
33
+
34
+ Examples:
35
+ - "What Jamf products are available?" → use this tool
36
+ - "List all Jamf documentation" → use this tool
37
+ - "What topics can I filter by?" → use this tool
38
+
39
+ Note: This is a read-only operation that does not modify any state.`;
40
+ export function registerListProductsTool(server) {
41
+ server.registerTool(TOOL_NAME, {
42
+ title: 'List Jamf Products',
43
+ description: TOOL_DESCRIPTION,
44
+ inputSchema: ListProductsInputSchema,
45
+ annotations: {
46
+ readOnlyHint: true,
47
+ destructiveHint: false,
48
+ idempotentHint: true,
49
+ openWorldHint: false
50
+ }
51
+ }, async (args) => {
52
+ // Parse and validate input
53
+ const parseResult = ListProductsInputSchema.safeParse(args);
54
+ if (!parseResult.success) {
55
+ return {
56
+ isError: true,
57
+ content: [{ type: 'text', text: `Invalid input: ${parseResult.error.message}` }]
58
+ };
59
+ }
60
+ const params = parseResult.data;
61
+ const maxTokens = params.maxTokens ?? TOKEN_CONFIG.DEFAULT_MAX_TOKENS;
62
+ try {
63
+ // Build product list
64
+ const products = Object.values(JAMF_PRODUCTS).map(product => ({
65
+ id: product.id,
66
+ name: product.name,
67
+ description: product.description,
68
+ currentVersion: product.latestVersion,
69
+ availableVersions: [...product.versions]
70
+ }));
71
+ // Build topics list
72
+ const topics = Object.entries(JAMF_TOPICS).map(([id, topic]) => ({
73
+ id,
74
+ name: topic.name,
75
+ keywords: topic.keywords
76
+ }));
77
+ // Format output based on requested format
78
+ if (params.responseFormat === ResponseFormat.JSON) {
79
+ const jsonOutput = JSON.stringify({
80
+ products,
81
+ topics,
82
+ tokenInfo: createTokenInfo(JSON.stringify({ products, topics }), maxTokens)
83
+ }, null, 2);
84
+ return {
85
+ content: [{
86
+ type: 'text',
87
+ text: jsonOutput
88
+ }]
89
+ };
90
+ }
91
+ // Markdown format
92
+ let markdown = '# Jamf Documentation Products\n\n';
93
+ for (const product of products) {
94
+ markdown += `## ${product.name}\n\n`;
95
+ markdown += `- **ID**: \`${product.id}\`\n`;
96
+ markdown += `- **Description**: ${product.description}\n`;
97
+ markdown += `- **Current Version**: ${product.currentVersion}\n`;
98
+ markdown += `- **Available Versions**: ${product.availableVersions.join(', ')}\n\n`;
99
+ }
100
+ markdown += '---\n\n';
101
+ markdown += '# Available Topics for Filtering\n\n';
102
+ markdown += 'Use these topic IDs with the `topic` parameter in `jamf_docs_search`:\n\n';
103
+ for (const topic of topics) {
104
+ markdown += `- **\`${topic.id}\`**: ${topic.name}\n`;
105
+ markdown += ` *Keywords: ${topic.keywords.slice(0, 4).join(', ')}${topic.keywords.length > 4 ? '...' : ''}*\n`;
106
+ }
107
+ markdown += '\n---\n\n';
108
+ // Token info
109
+ const tokenCount = estimateTokens(markdown);
110
+ markdown += `*${tokenCount.toLocaleString()} tokens*\n\n`;
111
+ markdown += '*Use `jamf_docs_search` to search within these products, ';
112
+ markdown += 'or `jamf_docs_get_toc` to browse the table of contents.*\n';
113
+ return {
114
+ content: [{
115
+ type: 'text',
116
+ text: markdown
117
+ }]
118
+ };
119
+ }
120
+ catch (error) {
121
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
122
+ return {
123
+ isError: true,
124
+ content: [{
125
+ type: 'text',
126
+ text: `Error listing products: ${errorMessage}`
127
+ }]
128
+ };
129
+ }
130
+ });
131
+ }
132
+ //# 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 { 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,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA6DpE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA0J1D"}
@@ -0,0 +1,212 @@
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, JAMF_PRODUCTS, JAMF_TOPICS, TOKEN_CONFIG } from '../constants.js';
7
+ import { searchDocumentation } from '../services/scraper.js';
8
+ const TOOL_NAME = 'jamf_docs_search';
9
+ const TOOL_DESCRIPTION = `Search Jamf documentation for articles matching your query.
10
+
11
+ This tool searches across all Jamf product documentation including Jamf Pro,
12
+ Jamf School, Jamf Connect, and Jamf Protect. Results include article titles,
13
+ snippets, and direct links.
14
+
15
+ Args:
16
+ - query (string, required): Search keywords (2-200 characters)
17
+ - product (string, optional): Filter by product ID (jamf-pro, jamf-school, jamf-connect, jamf-protect)
18
+ - topic (string, optional): Filter by topic (enrollment, profiles, security, inventory, policies, smart-groups, apps, identity, api, network)
19
+ - version (string, optional): Filter by version (e.g., "11.5.0", "10.x")
20
+ - limit (number, optional): Maximum results per page 1-50 (default: 10)
21
+ - page (number, optional): Page number for pagination 1-100 (default: 1)
22
+ - maxTokens (number, optional): Maximum tokens in response 100-20000 (default: 5000)
23
+ - responseFormat ('markdown' | 'json'): Output format (default: 'markdown')
24
+
25
+ Returns:
26
+ For JSON format:
27
+ {
28
+ "total": number,
29
+ "query": string,
30
+ "results": [...],
31
+ "tokenInfo": {
32
+ "tokenCount": number,
33
+ "truncated": boolean,
34
+ "maxTokens": number
35
+ },
36
+ "pagination": {
37
+ "page": number,
38
+ "pageSize": number,
39
+ "totalPages": number,
40
+ "totalItems": number,
41
+ "hasNext": boolean,
42
+ "hasPrev": boolean
43
+ }
44
+ }
45
+
46
+ For Markdown format:
47
+ A formatted list of search results with pagination and token info.
48
+
49
+ Examples:
50
+ - "How to configure SSO" → query="SSO configuration"
51
+ - "MDM enrollment steps" → query="MDM enrollment", topic="enrollment"
52
+ - "Jamf Pro configuration profiles" → query="configuration profile", product="jamf-pro", topic="profiles"
53
+ - Get page 2 of results → query="policy", page=2
54
+
55
+ Errors:
56
+ - "No results found" if search returns empty
57
+ - "Invalid product ID" if product parameter is not recognized
58
+
59
+ Note: Results are ranked by relevance. Use filters and pagination to navigate large result sets.`;
60
+ export function registerSearchTool(server) {
61
+ server.registerTool(TOOL_NAME, {
62
+ title: 'Search Jamf Documentation',
63
+ description: TOOL_DESCRIPTION,
64
+ inputSchema: SearchInputSchema,
65
+ annotations: {
66
+ readOnlyHint: true,
67
+ destructiveHint: false,
68
+ idempotentHint: true,
69
+ openWorldHint: true
70
+ }
71
+ }, async (args) => {
72
+ // Parse and validate input
73
+ const parseResult = SearchInputSchema.safeParse(args);
74
+ if (!parseResult.success) {
75
+ return {
76
+ isError: true,
77
+ content: [{ type: 'text', text: `Invalid input: ${parseResult.error.message}` }]
78
+ };
79
+ }
80
+ const params = parseResult.data;
81
+ try {
82
+ // Validate product if provided
83
+ if (params.product && !(params.product in JAMF_PRODUCTS)) {
84
+ return {
85
+ isError: true,
86
+ content: [{
87
+ type: 'text',
88
+ text: `Invalid product ID: "${params.product}". Valid options: ${Object.keys(JAMF_PRODUCTS).join(', ')}`
89
+ }]
90
+ };
91
+ }
92
+ // Validate topic if provided
93
+ if (params.topic && !(params.topic in JAMF_TOPICS)) {
94
+ return {
95
+ isError: true,
96
+ content: [{
97
+ type: 'text',
98
+ text: `Invalid topic ID: "${params.topic}". Valid options: ${Object.keys(JAMF_TOPICS).join(', ')}`
99
+ }]
100
+ };
101
+ }
102
+ // Perform search with new parameters
103
+ const searchResult = await searchDocumentation({
104
+ query: params.query,
105
+ product: params.product,
106
+ topic: params.topic,
107
+ version: params.version,
108
+ limit: params.limit,
109
+ page: params.page,
110
+ maxTokens: params.maxTokens ?? TOKEN_CONFIG.DEFAULT_MAX_TOKENS
111
+ });
112
+ const { results, pagination, tokenInfo } = searchResult;
113
+ // Build response
114
+ const response = {
115
+ total: pagination.totalItems,
116
+ query: params.query,
117
+ results,
118
+ filters: {
119
+ ...(params.product && { product: params.product }),
120
+ ...(params.version && { version: params.version }),
121
+ ...(params.topic && { topic: params.topic })
122
+ },
123
+ tokenInfo,
124
+ pagination
125
+ };
126
+ // Handle no results
127
+ if (results.length === 0 && pagination.totalItems === 0) {
128
+ const filterInfo = [];
129
+ if (params.product) {
130
+ filterInfo.push(`product: ${JAMF_PRODUCTS[params.product].name}`);
131
+ }
132
+ if (params.topic) {
133
+ filterInfo.push(`topic: ${JAMF_TOPICS[params.topic].name}`);
134
+ }
135
+ const filterStr = filterInfo.length > 0 ? ` (filtered by ${filterInfo.join(', ')})` : '';
136
+ return {
137
+ content: [{
138
+ type: 'text',
139
+ text: `No results found for "${params.query}"${filterStr}.\n\nTry:\n- Using different keywords\n- Removing filters\n- Checking spelling`
140
+ }]
141
+ };
142
+ }
143
+ // Format output
144
+ if (params.responseFormat === ResponseFormat.JSON) {
145
+ return {
146
+ content: [{
147
+ type: 'text',
148
+ text: JSON.stringify(response, null, 2)
149
+ }]
150
+ };
151
+ }
152
+ // Markdown format with Context7 style
153
+ let markdown = `# Search Results for "${params.query}"\n\n`;
154
+ markdown += `Found ${pagination.totalItems} result(s) | **Page ${pagination.page} of ${pagination.totalPages}** | ${tokenInfo.tokenCount.toLocaleString()} tokens`;
155
+ if (response.filters?.product || response.filters?.version || response.filters?.topic) {
156
+ const filters = [];
157
+ if (response.filters.product) {
158
+ filters.push(`product: ${response.filters.product}`);
159
+ }
160
+ if (response.filters.topic) {
161
+ filters.push(`topic: ${response.filters.topic}`);
162
+ }
163
+ if (response.filters.version) {
164
+ filters.push(`version: ${response.filters.version}`);
165
+ }
166
+ markdown += `\n*Filtered by: ${filters.join(', ')}*`;
167
+ }
168
+ markdown += '\n\n---\n\n';
169
+ for (const result of results) {
170
+ markdown += `### [${result.title}](${result.url})\n\n`;
171
+ markdown += `> ${result.snippet}\n\n`;
172
+ if (result.product || result.version) {
173
+ const meta = [];
174
+ if (result.product) {
175
+ meta.push(`**Product**: ${result.product}`);
176
+ }
177
+ if (result.version) {
178
+ meta.push(`**Version**: ${result.version}`);
179
+ }
180
+ markdown += `${meta.join(' | ')}\n\n`;
181
+ }
182
+ markdown += '---\n\n';
183
+ }
184
+ // Pagination footer
185
+ markdown += `**Page ${pagination.page} of ${pagination.totalPages}** (${tokenInfo.tokenCount.toLocaleString()} tokens)`;
186
+ if (pagination.hasNext) {
187
+ markdown += ` | Use \`page=${pagination.page + 1}\` for more results`;
188
+ }
189
+ if (tokenInfo.truncated) {
190
+ markdown += '\n*Results truncated due to token limit. Use a smaller `limit` or increase `maxTokens`.*';
191
+ }
192
+ markdown += '\n\n*Use `jamf_docs_get_article` with any URL above to read the full article.*\n';
193
+ return {
194
+ content: [{
195
+ type: 'text',
196
+ text: markdown
197
+ }]
198
+ };
199
+ }
200
+ catch (error) {
201
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
202
+ return {
203
+ isError: true,
204
+ content: [{
205
+ type: 'text',
206
+ text: `Search error: ${errorMessage}\n\nPlease try again or use different search terms.`
207
+ }]
208
+ };
209
+ }
210
+ });
211
+ }
212
+ //# 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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"}