@web-marketing-hr/azure-devops-mcp 2.3.5

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.
Files changed (45) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +238 -0
  3. package/dist/auth.js +117 -0
  4. package/dist/auth.js.map +1 -0
  5. package/dist/index.js +155 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/logger.js +35 -0
  8. package/dist/logger.js.map +1 -0
  9. package/dist/org-tenants.js +79 -0
  10. package/dist/org-tenants.js.map +1 -0
  11. package/dist/prompts.js +21 -0
  12. package/dist/prompts.js.map +1 -0
  13. package/dist/shared/domains.js +126 -0
  14. package/dist/shared/domains.js.map +1 -0
  15. package/dist/shared/tool-validation.js +93 -0
  16. package/dist/shared/tool-validation.js.map +1 -0
  17. package/dist/tools/advanced-security.js +109 -0
  18. package/dist/tools/advanced-security.js.map +1 -0
  19. package/dist/tools/auth.js +64 -0
  20. package/dist/tools/auth.js.map +1 -0
  21. package/dist/tools/core.js +96 -0
  22. package/dist/tools/core.js.map +1 -0
  23. package/dist/tools/pipelines.js +322 -0
  24. package/dist/tools/pipelines.js.map +1 -0
  25. package/dist/tools/repositories.js +938 -0
  26. package/dist/tools/repositories.js.map +1 -0
  27. package/dist/tools/search.js +211 -0
  28. package/dist/tools/search.js.map +1 -0
  29. package/dist/tools/test-plans.js +387 -0
  30. package/dist/tools/test-plans.js.map +1 -0
  31. package/dist/tools/wiki.js +390 -0
  32. package/dist/tools/wiki.js.map +1 -0
  33. package/dist/tools/work-items.js +1007 -0
  34. package/dist/tools/work-items.js.map +1 -0
  35. package/dist/tools/work.js +299 -0
  36. package/dist/tools/work.js.map +1 -0
  37. package/dist/tools.js +30 -0
  38. package/dist/tools.js.map +1 -0
  39. package/dist/useragent.js +21 -0
  40. package/dist/useragent.js.map +1 -0
  41. package/dist/utils.js +94 -0
  42. package/dist/utils.js.map +1 -0
  43. package/dist/version.js +2 -0
  44. package/dist/version.js.map +1 -0
  45. package/package.json +86 -0
@@ -0,0 +1,79 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+ import { readFile, writeFile } from "fs/promises";
4
+ import { logger } from "./logger.js";
5
+ import { homedir } from "os";
6
+ import { join } from "path";
7
+ const CACHE_FILE = join(homedir(), ".ado_orgs.cache");
8
+ const CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 1 week in milliseconds
9
+ async function loadCache() {
10
+ try {
11
+ const cacheData = await readFile(CACHE_FILE, "utf-8");
12
+ return JSON.parse(cacheData);
13
+ }
14
+ catch {
15
+ // Cache file doesn't exist or is invalid, return empty cache
16
+ return {};
17
+ }
18
+ }
19
+ async function trySavingCache(cache) {
20
+ try {
21
+ await writeFile(CACHE_FILE, JSON.stringify(cache, null, 2), "utf-8");
22
+ }
23
+ catch (error) {
24
+ logger.error("Failed to save org tenants cache:", error);
25
+ }
26
+ }
27
+ async function fetchTenantFromApi(orgName) {
28
+ const customUrl = process.env.ADO_MCP_VSSPS_URL;
29
+ const baseUrl = customUrl || "https://vssps.dev.azure.com";
30
+ const url = `${baseUrl}/${orgName}`;
31
+ try {
32
+ const response = await fetch(url, { method: "HEAD" });
33
+ if (response.status !== 404) {
34
+ throw new Error(`Expected status 404, got ${response.status}`);
35
+ }
36
+ const tenantId = response.headers.get("x-vss-resourcetenant");
37
+ if (!tenantId) {
38
+ throw new Error("x-vss-resourcetenant header not found in response");
39
+ }
40
+ return tenantId;
41
+ }
42
+ catch (error) {
43
+ throw new Error(`Failed to fetch tenant for organization ${orgName}: ${error}`);
44
+ }
45
+ }
46
+ function isCacheEntryExpired(entry) {
47
+ return Date.now() - entry.refreshedOn > CACHE_TTL_MS;
48
+ }
49
+ export async function getOrgTenant(orgName) {
50
+ // Load cache
51
+ const cache = await loadCache();
52
+ // Check if tenant is cached and not expired
53
+ const cachedEntry = cache[orgName];
54
+ if (cachedEntry && !isCacheEntryExpired(cachedEntry)) {
55
+ return cachedEntry.tenantId;
56
+ }
57
+ // Try to fetch fresh tenant from API
58
+ try {
59
+ const tenantId = await fetchTenantFromApi(orgName);
60
+ // Cache the result
61
+ cache[orgName] = {
62
+ tenantId,
63
+ refreshedOn: Date.now(),
64
+ };
65
+ await trySavingCache(cache);
66
+ return tenantId;
67
+ }
68
+ catch (error) {
69
+ // If we have an expired cache entry, return it as fallback
70
+ if (cachedEntry) {
71
+ logger.error(`Failed to fetch fresh tenant for ADO org ${orgName}, using expired cache entry:`, error);
72
+ return cachedEntry.tenantId;
73
+ }
74
+ // No cache entry available, log and return empty result
75
+ logger.error(`Failed to fetch tenant for ADO org ${orgName}:`, error);
76
+ return undefined;
77
+ }
78
+ }
79
+ //# sourceMappingURL=org-tenants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"org-tenants.js","sourceRoot":"","sources":["../src/org-tenants.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAS5B,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,iBAAiB,CAAC,CAAC;AACtD,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,yBAAyB;AAEvE,KAAK,UAAU,SAAS;IACtB,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACtD,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,6DAA6D;QAC7D,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,KAAqB;IACjD,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACvE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,OAAe;IAC/C,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAChD,MAAM,OAAO,GAAG,SAAS,IAAI,6BAA6B,CAAC;IAC3D,MAAM,GAAG,GAAG,GAAG,OAAO,IAAI,OAAO,EAAE,CAAC;IAEpC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QAEtD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,4BAA4B,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QACjE,CAAC;QAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;QAC9D,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;QACvE,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,2CAA2C,OAAO,KAAK,KAAK,EAAE,CAAC,CAAC;IAClF,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB,CAAC,KAA0B;IACrD,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,WAAW,GAAG,YAAY,CAAC;AACvD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAAe;IAChD,aAAa;IACb,MAAM,KAAK,GAAG,MAAM,SAAS,EAAE,CAAC;IAEhC,4CAA4C;IAC5C,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,WAAW,IAAI,CAAC,mBAAmB,CAAC,WAAW,CAAC,EAAE,CAAC;QACrD,OAAO,WAAW,CAAC,QAAQ,CAAC;IAC9B,CAAC;IAED,qCAAqC;IACrC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,OAAO,CAAC,CAAC;QAEnD,mBAAmB;QACnB,KAAK,CAAC,OAAO,CAAC,GAAG;YACf,QAAQ;YACR,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE;SACxB,CAAC;QACF,MAAM,cAAc,CAAC,KAAK,CAAC,CAAC;QAE5B,OAAO,QAAQ,CAAC;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,2DAA2D;QAC3D,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,CAAC,KAAK,CAAC,4CAA4C,OAAO,8BAA8B,EAAE,KAAK,CAAC,CAAC;YACvG,OAAO,WAAW,CAAC,QAAQ,CAAC;QAC9B,CAAC;QAED,wDAAwD;QACxD,MAAM,CAAC,KAAK,CAAC,sCAAsC,OAAO,GAAG,EAAE,KAAK,CAAC,CAAC;QACtE,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
@@ -0,0 +1,21 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+ import { CORE_TOOLS } from "./tools/core.js";
4
+ function configurePrompts(server) {
5
+ server.prompt("Projects", "Lists all projects in the Azure DevOps organization.", {}, () => ({
6
+ messages: [
7
+ {
8
+ role: "user",
9
+ content: {
10
+ type: "text",
11
+ text: String.raw `
12
+ # Task
13
+ Use the '${CORE_TOOLS.list_projects}' tool to retrieve all 'wellFormed' projects in the current Azure DevOps organization.
14
+ Present the results in alphabetical order in a table with the following columns: Name and ID.`,
15
+ },
16
+ },
17
+ ],
18
+ }));
19
+ }
20
+ export { configurePrompts };
21
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAGlC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,SAAS,gBAAgB,CAAC,MAAiB;IACzC,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,sDAAsD,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3F,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE;oBACP,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,MAAM,CAAC,GAAG,CAAA;;WAEf,UAAU,CAAC,aAAa;8FAC2D;iBACrF;aACF;SACF;KACF,CAAC,CAAC,CAAC;AACN,CAAC;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
@@ -0,0 +1,126 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+ import { logger } from "../logger.js";
4
+ /**
5
+ * Available Azure DevOps MCP domains
6
+ */
7
+ export var Domain;
8
+ (function (Domain) {
9
+ Domain["ADVANCED_SECURITY"] = "advanced-security";
10
+ Domain["PIPELINES"] = "pipelines";
11
+ Domain["CORE"] = "core";
12
+ Domain["REPOSITORIES"] = "repositories";
13
+ Domain["SEARCH"] = "search";
14
+ Domain["TEST_PLANS"] = "test-plans";
15
+ Domain["WIKI"] = "wiki";
16
+ Domain["WORK"] = "work";
17
+ Domain["WORK_ITEMS"] = "work-items";
18
+ })(Domain || (Domain = {}));
19
+ export const ALL_DOMAINS = "all";
20
+ /**
21
+ * Manages domain parsing and validation for Azure DevOps MCP server tools
22
+ */
23
+ export class DomainsManager {
24
+ static AVAILABLE_DOMAINS = Object.values(Domain);
25
+ enabledDomains;
26
+ constructor(domainsInput) {
27
+ this.enabledDomains = new Set();
28
+ this.parseDomains(domainsInput);
29
+ }
30
+ /**
31
+ * Parse and validate domains from input
32
+ * @param domainsInput - Either "all", single domain name, array of domain names, or undefined (defaults to "all")
33
+ */
34
+ parseDomains(domainsInput) {
35
+ if (!domainsInput) {
36
+ this.enableAllDomains();
37
+ return;
38
+ }
39
+ if (Array.isArray(domainsInput)) {
40
+ this.handleArrayInput(domainsInput);
41
+ return;
42
+ }
43
+ this.handleStringInput(domainsInput);
44
+ }
45
+ handleArrayInput(domainsInput) {
46
+ if (domainsInput.length === 0 || domainsInput.includes(ALL_DOMAINS)) {
47
+ this.enableAllDomains();
48
+ return;
49
+ }
50
+ const domains = domainsInput.map((d) => d.trim().toLowerCase());
51
+ this.validateAndAddDomains(domains);
52
+ }
53
+ handleStringInput(domainsInput) {
54
+ if (domainsInput === ALL_DOMAINS) {
55
+ this.enableAllDomains();
56
+ return;
57
+ }
58
+ // Handle comma-separated domains
59
+ const domains = domainsInput.split(",").map((d) => d.trim().toLowerCase());
60
+ this.validateAndAddDomains(domains);
61
+ }
62
+ validateAndAddDomains(domains) {
63
+ const availableDomainsAsStringArray = Object.values(Domain);
64
+ domains.forEach((domain) => {
65
+ if (availableDomainsAsStringArray.includes(domain)) {
66
+ this.enabledDomains.add(domain);
67
+ }
68
+ else if (domain === ALL_DOMAINS) {
69
+ this.enableAllDomains();
70
+ }
71
+ else {
72
+ logger.error(`Error: Specified invalid domain '${domain}'. Please specify exactly as available domains: ${Object.values(Domain).join(", ")}`);
73
+ }
74
+ });
75
+ if (this.enabledDomains.size === 0) {
76
+ this.enableAllDomains();
77
+ }
78
+ }
79
+ enableAllDomains() {
80
+ Object.values(Domain).forEach((domain) => this.enabledDomains.add(domain));
81
+ }
82
+ /**
83
+ * Check if a specific domain is enabled
84
+ * @param domain - Domain name to check
85
+ * @returns true if domain is enabled
86
+ */
87
+ isDomainEnabled(domain) {
88
+ return this.enabledDomains.has(domain);
89
+ }
90
+ /**
91
+ * Get all enabled domains
92
+ * @returns Set of enabled domain names
93
+ */
94
+ getEnabledDomains() {
95
+ return new Set(this.enabledDomains);
96
+ }
97
+ /**
98
+ * Get list of all available domains
99
+ * @returns Array of available domain names
100
+ */
101
+ static getAvailableDomains() {
102
+ return Object.values(Domain);
103
+ }
104
+ /**
105
+ * Parse domains input from string or array to a normalized array of strings
106
+ * @param domainsInput - Domains input to parse
107
+ * @returns Normalized array of domain strings
108
+ */
109
+ static parseDomainsInput(domainsInput) {
110
+ if (!domainsInput || this.isEmptyDomainsInput(domainsInput)) {
111
+ return ["all"];
112
+ }
113
+ if (typeof domainsInput === "string") {
114
+ return domainsInput.split(",").map((d) => d.trim().toLowerCase());
115
+ }
116
+ return domainsInput.map((d) => d.trim().toLowerCase());
117
+ }
118
+ static isEmptyDomainsInput(domainsInput) {
119
+ if (typeof domainsInput === "string" && domainsInput.trim() === "")
120
+ return true;
121
+ if (Array.isArray(domainsInput) && domainsInput.length === 0)
122
+ return true;
123
+ return false;
124
+ }
125
+ }
126
+ //# sourceMappingURL=domains.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domains.js","sourceRoot":"","sources":["../../src/shared/domains.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+ /**
4
+ * Validates that a name conforms to Claude API requirements.
5
+ * Names must match pattern: ^[a-zA-Z0-9_.-]{1,64}$
6
+ * @param name The name to validate
7
+ * @returns Object with isValid boolean and error/reason message if invalid
8
+ */
9
+ export function validateName(name) {
10
+ // Check length
11
+ if (name.length === 0) {
12
+ return { isValid: false, error: "Name cannot be empty", reason: "name cannot be empty" };
13
+ }
14
+ if (name.length > 64) {
15
+ return {
16
+ isValid: false,
17
+ error: `Name '${name}' is ${name.length} characters long, maximum allowed is 64`,
18
+ reason: `name is ${name.length} characters long, maximum allowed is 64`,
19
+ };
20
+ }
21
+ // Check pattern: only alphanumeric, underscore, dot, and hyphen allowed
22
+ const validPattern = /^[a-zA-Z0-9_.-]+$/;
23
+ if (!validPattern.test(name)) {
24
+ return {
25
+ isValid: false,
26
+ error: `Name '${name}' contains invalid characters. Only alphanumeric characters, underscores, dots, and hyphens are allowed`,
27
+ reason: "name contains invalid characters. Only alphanumeric characters, underscores, dots, and hyphens are allowed",
28
+ };
29
+ }
30
+ return { isValid: true };
31
+ }
32
+ /**
33
+ * Validates that a tool name conforms to Claude API requirements.
34
+ * @param toolName The tool name to validate
35
+ * @returns Object with isValid boolean and error message if invalid
36
+ */
37
+ export function validateToolName(toolName) {
38
+ const result = validateName(toolName);
39
+ if (!result.isValid) {
40
+ return { isValid: false, error: result.error?.replace("Name", "Tool name") };
41
+ }
42
+ return result;
43
+ }
44
+ /**
45
+ * Validates that a parameter name conforms to Claude API requirements.
46
+ * @param paramName The parameter name to validate
47
+ * @returns Object with isValid boolean and error message if invalid
48
+ */
49
+ export function validateParameterName(paramName) {
50
+ const result = validateName(paramName);
51
+ if (!result.isValid) {
52
+ return { isValid: false, error: result.error?.replace("Name", "Parameter name") };
53
+ }
54
+ return result;
55
+ }
56
+ /**
57
+ * Extracts tool names from tool constant definitions
58
+ * @param fileContent - The content of a TypeScript file
59
+ * @returns Array of tool names found
60
+ */
61
+ export function extractToolNames(fileContent) {
62
+ const toolNames = [];
63
+ // Pattern to match tool constant definitions in tool objects
64
+ // This looks for patterns like: const SOMETHING_TOOLS = { ... } or const Test_Plan_Tools = { ... }
65
+ const toolsObjectPattern = /const\s+\w*[Tt][Oo][Oo][Ll][Ss]?\s*=\s*\{([^}]+)\}/g;
66
+ let toolsMatch;
67
+ while ((toolsMatch = toolsObjectPattern.exec(fileContent)) !== null) {
68
+ const objectContent = toolsMatch[1];
69
+ // Now extract individual tool definitions from within the object
70
+ const toolPattern = /^\s*[a-zA-Z_][a-zA-Z0-9_]*:\s*"([^"]+)"/gm;
71
+ let match;
72
+ while ((match = toolPattern.exec(objectContent)) !== null) {
73
+ toolNames.push(match[1]);
74
+ }
75
+ }
76
+ return toolNames;
77
+ }
78
+ /**
79
+ * Extracts parameter names from Zod schema definitions
80
+ * @param fileContent - The content of a TypeScript file
81
+ * @returns Array of parameter names found
82
+ */
83
+ export function extractParameterNames(fileContent) {
84
+ const paramNames = [];
85
+ // Pattern to match parameter definitions like: paramName: z.string()
86
+ const paramPattern = /^\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*z\./gm;
87
+ let match;
88
+ while ((match = paramPattern.exec(fileContent)) !== null) {
89
+ paramNames.push(match[1]);
90
+ }
91
+ return paramNames;
92
+ }
93
+ //# sourceMappingURL=tool-validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-validation.js","sourceRoot":"","sources":["../../src/shared/tool-validation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,109 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+ import { AlertType, AlertValidityStatus, Confidence, Severity, State } from "azure-devops-node-api/interfaces/AlertInterfaces.js";
4
+ import { z } from "zod";
5
+ import { getEnumKeys, mapStringArrayToEnum, mapStringToEnum } from "../utils.js";
6
+ const ADVSEC_TOOLS = {
7
+ get_alerts: "advsec_get_alerts",
8
+ get_alert_details: "advsec_get_alert_details",
9
+ };
10
+ function configureAdvSecTools(server, _, connectionProvider) {
11
+ server.tool(ADVSEC_TOOLS.get_alerts, "Retrieve Advanced Security alerts for a repository.", {
12
+ project: z.string().describe("The name or ID of the Azure DevOps project."),
13
+ repository: z.string().describe("The name or ID of the repository to get alerts for."),
14
+ alertType: z
15
+ .enum(getEnumKeys(AlertType))
16
+ .optional()
17
+ .describe("Filter alerts by type. If not specified, returns all alert types."),
18
+ states: z
19
+ .array(z.enum(getEnumKeys(State)))
20
+ .optional()
21
+ .describe("Filter alerts by state. If not specified, returns alerts in any state."),
22
+ severities: z
23
+ .array(z.enum(getEnumKeys(Severity)))
24
+ .optional()
25
+ .describe("Filter alerts by severity level. If not specified, returns alerts at any severity."),
26
+ ruleId: z.string().optional().describe("Filter alerts by rule ID."),
27
+ ruleName: z.string().optional().describe("Filter alerts by rule name."),
28
+ toolName: z.string().optional().describe("Filter alerts by tool name."),
29
+ ref: z.string().optional().describe("Filter alerts by git reference (branch). If not provided and onlyDefaultBranch is true, only includes alerts from default branch."),
30
+ onlyDefaultBranch: z.boolean().optional().default(true).describe("If true, only return alerts found on the default branch. Defaults to true."),
31
+ confidenceLevels: z
32
+ .array(z.enum(getEnumKeys(Confidence)))
33
+ .optional()
34
+ .default(["high", "other"])
35
+ .describe("Filter alerts by confidence levels. Only applicable for secret alerts. Defaults to both 'high' and 'other'."),
36
+ validity: z
37
+ .array(z.enum(getEnumKeys(AlertValidityStatus)))
38
+ .optional()
39
+ .describe("Filter alerts by validity status. Only applicable for secret alerts."),
40
+ top: z.number().optional().default(100).describe("Maximum number of alerts to return. Defaults to 100."),
41
+ orderBy: z.enum(["id", "firstSeen", "lastSeen", "fixedOn", "severity"]).optional().default("severity").describe("Order results by specified field. Defaults to 'severity'."),
42
+ continuationToken: z.string().optional().describe("Continuation token for pagination."),
43
+ }, async ({ project, repository, alertType, states, severities, ruleId, ruleName, toolName, ref, onlyDefaultBranch, confidenceLevels, validity, top, orderBy, continuationToken }) => {
44
+ try {
45
+ const connection = await connectionProvider();
46
+ const alertApi = await connection.getAlertApi();
47
+ const isSecretAlert = !alertType || alertType.toLowerCase() === "secret";
48
+ const criteria = {
49
+ ...(alertType && { alertType: mapStringToEnum(alertType, AlertType) }),
50
+ ...(states && { states: mapStringArrayToEnum(states, State) }),
51
+ ...(severities && { severities: mapStringArrayToEnum(severities, Severity) }),
52
+ ...(ruleId && { ruleId }),
53
+ ...(ruleName && { ruleName }),
54
+ ...(toolName && { toolName }),
55
+ ...(ref && { ref }),
56
+ ...(onlyDefaultBranch !== undefined && { onlyDefaultBranch }),
57
+ ...(isSecretAlert && confidenceLevels && { confidenceLevels: mapStringArrayToEnum(confidenceLevels, Confidence) }),
58
+ ...(isSecretAlert && validity && { validity: mapStringArrayToEnum(validity, AlertValidityStatus) }),
59
+ };
60
+ const result = await alertApi.getAlerts(project, repository, top, orderBy, criteria, undefined, // expand parameter
61
+ continuationToken);
62
+ return {
63
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
64
+ };
65
+ }
66
+ catch (error) {
67
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
68
+ return {
69
+ content: [
70
+ {
71
+ type: "text",
72
+ text: `Error fetching Advanced Security alerts: ${errorMessage}`,
73
+ },
74
+ ],
75
+ isError: true,
76
+ };
77
+ }
78
+ });
79
+ server.tool(ADVSEC_TOOLS.get_alert_details, "Get detailed information about a specific Advanced Security alert.", {
80
+ project: z.string().describe("The name or ID of the Azure DevOps project."),
81
+ repository: z.string().describe("The name or ID of the repository containing the alert."),
82
+ alertId: z.number().describe("The ID of the alert to retrieve details for."),
83
+ ref: z.string().optional().describe("Git reference (branch) to filter the alert."),
84
+ }, async ({ project, repository, alertId, ref }) => {
85
+ try {
86
+ const connection = await connectionProvider();
87
+ const alertApi = await connection.getAlertApi();
88
+ const result = await alertApi.getAlert(project, alertId, repository, ref, undefined // expand parameter
89
+ );
90
+ return {
91
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
92
+ };
93
+ }
94
+ catch (error) {
95
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
96
+ return {
97
+ content: [
98
+ {
99
+ type: "text",
100
+ text: `Error fetching alert details: ${errorMessage}`,
101
+ },
102
+ ],
103
+ isError: true,
104
+ };
105
+ }
106
+ });
107
+ }
108
+ export { ADVSEC_TOOLS, configureAdvSecTools };
109
+ //# sourceMappingURL=advanced-security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"advanced-security.js","sourceRoot":"","sources":["../../src/tools/advanced-security.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+ import { apiVersion } from "../utils.js";
4
+ async function getCurrentUserDetails(tokenProvider, connectionProvider, userAgentProvider) {
5
+ const connection = await connectionProvider();
6
+ const url = `${connection.serverUrl}/_apis/connectionData`;
7
+ const token = await tokenProvider();
8
+ const response = await fetch(url, {
9
+ method: "GET",
10
+ headers: {
11
+ "Authorization": `Bearer ${token}`,
12
+ "Content-Type": "application/json",
13
+ "User-Agent": userAgentProvider(),
14
+ },
15
+ });
16
+ const data = await response.json();
17
+ if (!response.ok) {
18
+ throw new Error(`Error fetching user details: ${data.message}`);
19
+ }
20
+ return data;
21
+ }
22
+ /**
23
+ * Searches for identities using Azure DevOps Identity API
24
+ */
25
+ async function searchIdentities(identity, tokenProvider, connectionProvider, userAgentProvider) {
26
+ const token = await tokenProvider();
27
+ const connection = await connectionProvider();
28
+ const orgName = connection.serverUrl.split("/")[3];
29
+ const baseUrl = `https://vssps.dev.azure.com/${orgName}/_apis/identities`;
30
+ const params = new URLSearchParams({
31
+ "api-version": apiVersion,
32
+ "searchFilter": "General",
33
+ "filterValue": identity,
34
+ });
35
+ // TODO: OnPremise check
36
+ const response = await fetch(`${baseUrl}?${params}`, {
37
+ headers: {
38
+ "Authorization": `Bearer ${token}`,
39
+ "Content-Type": "application/json",
40
+ "User-Agent": userAgentProvider(),
41
+ },
42
+ });
43
+ if (!response.ok) {
44
+ const errorText = await response.text();
45
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
46
+ }
47
+ return await response.json();
48
+ }
49
+ /**
50
+ * Gets the user ID from email or unique name using Azure DevOps Identity API
51
+ */
52
+ async function getUserIdFromEmail(userEmail, tokenProvider, connectionProvider, userAgentProvider) {
53
+ const identities = await searchIdentities(userEmail, tokenProvider, connectionProvider, userAgentProvider);
54
+ if (!identities || identities.value?.length === 0) {
55
+ throw new Error(`No user found with email/unique name: ${userEmail}`);
56
+ }
57
+ const firstIdentity = identities.value[0];
58
+ if (!firstIdentity.id) {
59
+ throw new Error(`No ID found for user with email/unique name: ${userEmail}`);
60
+ }
61
+ return firstIdentity.id;
62
+ }
63
+ export { getCurrentUserDetails, getUserIdFromEmail, searchIdentities };
64
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/tools/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,96 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+ import { z } from "zod";
4
+ import { searchIdentities } from "./auth.js";
5
+ const CORE_TOOLS = {
6
+ list_project_teams: "core_list_project_teams",
7
+ list_projects: "core_list_projects",
8
+ get_identity_ids: "core_get_identity_ids",
9
+ };
10
+ function filterProjectsByName(projects, projectNameFilter) {
11
+ const lowerCaseFilter = projectNameFilter.toLowerCase();
12
+ return projects.filter((project) => project.name?.toLowerCase().includes(lowerCaseFilter));
13
+ }
14
+ function configureCoreTools(server, tokenProvider, connectionProvider, userAgentProvider) {
15
+ server.tool(CORE_TOOLS.list_project_teams, "Retrieve a list of teams for the specified Azure DevOps project.", {
16
+ project: z.string().describe("The name or ID of the Azure DevOps project."),
17
+ mine: z.boolean().optional().describe("If true, only return teams that the authenticated user is a member of."),
18
+ top: z.number().optional().describe("The maximum number of teams to return. Defaults to 100."),
19
+ skip: z.number().optional().describe("The number of teams to skip for pagination. Defaults to 0."),
20
+ }, async ({ project, mine, top, skip }) => {
21
+ try {
22
+ const connection = await connectionProvider();
23
+ const coreApi = await connection.getCoreApi();
24
+ const teams = await coreApi.getTeams(project, mine, top, skip, false);
25
+ if (!teams) {
26
+ return { content: [{ type: "text", text: "No teams found" }], isError: true };
27
+ }
28
+ return {
29
+ content: [{ type: "text", text: JSON.stringify(teams, null, 2) }],
30
+ };
31
+ }
32
+ catch (error) {
33
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
34
+ return {
35
+ content: [{ type: "text", text: `Error fetching project teams: ${errorMessage}` }],
36
+ isError: true,
37
+ };
38
+ }
39
+ });
40
+ server.tool(CORE_TOOLS.list_projects, "Retrieve a list of projects in your Azure DevOps organization.", {
41
+ stateFilter: z.enum(["all", "wellFormed", "createPending", "deleted"]).default("wellFormed").describe("Filter projects by their state. Defaults to 'wellFormed'."),
42
+ top: z.number().optional().describe("The maximum number of projects to return. Defaults to 100."),
43
+ skip: z.number().optional().describe("The number of projects to skip for pagination. Defaults to 0."),
44
+ continuationToken: z.number().optional().describe("Continuation token for pagination. Used to fetch the next set of results if available."),
45
+ projectNameFilter: z.string().optional().describe("Filter projects by name. Supports partial matches."),
46
+ }, async ({ stateFilter, top, skip, continuationToken, projectNameFilter }) => {
47
+ try {
48
+ const connection = await connectionProvider();
49
+ const coreApi = await connection.getCoreApi();
50
+ const projects = await coreApi.getProjects(stateFilter, top, skip, continuationToken, false);
51
+ if (!projects) {
52
+ return { content: [{ type: "text", text: "No projects found" }], isError: true };
53
+ }
54
+ const filteredProject = projectNameFilter ? filterProjectsByName(projects, projectNameFilter) : projects;
55
+ return {
56
+ content: [{ type: "text", text: JSON.stringify(filteredProject, null, 2) }],
57
+ };
58
+ }
59
+ catch (error) {
60
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
61
+ return {
62
+ content: [{ type: "text", text: `Error fetching projects: ${errorMessage}` }],
63
+ isError: true,
64
+ };
65
+ }
66
+ });
67
+ server.tool(CORE_TOOLS.get_identity_ids, "Retrieve Azure DevOps identity IDs for a provided search filter.", {
68
+ searchFilter: z.string().describe("Search filter (unique name, display name, email) to retrieve identity IDs for."),
69
+ }, async ({ searchFilter }) => {
70
+ try {
71
+ const identities = await searchIdentities(searchFilter, tokenProvider, connectionProvider, userAgentProvider);
72
+ if (!identities || identities.value?.length === 0) {
73
+ return { content: [{ type: "text", text: "No identities found" }], isError: true };
74
+ }
75
+ const identitiesTrimmed = identities.value?.map((identity) => {
76
+ return {
77
+ id: identity.id,
78
+ displayName: identity.providerDisplayName,
79
+ descriptor: identity.descriptor,
80
+ };
81
+ });
82
+ return {
83
+ content: [{ type: "text", text: JSON.stringify(identitiesTrimmed, null, 2) }],
84
+ };
85
+ }
86
+ catch (error) {
87
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
88
+ return {
89
+ content: [{ type: "text", text: `Error fetching identities: ${errorMessage}` }],
90
+ isError: true,
91
+ };
92
+ }
93
+ });
94
+ }
95
+ export { CORE_TOOLS, configureCoreTools };
96
+ //# sourceMappingURL=core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../../src/tools/core.ts"],"names":[],"mappings":"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"}