Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/tools/advanced-security.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ function configureAdvSecTools(server: McpServer, _: () => Promise<string>, conne
orderBy: z.enum(["id", "firstSeen", "lastSeen", "fixedOn", "severity"]).optional().default("severity").describe("Order results by specified field. Defaults to 'severity'."),
continuationToken: z.string().optional().describe("Continuation token for pagination."),
},
{
title: "Get Security Alerts",
readOnlyHint: true,
},
async ({ project, repository, alertType, states, severities, ruleId, ruleName, toolName, ref, onlyDefaultBranch, confidenceLevels, validity, top, orderBy, continuationToken }) => {
try {
const connection = await connectionProvider();
Expand Down Expand Up @@ -106,6 +110,10 @@ function configureAdvSecTools(server: McpServer, _: () => Promise<string>, conne
alertId: z.number().describe("The ID of the alert to retrieve details for."),
ref: z.string().optional().describe("Git reference (branch) to filter the alert."),
},
{
title: "Get Alert Details",
readOnlyHint: true,
},
async ({ project, repository, alertId, ref }) => {
try {
const connection = await connectionProvider();
Expand Down
12 changes: 12 additions & 0 deletions src/tools/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ function configureCoreTools(server: McpServer, tokenProvider: () => Promise<stri
top: z.number().optional().describe("The maximum number of teams to return. Defaults to 100."),
skip: z.number().optional().describe("The number of teams to skip for pagination. Defaults to 0."),
},
{
title: "List Project Teams",
readOnlyHint: true,
},
async ({ project, mine, top, skip }) => {
try {
const connection = await connectionProvider();
Expand Down Expand Up @@ -64,6 +68,10 @@ function configureCoreTools(server: McpServer, tokenProvider: () => Promise<stri
continuationToken: z.number().optional().describe("Continuation token for pagination. Used to fetch the next set of results if available."),
projectNameFilter: z.string().optional().describe("Filter projects by name. Supports partial matches."),
},
{
title: "List Projects",
readOnlyHint: true,
},
async ({ stateFilter, top, skip, continuationToken, projectNameFilter }) => {
try {
const connection = await connectionProvider();
Expand Down Expand Up @@ -96,6 +104,10 @@ function configureCoreTools(server: McpServer, tokenProvider: () => Promise<stri
{
searchFilter: z.string().describe("Search filter (unique name, display name, email) to retrieve identity IDs for."),
},
{
title: "Get Identity IDs",
readOnlyHint: true,
},
async ({ searchFilter }) => {
try {
const identities = await searchIdentities(searchFilter, tokenProvider, connectionProvider, userAgentProvider);
Expand Down
48 changes: 48 additions & 0 deletions src/tools/pipelines.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ function configurePipelineTools(server: McpServer, tokenProvider: () => Promise<
processType: z.number().optional().describe("Process type to filter build definitions"),
yamlFilename: z.string().optional().describe("YAML filename to filter build definitions"),
},
{
title: "Get Build Definitions",
readOnlyHint: true,
},
async ({
project,
repositoryId,
Expand Down Expand Up @@ -115,6 +119,10 @@ function configurePipelineTools(server: McpServer, tokenProvider: () => Promise<
repositoryId: z.string().optional().describe("The ID of the repository."),
repositoryConnectionId: z.string().optional().describe("The service connection ID for GitHub repositories. Not required for Azure Repos Git."),
},
{
title: "Create Pipeline",
destructiveHint: true,
},
async ({ project, name, folder, yamlPath, repositoryType, repositoryName, repositoryId, repositoryConnectionId }) => {
const connection = await connectionProvider();
const pipelinesApi = await connection.getPipelinesApi();
Expand Down Expand Up @@ -163,6 +171,10 @@ function configurePipelineTools(server: McpServer, tokenProvider: () => Promise<
project: z.string().describe("Project ID or name to get the build definition revisions for"),
definitionId: z.number().describe("ID of the build definition to get revisions for"),
},
{
title: "Get Build Definition Revisions",
readOnlyHint: true,
},
async ({ project, definitionId }) => {
const connection = await connectionProvider();
const buildApi = await connection.getBuildApi();
Expand Down Expand Up @@ -204,6 +216,10 @@ function configurePipelineTools(server: McpServer, tokenProvider: () => Promise<
repositoryId: z.string().optional().describe("Repository ID to filter builds"),
repositoryType: z.enum(["TfsGit", "GitHub", "BitbucketCloud"]).optional().describe("Type of repository to filter builds"),
},
{
title: "Get Builds",
readOnlyHint: true,
},
async ({
project,
definitions,
Expand Down Expand Up @@ -266,6 +282,10 @@ function configurePipelineTools(server: McpServer, tokenProvider: () => Promise<
project: z.string().describe("Project ID or name to get the build log for"),
buildId: z.number().describe("ID of the build to get the log for"),
},
{
title: "Get Build Log",
readOnlyHint: true,
},
async ({ project, buildId }) => {
const connection = await connectionProvider();
const buildApi = await connection.getBuildApi();
Expand All @@ -287,6 +307,10 @@ function configurePipelineTools(server: McpServer, tokenProvider: () => Promise<
startLine: z.number().optional().describe("Starting line number for the log content, defaults to 0"),
endLine: z.number().optional().describe("Ending line number for the log content, defaults to the end of the log"),
},
{
title: "Get Build Log By ID",
readOnlyHint: true,
},
async ({ project, buildId, logId, startLine, endLine }) => {
const connection = await connectionProvider();
const buildApi = await connection.getBuildApi();
Expand All @@ -308,6 +332,10 @@ function configurePipelineTools(server: McpServer, tokenProvider: () => Promise<
top: z.number().default(100).describe("Number of changes to retrieve, defaults to 100"),
includeSourceChange: z.boolean().optional().describe("Whether to include source changes in the results, defaults to false"),
},
{
title: "Get Build Changes",
readOnlyHint: true,
},
async ({ project, buildId, continuationToken, top, includeSourceChange }) => {
const connection = await connectionProvider();
const buildApi = await connection.getBuildApi();
Expand All @@ -327,6 +355,10 @@ function configurePipelineTools(server: McpServer, tokenProvider: () => Promise<
pipelineId: z.number().describe("ID of the pipeline to run"),
runId: z.number().describe("ID of the run to get"),
},
{
title: "Get Pipeline Run",
readOnlyHint: true,
},
async ({ project, pipelineId, runId }) => {
const connection = await connectionProvider();
const pipelinesApi = await connection.getPipelinesApi();
Expand All @@ -345,6 +377,10 @@ function configurePipelineTools(server: McpServer, tokenProvider: () => Promise<
project: z.string().describe("Project ID or name to run the build in"),
pipelineId: z.number().describe("ID of the pipeline to run"),
},
{
title: "List Pipeline Runs",
readOnlyHint: true,
},
async ({ project, pipelineId }) => {
const connection = await connectionProvider();
const pipelinesApi = await connection.getPipelinesApi();
Expand Down Expand Up @@ -415,6 +451,10 @@ function configurePipelineTools(server: McpServer, tokenProvider: () => Promise<
variables: z.record(z.string(), variableSchema).optional().describe("A dictionary of variables to pass to the pipeline."),
yamlOverride: z.string().optional().describe("YAML override for the pipeline run."),
},
{
title: "Run Pipeline",
destructiveHint: true,
},
async ({ project, pipelineId, pipelineVersion, previewRun, resources, stagesToSkip, templateParameters, variables, yamlOverride }) => {
if (!previewRun && yamlOverride) {
throw new Error("Parameter 'yamlOverride' can only be specified together with parameter 'previewRun'.");
Expand Down Expand Up @@ -453,6 +493,10 @@ function configurePipelineTools(server: McpServer, tokenProvider: () => Promise<
project: z.string().describe("Project ID or name to get the build status for"),
buildId: z.number().describe("ID of the build to get the status for"),
},
{
title: "Get Build Status",
readOnlyHint: true,
},
async ({ project, buildId }) => {
const connection = await connectionProvider();
const buildApi = await connection.getBuildApi();
Expand All @@ -474,6 +518,10 @@ function configurePipelineTools(server: McpServer, tokenProvider: () => Promise<
status: z.enum(getEnumKeys(StageUpdateType) as [string, ...string[]]).describe("New status for the stage"),
forceRetryAllJobs: z.boolean().default(false).describe("Whether to force retry all jobs in the stage."),
},
{
title: "Update Build Stage",
destructiveHint: true,
},
async ({ project, buildId, stageName, status, forceRetryAllJobs }) => {
const connection = await connectionProvider();
const orgUrl = connection.serverUrl;
Expand Down
72 changes: 72 additions & 0 deletions src/tools/repositories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<stri
forkSourceRepositoryId: z.string().optional().describe("The ID of the fork repository that the pull request originates from. Optional, used when creating a pull request from a fork."),
labels: z.array(z.string()).optional().describe("Array of label names to add to the pull request after creation."),
},
{
title: "Create Pull Request",
destructiveHint: true,
},
async ({ repositoryId, sourceRefName, targetRefName, title, description, isDraft, workItems, forkSourceRepositoryId, labels }) => {
try {
const connection = await connectionProvider();
Expand Down Expand Up @@ -204,6 +208,10 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<stri
sourceBranchName: z.string().optional().default("main").describe("The name of the source branch to create the new branch from. Defaults to 'main'."),
sourceCommitId: z.string().optional().describe("The commit ID to create the branch from. If not provided, uses the latest commit of the source branch."),
},
{
title: "Create Branch",
destructiveHint: true,
},
async ({ repositoryId, branchName, sourceBranchName, sourceCommitId }) => {
try {
const connection = await connectionProvider();
Expand Down Expand Up @@ -318,6 +326,10 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<stri
bypassReason: z.string().optional().describe("Reason for bypassing branch policies. When provided, branch policies will be automatically bypassed during autocompletion."),
labels: z.array(z.string()).optional().describe("Array of label names to replace existing labels on the pull request. This will remove all current labels and add the specified ones."),
},
{
title: "Update Pull Request",
destructiveHint: true,
},
async ({ repositoryId, pullRequestId, title, description, isDraft, targetRefName, status, autoComplete, mergeStrategy, deleteSourceBranch, transitionWorkItems, bypassReason, labels }) => {
try {
const connection = await connectionProvider();
Expand Down Expand Up @@ -415,6 +427,10 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<stri
reviewerIds: z.array(z.string()).describe("List of reviewer ids to add or remove from the pull request."),
action: z.enum(["add", "remove"]).describe("Action to perform on the reviewers. Can be 'add' or 'remove'."),
},
{
title: "Update Pull Request Reviewers",
destructiveHint: true,
},
async ({ repositoryId, pullRequestId, reviewerIds, action }) => {
try {
const connection = await connectionProvider();
Expand Down Expand Up @@ -469,6 +485,10 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<stri
skip: z.number().default(0).describe("The number of repositories to skip. Defaults to 0."),
repoNameFilter: z.string().optional().describe("Optional filter to search for repositories by name. If provided, only repositories with names containing this string will be returned."),
},
{
title: "List Repositories",
readOnlyHint: true,
},
async ({ project, top, skip, repoNameFilter }) => {
try {
const connection = await connectionProvider();
Expand Down Expand Up @@ -526,6 +546,10 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<stri
sourceRefName: z.string().optional().describe("Filter pull requests from this source branch (e.g., 'refs/heads/feature-branch')."),
targetRefName: z.string().optional().describe("Filter pull requests into this target branch (e.g., 'refs/heads/main')."),
},
{
title: "List Pull Requests",
readOnlyHint: true,
},
async ({ repositoryId, project, top, skip, created_by_me, created_by_user, i_am_reviewer, user_is_reviewer, status, sourceRefName, targetRefName }) => {
try {
const connection = await connectionProvider();
Expand Down Expand Up @@ -676,6 +700,10 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<stri
authorEmail: z.string().optional().describe("Filter threads by the email of the thread author (first comment author)."),
authorDisplayName: z.string().optional().describe("Filter threads by the display name of the thread author (first comment author). Case-insensitive partial matching."),
},
{
title: "List Pull Request Threads",
readOnlyHint: true,
},
async ({ repositoryId, pullRequestId, project, iteration, baseIteration, top, skip, fullResponse, status, authorEmail, authorDisplayName }) => {
try {
const connection = await connectionProvider();
Expand Down Expand Up @@ -742,6 +770,10 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<stri
skip: z.number().default(0).describe("The number of comments to skip."),
fullResponse: z.boolean().optional().default(false).describe("Return full comment JSON response instead of trimmed data."),
},
{
title: "List Thread Comments",
readOnlyHint: true,
},
async ({ repositoryId, pullRequestId, threadId, project, top, skip, fullResponse }) => {
try {
const connection = await connectionProvider();
Expand Down Expand Up @@ -783,6 +815,10 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<stri
top: z.number().default(100).describe("The maximum number of branches to return. Defaults to 100."),
filterContains: z.string().optional().describe("Filter to find branches that contain this string in their name."),
},
{
title: "List Branches",
readOnlyHint: true,
},
async ({ repositoryId, top, filterContains }) => {
try {
const connection = await connectionProvider();
Expand Down Expand Up @@ -813,6 +849,10 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<stri
top: z.number().default(100).describe("The maximum number of branches to return."),
filterContains: z.string().optional().describe("Filter to find branches that contain this string in their name."),
},
{
title: "List My Branches",
readOnlyHint: true,
},
async ({ repositoryId, top, filterContains }) => {
try {
const connection = await connectionProvider();
Expand Down Expand Up @@ -842,6 +882,10 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<stri
project: z.string().describe("Project name or ID where the repository is located."),
repositoryNameOrId: z.string().describe("Repository name or ID."),
},
{
title: "Get Repository",
readOnlyHint: true,
},
async ({ project, repositoryNameOrId }) => {
try {
const connection = await connectionProvider();
Expand Down Expand Up @@ -878,6 +922,10 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<stri
repositoryId: z.string().describe("The ID of the repository where the branch is located."),
branchName: z.string().describe("The name of the branch to retrieve, e.g., 'main' or 'feature-branch'."),
},
{
title: "Get Branch",
readOnlyHint: true,
},
async ({ repositoryId, branchName }) => {
try {
const connection = await connectionProvider();
Expand Down Expand Up @@ -918,6 +966,10 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<stri
includeWorkItemRefs: z.boolean().optional().default(false).describe("Whether to reference work items associated with the pull request."),
includeLabels: z.boolean().optional().default(false).describe("Whether to include a summary of labels in the response."),
},
{
title: "Get Pull Request",
readOnlyHint: true,
},
async ({ repositoryId, pullRequestId, includeWorkItemRefs, includeLabels }) => {
try {
const connection = await connectionProvider();
Expand Down Expand Up @@ -981,6 +1033,10 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<stri
project: z.string().optional().describe("Project ID or project name (optional)"),
fullResponse: z.boolean().optional().default(false).describe("Return full comment JSON response instead of a simple confirmation message."),
},
{
title: "Reply to Comment",
destructiveHint: true,
},
async ({ repositoryId, pullRequestId, threadId, content, project, fullResponse }) => {
try {
const connection = await connectionProvider();
Expand Down Expand Up @@ -1049,6 +1105,10 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<stri
"Position of last character of the thread's span in right file. The character offset of a thread's position inside of a line. Must be set if rightFileEndLine is also specified. (optional)"
),
},
{
title: "Create Comment Thread",
destructiveHint: true,
},
async ({ repositoryId, pullRequestId, content, project, filePath, status, rightFileStartLine, rightFileStartOffset, rightFileEndLine, rightFileEndOffset }) => {
try {
const connection = await connectionProvider();
Expand Down Expand Up @@ -1176,6 +1236,10 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<stri
.optional()
.describe("The new status for the comment thread."),
},
{
title: "Update Comment Thread",
destructiveHint: true,
},
async ({ repositoryId, pullRequestId, threadId, project, status }) => {
try {
const connection = await connectionProvider();
Expand Down Expand Up @@ -1250,6 +1314,10 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<stri
commitIds: z.array(z.string()).optional().describe("Array of specific commit IDs to retrieve. When provided, other filters are ignored except top/skip."),
historySimplificationMode: z.enum(["FirstParent", "SimplifyMerges", "FullHistory", "FullHistorySimplifyMerges"]).optional().describe("How to simplify the commit history"),
},
{
title: "Search Commits",
readOnlyHint: true,
},
async ({
project,
repository,
Expand Down Expand Up @@ -1411,6 +1479,10 @@ function configureRepoTools(server: McpServer, tokenProvider: () => Promise<stri
.default(GitPullRequestQueryType[GitPullRequestQueryType.LastMergeCommit])
.describe("Type of query to perform"),
},
{
title: "List Pull Requests by Commits",
readOnlyHint: true,
},
async ({ project, repository, commits, queryType }) => {
try {
const connection = await connectionProvider();
Expand Down
Loading