UNPKG

@jupiterone/jupiterone-mcp

Version:

Model Context Protocol server for JupiterOne account rules and rule details

103 lines 5.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.j1qlTools = void 0; const zod_1 = require("zod"); const load_description_js_1 = require("../../utils/load-description.js"); const errors_js_1 = require("./errors.js"); const result_js_1 = require("./result.js"); const types_js_1 = require("./types.js"); // J1QL output is highly variable: `data` rows carry open `entity`/`properties`, and the envelope // shape differs by query type. Fields are `.nullish()` (the SDK rejects a declared field receiving // `null`, e.g. `cursor: null` on the last page) and rows are open so real results never // false-reject; the schema documents the shape and exposes the typed object for code-mode / UI. // `data` is array-or-object: `RETURN TREE` returns `{ vertices, edges }`, everything else an array. const executeJ1qlOutput = { correlationId: zod_1.z.string().nullish(), status: zod_1.z.string().nullish(), query: zod_1.z.string().optional(), duration: zod_1.z.number().nullish(), url: zod_1.z.string().optional(), type: zod_1.z.string().nullish(), data: zod_1.z.union([zod_1.z.array(zod_1.z.any()), zod_1.z.record(zod_1.z.any())]).nullish(), cursor: zod_1.z.string().nullish(), hasMore: zod_1.z.boolean().optional(), messages: zod_1.z.array(zod_1.z.any()).optional(), }; // One-line note emitted as a separate text content block when more pages exist, steering agents to // the cursor parameter rather than SKIP (which re-scans from the start and is not a pagination // mechanism). A separate block keeps content[0] as pure payload JSON (parity with structuredContent) // for consumers that parse the text channel. const PAGINATION_NOTE = 'More results available — call execute-j1ql-query again with the `cursor` parameter. ' + 'Do not use SKIP for pagination.'; const listEntityTypesOutput = { classes: zod_1.z.record(zod_1.z.any()).nullish(), types: zod_1.z.record(zod_1.z.any()).nullish(), }; exports.j1qlTools = [ (0, types_js_1.defineTool)({ name: 'execute-j1ql-query', title: 'Execute J1QL Query', description: (0, load_description_js_1.loadDescription)('execute-j1ql-query.md'), inputSchema: { query: zod_1.z.string().describe('A J1QL query string that describes what data to return'), variables: zod_1.z .record(zod_1.z.any()) .optional() .describe('A JSON map of values to be used as parameters for the query'), cursor: zod_1.z .string() .optional() .describe('A token that can be exchanged to fetch the next page of information'), includeDeleted: zod_1.z .boolean() .optional() .describe('Include recently deleted information in the results'), flags: zod_1.z.record(zod_1.z.any()).optional().describe('Flags for query execution'), scopeFilters: zod_1.z .array(zod_1.z.record(zod_1.z.any())) .optional() .describe('Array of filters that define the desired vertex'), }, annotations: types_js_1.READ_ONLY, outputSchema: executeJ1qlOutput, errorContext: 'Error executing J1QL query', formatError: (error, { query }, validator) => (0, errors_js_1.createQueryErrorResponse)(error, query, validator), handler: async ({ query, variables, cursor, includeDeleted, flags, scopeFilters }, client) => { const queryFlags = { ...flags }; if (typeof includeDeleted === 'boolean') queryFlags.includeDeleted = includeDeleted; const result = await client.executeJ1qlQuery({ query, variables, cursor, scopeFilters, flags: Object.keys(queryFlags).length > 0 ? queryFlags : undefined, }); const accountInfo = await client.getAccountInfo(); const queryUrl = client.j1qlService.constructQueryUrl(query, accountInfo.subdomain); // The backend signals more pages by returning a cursor. Surface it as an explicit boolean and, // when true, prepend a cursor-paging note to the text (model-facing) channel; structuredContent // stays the pure payload. const hasMore = typeof result.cursor === 'string' && result.cursor.length > 0; const output = (0, result_js_1.structuredResult)({ ...result, url: queryUrl, hasMore }); if (hasMore) { output.content.push({ type: 'text', text: PAGINATION_NOTE }); } return output; }, }), (0, types_js_1.defineTool)({ name: 'list-entity-types', title: 'List Entity Types', description: (0, load_description_js_1.loadDescription)('list-entity-types.md'), inputSchema: {}, outputSchema: listEntityTypesOutput, annotations: types_js_1.READ_ONLY, errorContext: 'Error listing entity types', handler: async (_params, client) => { const results = await client.listEntityTypes(); return (0, result_js_1.structuredResult)(results); }, }), ]; //# sourceMappingURL=j1ql.js.map