UNPKG

@aashari/mcp-server-atlassian-bitbucket

Version:

Node.js/TypeScript MCP server for Atlassian Bitbucket. Enables AI systems (LLMs) to interact with workspaces, repositories, and pull requests via tools (list, get, comment, search). Connects AI directly to version control workflows through the standard MC

161 lines (160 loc) 6.52 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.searchCommits = searchCommits; exports.searchCode = searchCode; const transport_util_js_1 = require("../utils/transport.util.js"); const logger_util_js_1 = require("../utils/logger.util.js"); const url_1 = require("url"); const transport_util_js_2 = require("../utils/transport.util.js"); const logger = logger_util_js_1.Logger.forContext('services/vendor.atlassian.search.service.ts'); /** * Search for commits in a repository using the Bitbucket API * * @param {SearchCommitsParams} params - Parameters for the commit search * @returns {Promise<CommitsResponse>} The search results from the Bitbucket API */ async function searchCommits(params) { // Build the query parameters - the Bitbucket API allows searching commits by message const queryParams = new url_1.URLSearchParams(); // If search query is provided, add it as a q parameter if (params.searchQuery) { queryParams.append('q', `message ~ "${params.searchQuery}"`); } // Add optional pagination parameters if (params.page) { queryParams.append('page', params.page.toString()); } if (params.pageLen) { queryParams.append('pagelen', params.pageLen.toString()); } // Add optional fields parameter for enhanced responses if (params.fields) { queryParams.append('fields', params.fields); } // Get credentials for API call const credentials = (0, transport_util_js_2.getAtlassianCredentials)(); if (!credentials) { throw new Error('No Atlassian credentials available'); } // Set useBitbucketAuth to true since we're calling the Bitbucket API credentials.useBitbucketAuth = true; // Create API path for Bitbucket commits const path = `/2.0/repositories/${params.workspaceSlug}/${params.repoSlug}/commits${queryParams.toString() ? '?' + queryParams.toString() : ''}`; // Track searching commits in repository logger.debug(`Searching commits in repository: ${params.workspaceSlug}/${params.repoSlug}`, { searchQuery: params.searchQuery, path, }); // Call Bitbucket API with credentials and path return (0, transport_util_js_1.fetchAtlassian)(credentials, path); } /** * Search for code in a workspace using the Bitbucket API * * @param {SearchCodeParams} params - Parameters for the code search * @returns {Promise<CodeSearchResponse>} The search results from the Bitbucket API */ async function searchCode(params) { // If repoSlug is provided, enhance the search query with repo: syntax const searchQuery = params.repoSlug ? `${params.searchQuery} repo:${params.repoSlug}` : params.searchQuery; // Language mapping to handle common alternative names const languageMapping = { hcl: 'terraform', tf: 'terraform', typescript: 'ts', javascript: 'js', python: 'py', // Add more mappings as needed }; // Append language and extension filters if provided let finalSearchQuery = searchQuery; if (params.language) { // Use the mapped language name if available, otherwise use the original const mappedLanguage = params.language.toLowerCase(); const apiLanguage = languageMapping[mappedLanguage] || mappedLanguage; logger.debug(`Language mapping: "${mappedLanguage}" -> "${apiLanguage}"`); finalSearchQuery += ` lang:${apiLanguage}`; } if (params.extension) { finalSearchQuery += ` ext:${params.extension}`; } // Build the query parameters const queryParams = new url_1.URLSearchParams({ search_query: finalSearchQuery, }); // Add optional pagination parameters if (params.page) { queryParams.append('page', params.page.toString()); } if (params.pageLen) { queryParams.append('pagelen', params.pageLen.toString()); } // Add optional fields parameter for enhanced responses if (params.fields) { queryParams.append('fields', params.fields); } // Get credentials for API call const credentials = (0, transport_util_js_2.getAtlassianCredentials)(); if (!credentials) { throw new Error('No Atlassian credentials available'); } // Set useBitbucketAuth to true since we're calling the Bitbucket API credentials.useBitbucketAuth = true; // Create API path for Bitbucket code search const path = `/2.0/workspaces/${params.workspaceSlug}/search/code?${queryParams.toString()}`; // Track searching code in workspace logger.debug(`Searching code in workspace: ${params.workspaceSlug}`, { searchQuery: finalSearchQuery, path, }); // Call Bitbucket API with credentials and path return (0, transport_util_js_1.fetchAtlassian)(credentials, path); } /** * Search for content in Bitbucket * * @param params Search parameters * @returns Content search response */ async function searchContent(params) { const logger = logger_util_js_1.Logger.forContext('services/vendor.atlassian.search.service.ts', 'searchContent'); try { const credentials = (0, transport_util_js_2.getAtlassianCredentials)(); if (!credentials) { throw new Error('Atlassian credentials are required for content search'); } // Build query parameters const queryParams = new url_1.URLSearchParams(); // Format the query queryParams.set('q', params.query); // Add pagination parameters queryParams.set('pagelen', String(params.limit || 25)); queryParams.set('page', String(params.page || 1)); // Add content type filter if specified if (params.contentType) { queryParams.set('content_type', params.contentType); } // Construct URL based on whether a repository is specified let url = `/2.0/search/${params.workspaceSlug}`; if (params.repoSlug) { url = `/2.0/search/${params.workspaceSlug}/${params.repoSlug}`; } // Add query parameters url += `?${queryParams.toString()}`; logger.debug(`Content search request URL: ${url}`); // Make the request const response = await (0, transport_util_js_1.fetchAtlassian)(credentials, url); return response; } catch (error) { logger.error('Content search failed:', error); throw error; } } exports.default = { searchCode, searchCommits, searchContent, };