@robinmordasiewicz/f5xc-terraform-mcp 2.14.10 → 2.15.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 +97 -290
- package/dist/docs/data-sources/dns_zone.md +2 -2
- package/dist/docs/resources/api_credential.md +2 -2
- package/dist/docs/resources/child_tenant.md +2 -2
- package/dist/docs/resources/dns_zone.md +443 -306
- package/dist/index.d.ts +14 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +83 -1058
- package/dist/index.js.map +1 -1
- package/dist/schemas/common.d.ts +180 -0
- package/dist/schemas/common.d.ts.map +1 -0
- package/dist/schemas/common.js +230 -0
- package/dist/schemas/common.js.map +1 -0
- package/dist/schemas/index.d.ts +13 -13
- package/dist/tools/addon.d.ts +19 -0
- package/dist/tools/addon.d.ts.map +1 -0
- package/dist/tools/addon.js +219 -0
- package/dist/tools/addon.js.map +1 -0
- package/dist/tools/api.d.ts +20 -0
- package/dist/tools/api.d.ts.map +1 -0
- package/dist/tools/api.js +281 -0
- package/dist/tools/api.js.map +1 -0
- package/dist/tools/discover.d.ts +18 -0
- package/dist/tools/discover.d.ts.map +1 -0
- package/dist/tools/discover.js +190 -0
- package/dist/tools/discover.js.map +1 -0
- package/dist/tools/docs.d.ts +18 -0
- package/dist/tools/docs.d.ts.map +1 -0
- package/dist/tools/docs.js +158 -0
- package/dist/tools/docs.js.map +1 -0
- package/dist/tools/subscription.d.ts +18 -0
- package/dist/tools/subscription.d.ts.map +1 -0
- package/dist/tools/subscription.js +225 -0
- package/dist/tools/subscription.js.map +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,12 +2,20 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* F5 Distributed Cloud Terraform Provider MCP Server
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* -
|
|
9
|
-
* -
|
|
10
|
-
* -
|
|
5
|
+
* Token-optimized MCP server with consolidated tools for AI assistants.
|
|
6
|
+
*
|
|
7
|
+
* This MCP server provides:
|
|
8
|
+
* - Tool discovery meta-tool for lazy loading
|
|
9
|
+
* - Consolidated documentation tool (search/get/list)
|
|
10
|
+
* - Consolidated API specification tool (search/get/endpoints/definitions)
|
|
11
|
+
* - Consolidated subscription tier tool
|
|
12
|
+
* - Consolidated addon service tool
|
|
13
|
+
* - Provider summary tool
|
|
14
|
+
*
|
|
15
|
+
* Token Optimization:
|
|
16
|
+
* - 14 tools consolidated to 6 tools (~77% token reduction)
|
|
17
|
+
* - Optimized descriptions using shared parameter descriptions
|
|
18
|
+
* - Discovery meta-tool enables lazy schema loading
|
|
11
19
|
*
|
|
12
20
|
* Version Synchronization:
|
|
13
21
|
* The npm package version is automatically synced with GitHub releases via CI/CD.
|
|
@@ -24,10 +32,18 @@ const require = createRequire(import.meta.url);
|
|
|
24
32
|
const packageJson = require('../package.json');
|
|
25
33
|
const VERSION = packageJson.version;
|
|
26
34
|
import { ResponseFormat } from './types.js';
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
|
|
30
|
-
import {
|
|
35
|
+
import { getDocumentationSummary } from './services/documentation.js';
|
|
36
|
+
import { getApiSpecsSummary } from './services/api-specs.js';
|
|
37
|
+
// Consolidated tool handlers
|
|
38
|
+
import { handleDiscover, DISCOVER_TOOL_DEFINITION } from './tools/discover.js';
|
|
39
|
+
import { handleDocs, DOCS_TOOL_DEFINITION } from './tools/docs.js';
|
|
40
|
+
import { handleApi, API_TOOL_DEFINITION } from './tools/api.js';
|
|
41
|
+
import { handleSubscription, SUBSCRIPTION_TOOL_DEFINITION } from './tools/subscription.js';
|
|
42
|
+
import { handleAddon, ADDON_TOOL_DEFINITION } from './tools/addon.js';
|
|
43
|
+
// Consolidated schemas
|
|
44
|
+
import { DiscoverSchema, DocsSchema, ApiSchema, SubscriptionSchema, AddonSchema, } from './schemas/common.js';
|
|
45
|
+
// Legacy schemas for get_summary tool
|
|
46
|
+
import { GetSummarySchema } from './schemas/index.js';
|
|
31
47
|
// Constants
|
|
32
48
|
const CHARACTER_LIMIT = 50000; // Maximum response size
|
|
33
49
|
// Create MCP server instance
|
|
@@ -36,29 +52,12 @@ const server = new McpServer({
|
|
|
36
52
|
version: VERSION,
|
|
37
53
|
});
|
|
38
54
|
// =============================================================================
|
|
39
|
-
//
|
|
55
|
+
// TOOL 1: DISCOVERY META-TOOL (NEW)
|
|
40
56
|
// =============================================================================
|
|
41
|
-
server.registerTool(
|
|
42
|
-
title: '
|
|
43
|
-
description:
|
|
44
|
-
|
|
45
|
-
Searches across all resource documentation, data sources, functions, and guides
|
|
46
|
-
to find relevant information about configuring F5XC resources with Terraform.
|
|
47
|
-
|
|
48
|
-
Args:
|
|
49
|
-
- query (string): Search terms (resource names, attributes, descriptions)
|
|
50
|
-
- type (optional): Filter by 'resource', 'data-source', 'function', or 'guide'
|
|
51
|
-
- limit (number): Maximum results (default: 20, max: 50)
|
|
52
|
-
- response_format: 'markdown' or 'json'
|
|
53
|
-
|
|
54
|
-
Returns:
|
|
55
|
-
List of matching documentation with relevance scores and snippets.
|
|
56
|
-
|
|
57
|
-
Examples:
|
|
58
|
-
- "http_loadbalancer" -> Find HTTP load balancer documentation
|
|
59
|
-
- "origin pool" -> Find origin pool related docs
|
|
60
|
-
- "waf" -> Find Web Application Firewall docs`,
|
|
61
|
-
inputSchema: SearchDocsSchema,
|
|
57
|
+
server.registerTool(DISCOVER_TOOL_DEFINITION.name, {
|
|
58
|
+
title: 'Discover F5XC Terraform Tools',
|
|
59
|
+
description: DISCOVER_TOOL_DEFINITION.description,
|
|
60
|
+
inputSchema: DiscoverSchema,
|
|
62
61
|
annotations: {
|
|
63
62
|
readOnlyHint: true,
|
|
64
63
|
destructiveHint: false,
|
|
@@ -66,73 +65,18 @@ Examples:
|
|
|
66
65
|
openWorldHint: false,
|
|
67
66
|
},
|
|
68
67
|
}, async (params) => {
|
|
69
|
-
const
|
|
70
|
-
if (results.length === 0) {
|
|
71
|
-
return {
|
|
72
|
-
content: [{
|
|
73
|
-
type: 'text',
|
|
74
|
-
text: `No documentation found matching "${params.query}"`,
|
|
75
|
-
}],
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
const output = {
|
|
79
|
-
query: params.query,
|
|
80
|
-
total: results.length,
|
|
81
|
-
results: results.map(r => ({
|
|
82
|
-
name: r.name,
|
|
83
|
-
type: r.type,
|
|
84
|
-
score: r.score,
|
|
85
|
-
snippet: r.snippet,
|
|
86
|
-
})),
|
|
87
|
-
};
|
|
88
|
-
let textContent;
|
|
89
|
-
if (params.response_format === ResponseFormat.MARKDOWN) {
|
|
90
|
-
const lines = [
|
|
91
|
-
`# Documentation Search Results: "${params.query}"`,
|
|
92
|
-
'',
|
|
93
|
-
`Found ${results.length} results:`,
|
|
94
|
-
'',
|
|
95
|
-
];
|
|
96
|
-
for (const result of results) {
|
|
97
|
-
lines.push(`## ${result.name} (${result.type})`);
|
|
98
|
-
lines.push(`Score: ${result.score}`);
|
|
99
|
-
lines.push(result.snippet);
|
|
100
|
-
lines.push('');
|
|
101
|
-
}
|
|
102
|
-
textContent = lines.join('\n');
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
textContent = JSON.stringify(output, null, 2);
|
|
106
|
-
}
|
|
68
|
+
const result = await handleDiscover(params);
|
|
107
69
|
return {
|
|
108
|
-
content: [{ type: 'text', text:
|
|
109
|
-
structuredContent: output,
|
|
70
|
+
content: [{ type: 'text', text: result }],
|
|
110
71
|
};
|
|
111
72
|
});
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
- Attribute reference (computed/read-only attributes)
|
|
120
|
-
- Import instructions
|
|
121
|
-
- Example configurations
|
|
122
|
-
|
|
123
|
-
Args:
|
|
124
|
-
- name (string): Resource name (e.g., "http_loadbalancer", "namespace", "origin_pool")
|
|
125
|
-
- type (optional): 'resource', 'data-source', 'function', or 'guide'
|
|
126
|
-
- response_format: 'markdown' or 'json'
|
|
127
|
-
|
|
128
|
-
Returns:
|
|
129
|
-
Complete documentation content.
|
|
130
|
-
|
|
131
|
-
Examples:
|
|
132
|
-
- name="http_loadbalancer" -> HTTP Load Balancer resource docs
|
|
133
|
-
- name="app_firewall" -> Application Firewall (WAF) docs
|
|
134
|
-
- name="blindfold", type="function" -> Blindfold encryption function docs`,
|
|
135
|
-
inputSchema: GetDocSchema,
|
|
73
|
+
// =============================================================================
|
|
74
|
+
// TOOL 2: CONSOLIDATED DOCUMENTATION TOOL
|
|
75
|
+
// =============================================================================
|
|
76
|
+
server.registerTool(DOCS_TOOL_DEFINITION.name, {
|
|
77
|
+
title: 'F5XC Terraform Documentation',
|
|
78
|
+
description: DOCS_TOOL_DEFINITION.description,
|
|
79
|
+
inputSchema: DocsSchema,
|
|
136
80
|
annotations: {
|
|
137
81
|
readOnlyHint: true,
|
|
138
82
|
destructiveHint: false,
|
|
@@ -140,119 +84,23 @@ Examples:
|
|
|
140
84
|
openWorldHint: false,
|
|
141
85
|
},
|
|
142
86
|
}, async (params) => {
|
|
143
|
-
const
|
|
144
|
-
if (!doc) {
|
|
145
|
-
return {
|
|
146
|
-
content: [{
|
|
147
|
-
type: 'text',
|
|
148
|
-
text: `Documentation not found for "${params.name}"${params.type ? ` (type: ${params.type})` : ''}. Use f5xc_terraform_search_docs to find available documentation.`,
|
|
149
|
-
}],
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
const output = {
|
|
153
|
-
name: doc.name,
|
|
154
|
-
type: doc.type,
|
|
155
|
-
path: doc.path,
|
|
156
|
-
content: doc.content,
|
|
157
|
-
};
|
|
158
|
-
let textContent;
|
|
159
|
-
if (params.response_format === ResponseFormat.MARKDOWN) {
|
|
160
|
-
textContent = doc.content || `# ${doc.name}\n\nNo content available.`;
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
textContent = JSON.stringify(output, null, 2);
|
|
164
|
-
}
|
|
87
|
+
const result = await handleDocs(params);
|
|
165
88
|
// Truncate if too long
|
|
89
|
+
let textContent = result;
|
|
166
90
|
if (textContent.length > CHARACTER_LIMIT) {
|
|
167
91
|
textContent = textContent.slice(0, CHARACTER_LIMIT) + '\n\n... (truncated)';
|
|
168
92
|
}
|
|
169
93
|
return {
|
|
170
94
|
content: [{ type: 'text', text: textContent }],
|
|
171
|
-
structuredContent: output,
|
|
172
|
-
};
|
|
173
|
-
});
|
|
174
|
-
server.registerTool('f5xc_terraform_list_docs', {
|
|
175
|
-
title: 'List F5XC Documentation',
|
|
176
|
-
description: `List all available F5 Distributed Cloud Terraform provider documentation.
|
|
177
|
-
|
|
178
|
-
Lists all resources, data sources, functions, and guides available in the provider.
|
|
179
|
-
|
|
180
|
-
Args:
|
|
181
|
-
- type (optional): Filter by 'resource', 'data-source', 'function', or 'guide'
|
|
182
|
-
- response_format: 'markdown' or 'json'
|
|
183
|
-
|
|
184
|
-
Returns:
|
|
185
|
-
List of all available documentation items.`,
|
|
186
|
-
inputSchema: ListDocsSchema,
|
|
187
|
-
annotations: {
|
|
188
|
-
readOnlyHint: true,
|
|
189
|
-
destructiveHint: false,
|
|
190
|
-
idempotentHint: true,
|
|
191
|
-
openWorldHint: false,
|
|
192
|
-
},
|
|
193
|
-
}, async (params) => {
|
|
194
|
-
const docs = listDocumentation(params.type);
|
|
195
|
-
const output = {
|
|
196
|
-
total: docs.length,
|
|
197
|
-
type_filter: params.type || 'all',
|
|
198
|
-
items: docs.map(d => ({
|
|
199
|
-
name: d.name,
|
|
200
|
-
type: d.type,
|
|
201
|
-
})),
|
|
202
|
-
};
|
|
203
|
-
let textContent;
|
|
204
|
-
if (params.response_format === ResponseFormat.MARKDOWN) {
|
|
205
|
-
const lines = [
|
|
206
|
-
`# F5XC Terraform Documentation`,
|
|
207
|
-
'',
|
|
208
|
-
`Total: ${docs.length} items${params.type ? ` (filtered: ${params.type})` : ''}`,
|
|
209
|
-
'',
|
|
210
|
-
];
|
|
211
|
-
// Group by type
|
|
212
|
-
const byType = {};
|
|
213
|
-
for (const doc of docs) {
|
|
214
|
-
if (!byType[doc.type])
|
|
215
|
-
byType[doc.type] = [];
|
|
216
|
-
byType[doc.type].push(doc.name);
|
|
217
|
-
}
|
|
218
|
-
for (const [type, names] of Object.entries(byType)) {
|
|
219
|
-
lines.push(`## ${type}s (${names.length})`);
|
|
220
|
-
lines.push(names.sort().join(', '));
|
|
221
|
-
lines.push('');
|
|
222
|
-
}
|
|
223
|
-
textContent = lines.join('\n');
|
|
224
|
-
}
|
|
225
|
-
else {
|
|
226
|
-
textContent = JSON.stringify(output, null, 2);
|
|
227
|
-
}
|
|
228
|
-
return {
|
|
229
|
-
content: [{ type: 'text', text: textContent }],
|
|
230
|
-
structuredContent: output,
|
|
231
95
|
};
|
|
232
96
|
});
|
|
233
97
|
// =============================================================================
|
|
234
|
-
// API
|
|
98
|
+
// TOOL 3: CONSOLIDATED API TOOL
|
|
235
99
|
// =============================================================================
|
|
236
|
-
server.registerTool(
|
|
237
|
-
title: '
|
|
238
|
-
description:
|
|
239
|
-
|
|
240
|
-
The provider includes 270+ OpenAPI specs covering all F5XC API endpoints.
|
|
241
|
-
Use this to find API specifications for specific services or operations.
|
|
242
|
-
|
|
243
|
-
Args:
|
|
244
|
-
- query (string): Search terms (schema names, service names)
|
|
245
|
-
- limit (number): Maximum results (default: 20, max: 50)
|
|
246
|
-
- response_format: 'markdown' or 'json'
|
|
247
|
-
|
|
248
|
-
Returns:
|
|
249
|
-
List of matching API specifications with titles and descriptions.
|
|
250
|
-
|
|
251
|
-
Examples:
|
|
252
|
-
- "http_loadbalancer" -> Find HTTP LB API spec
|
|
253
|
-
- "namespace" -> Find namespace management API
|
|
254
|
-
- "waf" or "app_firewall" -> Find WAF API specs`,
|
|
255
|
-
inputSchema: SearchApiSpecsSchema,
|
|
100
|
+
server.registerTool(API_TOOL_DEFINITION.name, {
|
|
101
|
+
title: 'F5XC OpenAPI Specifications',
|
|
102
|
+
description: API_TOOL_DEFINITION.description,
|
|
103
|
+
inputSchema: ApiSchema,
|
|
256
104
|
annotations: {
|
|
257
105
|
readOnlyHint: true,
|
|
258
106
|
destructiveHint: false,
|
|
@@ -260,170 +108,25 @@ Examples:
|
|
|
260
108
|
openWorldHint: false,
|
|
261
109
|
},
|
|
262
110
|
}, async (params) => {
|
|
263
|
-
const
|
|
264
|
-
if (results.length === 0) {
|
|
265
|
-
return {
|
|
266
|
-
content: [{
|
|
267
|
-
type: 'text',
|
|
268
|
-
text: `No API specifications found matching "${params.query}"`,
|
|
269
|
-
}],
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
const output = {
|
|
273
|
-
query: params.query,
|
|
274
|
-
total: results.length,
|
|
275
|
-
results: results.map(r => ({
|
|
276
|
-
name: r.name,
|
|
277
|
-
snippet: r.snippet,
|
|
278
|
-
score: r.score,
|
|
279
|
-
})),
|
|
280
|
-
};
|
|
281
|
-
let textContent;
|
|
282
|
-
if (params.response_format === ResponseFormat.MARKDOWN) {
|
|
283
|
-
const lines = [
|
|
284
|
-
`# API Specification Search: "${params.query}"`,
|
|
285
|
-
'',
|
|
286
|
-
`Found ${results.length} specifications:`,
|
|
287
|
-
'',
|
|
288
|
-
];
|
|
289
|
-
for (const result of results) {
|
|
290
|
-
lines.push(`## ${result.name}`);
|
|
291
|
-
lines.push(result.snippet);
|
|
292
|
-
lines.push('');
|
|
293
|
-
}
|
|
294
|
-
textContent = lines.join('\n');
|
|
295
|
-
}
|
|
296
|
-
else {
|
|
297
|
-
textContent = JSON.stringify(output, null, 2);
|
|
298
|
-
}
|
|
299
|
-
return {
|
|
300
|
-
content: [{ type: 'text', text: textContent }],
|
|
301
|
-
structuredContent: output,
|
|
302
|
-
};
|
|
303
|
-
});
|
|
304
|
-
server.registerTool('f5xc_terraform_get_api_spec', {
|
|
305
|
-
title: 'Get F5XC API Specification',
|
|
306
|
-
description: `Get a specific F5 Distributed Cloud OpenAPI specification.
|
|
307
|
-
|
|
308
|
-
Retrieves the complete OpenAPI spec including:
|
|
309
|
-
- API info and description
|
|
310
|
-
- Available endpoints and methods
|
|
311
|
-
- Request/response schemas
|
|
312
|
-
- Authentication requirements
|
|
313
|
-
|
|
314
|
-
Args:
|
|
315
|
-
- name (string): Spec name (e.g., "http_loadbalancer", "namespace", "app_firewall")
|
|
316
|
-
- include_paths (boolean): Include endpoint paths (default: true)
|
|
317
|
-
- include_definitions (boolean): Include schema definitions (default: false, can be large)
|
|
318
|
-
- response_format: 'markdown' or 'json'
|
|
319
|
-
|
|
320
|
-
Returns:
|
|
321
|
-
OpenAPI specification content.`,
|
|
322
|
-
inputSchema: GetApiSpecSchema,
|
|
323
|
-
annotations: {
|
|
324
|
-
readOnlyHint: true,
|
|
325
|
-
destructiveHint: false,
|
|
326
|
-
idempotentHint: true,
|
|
327
|
-
openWorldHint: false,
|
|
328
|
-
},
|
|
329
|
-
}, async (params) => {
|
|
330
|
-
const spec = getApiSpec(params.name);
|
|
331
|
-
if (!spec?.content) {
|
|
332
|
-
return {
|
|
333
|
-
content: [{
|
|
334
|
-
type: 'text',
|
|
335
|
-
text: `API specification not found for "${params.name}". Use f5xc_terraform_search_api_specs to find available specs.`,
|
|
336
|
-
}],
|
|
337
|
-
};
|
|
338
|
-
}
|
|
339
|
-
const content = spec.content;
|
|
340
|
-
const output = {
|
|
341
|
-
name: spec.schemaName,
|
|
342
|
-
info: content.info,
|
|
343
|
-
};
|
|
344
|
-
if (params.include_paths && content.paths) {
|
|
345
|
-
output.paths = Object.keys(content.paths).map(path => {
|
|
346
|
-
const pathItem = content.paths[path];
|
|
347
|
-
const methods = [];
|
|
348
|
-
if (pathItem.get)
|
|
349
|
-
methods.push('GET');
|
|
350
|
-
if (pathItem.post)
|
|
351
|
-
methods.push('POST');
|
|
352
|
-
if (pathItem.put)
|
|
353
|
-
methods.push('PUT');
|
|
354
|
-
if (pathItem.delete)
|
|
355
|
-
methods.push('DELETE');
|
|
356
|
-
if (pathItem.patch)
|
|
357
|
-
methods.push('PATCH');
|
|
358
|
-
return { path, methods };
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
if (params.include_definitions) {
|
|
362
|
-
output.definitions = content.definitions || content.components?.schemas || {};
|
|
363
|
-
}
|
|
364
|
-
let textContent;
|
|
365
|
-
if (params.response_format === ResponseFormat.MARKDOWN) {
|
|
366
|
-
const lines = [
|
|
367
|
-
`# ${content.info?.title || spec.schemaName}`,
|
|
368
|
-
'',
|
|
369
|
-
content.info?.description || '',
|
|
370
|
-
'',
|
|
371
|
-
`**Version**: ${content.info?.version || 'N/A'}`,
|
|
372
|
-
'',
|
|
373
|
-
];
|
|
374
|
-
if (params.include_paths && content.paths) {
|
|
375
|
-
lines.push('## Endpoints');
|
|
376
|
-
lines.push('');
|
|
377
|
-
for (const [path, pathItem] of Object.entries(content.paths)) {
|
|
378
|
-
const methods = [];
|
|
379
|
-
if (pathItem.get)
|
|
380
|
-
methods.push('GET');
|
|
381
|
-
if (pathItem.post)
|
|
382
|
-
methods.push('POST');
|
|
383
|
-
if (pathItem.put)
|
|
384
|
-
methods.push('PUT');
|
|
385
|
-
if (pathItem.delete)
|
|
386
|
-
methods.push('DELETE');
|
|
387
|
-
if (pathItem.patch)
|
|
388
|
-
methods.push('PATCH');
|
|
389
|
-
lines.push(`- \`${methods.join('|')} ${path}\``);
|
|
390
|
-
}
|
|
391
|
-
lines.push('');
|
|
392
|
-
}
|
|
393
|
-
textContent = lines.join('\n');
|
|
394
|
-
}
|
|
395
|
-
else {
|
|
396
|
-
textContent = JSON.stringify(output, null, 2);
|
|
397
|
-
}
|
|
111
|
+
const result = await handleApi(params);
|
|
398
112
|
// Truncate if too long
|
|
113
|
+
let textContent = result;
|
|
399
114
|
if (textContent.length > CHARACTER_LIMIT) {
|
|
400
|
-
textContent =
|
|
115
|
+
textContent =
|
|
116
|
+
textContent.slice(0, CHARACTER_LIMIT) +
|
|
117
|
+
'\n\n... (truncated, use include_definitions=false for smaller response)';
|
|
401
118
|
}
|
|
402
119
|
return {
|
|
403
120
|
content: [{ type: 'text', text: textContent }],
|
|
404
|
-
structuredContent: output,
|
|
405
121
|
};
|
|
406
122
|
});
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
Args:
|
|
415
|
-
- pattern (string): URL pattern to search (e.g., "/namespaces", "http_loadbalancer")
|
|
416
|
-
- method (optional): Filter by HTTP method (GET, POST, PUT, DELETE, PATCH)
|
|
417
|
-
- limit (number): Maximum results (default: 20, max: 100)
|
|
418
|
-
- response_format: 'markdown' or 'json'
|
|
419
|
-
|
|
420
|
-
Returns:
|
|
421
|
-
List of matching endpoints with spec name, path, method, and description.
|
|
422
|
-
|
|
423
|
-
Examples:
|
|
424
|
-
- pattern="/namespaces" -> All namespace-related endpoints
|
|
425
|
-
- pattern="config", method="POST" -> POST endpoints for configuration`,
|
|
426
|
-
inputSchema: FindEndpointsSchema,
|
|
123
|
+
// =============================================================================
|
|
124
|
+
// TOOL 4: CONSOLIDATED SUBSCRIPTION TOOL
|
|
125
|
+
// =============================================================================
|
|
126
|
+
server.registerTool(SUBSCRIPTION_TOOL_DEFINITION.name, {
|
|
127
|
+
title: 'F5XC Subscription Tiers',
|
|
128
|
+
description: SUBSCRIPTION_TOOL_DEFINITION.description,
|
|
129
|
+
inputSchema: SubscriptionSchema,
|
|
427
130
|
annotations: {
|
|
428
131
|
readOnlyHint: true,
|
|
429
132
|
destructiveHint: false,
|
|
@@ -431,63 +134,18 @@ Examples:
|
|
|
431
134
|
openWorldHint: false,
|
|
432
135
|
},
|
|
433
136
|
}, async (params) => {
|
|
434
|
-
const
|
|
435
|
-
if (endpoints.length === 0) {
|
|
436
|
-
return {
|
|
437
|
-
content: [{
|
|
438
|
-
type: 'text',
|
|
439
|
-
text: `No endpoints found matching pattern "${params.pattern}"${params.method ? ` with method ${params.method}` : ''}`,
|
|
440
|
-
}],
|
|
441
|
-
};
|
|
442
|
-
}
|
|
443
|
-
const output = {
|
|
444
|
-
pattern: params.pattern,
|
|
445
|
-
method_filter: params.method || 'all',
|
|
446
|
-
total: endpoints.length,
|
|
447
|
-
endpoints,
|
|
448
|
-
};
|
|
449
|
-
let textContent;
|
|
450
|
-
if (params.response_format === ResponseFormat.MARKDOWN) {
|
|
451
|
-
const lines = [
|
|
452
|
-
`# API Endpoints: "${params.pattern}"`,
|
|
453
|
-
'',
|
|
454
|
-
`Found ${endpoints.length} endpoints:`,
|
|
455
|
-
'',
|
|
456
|
-
];
|
|
457
|
-
for (const ep of endpoints) {
|
|
458
|
-
lines.push(`## ${ep.method} ${ep.path}`);
|
|
459
|
-
lines.push(`**Spec**: ${ep.specName}`);
|
|
460
|
-
if (ep.summary)
|
|
461
|
-
lines.push(`**Summary**: ${ep.summary}`);
|
|
462
|
-
if (ep.operationId)
|
|
463
|
-
lines.push(`**Operation ID**: ${ep.operationId}`);
|
|
464
|
-
lines.push('');
|
|
465
|
-
}
|
|
466
|
-
textContent = lines.join('\n');
|
|
467
|
-
}
|
|
468
|
-
else {
|
|
469
|
-
textContent = JSON.stringify(output, null, 2);
|
|
470
|
-
}
|
|
137
|
+
const result = await handleSubscription(params);
|
|
471
138
|
return {
|
|
472
|
-
content: [{ type: 'text', text:
|
|
473
|
-
structuredContent: output,
|
|
139
|
+
content: [{ type: 'text', text: result }],
|
|
474
140
|
};
|
|
475
141
|
});
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
Args:
|
|
484
|
-
- spec_name (string): Name of the API spec
|
|
485
|
-
- definition_name (string): Name of the schema definition
|
|
486
|
-
- response_format: 'markdown' or 'json'
|
|
487
|
-
|
|
488
|
-
Returns:
|
|
489
|
-
JSON schema definition with properties, types, and descriptions.`,
|
|
490
|
-
inputSchema: GetSchemaDefSchema,
|
|
142
|
+
// =============================================================================
|
|
143
|
+
// TOOL 5: CONSOLIDATED ADDON TOOL
|
|
144
|
+
// =============================================================================
|
|
145
|
+
server.registerTool(ADDON_TOOL_DEFINITION.name, {
|
|
146
|
+
title: 'F5XC Addon Services',
|
|
147
|
+
description: ADDON_TOOL_DEFINITION.description,
|
|
148
|
+
inputSchema: AddonSchema,
|
|
491
149
|
annotations: {
|
|
492
150
|
readOnlyHint: true,
|
|
493
151
|
destructiveHint: false,
|
|
@@ -495,118 +153,22 @@ Returns:
|
|
|
495
153
|
openWorldHint: false,
|
|
496
154
|
},
|
|
497
155
|
}, async (params) => {
|
|
498
|
-
const
|
|
499
|
-
if (!definition) {
|
|
500
|
-
return {
|
|
501
|
-
content: [{
|
|
502
|
-
type: 'text',
|
|
503
|
-
text: `Schema definition "${params.definition_name}" not found in spec "${params.spec_name}". Use f5xc_terraform_list_definitions to see available definitions.`,
|
|
504
|
-
}],
|
|
505
|
-
};
|
|
506
|
-
}
|
|
507
|
-
const output = {
|
|
508
|
-
spec_name: params.spec_name,
|
|
509
|
-
definition_name: params.definition_name,
|
|
510
|
-
schema: definition,
|
|
511
|
-
};
|
|
512
|
-
let textContent;
|
|
513
|
-
if (params.response_format === ResponseFormat.MARKDOWN) {
|
|
514
|
-
const lines = [
|
|
515
|
-
`# Schema: ${params.definition_name}`,
|
|
516
|
-
'',
|
|
517
|
-
`**Spec**: ${params.spec_name}`,
|
|
518
|
-
'',
|
|
519
|
-
'```json',
|
|
520
|
-
JSON.stringify(definition, null, 2),
|
|
521
|
-
'```',
|
|
522
|
-
];
|
|
523
|
-
textContent = lines.join('\n');
|
|
524
|
-
}
|
|
525
|
-
else {
|
|
526
|
-
textContent = JSON.stringify(output, null, 2);
|
|
527
|
-
}
|
|
156
|
+
const result = await handleAddon(params);
|
|
528
157
|
// Truncate if too long
|
|
158
|
+
let textContent = result;
|
|
529
159
|
if (textContent.length > CHARACTER_LIMIT) {
|
|
530
160
|
textContent = textContent.slice(0, CHARACTER_LIMIT) + '\n\n... (truncated)';
|
|
531
161
|
}
|
|
532
162
|
return {
|
|
533
163
|
content: [{ type: 'text', text: textContent }],
|
|
534
|
-
structuredContent: output,
|
|
535
|
-
};
|
|
536
|
-
});
|
|
537
|
-
server.registerTool('f5xc_terraform_list_definitions', {
|
|
538
|
-
title: 'List API Schema Definitions',
|
|
539
|
-
description: `List all schema definitions in an F5XC OpenAPI spec.
|
|
540
|
-
|
|
541
|
-
Lists the names of all type definitions available in a specification,
|
|
542
|
-
useful for discovering what schemas are available to query.
|
|
543
|
-
|
|
544
|
-
Args:
|
|
545
|
-
- spec_name (string): Name of the API spec
|
|
546
|
-
- response_format: 'markdown' or 'json'
|
|
547
|
-
|
|
548
|
-
Returns:
|
|
549
|
-
List of definition names in the spec.`,
|
|
550
|
-
inputSchema: ListDefinitionsSchema,
|
|
551
|
-
annotations: {
|
|
552
|
-
readOnlyHint: true,
|
|
553
|
-
destructiveHint: false,
|
|
554
|
-
idempotentHint: true,
|
|
555
|
-
openWorldHint: false,
|
|
556
|
-
},
|
|
557
|
-
}, async (params) => {
|
|
558
|
-
const definitions = listDefinitions(params.spec_name);
|
|
559
|
-
if (definitions.length === 0) {
|
|
560
|
-
return {
|
|
561
|
-
content: [{
|
|
562
|
-
type: 'text',
|
|
563
|
-
text: `No definitions found in spec "${params.spec_name}". Use f5xc_terraform_search_api_specs to find available specs.`,
|
|
564
|
-
}],
|
|
565
|
-
};
|
|
566
|
-
}
|
|
567
|
-
const output = {
|
|
568
|
-
spec_name: params.spec_name,
|
|
569
|
-
total: definitions.length,
|
|
570
|
-
definitions,
|
|
571
|
-
};
|
|
572
|
-
let textContent;
|
|
573
|
-
if (params.response_format === ResponseFormat.MARKDOWN) {
|
|
574
|
-
const lines = [
|
|
575
|
-
`# Schema Definitions: ${params.spec_name}`,
|
|
576
|
-
'',
|
|
577
|
-
`Total: ${definitions.length} definitions`,
|
|
578
|
-
'',
|
|
579
|
-
definitions.sort().join(', '),
|
|
580
|
-
];
|
|
581
|
-
textContent = lines.join('\n');
|
|
582
|
-
}
|
|
583
|
-
else {
|
|
584
|
-
textContent = JSON.stringify(output, null, 2);
|
|
585
|
-
}
|
|
586
|
-
return {
|
|
587
|
-
content: [{ type: 'text', text: textContent }],
|
|
588
|
-
structuredContent: output,
|
|
589
164
|
};
|
|
590
165
|
});
|
|
591
166
|
// =============================================================================
|
|
592
|
-
// SUMMARY TOOL
|
|
167
|
+
// TOOL 6: SUMMARY TOOL (KEEP AS-IS)
|
|
593
168
|
// =============================================================================
|
|
594
169
|
server.registerTool('f5xc_terraform_get_summary', {
|
|
595
|
-
title: '
|
|
596
|
-
description:
|
|
597
|
-
|
|
598
|
-
Provides an overview of:
|
|
599
|
-
- Total number of resources, data sources, functions, and guides
|
|
600
|
-
- Total number of API specifications
|
|
601
|
-
- Categories and counts
|
|
602
|
-
|
|
603
|
-
Useful as a starting point to understand what's available.
|
|
604
|
-
|
|
605
|
-
Args:
|
|
606
|
-
- response_format: 'markdown' or 'json'
|
|
607
|
-
|
|
608
|
-
Returns:
|
|
609
|
-
Summary statistics of all documentation and API specs.`,
|
|
170
|
+
title: 'F5XC Provider Summary',
|
|
171
|
+
description: 'Get provider documentation and API specs summary',
|
|
610
172
|
inputSchema: GetSummarySchema,
|
|
611
173
|
annotations: {
|
|
612
174
|
readOnlyHint: true,
|
|
@@ -645,448 +207,16 @@ Returns:
|
|
|
645
207
|
lines.push('');
|
|
646
208
|
lines.push(`Total: ${apiSummary.total} OpenAPI specs`);
|
|
647
209
|
lines.push('');
|
|
648
|
-
lines.push('
|
|
210
|
+
lines.push('## Available Tools (Token-Optimized)');
|
|
649
211
|
lines.push('');
|
|
650
|
-
lines.push('- `
|
|
651
|
-
lines.push('- `
|
|
652
|
-
lines.push('- `
|
|
653
|
-
lines.push('- `
|
|
654
|
-
lines.push('- `
|
|
655
|
-
lines.push('- `
|
|
656
|
-
lines.push('- `f5xc_terraform_get_schema_definition` - Get schema definition');
|
|
657
|
-
lines.push('- `f5xc_terraform_list_definitions` - List definitions in a spec');
|
|
658
|
-
lines.push('- `f5xc_terraform_get_subscription_info` - Check resource subscription tier requirements');
|
|
659
|
-
lines.push('- `f5xc_terraform_get_property_subscription_info` - Check property-level subscription tier requirements');
|
|
660
|
-
lines.push('- `f5xc_terraform_addon_list_services` - List all addon services with tier requirements');
|
|
661
|
-
lines.push('- `f5xc_terraform_addon_check_activation` - Check activation requirements for an addon');
|
|
662
|
-
lines.push('- `f5xc_terraform_addon_activation_workflow` - Get detailed activation workflow with Terraform config');
|
|
663
|
-
textContent = lines.join('\n');
|
|
664
|
-
}
|
|
665
|
-
else {
|
|
666
|
-
textContent = JSON.stringify(output, null, 2);
|
|
667
|
-
}
|
|
668
|
-
return {
|
|
669
|
-
content: [{ type: 'text', text: textContent }],
|
|
670
|
-
structuredContent: output,
|
|
671
|
-
};
|
|
672
|
-
});
|
|
673
|
-
// =============================================================================
|
|
674
|
-
// SUBSCRIPTION TIER TOOL
|
|
675
|
-
// =============================================================================
|
|
676
|
-
server.registerTool('f5xc_terraform_get_subscription_info', {
|
|
677
|
-
title: 'Get F5XC Subscription Tier Info',
|
|
678
|
-
description: `Get subscription tier requirements for F5 Distributed Cloud resources.
|
|
679
|
-
|
|
680
|
-
Returns information about which resources require an Advanced subscription tier.
|
|
681
|
-
Only Standard and Advanced subscription tiers are available.
|
|
682
|
-
Resources not requiring Advanced are available with Standard subscription.
|
|
683
|
-
|
|
684
|
-
Args:
|
|
685
|
-
- resource (optional): Specific resource name to check
|
|
686
|
-
- tier (optional): Filter by 'STANDARD' or 'ADVANCED'
|
|
687
|
-
- response_format: 'markdown' or 'json'
|
|
688
|
-
|
|
689
|
-
Returns:
|
|
690
|
-
- For specific resource: Tier requirement and any Advanced-only features
|
|
691
|
-
- For no resource specified: List of all resources requiring Advanced tier
|
|
692
|
-
|
|
693
|
-
Examples:
|
|
694
|
-
- resource="http_loadbalancer" -> Shows features requiring Advanced
|
|
695
|
-
- tier="ADVANCED" -> Lists all resources requiring Advanced subscription
|
|
696
|
-
- No args -> Summary of Advanced tier requirements`,
|
|
697
|
-
inputSchema: GetSubscriptionInfoSchema,
|
|
698
|
-
annotations: {
|
|
699
|
-
readOnlyHint: true,
|
|
700
|
-
destructiveHint: false,
|
|
701
|
-
idempotentHint: true,
|
|
702
|
-
openWorldHint: false,
|
|
703
|
-
},
|
|
704
|
-
}, async (params) => {
|
|
705
|
-
// Query for specific resource
|
|
706
|
-
if (params.resource) {
|
|
707
|
-
const info = getResourceSubscriptionInfo(params.resource);
|
|
708
|
-
if (!info) {
|
|
709
|
-
return {
|
|
710
|
-
content: [{
|
|
711
|
-
type: 'text',
|
|
712
|
-
text: `No subscription information found for resource "${params.resource}". The resource may not exist or may not have tier metadata.`,
|
|
713
|
-
}],
|
|
714
|
-
};
|
|
715
|
-
}
|
|
716
|
-
const output = {
|
|
717
|
-
resource: params.resource,
|
|
718
|
-
tier: info.tier,
|
|
719
|
-
service: info.service,
|
|
720
|
-
requires_advanced: info.requiresAdvanced,
|
|
721
|
-
advanced_features: info.advancedFeatures || [],
|
|
722
|
-
};
|
|
723
|
-
let textContent;
|
|
724
|
-
if (params.response_format === ResponseFormat.MARKDOWN) {
|
|
725
|
-
const lines = [
|
|
726
|
-
`# Subscription Info: ${params.resource}`,
|
|
727
|
-
'',
|
|
728
|
-
`**Minimum Tier**: ${info.tier}`,
|
|
729
|
-
`**Service**: ${info.service}`,
|
|
730
|
-
`**Requires Advanced**: ${info.requiresAdvanced ? 'Yes' : 'No'}`,
|
|
731
|
-
'',
|
|
732
|
-
];
|
|
733
|
-
if (info.advancedFeatures && info.advancedFeatures.length > 0) {
|
|
734
|
-
lines.push('## Features Requiring Advanced Subscription');
|
|
735
|
-
lines.push('');
|
|
736
|
-
for (const feature of info.advancedFeatures) {
|
|
737
|
-
lines.push(`- \`${feature}\``);
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
else if (!info.requiresAdvanced) {
|
|
741
|
-
lines.push('This resource is fully available with a Standard subscription.');
|
|
742
|
-
}
|
|
743
|
-
textContent = lines.join('\n');
|
|
744
|
-
}
|
|
745
|
-
else {
|
|
746
|
-
textContent = JSON.stringify(output, null, 2);
|
|
747
|
-
}
|
|
748
|
-
return {
|
|
749
|
-
content: [{ type: 'text', text: textContent }],
|
|
750
|
-
structuredContent: output,
|
|
751
|
-
};
|
|
752
|
-
}
|
|
753
|
-
// List all Advanced tier resources
|
|
754
|
-
const advancedResources = getAdvancedTierResources();
|
|
755
|
-
const summary = getSubscriptionSummary();
|
|
756
|
-
// Filter by tier if specified
|
|
757
|
-
let filteredResources = advancedResources;
|
|
758
|
-
if (params.tier === 'ADVANCED') {
|
|
759
|
-
filteredResources = advancedResources.filter(r => r.subscriptionTier === 'ADVANCED');
|
|
760
|
-
}
|
|
761
|
-
const output = {
|
|
762
|
-
summary: {
|
|
763
|
-
total_resources: summary.totalResources,
|
|
764
|
-
advanced_only_resources: summary.advancedOnlyResources,
|
|
765
|
-
resources_with_advanced_features: summary.resourcesWithAdvancedFeatures,
|
|
766
|
-
advanced_features: summary.advancedFeaturesList,
|
|
767
|
-
},
|
|
768
|
-
resources: filteredResources.map(r => ({
|
|
769
|
-
name: r.name,
|
|
770
|
-
type: r.type,
|
|
771
|
-
tier: r.subscriptionTier,
|
|
772
|
-
service: r.addonService,
|
|
773
|
-
advanced_features: r.advancedFeatures,
|
|
774
|
-
})),
|
|
775
|
-
};
|
|
776
|
-
let textContent;
|
|
777
|
-
if (params.response_format === ResponseFormat.MARKDOWN) {
|
|
778
|
-
const lines = [
|
|
779
|
-
'# F5XC Subscription Tier Requirements',
|
|
780
|
-
'',
|
|
781
|
-
'## Summary',
|
|
782
|
-
'',
|
|
783
|
-
`- **Total Resources**: ${summary.totalResources}`,
|
|
784
|
-
`- **Resources Requiring Advanced**: ${summary.advancedOnlyResources}`,
|
|
785
|
-
`- **Resources with Advanced Features**: ${summary.resourcesWithAdvancedFeatures}`,
|
|
786
|
-
'',
|
|
787
|
-
];
|
|
788
|
-
if (filteredResources.length > 0) {
|
|
789
|
-
lines.push('## Resources Requiring Advanced Subscription');
|
|
790
|
-
lines.push('');
|
|
791
|
-
for (const res of filteredResources) {
|
|
792
|
-
lines.push(`### ${res.name} (${res.type})`);
|
|
793
|
-
if (res.subscriptionTier === 'ADVANCED') {
|
|
794
|
-
lines.push('**Requires Advanced subscription**');
|
|
795
|
-
}
|
|
796
|
-
if (res.advancedFeatures && res.advancedFeatures.length > 0) {
|
|
797
|
-
lines.push('');
|
|
798
|
-
lines.push('Advanced-only features:');
|
|
799
|
-
for (const feat of res.advancedFeatures) {
|
|
800
|
-
lines.push(`- \`${feat}\``);
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
lines.push('');
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
if (summary.advancedFeaturesList.length > 0) {
|
|
807
|
-
lines.push('## All Advanced Features');
|
|
808
|
-
lines.push('');
|
|
809
|
-
lines.push(summary.advancedFeaturesList.map(f => `\`${f}\``).join(', '));
|
|
810
|
-
}
|
|
811
|
-
textContent = lines.join('\n');
|
|
812
|
-
}
|
|
813
|
-
else {
|
|
814
|
-
textContent = JSON.stringify(output, null, 2);
|
|
815
|
-
}
|
|
816
|
-
return {
|
|
817
|
-
content: [{ type: 'text', text: textContent }],
|
|
818
|
-
structuredContent: output,
|
|
819
|
-
};
|
|
820
|
-
});
|
|
821
|
-
// =============================================================================
|
|
822
|
-
// PROPERTY SUBSCRIPTION TIER TOOL
|
|
823
|
-
// =============================================================================
|
|
824
|
-
server.registerTool('f5xc_terraform_get_property_subscription_info', {
|
|
825
|
-
title: 'Get Property Subscription Tier Info',
|
|
826
|
-
description: `Get subscription tier requirements for a specific property within an F5XC resource.
|
|
827
|
-
|
|
828
|
-
Checks if a specific property/attribute requires the Advanced subscription tier.
|
|
829
|
-
This is useful for determining if a particular configuration option is available
|
|
830
|
-
with your current subscription level.
|
|
831
|
-
|
|
832
|
-
Args:
|
|
833
|
-
- resource (string): Resource name (e.g., "http_loadbalancer", "app_firewall")
|
|
834
|
-
- property (optional): Property name to check (e.g., "enable_malicious_user_detection")
|
|
835
|
-
If omitted, returns all advanced features for the resource
|
|
836
|
-
- response_format: 'markdown' or 'json'
|
|
837
|
-
|
|
838
|
-
Returns:
|
|
839
|
-
- For specific property: Whether it requires Advanced subscription and matched feature
|
|
840
|
-
- For no property: List of all Advanced-only features for the resource
|
|
841
|
-
|
|
842
|
-
Examples:
|
|
843
|
-
- resource="http_loadbalancer", property="enable_malicious_user_detection" -> Advanced required
|
|
844
|
-
- resource="http_loadbalancer", property="domains" -> Standard (no advanced requirement)
|
|
845
|
-
- resource="http_loadbalancer" -> Lists all advanced features for HTTP LB`,
|
|
846
|
-
inputSchema: GetPropertySubscriptionInfoSchema,
|
|
847
|
-
annotations: {
|
|
848
|
-
readOnlyHint: true,
|
|
849
|
-
destructiveHint: false,
|
|
850
|
-
idempotentHint: true,
|
|
851
|
-
openWorldHint: false,
|
|
852
|
-
},
|
|
853
|
-
}, async (params) => {
|
|
854
|
-
// Query for specific property
|
|
855
|
-
if (params.property) {
|
|
856
|
-
const info = getPropertySubscriptionInfo(params.resource, params.property);
|
|
857
|
-
if (!info) {
|
|
858
|
-
return {
|
|
859
|
-
content: [{
|
|
860
|
-
type: 'text',
|
|
861
|
-
text: `No subscription information found for resource "${params.resource}". The resource may not exist or may not have tier metadata.`,
|
|
862
|
-
}],
|
|
863
|
-
};
|
|
864
|
-
}
|
|
865
|
-
const output = {
|
|
866
|
-
resource: info.resourceName,
|
|
867
|
-
property: info.propertyName,
|
|
868
|
-
requires_advanced: info.requiresAdvanced,
|
|
869
|
-
matched_feature: info.matchedFeature || null,
|
|
870
|
-
resource_tier: info.resourceTier,
|
|
871
|
-
service: info.service,
|
|
872
|
-
};
|
|
873
|
-
let textContent;
|
|
874
|
-
if (params.response_format === ResponseFormat.MARKDOWN) {
|
|
875
|
-
const lines = [
|
|
876
|
-
`# Property Subscription Info`,
|
|
877
|
-
'',
|
|
878
|
-
`**Resource**: \`${info.resourceName}\``,
|
|
879
|
-
`**Property**: \`${info.propertyName}\``,
|
|
880
|
-
'',
|
|
881
|
-
`**Requires Advanced Subscription**: ${info.requiresAdvanced ? '**Yes**' : 'No'}`,
|
|
882
|
-
];
|
|
883
|
-
if (info.matchedFeature) {
|
|
884
|
-
lines.push(`**Matched Feature**: \`${info.matchedFeature}\``);
|
|
885
|
-
lines.push('');
|
|
886
|
-
lines.push('> ⚠️ This property requires an Advanced subscription to use.');
|
|
887
|
-
}
|
|
888
|
-
else {
|
|
889
|
-
lines.push('');
|
|
890
|
-
lines.push('✓ This property is available with a Standard subscription.');
|
|
891
|
-
}
|
|
892
|
-
lines.push('');
|
|
893
|
-
lines.push(`**Resource Tier**: ${info.resourceTier}`);
|
|
894
|
-
lines.push(`**Service**: ${info.service}`);
|
|
895
|
-
textContent = lines.join('\n');
|
|
896
|
-
}
|
|
897
|
-
else {
|
|
898
|
-
textContent = JSON.stringify(output, null, 2);
|
|
899
|
-
}
|
|
900
|
-
return {
|
|
901
|
-
content: [{ type: 'text', text: textContent }],
|
|
902
|
-
structuredContent: output,
|
|
903
|
-
};
|
|
904
|
-
}
|
|
905
|
-
// List all advanced features for the resource
|
|
906
|
-
const resourceInfo = getResourceAdvancedProperties(params.resource);
|
|
907
|
-
if (!resourceInfo) {
|
|
908
|
-
return {
|
|
909
|
-
content: [{
|
|
910
|
-
type: 'text',
|
|
911
|
-
text: `No subscription information found for resource "${params.resource}". The resource may not exist or may not have tier metadata.`,
|
|
912
|
-
}],
|
|
913
|
-
};
|
|
914
|
-
}
|
|
915
|
-
const output = {
|
|
916
|
-
resource: resourceInfo.resourceName,
|
|
917
|
-
resource_tier: resourceInfo.resourceTier,
|
|
918
|
-
service: resourceInfo.service,
|
|
919
|
-
advanced_features: resourceInfo.advancedFeatures,
|
|
920
|
-
has_advanced_features: resourceInfo.advancedFeatures.length > 0,
|
|
921
|
-
};
|
|
922
|
-
let textContent;
|
|
923
|
-
if (params.response_format === ResponseFormat.MARKDOWN) {
|
|
924
|
-
const lines = [
|
|
925
|
-
`# Advanced Features: ${resourceInfo.resourceName}`,
|
|
926
|
-
'',
|
|
927
|
-
`**Resource Tier**: ${resourceInfo.resourceTier}`,
|
|
928
|
-
`**Service**: ${resourceInfo.service}`,
|
|
929
|
-
'',
|
|
930
|
-
];
|
|
931
|
-
if (resourceInfo.advancedFeatures.length > 0) {
|
|
932
|
-
lines.push('## Properties Requiring Advanced Subscription');
|
|
933
|
-
lines.push('');
|
|
934
|
-
lines.push('The following features/properties require an Advanced subscription:');
|
|
935
|
-
lines.push('');
|
|
936
|
-
for (const feature of resourceInfo.advancedFeatures) {
|
|
937
|
-
lines.push(`- \`${feature}\``);
|
|
938
|
-
}
|
|
939
|
-
lines.push('');
|
|
940
|
-
lines.push('> Note: Property names may vary (e.g., `enable_malicious_user_detection` for feature `malicious_user_detection`)');
|
|
941
|
-
}
|
|
942
|
-
else {
|
|
943
|
-
lines.push('✓ All properties of this resource are available with a Standard subscription.');
|
|
944
|
-
}
|
|
945
|
-
textContent = lines.join('\n');
|
|
946
|
-
}
|
|
947
|
-
else {
|
|
948
|
-
textContent = JSON.stringify(output, null, 2);
|
|
949
|
-
}
|
|
950
|
-
return {
|
|
951
|
-
content: [{ type: 'text', text: textContent }],
|
|
952
|
-
structuredContent: output,
|
|
953
|
-
};
|
|
954
|
-
});
|
|
955
|
-
// =============================================================================
|
|
956
|
-
// ADDON SERVICE TOOLS
|
|
957
|
-
// =============================================================================
|
|
958
|
-
server.registerTool('f5xc_terraform_addon_list_services', {
|
|
959
|
-
title: 'List F5XC Addon Services',
|
|
960
|
-
description: `List all available F5 Distributed Cloud addon services with their activation types and tier requirements.
|
|
961
|
-
|
|
962
|
-
Addon services are additional features that can be activated for your F5XC tenant,
|
|
963
|
-
such as Bot Defense, Client Side Defense, API Discovery, and more.
|
|
964
|
-
|
|
965
|
-
Args:
|
|
966
|
-
- tier (optional): Filter by 'STANDARD', 'ADVANCED', or 'PREMIUM'
|
|
967
|
-
- activation_type (optional): Filter by 'self' (user-activated) or 'managed' (requires sales contact)
|
|
968
|
-
- response_format: 'markdown' or 'json'
|
|
969
|
-
|
|
970
|
-
Returns:
|
|
971
|
-
List of addon services with name, tier requirement, activation type, and description.
|
|
972
|
-
|
|
973
|
-
Examples:
|
|
974
|
-
- tier="ADVANCED" -> List all Advanced tier addon services
|
|
975
|
-
- activation_type="self" -> List all self-activatable services`,
|
|
976
|
-
inputSchema: ListAddonServicesSchema,
|
|
977
|
-
annotations: {
|
|
978
|
-
readOnlyHint: true,
|
|
979
|
-
destructiveHint: false,
|
|
980
|
-
idempotentHint: true,
|
|
981
|
-
openWorldHint: false,
|
|
982
|
-
},
|
|
983
|
-
}, async (params) => {
|
|
984
|
-
const result = listAddonServices(params.tier, params.activation_type);
|
|
985
|
-
const output = {
|
|
986
|
-
total: result.total,
|
|
987
|
-
filters: {
|
|
988
|
-
tier: params.tier || 'all',
|
|
989
|
-
activation_type: params.activation_type || 'all',
|
|
990
|
-
},
|
|
991
|
-
services: result.services,
|
|
992
|
-
};
|
|
993
|
-
let textContent;
|
|
994
|
-
if (params.response_format === ResponseFormat.MARKDOWN) {
|
|
995
|
-
const lines = [
|
|
996
|
-
'# F5XC Addon Services',
|
|
997
|
-
'',
|
|
998
|
-
`Total: ${result.total} services`,
|
|
999
|
-
'',
|
|
1000
|
-
];
|
|
1001
|
-
for (const service of result.services) {
|
|
1002
|
-
lines.push(`## ${service.displayName} (\`${service.name}\`)`);
|
|
1003
|
-
lines.push('');
|
|
1004
|
-
lines.push(service.description);
|
|
1005
|
-
lines.push('');
|
|
1006
|
-
lines.push(`- **Tier**: ${service.tier}`);
|
|
1007
|
-
lines.push(`- **Activation Type**: ${service.activationType}`);
|
|
1008
|
-
lines.push(`- **Category**: ${service.category}`);
|
|
1009
|
-
lines.push('');
|
|
1010
|
-
}
|
|
1011
|
-
textContent = lines.join('\n');
|
|
1012
|
-
}
|
|
1013
|
-
else {
|
|
1014
|
-
textContent = JSON.stringify(output, null, 2);
|
|
1015
|
-
}
|
|
1016
|
-
return {
|
|
1017
|
-
content: [{ type: 'text', text: textContent }],
|
|
1018
|
-
structuredContent: output,
|
|
1019
|
-
};
|
|
1020
|
-
});
|
|
1021
|
-
server.registerTool('f5xc_terraform_addon_check_activation', {
|
|
1022
|
-
title: 'Check Addon Activation Requirements',
|
|
1023
|
-
description: `Check activation requirements for a specific F5XC addon service.
|
|
1024
|
-
|
|
1025
|
-
Provides information about whether an addon service can be activated,
|
|
1026
|
-
the required subscription tier, and step-by-step activation guidance.
|
|
1027
|
-
|
|
1028
|
-
Args:
|
|
1029
|
-
- addon_service (string): Name of the addon service (e.g., "bot_defense", "client_side_defense")
|
|
1030
|
-
- response_format: 'markdown' or 'json'
|
|
1031
|
-
|
|
1032
|
-
Returns:
|
|
1033
|
-
- Activation status (can activate, requirements)
|
|
1034
|
-
- Required subscription tier
|
|
1035
|
-
- Activation type (self, partial, managed)
|
|
1036
|
-
- Step-by-step activation process
|
|
1037
|
-
- Terraform example configuration
|
|
1038
|
-
|
|
1039
|
-
Examples:
|
|
1040
|
-
- addon_service="bot_defense" -> Bot Defense activation requirements
|
|
1041
|
-
- addon_service="api_discovery" -> API Discovery activation info`,
|
|
1042
|
-
inputSchema: CheckAddonActivationSchema,
|
|
1043
|
-
annotations: {
|
|
1044
|
-
readOnlyHint: true,
|
|
1045
|
-
destructiveHint: false,
|
|
1046
|
-
idempotentHint: true,
|
|
1047
|
-
openWorldHint: false,
|
|
1048
|
-
},
|
|
1049
|
-
}, async (params) => {
|
|
1050
|
-
const result = checkAddonActivation(params.addon_service);
|
|
1051
|
-
if (!result) {
|
|
1052
|
-
return {
|
|
1053
|
-
content: [{
|
|
1054
|
-
type: 'text',
|
|
1055
|
-
text: `Addon service "${params.addon_service}" not found. Use f5xc_terraform_addon_list_services to see available services.`,
|
|
1056
|
-
}],
|
|
1057
|
-
};
|
|
1058
|
-
}
|
|
1059
|
-
const output = {
|
|
1060
|
-
addon_service: result.addonService,
|
|
1061
|
-
display_name: result.displayName,
|
|
1062
|
-
tier: result.tier,
|
|
1063
|
-
activation_type: result.activationType,
|
|
1064
|
-
can_activate: result.canActivate,
|
|
1065
|
-
steps: result.steps,
|
|
1066
|
-
terraform_example: result.terraformExample,
|
|
1067
|
-
};
|
|
1068
|
-
let textContent;
|
|
1069
|
-
if (params.response_format === ResponseFormat.MARKDOWN) {
|
|
1070
|
-
const lines = [
|
|
1071
|
-
`# Activation Requirements: ${result.displayName}`,
|
|
1072
|
-
'',
|
|
1073
|
-
`**Addon Service**: \`${result.addonService}\``,
|
|
1074
|
-
`**Required Tier**: ${result.tier}`,
|
|
1075
|
-
`**Activation Type**: ${result.activationType}`,
|
|
1076
|
-
`**Can Activate Directly**: ${result.canActivate ? 'Yes' : 'No (requires sales contact)'}`,
|
|
1077
|
-
'',
|
|
1078
|
-
'## Activation Steps',
|
|
1079
|
-
'',
|
|
1080
|
-
];
|
|
1081
|
-
result.steps.forEach((step, index) => {
|
|
1082
|
-
lines.push(`${index + 1}. ${step}`);
|
|
1083
|
-
});
|
|
212
|
+
lines.push('- `f5xc_terraform_discover` - Discover available tools with optional schema details');
|
|
213
|
+
lines.push('- `f5xc_terraform_docs` - Search, get, or list documentation (operations: search, get, list)');
|
|
214
|
+
lines.push('- `f5xc_terraform_api` - Query API specs (operations: search, get, find_endpoints, get_definition, list_definitions)');
|
|
215
|
+
lines.push('- `f5xc_terraform_subscription` - Check subscription tiers (operations: resource, property)');
|
|
216
|
+
lines.push('- `f5xc_terraform_addon` - Addon services (operations: list, check, workflow)');
|
|
217
|
+
lines.push('- `f5xc_terraform_get_summary` - This summary');
|
|
1084
218
|
lines.push('');
|
|
1085
|
-
lines.push('
|
|
1086
|
-
lines.push('');
|
|
1087
|
-
lines.push('```hcl');
|
|
1088
|
-
lines.push(result.terraformExample);
|
|
1089
|
-
lines.push('```');
|
|
219
|
+
lines.push('> **Token Optimization**: 14 tools consolidated to 6 tools (~77% reduction)');
|
|
1090
220
|
textContent = lines.join('\n');
|
|
1091
221
|
}
|
|
1092
222
|
else {
|
|
@@ -1097,120 +227,15 @@ Examples:
|
|
|
1097
227
|
structuredContent: output,
|
|
1098
228
|
};
|
|
1099
229
|
});
|
|
1100
|
-
server.registerTool('f5xc_terraform_addon_activation_workflow', {
|
|
1101
|
-
title: 'Get Addon Activation Workflow',
|
|
1102
|
-
description: `Get a detailed step-by-step activation workflow for an F5XC addon service.
|
|
1103
|
-
|
|
1104
|
-
Provides comprehensive guidance for activating an addon service including:
|
|
1105
|
-
- Prerequisites and requirements
|
|
1106
|
-
- Step-by-step instructions with Terraform snippets
|
|
1107
|
-
- Complete Terraform configuration
|
|
1108
|
-
- Estimated activation time
|
|
1109
|
-
- Important notes and considerations
|
|
1110
|
-
|
|
1111
|
-
Args:
|
|
1112
|
-
- addon_service (string): Name of the addon service
|
|
1113
|
-
- activation_type (optional): Override workflow type ('self', 'partial', 'managed')
|
|
1114
|
-
- response_format: 'markdown' or 'json'
|
|
1115
|
-
|
|
1116
|
-
Returns:
|
|
1117
|
-
Complete activation workflow with Terraform configuration examples.
|
|
1118
|
-
|
|
1119
|
-
Examples:
|
|
1120
|
-
- addon_service="bot_defense" -> Self-activation workflow
|
|
1121
|
-
- addon_service="bot_defense", activation_type="partial" -> Partial managed workflow`,
|
|
1122
|
-
inputSchema: GetAddonWorkflowSchema,
|
|
1123
|
-
annotations: {
|
|
1124
|
-
readOnlyHint: true,
|
|
1125
|
-
destructiveHint: false,
|
|
1126
|
-
idempotentHint: true,
|
|
1127
|
-
openWorldHint: false,
|
|
1128
|
-
},
|
|
1129
|
-
}, async (params) => {
|
|
1130
|
-
const result = getAddonWorkflow(params.addon_service, params.activation_type);
|
|
1131
|
-
if (!result) {
|
|
1132
|
-
return {
|
|
1133
|
-
content: [{
|
|
1134
|
-
type: 'text',
|
|
1135
|
-
text: `Addon service "${params.addon_service}" not found or invalid activation type. Use f5xc_terraform_addon_list_services to see available services.`,
|
|
1136
|
-
}],
|
|
1137
|
-
};
|
|
1138
|
-
}
|
|
1139
|
-
const output = {
|
|
1140
|
-
addon_service: result.addonService,
|
|
1141
|
-
activation_type: result.activationType,
|
|
1142
|
-
description: result.description,
|
|
1143
|
-
prerequisites: result.prerequisites,
|
|
1144
|
-
steps: result.steps,
|
|
1145
|
-
terraform_config: result.terraformConfig,
|
|
1146
|
-
estimated_time: result.estimatedTime,
|
|
1147
|
-
notes: result.notes,
|
|
1148
|
-
};
|
|
1149
|
-
let textContent;
|
|
1150
|
-
if (params.response_format === ResponseFormat.MARKDOWN) {
|
|
1151
|
-
const lines = [
|
|
1152
|
-
`# Activation Workflow: ${result.addonService}`,
|
|
1153
|
-
'',
|
|
1154
|
-
result.description,
|
|
1155
|
-
'',
|
|
1156
|
-
`**Activation Type**: ${result.activationType}`,
|
|
1157
|
-
`**Estimated Time**: ${result.estimatedTime}`,
|
|
1158
|
-
'',
|
|
1159
|
-
'## Prerequisites',
|
|
1160
|
-
'',
|
|
1161
|
-
];
|
|
1162
|
-
for (const prereq of result.prerequisites) {
|
|
1163
|
-
lines.push(`- ${prereq}`);
|
|
1164
|
-
}
|
|
1165
|
-
lines.push('');
|
|
1166
|
-
lines.push('## Step-by-Step Instructions');
|
|
1167
|
-
lines.push('');
|
|
1168
|
-
for (const step of result.steps) {
|
|
1169
|
-
lines.push(`### Step ${step.step}: ${step.action}`);
|
|
1170
|
-
lines.push('');
|
|
1171
|
-
lines.push(step.description);
|
|
1172
|
-
if (step.terraformSnippet) {
|
|
1173
|
-
lines.push('');
|
|
1174
|
-
lines.push('```hcl');
|
|
1175
|
-
lines.push(step.terraformSnippet);
|
|
1176
|
-
lines.push('```');
|
|
1177
|
-
}
|
|
1178
|
-
lines.push('');
|
|
1179
|
-
}
|
|
1180
|
-
lines.push('## Complete Terraform Configuration');
|
|
1181
|
-
lines.push('');
|
|
1182
|
-
lines.push('```hcl');
|
|
1183
|
-
lines.push(result.terraformConfig);
|
|
1184
|
-
lines.push('```');
|
|
1185
|
-
lines.push('');
|
|
1186
|
-
lines.push('## Notes');
|
|
1187
|
-
lines.push('');
|
|
1188
|
-
for (const note of result.notes) {
|
|
1189
|
-
lines.push(`- ${note}`);
|
|
1190
|
-
}
|
|
1191
|
-
textContent = lines.join('\n');
|
|
1192
|
-
}
|
|
1193
|
-
else {
|
|
1194
|
-
textContent = JSON.stringify(output, null, 2);
|
|
1195
|
-
}
|
|
1196
|
-
// Truncate if too long
|
|
1197
|
-
if (textContent.length > CHARACTER_LIMIT) {
|
|
1198
|
-
textContent = textContent.slice(0, CHARACTER_LIMIT) + '\n\n... (truncated)';
|
|
1199
|
-
}
|
|
1200
|
-
return {
|
|
1201
|
-
content: [{ type: 'text', text: textContent }],
|
|
1202
|
-
structuredContent: output,
|
|
1203
|
-
};
|
|
1204
|
-
});
|
|
1205
230
|
// =============================================================================
|
|
1206
231
|
// SERVER STARTUP
|
|
1207
232
|
// =============================================================================
|
|
1208
233
|
async function main() {
|
|
1209
234
|
const transport = new StdioServerTransport();
|
|
1210
235
|
await server.connect(transport);
|
|
1211
|
-
console.error('F5XC Terraform MCP server running on stdio');
|
|
236
|
+
console.error('F5XC Terraform MCP server running on stdio (token-optimized)');
|
|
1212
237
|
}
|
|
1213
|
-
main().catch(error => {
|
|
238
|
+
main().catch((error) => {
|
|
1214
239
|
console.error('Server error:', error);
|
|
1215
240
|
process.exit(1);
|
|
1216
241
|
});
|