@tiberriver256/mcp-server-azure-devops
Version:
Azure DevOps reference server for the Model Context Protocol (MCP)
132 lines • 5.86 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.searchWorkItems = searchWorkItems;
const axios_1 = __importDefault(require("axios"));
const identity_1 = require("@azure/identity");
const errors_1 = require("../../../shared/errors");
/**
* Search for work items in Azure DevOps projects
*
* @param connection The Azure DevOps WebApi connection
* @param options Parameters for searching work items
* @returns Search results with work item details and highlights
*/
async function searchWorkItems(connection, options) {
try {
// Prepare the search request
const searchRequest = {
searchText: options.searchText,
$skip: options.skip,
$top: options.top,
filters: {
...(options.projectId
? { 'System.TeamProject': [options.projectId] }
: {}),
...options.filters,
},
includeFacets: options.includeFacets,
$orderBy: options.orderBy,
};
// Get the authorization header from the connection
const authHeader = await getAuthorizationHeader();
// Extract organization and project from the connection URL
const { organization, project } = extractOrgAndProject(connection, options.projectId);
// Make the search API request
// If projectId is provided, include it in the URL, otherwise perform organization-wide search
const searchUrl = options.projectId
? `https://almsearch.dev.azure.com/${organization}/${project}/_apis/search/workitemsearchresults?api-version=7.1`
: `https://almsearch.dev.azure.com/${organization}/_apis/search/workitemsearchresults?api-version=7.1`;
const searchResponse = await axios_1.default.post(searchUrl, searchRequest, {
headers: {
Authorization: authHeader,
'Content-Type': 'application/json',
},
});
return searchResponse.data;
}
catch (error) {
// If it's already an AzureDevOpsError, rethrow it
if (error instanceof errors_1.AzureDevOpsError) {
throw error;
}
// Handle axios errors
if (axios_1.default.isAxiosError(error)) {
const status = error.response?.status;
const message = error.response?.data?.message || error.message;
if (status === 404) {
throw new errors_1.AzureDevOpsResourceNotFoundError(`Resource not found: ${message}`);
}
else if (status === 400) {
throw new errors_1.AzureDevOpsValidationError(`Invalid request: ${message}`, error.response?.data);
}
else if (status === 401 || status === 403) {
throw new errors_1.AzureDevOpsPermissionError(`Permission denied: ${message}`);
}
else {
// For other axios errors, wrap in a generic AzureDevOpsError
throw new errors_1.AzureDevOpsError(`Azure DevOps API error: ${message}`);
}
// This code is unreachable but TypeScript doesn't know that
}
// Otherwise, wrap it in a generic error
throw new errors_1.AzureDevOpsError(`Failed to search work items: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Extract organization and project from the connection URL
*
* @param connection The Azure DevOps WebApi connection
* @param projectId The project ID or name (optional)
* @returns The organization and project
*/
function extractOrgAndProject(connection, projectId) {
// Extract organization from the connection URL
const url = connection.serverUrl;
const match = url.match(/https?:\/\/dev\.azure\.com\/([^/]+)/);
const organization = match ? match[1] : '';
if (!organization) {
throw new errors_1.AzureDevOpsValidationError('Could not extract organization from connection URL');
}
return {
organization,
project: projectId || '',
};
}
/**
* Get the authorization header from the connection
*
* @returns The authorization header
*/
async function getAuthorizationHeader() {
try {
// For PAT authentication, we can construct the header directly
if (process.env.AZURE_DEVOPS_AUTH_METHOD?.toLowerCase() === 'pat' &&
process.env.AZURE_DEVOPS_PAT) {
// For PAT auth, we can construct the Basic auth header directly
const token = process.env.AZURE_DEVOPS_PAT;
const base64Token = Buffer.from(`:${token}`).toString('base64');
return `Basic ${base64Token}`;
}
// For Azure Identity / Azure CLI auth, we need to get a token
// using the Azure DevOps resource ID
// Choose the appropriate credential based on auth method
const credential = process.env.AZURE_DEVOPS_AUTH_METHOD?.toLowerCase() === 'azure-cli'
? new identity_1.AzureCliCredential()
: new identity_1.DefaultAzureCredential();
// Azure DevOps resource ID for token acquisition
const AZURE_DEVOPS_RESOURCE_ID = '499b84ac-1321-427f-aa17-267ca6975798';
// Get token for Azure DevOps
const token = await credential.getToken(`${AZURE_DEVOPS_RESOURCE_ID}/.default`);
if (!token || !token.token) {
throw new Error('Failed to acquire token for Azure DevOps');
}
return `Bearer ${token.token}`;
}
catch (error) {
throw new errors_1.AzureDevOpsValidationError(`Failed to get authorization header: ${error instanceof Error ? error.message : String(error)}`);
}
}
//# sourceMappingURL=feature.js.map