UNPKG

leanix-pathfinder-mcp-server

Version:

MCP Server for LeanIX Pathfinder API - Enterprise Architecture Management Platform

923 lines 32.4 kB
#!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js'; import { LeanIXClient } from './client.js'; // Server configuration const server = new Server({ name: 'leanix-pathfinder-mcp-server', version: '1.0.0', }, { capabilities: { tools: {}, }, }); // Initialize LeanIX client let leanixClient = null; function initializeClient() { if (!leanixClient) { const config = { baseUrl: process.env.LEANIX_BASE_URL || '', clientId: process.env.LEANIX_CLIENT_ID || '', clientSecret: process.env.LEANIX_CLIENT_SECRET || '', workspaceId: process.env.LEANIX_WORKSPACE_ID, }; if (!config.baseUrl || !config.clientId || !config.clientSecret) { throw new Error('Missing required LeanIX configuration. Please set LEANIX_BASE_URL, LEANIX_CLIENT_ID, and LEANIX_CLIENT_SECRET environment variables.'); } leanixClient = new LeanIXClient(config); } return leanixClient; } // Tool definitions const tools = [ // Fact Sheets { name: 'leanix_get_fact_sheet', description: 'Get a specific fact sheet by ID', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'The ID of the fact sheet to retrieve', }, version: { type: 'number', description: 'Optional version number', }, }, required: ['id'], }, }, { name: 'leanix_list_fact_sheets', description: 'List fact sheets with optional filtering', inputSchema: { type: 'object', properties: { types: { type: 'string', description: 'Comma-separated list of fact sheet types to filter by', }, ids: { type: 'string', description: 'Comma-separated list of fact sheet IDs', }, relations: { type: 'string', description: 'Include relations in response', }, pageSize: { type: 'number', description: 'Number of results per page', }, cursor: { type: 'string', description: 'Cursor for pagination', }, }, }, }, { name: 'leanix_create_fact_sheet', description: 'Create a new fact sheet', inputSchema: { type: 'object', properties: { factSheet: { type: 'object', description: 'The fact sheet data to create', properties: { name: { type: 'string' }, type: { type: 'string' }, description: { type: 'string' }, displayName: { type: 'string' }, }, required: ['name', 'type'], }, }, required: ['factSheet'], }, }, { name: 'leanix_update_fact_sheet', description: 'Update an existing fact sheet', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'The ID of the fact sheet to update', }, factSheet: { type: 'object', description: 'The fact sheet data to update', }, relationTypes: { type: 'string', description: 'Comma-separated list of relation types to update', }, }, required: ['id', 'factSheet'], }, }, { name: 'leanix_delete_fact_sheet', description: 'Delete a fact sheet', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'The ID of the fact sheet to delete', }, comment: { type: 'string', description: 'Optional comment for the deletion', }, }, required: ['id'], }, }, { name: 'leanix_get_fact_sheet_relations', description: 'Get relations for a specific fact sheet', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'The ID of the fact sheet', }, relationType: { type: 'string', description: 'Filter by relation type', }, withFactSheets: { type: 'boolean', description: 'Include fact sheet data in relations', }, }, required: ['id'], }, }, // Bookmarks { name: 'leanix_list_bookmarks', description: 'List all bookmarks', inputSchema: { type: 'object', properties: { bookmarkType: { type: 'string', description: 'Filter by bookmark type (INVENTORY, REPORTING, VISUALIZER, DASHBOARD, INVENTORY_EXPORT)', }, pageSize: { type: 'number', description: 'Number of results per page', }, cursor: { type: 'string', description: 'Cursor for pagination', }, }, }, }, { name: 'leanix_get_bookmark', description: 'Get a specific bookmark by ID', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'The ID of the bookmark to retrieve', }, markAsViewed: { type: 'boolean', description: 'Mark the bookmark as viewed', }, version: { type: 'number', description: 'Optional version number', }, }, required: ['id'], }, }, { name: 'leanix_create_bookmark', description: 'Create a new bookmark', inputSchema: { type: 'object', properties: { bookmark: { type: 'object', description: 'The bookmark data to create', properties: { name: { type: 'string' }, type: { type: 'string' }, description: { type: 'string' }, permittedReadUserIds: { type: 'array', items: { type: 'string' } }, permittedWriteUserIds: { type: 'array', items: { type: 'string' } }, referencedFactSheetIds: { type: 'array', items: { type: 'string' } }, }, required: ['name', 'type', 'permittedReadUserIds', 'permittedWriteUserIds', 'referencedFactSheetIds'], }, }, required: ['bookmark'], }, }, { name: 'leanix_update_bookmark', description: 'Update an existing bookmark', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'The ID of the bookmark to update', }, bookmark: { type: 'object', description: 'The bookmark data to update', }, }, required: ['id', 'bookmark'], }, }, { name: 'leanix_delete_bookmark', description: 'Delete a bookmark', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'The ID of the bookmark to delete', }, }, required: ['id'], }, }, { name: 'leanix_share_bookmark', description: 'Share a bookmark with users', inputSchema: { type: 'object', properties: { bookmarkId: { type: 'string', description: 'The ID of the bookmark to share', }, sharedWithUserIds: { type: 'array', items: { type: 'string' }, description: 'Array of user IDs to share with', }, notifyUsers: { type: 'boolean', description: 'Whether to notify users about the share', }, }, required: ['bookmarkId', 'sharedWithUserIds'], }, }, // Models { name: 'leanix_get_data_model', description: 'Get the data model for the workspace', inputSchema: { type: 'object', properties: { workspaceId: { type: 'string', description: 'Optional workspace ID (uses default if not provided)', }, useCaseId: { type: 'string', description: 'Optional use case ID', }, }, }, }, { name: 'leanix_get_view_model', description: 'Get the view model for the workspace', inputSchema: { type: 'object', properties: { workspaceId: { type: 'string', description: 'Optional workspace ID (uses default if not provided)', }, useCaseId: { type: 'string', description: 'Optional use case ID', }, }, }, }, { name: 'leanix_get_authorization', description: 'Get authorization roles and permissions', inputSchema: { type: 'object', properties: { workspaceId: { type: 'string', description: 'Optional workspace ID (uses default if not provided)', }, useCaseId: { type: 'string', description: 'Optional use case ID', }, }, }, }, { name: 'leanix_get_meta_model', description: 'Get the meta model', inputSchema: { type: 'object', properties: { factSheetType: { type: 'string', description: 'Optional fact sheet type to filter the meta model', }, }, }, }, // GraphQL { name: 'leanix_execute_graphql', description: 'Execute a GraphQL query or mutation', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'The GraphQL query or mutation string', }, variables: { type: 'object', description: 'Optional variables for the GraphQL query', }, operationName: { type: 'string', description: 'Optional operation name for multi-operation queries', }, }, required: ['query'], }, }, // Features { name: 'leanix_list_features', description: 'List all workspace features', inputSchema: { type: 'object', properties: {}, }, }, { name: 'leanix_get_feature', description: 'Get a specific feature by ID', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'The ID of the feature to retrieve', }, }, required: ['id'], }, }, { name: 'leanix_update_feature', description: 'Update a feature (Admin role only)', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'The ID of the feature to update', }, enabled: { type: 'boolean', description: 'Whether the feature should be enabled', }, }, required: ['id'], }, }, // Settings { name: 'leanix_get_settings', description: 'Get workspace settings', inputSchema: { type: 'object', properties: { workspaceId: { type: 'string', description: 'Optional workspace ID (uses default if not provided)', }, }, }, }, { name: 'leanix_update_settings', description: 'Update workspace settings', inputSchema: { type: 'object', properties: { settings: { type: 'object', description: 'The settings to update', }, }, required: ['settings'], }, }, // Exports { name: 'leanix_list_exports', description: 'List available exports', inputSchema: { type: 'object', properties: { type: { type: 'string', description: 'Filter by export type', }, pageSize: { type: 'number', description: 'Number of results per page', }, cursor: { type: 'string', description: 'Cursor for pagination', }, }, }, }, { name: 'leanix_create_export', description: 'Create a new export', inputSchema: { type: 'object', properties: { exportConfig: { type: 'object', description: 'Export configuration', properties: { type: { type: 'string' }, factSheetTypes: { type: 'string' }, bookmarkId: { type: 'string' }, }, }, }, required: ['exportConfig'], }, }, // Suggestions { name: 'leanix_get_suggestions', description: 'Get search suggestions for a given term', inputSchema: { type: 'object', properties: { q: { type: 'string', description: 'Search term (2-1000 characters)', }, object: { type: 'string', description: 'Suggestions object type (default: factSheet)', }, count: { type: 'number', description: 'Number of suggestions (1-100)', }, perType: { type: 'boolean', description: 'Group suggestions per object type', }, useCaseId: { type: 'string', description: 'Optional use case ID', }, }, required: ['q'], }, }, ]; // List tools handler server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools, }; }); // Call tool handler server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { const client = initializeClient(); let result; switch (name) { // Fact Sheets case 'leanix_get_fact_sheet': { const { id, version } = args; const queryParams = client.buildQueryParams({ version }); const response = await client.get(`/services/pathfinder/v1/factSheets/${id}${queryParams}`); result = { content: [ { type: 'text', text: JSON.stringify(response.data, null, 2), }, ], }; break; } case 'leanix_list_fact_sheets': { const { types, ids, relations, pageSize, cursor } = args; const queryParams = client.buildQueryParams({ types, ids, relations, pageSize, cursor }); const response = await client.get(`/services/pathfinder/v1/factSheets${queryParams}`); result = { content: [ { type: 'text', text: JSON.stringify(response.data, null, 2), }, ], }; break; } case 'leanix_create_fact_sheet': { const { factSheet } = args; const response = await client.post('/services/pathfinder/v1/factSheets', factSheet); result = { content: [ { type: 'text', text: JSON.stringify(response.data, null, 2), }, ], }; break; } case 'leanix_update_fact_sheet': { const { id, factSheet, relationTypes } = args; const queryParams = client.buildQueryParams({ relationTypes }); const response = await client.put(`/services/pathfinder/v1/factSheets/${id}${queryParams}`, factSheet); result = { content: [ { type: 'text', text: JSON.stringify(response.data, null, 2), }, ], }; break; } case 'leanix_delete_fact_sheet': { const { id, comment } = args; const body = comment ? { comment } : undefined; const response = await client.delete(`/services/pathfinder/v1/factSheets/${id}`, { body }); result = { content: [ { type: 'text', text: `Fact sheet ${id} deleted successfully`, }, ], }; break; } case 'leanix_get_fact_sheet_relations': { const { id, relationType, withFactSheets } = args; const queryParams = client.buildQueryParams({ relationType, withFactSheets }); const response = await client.get(`/services/pathfinder/v1/factSheets/${id}/relations${queryParams}`); result = { content: [ { type: 'text', text: JSON.stringify(response.data, null, 2), }, ], }; break; } // Bookmarks case 'leanix_list_bookmarks': { const { bookmarkType, pageSize, cursor } = args; const queryParams = client.buildQueryParams({ bookmarkType, pageSize, cursor }); const response = await client.get(`/services/pathfinder/v1/bookmarks${queryParams}`); result = { content: [ { type: 'text', text: JSON.stringify(response.data, null, 2), }, ], }; break; } case 'leanix_get_bookmark': { const { id, markAsViewed, version } = args; const queryParams = client.buildQueryParams({ markAsViewed, version }); const response = await client.get(`/services/pathfinder/v1/bookmarks/${id}${queryParams}`); result = { content: [ { type: 'text', text: JSON.stringify(response.data, null, 2), }, ], }; break; } case 'leanix_create_bookmark': { const { bookmark } = args; const response = await client.post('/services/pathfinder/v1/bookmarks', bookmark); result = { content: [ { type: 'text', text: JSON.stringify(response.data, null, 2), }, ], }; break; } case 'leanix_update_bookmark': { const { id, bookmark } = args; const response = await client.put(`/services/pathfinder/v1/bookmarks/${id}`, bookmark); result = { content: [ { type: 'text', text: JSON.stringify(response.data, null, 2), }, ], }; break; } case 'leanix_delete_bookmark': { const { id } = args; await client.delete(`/services/pathfinder/v1/bookmarks/${id}`); result = { content: [ { type: 'text', text: `Bookmark ${id} deleted successfully`, }, ], }; break; } case 'leanix_share_bookmark': { const { bookmarkId, sharedWithUserIds, notifyUsers } = args; const shareData = { bookmarkId, sharedWithUserIds, notifyUsers: notifyUsers || false, }; const response = await client.post('/services/pathfinder/v1/bookmarkShares', shareData); result = { content: [ { type: 'text', text: JSON.stringify(response.data, null, 2), }, ], }; break; } // Models case 'leanix_get_data_model': { const { workspaceId, useCaseId } = args; const queryParams = client.buildQueryParams({ workspaceId, useCaseId }); const response = await client.get(`/services/pathfinder/v1/models/dataModel${queryParams}`); result = { content: [ { type: 'text', text: JSON.stringify(response.data, null, 2), }, ], }; break; } case 'leanix_get_view_model': { const { workspaceId, useCaseId } = args; const queryParams = client.buildQueryParams({ workspaceId, useCaseId }); const response = await client.get(`/services/pathfinder/v1/models/viewModel${queryParams}`); result = { content: [ { type: 'text', text: JSON.stringify(response.data, null, 2), }, ], }; break; } case 'leanix_get_authorization': { const { workspaceId, useCaseId } = args; const queryParams = client.buildQueryParams({ workspaceId, useCaseId }); const response = await client.get(`/services/pathfinder/v1/models/authorization${queryParams}`); result = { content: [ { type: 'text', text: JSON.stringify(response.data, null, 2), }, ], }; break; } case 'leanix_get_meta_model': { const { factSheetType } = args; let url = '/services/pathfinder/v1/models/metaModel'; if (factSheetType) { url += `/${factSheetType}`; } const response = await client.get(url); result = { content: [ { type: 'text', text: JSON.stringify(response.data, null, 2), }, ], }; break; } // GraphQL case 'leanix_execute_graphql': { const request = args; if (!request.query) { throw new Error('GraphQL query is required'); } const { query, variables, operationName } = request; const graphqlRequest = { query, variables, operationName, }; const response = await client.post('/services/pathfinder/v1/graphql', graphqlRequest); result = { content: [ { type: 'text', text: JSON.stringify(response.data, null, 2), }, ], }; break; } // Features case 'leanix_list_features': { const response = await client.get('/services/pathfinder/v1/features'); result = { content: [ { type: 'text', text: JSON.stringify(response.data, null, 2), }, ], }; break; } case 'leanix_get_feature': { const { id } = args; const response = await client.get(`/services/pathfinder/v1/features/${id}`); result = { content: [ { type: 'text', text: JSON.stringify(response.data, null, 2), }, ], }; break; } case 'leanix_update_feature': { const { id, enabled } = args; const queryParams = client.buildQueryParams({ enabled }); const response = await client.post(`/services/pathfinder/v1/features/${id}${queryParams}`); result = { content: [ { type: 'text', text: JSON.stringify(response.data, null, 2), }, ], }; break; } // Settings case 'leanix_get_settings': { const { workspaceId } = args; const queryParams = client.buildQueryParams({ workspaceId }); const response = await client.get(`/services/pathfinder/v1/settings${queryParams}`); result = { content: [ { type: 'text', text: JSON.stringify(response.data, null, 2), }, ], }; break; } case 'leanix_update_settings': { const { settings } = args; const response = await client.put('/services/pathfinder/v1/settings', settings); result = { content: [ { type: 'text', text: JSON.stringify(response.data, null, 2), }, ], }; break; } // Exports case 'leanix_list_exports': { const { type, pageSize, cursor } = args; const queryParams = client.buildQueryParams({ type, pageSize, cursor }); const response = await client.get(`/services/pathfinder/v1/exports${queryParams}`); result = { content: [ { type: 'text', text: JSON.stringify(response.data, null, 2), }, ], }; break; } case 'leanix_create_export': { const { exportConfig } = args; const response = await client.post('/services/pathfinder/v1/exports', exportConfig); result = { content: [ { type: 'text', text: JSON.stringify(response.data, null, 2), }, ], }; break; } // Suggestions case 'leanix_get_suggestions': { const { q, object, count, perType, useCaseId } = args; const queryParams = client.buildQueryParams({ q, object, count, perType, useCaseId }); const response = await client.get(`/services/pathfinder/v1/suggestions${queryParams}`); result = { content: [ { type: 'text', text: JSON.stringify(response.data, null, 2), }, ], }; break; } default: throw new Error(`Unknown tool: ${name}`); } return result; } catch (error) { const errorMessage = error.response?.data?.errorMessage || error.message || 'Unknown error occurred'; const statusCode = error.response?.status || 500; return { content: [ { type: 'text', text: `Error ${statusCode}: ${errorMessage}`, }, ], isError: true, }; } }); // Start the server async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error('LeanIX Pathfinder MCP Server started'); } main().catch((error) => { console.error('Server failed to start:', error); process.exit(1); }); //# sourceMappingURL=index.js.map