This is page 7 of 7. Use http://codebase.md/tiberriver256/azure-devops-mcp?lines=false&page={x} to view the full context.
# Directory Structure
```
├── .clinerules
├── .env.example
├── .eslintrc.json
├── .github
│ ├── copilot-instructions.md
│ ├── FUNDING.yml
│ ├── release-please-config.json
│ ├── release-please-manifest.json
│ ├── skills
│ │ ├── azure-devops-rest-api
│ │ │ ├── references
│ │ │ │ └── api_areas.md
│ │ │ ├── scripts
│ │ │ │ ├── clone_specs.sh
│ │ │ │ └── find_endpoint.py
│ │ │ └── SKILL.md
│ │ └── skill-creator
│ │ ├── LICENSE.txt
│ │ ├── references
│ │ │ ├── output-patterns.md
│ │ │ └── workflows.md
│ │ ├── scripts
│ │ │ ├── init_skill.py
│ │ │ └── quick_validate.py
│ │ └── SKILL.md
│ └── workflows
│ ├── main.yml
│ ├── release-please.yml
│ └── update-skills.yml
├── .gitignore
├── .husky
│ ├── commit-msg
│ └── pre-commit
├── .kilocode
│ └── mcp.json
├── .prettierrc
├── .vscode
│ └── settings.json
├── CHANGELOG.md
├── commitlint.config.js
├── CONTRIBUTING.md
├── create_branch.sh
├── docs
│ ├── authentication.md
│ ├── azure-identity-authentication.md
│ ├── ci-setup.md
│ ├── examples
│ │ ├── azure-cli-authentication.env
│ │ ├── azure-identity-authentication.env
│ │ ├── pat-authentication.env
│ │ └── README.md
│ ├── testing
│ │ ├── README.md
│ │ └── setup.md
│ └── tools
│ ├── core-navigation.md
│ ├── organizations.md
│ ├── pipelines.md
│ ├── projects.md
│ ├── pull-requests.md
│ ├── README.md
│ ├── repositories.md
│ ├── resources.md
│ ├── search.md
│ ├── user-tools.md
│ ├── wiki.md
│ └── work-items.md
├── finish_task.sh
├── jest.e2e.config.js
├── jest.int.config.js
├── jest.unit.config.js
├── LICENSE
├── memory
│ └── tasks_memory_2025-05-26T16-18-03.json
├── package-lock.json
├── package.json
├── project-management
│ ├── planning
│ │ ├── architecture-guide.md
│ │ ├── azure-identity-authentication-design.md
│ │ ├── project-plan.md
│ │ ├── project-structure.md
│ │ ├── tech-stack.md
│ │ └── the-dream-team.md
│ ├── startup.xml
│ ├── tdd-cycle.xml
│ └── troubleshooter.xml
├── README.md
├── setup_env.sh
├── shrimp-rules.md
├── src
│ ├── clients
│ │ └── azure-devops.ts
│ ├── features
│ │ ├── organizations
│ │ │ ├── __test__
│ │ │ │ └── test-helpers.ts
│ │ │ ├── index.spec.unit.ts
│ │ │ ├── index.ts
│ │ │ ├── list-organizations
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ ├── schemas.ts
│ │ │ ├── tool-definitions.ts
│ │ │ └── types.ts
│ │ ├── pipelines
│ │ │ ├── artifacts.spec.unit.ts
│ │ │ ├── artifacts.ts
│ │ │ ├── download-pipeline-artifact
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ ├── get-pipeline
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ ├── get-pipeline-log
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ ├── get-pipeline-run
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ ├── helpers.ts
│ │ │ ├── index.spec.unit.ts
│ │ │ ├── index.ts
│ │ │ ├── list-pipeline-runs
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ ├── list-pipelines
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ ├── pipeline-timeline
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ ├── tool-definitions.ts
│ │ │ ├── trigger-pipeline
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ └── types.ts
│ │ ├── projects
│ │ │ ├── __test__
│ │ │ │ └── test-helpers.ts
│ │ │ ├── get-project
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ ├── get-project-details
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ ├── index.spec.unit.ts
│ │ │ ├── index.ts
│ │ │ ├── list-projects
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ ├── schemas.ts
│ │ │ ├── tool-definitions.ts
│ │ │ └── types.ts
│ │ ├── pull-requests
│ │ │ ├── add-pull-request-comment
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ └── index.ts
│ │ │ ├── create-pull-request
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ ├── get-pull-request-changes
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ └── index.ts
│ │ │ ├── get-pull-request-checks
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ └── index.ts
│ │ │ ├── get-pull-request-comments
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ └── index.ts
│ │ │ ├── index.spec.unit.ts
│ │ │ ├── index.ts
│ │ │ ├── list-pull-requests
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ ├── schemas.ts
│ │ │ ├── tool-definitions.ts
│ │ │ ├── types.ts
│ │ │ └── update-pull-request
│ │ │ ├── feature.spec.int.ts
│ │ │ ├── feature.spec.unit.ts
│ │ │ ├── feature.ts
│ │ │ └── index.ts
│ │ ├── repositories
│ │ │ ├── __test__
│ │ │ │ └── test-helpers.ts
│ │ │ ├── create-branch
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ └── index.ts
│ │ │ ├── create-commit
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ └── index.ts
│ │ │ ├── get-all-repositories-tree
│ │ │ │ ├── __snapshots__
│ │ │ │ │ └── feature.spec.unit.ts.snap
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ ├── get-file-content
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ ├── get-repository
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ ├── get-repository-details
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ ├── get-repository-tree
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ └── index.ts
│ │ │ ├── index.spec.unit.ts
│ │ │ ├── index.ts
│ │ │ ├── list-commits
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ └── index.ts
│ │ │ ├── list-repositories
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ ├── schemas.ts
│ │ │ ├── tool-definitions.ts
│ │ │ └── types.ts
│ │ ├── search
│ │ │ ├── index.spec.unit.ts
│ │ │ ├── index.ts
│ │ │ ├── schemas.ts
│ │ │ ├── search-code
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ └── index.ts
│ │ │ ├── search-wiki
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ └── index.ts
│ │ │ ├── search-work-items
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ └── index.ts
│ │ │ ├── tool-definitions.ts
│ │ │ └── types.ts
│ │ ├── users
│ │ │ ├── get-me
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ ├── index.spec.unit.ts
│ │ │ ├── index.ts
│ │ │ ├── schemas.ts
│ │ │ ├── tool-definitions.ts
│ │ │ └── types.ts
│ │ ├── wikis
│ │ │ ├── create-wiki
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ ├── create-wiki-page
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ ├── get-wiki-page
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ ├── get-wikis
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ ├── index.spec.unit.ts
│ │ │ ├── index.ts
│ │ │ ├── list-wiki-pages
│ │ │ │ ├── feature.spec.int.ts
│ │ │ │ ├── feature.spec.unit.ts
│ │ │ │ ├── feature.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── schema.ts
│ │ │ ├── tool-definitions.ts
│ │ │ └── update-wiki-page
│ │ │ ├── feature.spec.int.ts
│ │ │ ├── feature.ts
│ │ │ ├── index.ts
│ │ │ └── schema.ts
│ │ └── work-items
│ │ ├── __test__
│ │ │ ├── fixtures.ts
│ │ │ ├── test-helpers.ts
│ │ │ └── test-utils.ts
│ │ ├── create-work-item
│ │ │ ├── feature.spec.int.ts
│ │ │ ├── feature.spec.unit.ts
│ │ │ ├── feature.ts
│ │ │ ├── index.ts
│ │ │ └── schema.ts
│ │ ├── get-work-item
│ │ │ ├── feature.spec.int.ts
│ │ │ ├── feature.spec.unit.ts
│ │ │ ├── feature.ts
│ │ │ ├── index.ts
│ │ │ └── schema.ts
│ │ ├── index.spec.unit.ts
│ │ ├── index.ts
│ │ ├── list-work-items
│ │ │ ├── feature.spec.int.ts
│ │ │ ├── feature.spec.unit.ts
│ │ │ ├── feature.ts
│ │ │ ├── index.ts
│ │ │ └── schema.ts
│ │ ├── manage-work-item-link
│ │ │ ├── feature.spec.int.ts
│ │ │ ├── feature.spec.unit.ts
│ │ │ ├── feature.ts
│ │ │ ├── index.ts
│ │ │ └── schema.ts
│ │ ├── schemas.ts
│ │ ├── tool-definitions.ts
│ │ ├── types.ts
│ │ └── update-work-item
│ │ ├── feature.spec.int.ts
│ │ ├── feature.spec.unit.ts
│ │ ├── feature.ts
│ │ ├── index.ts
│ │ └── schema.ts
│ ├── index.spec.unit.ts
│ ├── index.ts
│ ├── server.spec.e2e.ts
│ ├── server.ts
│ ├── shared
│ │ ├── api
│ │ │ ├── client.ts
│ │ │ └── index.ts
│ │ ├── auth
│ │ │ ├── auth-factory.ts
│ │ │ ├── client-factory.ts
│ │ │ └── index.ts
│ │ ├── config
│ │ │ ├── index.ts
│ │ │ └── version.ts
│ │ ├── enums
│ │ │ ├── index.spec.unit.ts
│ │ │ └── index.ts
│ │ ├── errors
│ │ │ ├── azure-devops-errors.ts
│ │ │ ├── handle-request-error.ts
│ │ │ └── index.ts
│ │ ├── test
│ │ │ └── test-helpers.ts
│ │ └── types
│ │ ├── config.ts
│ │ ├── index.ts
│ │ ├── request-handler.ts
│ │ └── tool-definition.ts
│ ├── types
│ │ └── diff.d.ts
│ └── utils
│ ├── environment.spec.unit.ts
│ └── environment.ts
├── tasks.json
├── tests
│ └── setup.ts
└── tsconfig.json
```
# Files
--------------------------------------------------------------------------------
/docs/tools/repositories.md:
--------------------------------------------------------------------------------
```markdown
# Azure DevOps Repositories Tools
This document describes the tools available for working with Azure DevOps Git repositories.
## get_repository_details
Gets detailed information about a specific Git repository, including optional branch statistics and refs.
### Description
The `get_repository_details` tool retrieves comprehensive information about a specific Git repository in Azure DevOps. It can optionally include branch statistics (ahead/behind counts, commit information) and repository refs (branches, tags). This is useful for tasks like branch management, policy configuration, and repository statistics tracking.
### Parameters
```json
{
"projectId": "MyProject", // Required: The ID or name of the project
"repositoryId": "MyRepo", // Required: The ID or name of the repository
"includeStatistics": true, // Optional: Whether to include branch statistics (default: false)
"includeRefs": true, // Optional: Whether to include repository refs (default: false)
"refFilter": "heads/", // Optional: Filter for refs (e.g., "heads/" or "tags/")
"branchName": "main" // Optional: Name of specific branch to get statistics for
}
```
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `projectId` | string | Yes | The ID or name of the project containing the repository |
| `repositoryId` | string | Yes | The ID or name of the repository to get details for |
| `includeStatistics` | boolean | No | Whether to include branch statistics (default: false) |
| `includeRefs` | boolean | No | Whether to include repository refs (default: false) |
| `refFilter` | string | No | Optional filter for refs (e.g., "heads/" or "tags/") |
| `branchName` | string | No | Name of specific branch to get statistics for (if includeStatistics is true) |
### Response
The tool returns a `RepositoryDetails` object containing:
- `repository`: The basic repository information (same as returned by `get_repository`)
- `statistics` (optional): Branch statistics if requested
- `refs` (optional): Repository refs if requested
Example response:
```json
{
"repository": {
"id": "repo-guid",
"name": "MyRepository",
"url": "https://dev.azure.com/organization/MyProject/_apis/git/repositories/MyRepository",
"project": {
"id": "project-guid",
"name": "MyProject",
"url": "https://dev.azure.com/organization/_apis/projects/project-guid"
},
"defaultBranch": "refs/heads/main",
"size": 25478,
"remoteUrl": "https://dev.azure.com/organization/MyProject/_git/MyRepository",
"sshUrl": "[email protected]:v3/organization/MyProject/MyRepository",
"webUrl": "https://dev.azure.com/organization/MyProject/_git/MyRepository"
},
"statistics": {
"branches": [
{
"name": "refs/heads/main",
"aheadCount": 0,
"behindCount": 0,
"isBaseVersion": true,
"commit": {
"commitId": "commit-guid",
"author": {
"name": "John Doe",
"email": "[email protected]",
"date": "2023-01-01T12:00:00Z"
},
"committer": {
"name": "John Doe",
"email": "[email protected]",
"date": "2023-01-01T12:00:00Z"
},
"comment": "Initial commit"
}
}
]
},
"refs": {
"value": [
{
"name": "refs/heads/main",
"objectId": "commit-guid",
"creator": {
"displayName": "John Doe",
"id": "user-guid"
},
"url": "https://dev.azure.com/organization/MyProject/_apis/git/repositories/repo-guid/refs/heads/main"
}
],
"count": 1
}
}
```
### Error Handling
The tool may throw the following errors:
- General errors: If the API call fails or other unexpected errors occur
- Authentication errors: If the authentication credentials are invalid or expired
- Permission errors: If the authenticated user doesn't have permission to access the repository
- ResourceNotFound errors: If the specified project or repository doesn't exist
Error messages will be formatted as text and provide details about what went wrong.
### Example Usage
```typescript
// Basic example - just repository info
const repoDetails = await mcpClient.callTool('get_repository_details', {
projectId: 'MyProject',
repositoryId: 'MyRepo'
});
console.log(repoDetails);
// Example with branch statistics
const repoWithStats = await mcpClient.callTool('get_repository_details', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
includeStatistics: true
});
console.log(repoWithStats);
// Example with refs filtered to branches
const repoWithBranches = await mcpClient.callTool('get_repository_details', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
includeRefs: true,
refFilter: 'heads/'
});
console.log(repoWithBranches);
// Example with all options
const fullRepoDetails = await mcpClient.callTool('get_repository_details', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
includeStatistics: true,
includeRefs: true,
refFilter: 'heads/',
branchName: 'main'
});
console.log(fullRepoDetails);
```
### Implementation Details
This tool uses the Azure DevOps Node API's Git API to retrieve repository details:
1. It gets a connection to the Azure DevOps WebApi client
2. It calls the `getGitApi()` method to get a handle to the Git API
3. It retrieves the basic repository information using `getRepository()`
4. If requested, it retrieves branch statistics using `getBranches()`
5. If requested, it retrieves repository refs using `getRefs()`
6. The combined results are returned to the caller
## list_repositories
Lists all Git repositories in a specific project.
### Description
The `list_repositories` tool retrieves all Git repositories within a specified Azure DevOps project. This is useful for discovering which repositories are available for cloning, accessing files, or creating branches and pull requests.
This tool uses the Azure DevOps WebApi client to interact with the Git API.
### Parameters
```json
{
"projectId": "MyProject", // Required: The ID or name of the project
"includeLinks": true // Optional: Whether to include reference links
}
```
| Parameter | Type | Required | Description |
| -------------- | ------- | -------- | ------------------------------------------------------------ |
| `projectId` | string | Yes | The ID or name of the project containing the repositories |
| `includeLinks` | boolean | No | Whether to include reference links in the repository objects |
### Response
The tool returns an array of `GitRepository` objects, each containing:
- `id`: The unique identifier of the repository
- `name`: The name of the repository
- `url`: The URL of the repository
- `project`: Object containing basic project information
- `defaultBranch`: The default branch of the repository (e.g., "refs/heads/main")
- `size`: The size of the repository
- `remoteUrl`: The remote URL for cloning the repository
- `sshUrl`: The SSH URL for cloning the repository
- `webUrl`: The web URL for browsing the repository in browser
- ... and potentially other repository properties
Example response:
```json
[
{
"id": "repo-guid-1",
"name": "FirstRepository",
"url": "https://dev.azure.com/organization/MyProject/_apis/git/repositories/FirstRepository",
"project": {
"id": "project-guid",
"name": "MyProject",
"url": "https://dev.azure.com/organization/_apis/projects/project-guid"
},
"defaultBranch": "refs/heads/main",
"size": 25478,
"remoteUrl": "https://dev.azure.com/organization/MyProject/_git/FirstRepository",
"sshUrl": "[email protected]:v3/organization/MyProject/FirstRepository",
"webUrl": "https://dev.azure.com/organization/MyProject/_git/FirstRepository"
},
{
"id": "repo-guid-2",
"name": "SecondRepository",
"url": "https://dev.azure.com/organization/MyProject/_apis/git/repositories/SecondRepository",
"project": {
"id": "project-guid",
"name": "MyProject",
"url": "https://dev.azure.com/organization/_apis/projects/project-guid"
},
"defaultBranch": "refs/heads/main",
"size": 15789,
"remoteUrl": "https://dev.azure.com/organization/MyProject/_git/SecondRepository",
"sshUrl": "[email protected]:v3/organization/MyProject/SecondRepository",
"webUrl": "https://dev.azure.com/organization/MyProject/_git/SecondRepository"
}
]
```
### Error Handling
The tool may throw the following errors:
- General errors: If the API call fails or other unexpected errors occur
- Authentication errors: If the authentication credentials are invalid or expired
- Permission errors: If the authenticated user doesn't have permission to list repositories
- ResourceNotFound errors: If the specified project doesn't exist
Error messages will be formatted as text and provide details about what went wrong.
### Example Usage
```typescript
// Basic example
const repositories = await mcpClient.callTool('list_repositories', {
projectId: 'MyProject',
});
console.log(repositories);
// Example with includeLinks parameter
const repositoriesWithLinks = await mcpClient.callTool('list_repositories', {
projectId: 'MyProject',
includeLinks: true,
});
console.log(repositoriesWithLinks);
```
### Implementation Details
This tool uses the Azure DevOps Node API's Git API to retrieve repositories:
1. It gets a connection to the Azure DevOps WebApi client
2. It calls the `getGitApi()` method to get a handle to the Git API
3. It then calls `getRepositories()` with the specified project ID and optional include links parameter
4. The results are returned directly to the caller
### Related Tools
- `get_repository`: Get details of a specific repository
- `get_repository_details`: Get detailed information about a repository including statistics and refs
- `list_projects`: List all projects in the organization (to find project IDs)
## get_file_content
Retrieves the content of a file or directory from a Git repository.
### Description
The `get_file_content` tool allows you to access the contents of files and directories within a Git repository. This is useful for examining code, documentation, or other files stored in repositories without having to clone the entire repository. It supports fetching file content from the default branch or from specific branches, tags, or commits.
### Parameters
```json
{
"projectId": "MyProject", // Required: The ID or name of the project
"repositoryId": "MyRepo", // Required: The ID or name of the repository
"path": "/src/index.ts", // Required: The path to the file or directory
"versionType": "branch", // Optional: The type of version (branch, tag, or commit)
"version": "main" // Optional: The name of the branch/tag, or commit ID
}
```
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `projectId` | string | Yes | The ID or name of the project containing the repository |
| `repositoryId` | string | Yes | The ID or name of the repository |
| `path` | string | Yes | The path to the file or directory (starting with "/") |
| `versionType` | enum | No | The type of version: "branch", "tag", or "commit" (GitVersionType) |
| `version` | string | No | The name of the branch/tag, or the commit ID |
### Response
The tool returns a `FileContentResponse` object containing:
- `content`: The content of the file as a string, or a JSON string of items for directories
- `isDirectory`: Boolean indicating whether the path refers to a directory
Example response for a file:
```json
{
"content": "import { Component } from '@angular/core';\n\n@Component({\n selector: 'app-root',\n templateUrl: './app.component.html',\n styleUrls: ['./app.component.css']\n})\nexport class AppComponent {\n title = 'My App';\n}\n",
"isDirectory": false
}
```
Example response for a directory:
```json
{
"content": "[{\"objectId\":\"c7be24d3\",\"gitObjectType\":\"blob\",\"commitId\":\"d5b8e757\",\"path\":\"/src/app/app.component.ts\",\"contentMetadata\":{\"fileName\":\"app.component.ts\"}},{\"objectId\":\"a8c2e5f1\",\"gitObjectType\":\"blob\",\"commitId\":\"d5b8e757\",\"path\":\"/src/app/app.module.ts\",\"contentMetadata\":{\"fileName\":\"app.module.ts\"}}]",
"isDirectory": true
}
```
### Error Handling
The tool may throw the following errors:
- General errors: If the API call fails or other unexpected errors occur
- Authentication errors: If the authentication credentials are invalid or expired
- Permission errors: If the authenticated user doesn't have permission to access the repository
- ResourceNotFound errors: If the specified project, repository, or path doesn't exist
Error messages will be formatted as text and provide details about what went wrong.
### Example Usage
```typescript
// Basic example - get file from default branch
const fileContent = await mcpClient.callTool('get_file_content', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
path: '/src/index.ts'
});
console.log(fileContent.content);
// Get directory content
const directoryContent = await mcpClient.callTool('get_file_content', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
path: '/src'
});
if (directoryContent.isDirectory) {
const items = JSON.parse(directoryContent.content);
console.log(`Directory contains ${items.length} items`);
}
// Get file from specific branch
const branchFileContent = await mcpClient.callTool('get_file_content', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
path: '/src/index.ts',
versionType: 'branch',
version: 'feature/new-ui'
});
console.log(branchFileContent.content);
// Get file from specific commit
const commitFileContent = await mcpClient.callTool('get_file_content', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
path: '/src/index.ts',
versionType: 'commit',
version: 'a1b2c3d4e5f6g7h8i9j0'
});
console.log(commitFileContent.content);
```
### Implementation Details
This tool uses the Azure DevOps Node API's Git API to retrieve file or directory content:
1. It gets a connection to the Azure DevOps WebApi client
2. It calls the `getGitApi()` method to get a handle to the Git API
3. It determines if the path is a file or directory by attempting to fetch items
4. For directories, it returns the list of items as a JSON string
5. For files, it fetches the file content and returns it as a string
6. The results are wrapped in a `FileContentResponse` object with the appropriate `isDirectory` flag
### Resource URI Access
In addition to using this tool, file content can also be accessed via resource URIs with the following patterns:
- Default branch: `ado://{organization}/{project}/{repo}/contents/{path}`
- Specific branch: `ado://{organization}/{project}/{repo}/branches/{branch}/contents/{path}`
- Specific commit: `ado://{organization}/{project}/{repo}/commits/{commit}/contents/{path}`
- Specific tag: `ado://{organization}/{project}/{repo}/tags/{tag}/contents/{path}`
- Pull request: `ado://{organization}/{project}/{repo}/pullrequests/{prId}/contents/{path}`
### Related Tools
- `list_repositories`: List all repositories in a project
- `get_repository`: Get details of a specific repository
- `get_repository_details`: Get detailed information about a repository including statistics and refs
- `search_code`: Search for code across repositories in a project
## get_all_repositories_tree
Displays a hierarchical tree view of files and directories across multiple Azure DevOps repositories within a project, based on their default branches.
### Description
The `get_all_repositories_tree` tool provides a broad overview of file and directory structure across multiple repositories in a project. It uses a tree-like structure similar to the Unix `tree` command, with each repository's tree displayed sequentially.
Key features:
- Views multiple repositories at once
- Filter repositories by name pattern
- Filter files by pattern
- Control depth to balance performance and detail
- Shows directories and files in a hierarchical view
- Provides statistics (count of files and directories)
- Works with the default branch of each repository
- Handles errors gracefully
### Parameters
```json
{
"organizationId": "MyOrg",
"projectId": "MyProject",
"repositoryPattern": "API*",
"depth": 0,
"pattern": "*.yaml"
}
```
- `organizationId` (string, required): The ID or name of the Azure DevOps organization.
- `projectId` (string, required): The ID or name of the project containing the repositories.
- `repositoryPattern` (string, optional): Pattern to filter repositories by name (PowerShell wildcard).
- `depth` (number, optional, default: 0): Maximum depth to traverse in each repository's file hierarchy. Use 0 for unlimited depth (more efficient server-side recursion), or a specific number (1-10) for limited depth.
- `pattern` (string, optional): Pattern to filter files by name (PowerShell wildcard). Note: Directories are always shown regardless of this filter.
### Response
The response is a formatted ASCII tree showing the file and directory structure of each repository:
```
Repo-API-1/
|-- src/
| |-- config.yaml
| `-- utils/
`-- deploy.yaml
1 directory, 2 files
Repo-API-Gateway/
|-- charts/
| `-- values.yaml
`-- README.md
1 directory, 2 files
Repo-Data-Service/
(Repository is empty or default branch not found)
0 directories, 0 files
```
### Examples
#### Basic Example - View All Repositories with Maximum Depth
```javascript
const result = await mcpClient.callTool('get_all_repositories_tree', {
organizationId: 'MyOrg',
projectId: 'MyProject'
});
console.log(result);
```
#### Filter Repositories by Name Pattern
```javascript
const result = await mcpClient.callTool('get_all_repositories_tree', {
organizationId: 'MyOrg',
projectId: 'MyProject',
repositoryPattern: 'API*'
});
console.log(result);
```
#### Limited Depth and File Pattern Filter
```javascript
const result = await mcpClient.callTool('get_all_repositories_tree', {
organizationId: 'MyOrg',
projectId: 'MyProject',
depth: 1, // Only one level deep
pattern: '*.yaml'
});
console.log(result);
```
### Performance Considerations
- For maximum depth (depth=0), the tool uses server-side recursion (VersionControlRecursionType.Full) which is more efficient for retrieving deep directory structures.
- For limited depth (depth=1 to 10), the tool uses client-side recursion which is better for controlled exploration.
- When viewing very large repositories, consider using a limited depth or file pattern to reduce response time.
### Related Tools
- `list_repositories`: Lists all repositories in a project (summary only)
- `get_repository_details`: Gets detailed info about a single repository
- `get_repository_tree`: Explores structure within a single repository (more detailed)
- `get_file_content`: Gets content of a specific file
- `get_repository_tree`: Explore the tree for a single repository
- `create_branch`: Create a branch from an existing one
- `create_commit`: Apply file additions, updates, or deletions in a single commit (supports unified diffs or search/replace instructions)
## get_repository_tree
Lists files and folders from any point in a repository. You can specify a repository name or path to start from and limit how deep the tree goes.
### Parameters
```json
{
"projectId": "MyProject",
"repositoryId": "MyRepo",
"path": "src/utils", // Optional path to start from
"depth": 2 // Optional maximum depth
}
```
### Response
Returns a formatted tree showing directories and files starting from the requested location.
## create_branch
Creates a new branch from an existing branch's latest commit.
### Parameters
```json
{
"projectId": "MyProject",
"repositoryId": "MyRepo",
"sourceBranch": "main",
"newBranch": "feature-branch"
}
```
### Response
Returns the newly created branch reference.
## create_commit
Commits multiple file changes to a branch, supporting additions, modifications, and deletions (renames are not currently supported).
- ⚠️ Azure DevOps accepts only one change entry per file path in a commit request. Combine all edits to the same file into a single change object before calling this tool.
- For sparse or unrelated edits within the same file, prefer splitting work into multiple commits so each request stays focused.
### Parameters
```json
{
"projectId": "MyProject",
"repositoryId": "MyRepo",
"branchName": "feature-branch",
"commitMessage": "feat: demo commit",
"changes": [
{
"path": "src/new.ts", // Optional override when the diff header does not reflect the desired path
"patch": "diff --git a/src/new.ts b/src/new.ts\n--- /dev/null\n+++ b/src/new.ts\n@@\n+console.log('hi');\n"
},
{
"patch": "diff --git a/README.md b/README.md\n--- a/README.md\n+++ b/README.md\n@@\n-Old content\n+New content\n"
},
{
"patch": "diff --git a/old.txt b/old.txt\n--- a/old.txt\n+++ /dev/null\n@@\n-This file will be deleted\n"
},
{
"path": "src/index.ts", // Required when using search/replace
"search": "return axios.post(apiUrl, payload, requestConfig);",
"replace": "return axios.post(apiUrl, payload, requestConfig).then(res => handleResponse(res));"
}
]
}
```
- `branchName` identifies the branch to update.
- Provide `path` only when the diff header cannot be trusted (for example, when generated without `a/` and `b/` prefixes). For search/replace changes, `path` is required so the server can load the file.
- Each entry in `changes` can be either a unified diff (`patch`) or a search/replace pair (`search` and `replace`). `/dev/null` still indicates file creation or deletion for diff-based changes.
- Instead of crafting diffs manually you can supply `search` and `replace` text. The server confirms the search string exists in the latest version of the file, applies the replacement, and generates the diff automatically.
- Diffs (including ones generated from search/replace) must be based on the latest branch head to avoid merge conflicts during commit creation.
- If the search text cannot be found, the request fails so you can review upstream modifications before retrying.
### Response
Returns the commit ID after applying the changes.
```
--------------------------------------------------------------------------------
/src/features/search/search-code/feature.spec.unit.ts:
--------------------------------------------------------------------------------
```typescript
import axios from 'axios';
import { searchCode } from './feature';
import { WebApi } from 'azure-devops-node-api';
import { AzureDevOpsError } from '../../../shared/errors';
import { GitVersionType } from 'azure-devops-node-api/interfaces/GitInterfaces';
// Mock Azure Identity
jest.mock('@azure/identity', () => {
const mockGetToken = jest.fn().mockResolvedValue({ token: 'mock-token' });
return {
DefaultAzureCredential: jest.fn().mockImplementation(() => ({
getToken: mockGetToken,
})),
AzureCliCredential: jest.fn().mockImplementation(() => ({
getToken: mockGetToken,
})),
};
});
// Mock axios
jest.mock('axios');
const mockedAxios = axios as jest.Mocked<typeof axios>;
describe('searchCode unit', () => {
// Mock WebApi connection
const mockConnection = {
getGitApi: jest.fn().mockImplementation(() => ({
getItemContent: jest.fn().mockImplementation((_repoId, path) => {
// Return different content based on the path to simulate different files
if (path === '/src/example.ts') {
return Buffer.from('export function example() { return "test"; }');
}
return Buffer.from('// Empty file');
}),
})),
_getHttpClient: jest.fn().mockReturnValue({
getAuthorizationHeader: jest.fn().mockReturnValue('Bearer mock-token'),
}),
getCoreApi: jest.fn().mockImplementation(() => ({
getProjects: jest
.fn()
.mockResolvedValue([{ name: 'TestProject', id: 'project-id' }]),
})),
serverUrl: 'https://dev.azure.com/testorg',
} as unknown as WebApi;
// Store original console.error
const originalConsoleError = console.error;
beforeEach(() => {
jest.clearAllMocks();
// Mock console.error to prevent error messages from being displayed during tests
console.error = jest.fn();
});
afterEach(() => {
// Restore original console.error
console.error = originalConsoleError;
});
test('should return search results with content', async () => {
// Arrange
const mockSearchResponse = {
data: {
count: 1,
results: [
{
fileName: 'example.ts',
path: '/src/example.ts',
matches: {
content: [
{
charOffset: 17,
length: 7,
},
],
},
collection: {
name: 'DefaultCollection',
},
project: {
name: 'TestProject',
id: 'project-id',
},
repository: {
name: 'TestRepo',
id: 'repo-id',
type: 'git',
},
versions: [
{
branchName: 'main',
changeId: 'commit-hash',
},
],
contentId: 'content-hash',
},
],
},
};
mockedAxios.post.mockResolvedValueOnce(mockSearchResponse);
// Create a mock stream with content
const fileContent = 'export function example() { return "test"; }';
const mockStream = {
on: jest.fn().mockImplementation((event, callback) => {
if (event === 'data') {
// Call the callback with the data
callback(Buffer.from(fileContent));
} else if (event === 'end') {
// Call the end callback asynchronously
setTimeout(callback, 0);
}
return mockStream; // Return this for chaining
}),
};
// Mock Git API to return content
const mockGitApi = {
getItemContent: jest.fn().mockResolvedValue(mockStream),
};
const mockConnectionWithContent = {
...mockConnection,
getGitApi: jest.fn().mockResolvedValue(mockGitApi),
serverUrl: 'https://dev.azure.com/testorg',
} as unknown as WebApi;
// Act
const result = await searchCode(mockConnectionWithContent, {
searchText: 'example',
projectId: 'TestProject',
includeContent: true,
});
// Assert
expect(result).toBeDefined();
expect(result.count).toBe(1);
expect(result.results).toHaveLength(1);
expect(result.results[0].fileName).toBe('example.ts');
expect(result.results[0].content).toBe(
'export function example() { return "test"; }',
);
expect(mockedAxios.post).toHaveBeenCalledTimes(1);
expect(mockGitApi.getItemContent).toHaveBeenCalledTimes(1);
expect(mockGitApi.getItemContent).toHaveBeenCalledWith(
'repo-id',
'/src/example.ts',
'TestProject',
undefined,
undefined,
undefined,
undefined,
false,
{
version: 'commit-hash',
versionType: GitVersionType.Commit,
},
true,
);
});
test('should not fetch content when includeContent is false', async () => {
// Arrange
const mockSearchResponse = {
data: {
count: 1,
results: [
{
fileName: 'example.ts',
path: '/src/example.ts',
matches: {
content: [
{
charOffset: 17,
length: 7,
},
],
},
collection: {
name: 'DefaultCollection',
},
project: {
name: 'TestProject',
id: 'project-id',
},
repository: {
name: 'TestRepo',
id: 'repo-id',
type: 'git',
},
versions: [
{
branchName: 'main',
changeId: 'commit-hash',
},
],
contentId: 'content-hash',
},
],
},
};
mockedAxios.post.mockResolvedValueOnce(mockSearchResponse);
// Act
const result = await searchCode(mockConnection, {
searchText: 'example',
projectId: 'TestProject',
includeContent: false,
});
// Assert
expect(result).toBeDefined();
expect(result.count).toBe(1);
expect(result.results).toHaveLength(1);
expect(result.results[0].fileName).toBe('example.ts');
expect(result.results[0].content).toBeUndefined();
expect(mockConnection.getGitApi).not.toHaveBeenCalled();
});
test('should handle empty search results', async () => {
// Arrange
const mockSearchResponse = {
data: {
count: 0,
results: [],
},
};
mockedAxios.post.mockResolvedValueOnce(mockSearchResponse);
// Act
const result = await searchCode(mockConnection, {
searchText: 'nonexistent',
projectId: 'TestProject',
});
// Assert
expect(result).toBeDefined();
expect(result.count).toBe(0);
expect(result.results).toHaveLength(0);
});
test('should handle API errors', async () => {
// Arrange
const axiosError = new Error('API Error');
(axiosError as any).isAxiosError = true;
(axiosError as any).response = {
status: 404,
data: {
message: 'Project not found',
},
};
mockedAxios.post.mockRejectedValueOnce(axiosError);
// Act & Assert
await expect(
searchCode(mockConnection, {
searchText: 'example',
projectId: 'NonExistentProject',
}),
).rejects.toThrow(AzureDevOpsError);
});
test('should propagate custom errors when thrown internally', async () => {
// Arrange
const customError = new AzureDevOpsError('Custom error');
// Mock axios to properly return the custom error
mockedAxios.post.mockImplementationOnce(() => {
throw customError;
});
// Act & Assert
await expect(
searchCode(mockConnection, {
searchText: 'example',
projectId: 'TestProject',
}),
).rejects.toThrow(AzureDevOpsError);
// Reset mock and set it up again for the second test
mockedAxios.post.mockReset();
mockedAxios.post.mockImplementationOnce(() => {
throw customError;
});
await expect(
searchCode(mockConnection, {
searchText: 'example',
projectId: 'TestProject',
}),
).rejects.toThrow('Custom error');
});
test('should apply filters when provided', async () => {
// Arrange
const mockSearchResponse = {
data: {
count: 1,
results: [
{
fileName: 'example.ts',
path: '/src/example.ts',
matches: {
content: [
{
charOffset: 17,
length: 7,
},
],
},
collection: {
name: 'DefaultCollection',
},
project: {
name: 'TestProject',
id: 'project-id',
},
repository: {
name: 'TestRepo',
id: 'repo-id',
type: 'git',
},
versions: [
{
branchName: 'main',
changeId: 'commit-hash',
},
],
contentId: 'content-hash',
},
],
},
};
mockedAxios.post.mockResolvedValueOnce(mockSearchResponse);
// Act
await searchCode(mockConnection, {
searchText: 'example',
projectId: 'TestProject',
filters: {
Repository: ['TestRepo'],
Path: ['/src'],
Branch: ['main'],
CodeElement: ['function'],
},
});
// Assert
expect(mockedAxios.post).toHaveBeenCalledWith(
expect.any(String),
expect.objectContaining({
filters: {
Project: ['TestProject'],
Repository: ['TestRepo'],
Path: ['/src'],
Branch: ['main'],
CodeElement: ['function'],
},
}),
expect.any(Object),
);
});
test('should handle pagination parameters', async () => {
// Arrange
const mockSearchResponse = {
data: {
count: 100,
results: Array(10)
.fill(0)
.map((_, i) => ({
fileName: `example${i}.ts`,
path: `/src/example${i}.ts`,
matches: {
content: [
{
charOffset: 17,
length: 7,
},
],
},
collection: {
name: 'DefaultCollection',
},
project: {
name: 'TestProject',
id: 'project-id',
},
repository: {
name: 'TestRepo',
id: 'repo-id',
type: 'git',
},
versions: [
{
branchName: 'main',
changeId: 'commit-hash',
},
],
contentId: `content-hash-${i}`,
})),
},
};
mockedAxios.post.mockResolvedValueOnce(mockSearchResponse);
// Act
await searchCode(mockConnection, {
searchText: 'example',
projectId: 'TestProject',
top: 10,
skip: 20,
});
// Assert
expect(mockedAxios.post).toHaveBeenCalledWith(
expect.any(String),
expect.objectContaining({
$top: 10,
$skip: 20,
}),
expect.any(Object),
);
});
test('should handle errors when fetching file content', async () => {
// Arrange
const mockSearchResponse = {
data: {
count: 1,
results: [
{
fileName: 'example.ts',
path: '/src/example.ts',
matches: {
content: [
{
charOffset: 17,
length: 7,
},
],
},
collection: {
name: 'DefaultCollection',
},
project: {
name: 'TestProject',
id: 'project-id',
},
repository: {
name: 'TestRepo',
id: 'repo-id',
type: 'git',
},
versions: [
{
branchName: 'main',
changeId: 'commit-hash',
},
],
contentId: 'content-hash',
},
],
},
};
mockedAxios.post.mockResolvedValueOnce(mockSearchResponse);
// Mock Git API to throw an error
const mockGitApi = {
getItemContent: jest
.fn()
.mockRejectedValue(new Error('Failed to fetch content')),
};
const mockConnectionWithError = {
...mockConnection,
getGitApi: jest.fn().mockResolvedValue(mockGitApi),
} as unknown as WebApi;
// Act
const result = await searchCode(mockConnectionWithError, {
searchText: 'example',
projectId: 'TestProject',
includeContent: true,
});
// Assert
expect(result).toBeDefined();
expect(result.count).toBe(1);
expect(result.results).toHaveLength(1);
// Content should be undefined when there's an error fetching it
expect(result.results[0].content).toBeUndefined();
});
test('should use default project when projectId is not provided', async () => {
// Arrange
// Set up environment variable for default project
const originalEnv = process.env.AZURE_DEVOPS_DEFAULT_PROJECT;
process.env.AZURE_DEVOPS_DEFAULT_PROJECT = 'DefaultProject';
const mockSearchResponse = {
data: {
count: 2,
results: [
{
fileName: 'example1.ts',
path: '/src/example1.ts',
matches: {
content: [
{
charOffset: 17,
length: 7,
},
],
},
collection: {
name: 'DefaultCollection',
},
project: {
name: 'DefaultProject',
id: 'default-project-id',
},
repository: {
name: 'Repo1',
id: 'repo-id-1',
type: 'git',
},
versions: [
{
branchName: 'main',
changeId: 'commit-hash-1',
},
],
contentId: 'content-hash-1',
},
{
fileName: 'example2.ts',
path: '/src/example2.ts',
matches: {
content: [
{
charOffset: 17,
length: 7,
},
],
},
collection: {
name: 'DefaultCollection',
},
project: {
name: 'DefaultProject',
id: 'default-project-id',
},
repository: {
name: 'Repo2',
id: 'repo-id-2',
type: 'git',
},
versions: [
{
branchName: 'main',
changeId: 'commit-hash-2',
},
],
contentId: 'content-hash-2',
},
],
},
};
mockedAxios.post.mockResolvedValueOnce(mockSearchResponse);
try {
// Act
const result = await searchCode(mockConnection, {
searchText: 'example',
includeContent: false,
});
// Assert
expect(result).toBeDefined();
expect(result.count).toBe(2);
expect(result.results).toHaveLength(2);
expect(result.results[0].project.name).toBe('DefaultProject');
expect(result.results[1].project.name).toBe('DefaultProject');
expect(mockedAxios.post).toHaveBeenCalledTimes(1);
expect(mockedAxios.post).toHaveBeenCalledWith(
expect.stringContaining(
'https://almsearch.dev.azure.com/testorg/DefaultProject/_apis/search/codesearchresults',
),
expect.objectContaining({
filters: expect.objectContaining({
Project: ['DefaultProject'],
}),
}),
expect.any(Object),
);
} finally {
// Restore original environment variable
process.env.AZURE_DEVOPS_DEFAULT_PROJECT = originalEnv;
}
});
test('should throw error when no projectId is provided and no default project is set', async () => {
// Arrange
// Ensure no default project is set
const originalEnv = process.env.AZURE_DEVOPS_DEFAULT_PROJECT;
process.env.AZURE_DEVOPS_DEFAULT_PROJECT = '';
try {
// Act & Assert
await expect(
searchCode(mockConnection, {
searchText: 'example',
includeContent: false,
}),
).rejects.toThrow('Project ID is required');
} finally {
// Restore original environment variable
process.env.AZURE_DEVOPS_DEFAULT_PROJECT = originalEnv;
}
});
test('should handle includeContent for different content types', async () => {
// Arrange
const mockSearchResponse = {
data: {
count: 4,
results: [
// Result 1 - Buffer content
{
fileName: 'example1.ts',
path: '/src/example1.ts',
matches: {
content: [
{
charOffset: 17,
length: 7,
},
],
},
collection: {
name: 'DefaultCollection',
},
project: {
name: 'TestProject',
id: 'project-id',
},
repository: {
name: 'TestRepo',
id: 'repo-id-1',
type: 'git',
},
versions: [
{
branchName: 'main',
changeId: 'commit-hash-1',
},
],
contentId: 'content-hash-1',
},
// Result 2 - String content
{
fileName: 'example2.ts',
path: '/src/example2.ts',
matches: {
content: [
{
charOffset: 17,
length: 7,
},
],
},
collection: {
name: 'DefaultCollection',
},
project: {
name: 'TestProject',
id: 'project-id',
},
repository: {
name: 'TestRepo',
id: 'repo-id-2',
type: 'git',
},
versions: [
{
branchName: 'main',
changeId: 'commit-hash-2',
},
],
contentId: 'content-hash-2',
},
// Result 3 - Object content
{
fileName: 'example3.ts',
path: '/src/example3.ts',
matches: {
content: [
{
charOffset: 17,
length: 7,
},
],
},
collection: {
name: 'DefaultCollection',
},
project: {
name: 'TestProject',
id: 'project-id',
},
repository: {
name: 'TestRepo',
id: 'repo-id-3',
type: 'git',
},
versions: [
{
branchName: 'main',
changeId: 'commit-hash-3',
},
],
contentId: 'content-hash-3',
},
// Result 4 - Uint8Array content
{
fileName: 'example4.ts',
path: '/src/example4.ts',
matches: {
content: [
{
charOffset: 17,
length: 7,
},
],
},
collection: {
name: 'DefaultCollection',
},
project: {
name: 'TestProject',
id: 'project-id',
},
repository: {
name: 'TestRepo',
id: 'repo-id-4',
type: 'git',
},
versions: [
{
branchName: 'main',
changeId: 'commit-hash-4',
},
],
contentId: 'content-hash-4',
},
],
},
};
mockedAxios.post.mockResolvedValueOnce(mockSearchResponse);
// Create mock contents for each type - all as streams, since that's what getItemContent returns
// These are all streams but with different content to demonstrate handling different data types from the stream
const createMockStream = (content: string) => ({
on: jest.fn().mockImplementation((event, callback) => {
if (event === 'data') {
callback(Buffer.from(content));
} else if (event === 'end') {
setTimeout(callback, 0);
}
return createMockStream(content); // Return this for chaining
}),
});
// Create four different mock streams with different content
const mockStream1 = createMockStream('Buffer content');
const mockStream2 = createMockStream('String content');
const mockStream3 = createMockStream(
JSON.stringify({ foo: 'bar', baz: 42 }),
);
const mockStream4 = createMockStream('hello');
// Mock Git API to return our different mock streams for each repository
const mockGitApi = {
getItemContent: jest
.fn()
.mockImplementationOnce(() => Promise.resolve(mockStream1))
.mockImplementationOnce(() => Promise.resolve(mockStream2))
.mockImplementationOnce(() => Promise.resolve(mockStream3))
.mockImplementationOnce(() => Promise.resolve(mockStream4)),
};
const mockConnectionWithStreams = {
...mockConnection,
getGitApi: jest.fn().mockResolvedValue(mockGitApi),
serverUrl: 'https://dev.azure.com/testorg',
} as unknown as WebApi;
// Act
const result = await searchCode(mockConnectionWithStreams, {
searchText: 'example',
projectId: 'TestProject',
includeContent: true,
});
// Assert
expect(result).toBeDefined();
expect(result.count).toBe(4);
expect(result.results).toHaveLength(4);
// Check each result has appropriate content from the streams
// Result 1 - Buffer content stream
expect(result.results[0].content).toBe('Buffer content');
// Result 2 - String content stream
expect(result.results[1].content).toBe('String content');
// Result 3 - JSON object content stream
expect(result.results[2].content).toBe('{"foo":"bar","baz":42}');
// Result 4 - Text content stream
expect(result.results[3].content).toBe('hello');
// Git API should have been called 4 times
expect(mockGitApi.getItemContent).toHaveBeenCalledTimes(4);
// Verify the parameters for the first call
expect(mockGitApi.getItemContent.mock.calls[0]).toEqual([
'repo-id-1',
'/src/example1.ts',
'TestProject',
undefined,
undefined,
undefined,
undefined,
false,
{
version: 'commit-hash-1',
versionType: GitVersionType.Commit,
},
true,
]);
});
test('should properly convert content stream to string', async () => {
// Arrange
const mockSearchResponse = {
data: {
count: 1,
results: [
{
fileName: 'example.ts',
path: '/src/example.ts',
matches: {
content: [
{
charOffset: 17,
length: 7,
},
],
},
collection: {
name: 'DefaultCollection',
},
project: {
name: 'TestProject',
id: 'project-id',
},
repository: {
name: 'TestRepo',
id: 'repo-id',
type: 'git',
},
versions: [
{
branchName: 'main',
changeId: 'commit-hash',
},
],
contentId: 'content-hash',
},
],
},
};
mockedAxios.post.mockResolvedValueOnce(mockSearchResponse);
// Create a mock ReadableStream
const mockContent = 'This is the file content';
// Create a simplified mock stream that emits the content
const mockStream = {
on: jest.fn().mockImplementation((event, callback) => {
if (event === 'data') {
// Call the callback with the data
callback(Buffer.from(mockContent));
} else if (event === 'end') {
// Call the end callback asynchronously
setTimeout(callback, 0);
}
return mockStream; // Return this for chaining
}),
};
// Mock Git API to return our mock stream
const mockGitApi = {
getItemContent: jest.fn().mockResolvedValue(mockStream),
};
const mockConnectionWithStream = {
...mockConnection,
getGitApi: jest.fn().mockResolvedValue(mockGitApi),
serverUrl: 'https://dev.azure.com/testorg',
} as unknown as WebApi;
// Act
const result = await searchCode(mockConnectionWithStream, {
searchText: 'example',
projectId: 'TestProject',
includeContent: true,
});
// Assert
expect(result).toBeDefined();
expect(result.count).toBe(1);
expect(result.results).toHaveLength(1);
// Check that the content was properly converted from stream to string
expect(result.results[0].content).toBe(mockContent);
// Verify the stream event handlers were attached
expect(mockStream.on).toHaveBeenCalledWith('data', expect.any(Function));
expect(mockStream.on).toHaveBeenCalledWith('end', expect.any(Function));
expect(mockStream.on).toHaveBeenCalledWith('error', expect.any(Function));
// Verify the parameters for getItemContent
expect(mockGitApi.getItemContent).toHaveBeenCalledWith(
'repo-id',
'/src/example.ts',
'TestProject',
undefined,
undefined,
undefined,
undefined,
false,
{
version: 'commit-hash',
versionType: GitVersionType.Commit,
},
true,
);
});
test('should limit top to 10 when includeContent is true', async () => {
// Arrange
const mockSearchResponse = {
data: {
count: 10,
results: Array(10)
.fill(0)
.map((_, i) => ({
fileName: `example${i}.ts`,
path: `/src/example${i}.ts`,
matches: {
content: [
{
charOffset: 17,
length: 7,
},
],
},
collection: {
name: 'DefaultCollection',
},
project: {
name: 'TestProject',
id: 'project-id',
},
repository: {
name: 'TestRepo',
id: 'repo-id',
type: 'git',
},
versions: [
{
branchName: 'main',
changeId: 'commit-hash',
},
],
contentId: `content-hash-${i}`,
})),
},
};
mockedAxios.post.mockResolvedValueOnce(mockSearchResponse);
// For this test, we don't need to mock the Git API since we're only testing the top parameter
// We'll create a connection that doesn't have includeContent functionality
const mockConnectionWithoutContent = {
...mockConnection,
getGitApi: jest.fn().mockImplementation(() => {
throw new Error('Git API not available');
}),
serverUrl: 'https://dev.azure.com/testorg',
} as unknown as WebApi;
// Act
await searchCode(mockConnectionWithoutContent, {
searchText: 'example',
projectId: 'TestProject',
top: 50, // User tries to get 50 results
includeContent: true, // But includeContent is true
});
// Assert
expect(mockedAxios.post).toHaveBeenCalledWith(
expect.any(String),
expect.objectContaining({
$top: 10, // Should be limited to 10
}),
expect.any(Object),
);
});
test('should not limit top when includeContent is false', async () => {
// Arrange
const mockSearchResponse = {
data: {
count: 50,
results: Array(50)
.fill(0)
.map((_, i) => ({
// ... simplified result object
fileName: `example${i}.ts`,
})),
},
};
mockedAxios.post.mockResolvedValueOnce(mockSearchResponse);
// Act
await searchCode(mockConnection, {
searchText: 'example',
projectId: 'TestProject',
top: 50, // User wants 50 results
includeContent: false, // includeContent is false
});
// Assert
expect(mockedAxios.post).toHaveBeenCalledWith(
expect.any(String),
expect.objectContaining({
$top: 50, // Should use requested value
}),
expect.any(Object),
);
});
});
```
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
```markdown
# Changelog
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
## [0.1.43](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.42...mcp-server-azure-devops-v0.1.43) (2025-11-19)
### Features
* - adding a pullRequestId filter in - adding source and target … ([#12](https://github.com/Tiberriver256/mcp-server-azure-devops/issues/12)) ([f33e557](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/f33e5575a5069713c81d01dca46176e485cfe612))
* add publishing configuration ([c058e59](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/c058e59b96991f47a91ee3494fd3dfed8c02edd5))
* add pull request checks tool ([#11](https://github.com/Tiberriver256/mcp-server-azure-devops/issues/11)) ([6c1dfd5](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/6c1dfd540bd7493b497076d302f591ffcfa49ccf))
* add repository tree and branch/commit tools ([a95e6f2](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/a95e6f2630e7728b796afc0ba5491414b1e3634c))
* added prepack script to ensure the binary is built and marked executable before publishing ([757fea8](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/757fea8e35e33f1300bda3d2b12d49eb2053711f))
* improve commit workflow and add branch commit listing tool ([#7](https://github.com/Tiberriver256/mcp-server-azure-devops/issues/7)) ([867bbc8](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/867bbc8383ee87f110f772531d9099ab588e126d))
* include file diffs in pull request changes ([#3](https://github.com/Tiberriver256/mcp-server-azure-devops/issues/3)) ([0335c68](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/0335c685a2acff6712220e5d6ad87ff13553a7d0))
* provide simpler search/replace functionality for the create_commit tool ([1d1ec3f](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/1d1ec3f621d1d9677bb6aab94aadf9020fd9f66a))
* version bump to 0.1.45 ([67e7a3d](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/67e7a3d99a9bb0b0198173e13159854249aa24a8))
### Bug Fixes
* **ci:** update workflow to use pull_request_target and latest checkout action ([fb109a7](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/fb109a7614662ce6b32453f1f195b3496326c659))
* clarify instruction on how to use the create_commit tool ([bd82c00](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/bd82c000d79d1a514b946701abb11fadbb2eb869))
* clarify instruction on how to use the create_commit tool ([167893e](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/167893e23da37e8070c00e15b85395617edd0c7a))
* **deps:** address high vulnerability without breaking changes ([#4](https://github.com/Tiberriver256/mcp-server-azure-devops/issues/4)) ([cb20e2d](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/cb20e2de1835b87408a3e09d85bcc9b2c9d6e85d))
* **pull-requests:** include diff content in pull request changes ([#6](https://github.com/Tiberriver256/mcp-server-azure-devops/issues/6)) ([d48aacc](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/d48aacc24b0f748159b60e792feb9bd5d17e692f))
## [0.1.42](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.41...mcp-server-azure-devops-v0.1.42) (2025-07-15)
### Features
* implement human-readable string enums for Azure DevOps API responses ([8168bcb](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/8168bcbe8e4957e9632927f57ecbe9632c911735))
## [0.1.41](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.40...mcp-server-azure-devops-v0.1.41) (2025-07-14)
### Features
* **pull-requests:** enhance get_pull_request_comments response with … ([#229](https://github.com/Tiberriver256/mcp-server-azure-devops/issues/229)) ([6997a04](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/6997a04e92b4fe453354b8fd9f0f25c974fcad2b))
### Bug Fixes
* **work-items:** make expand enum compatible with Gemini CLI ([#240](https://github.com/Tiberriver256/mcp-server-azure-devops/issues/240)) ([ac1dcac](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/ac1dcace4cd6f63d5decd4820307b52a4d0d431d))
## [0.1.40](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.39...mcp-server-azure-devops-v0.1.40) (2025-06-20)
### Bug Fixes
* simplify listWikiPages API by removing unused parameters ([fff7238](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/fff72384f69433942ee8439de0dda90d7fc85c38))
## [0.1.39](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.38...mcp-server-azure-devops-v0.1.39) (2025-06-03)
### Features
* add listWikiPages functionality to Azure DevOps wiki client ([bb9ddc0](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/bb9ddc077e80be0caeda106a7e75dc336a62c9ae))
* implement create_wiki_page feature for Azure DevOps wiki API integration ([#225](https://github.com/Tiberriver256/mcp-server-azure-devops/issues/225)) ([7e3294d](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/7e3294d1f1b6e82d5ca34cf86f3eaa51579dad02))
### Bug Fixes
* enhanced the get-pull-request-comments tool to include path and line number ([f6017e5](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/f6017e5dd352b63b189e761c9cf27d103dd24b9d))
* remove uuid() validator to resolve unknown format error ([b251252](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/b251252c7c455ee11d8076380b70a546ebf40a6e))
## [0.1.38](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.37...mcp-server-azure-devops-v0.1.38) (2025-05-25)
### Bug Fixes
* improve org name extraction from url ([496abc7](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/496abc7a9c5fd0867cf8484f8c33c47a3cc42edf))
## [0.1.37](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.36...mcp-server-azure-devops-v0.1.37) (2025-05-14)
### Bug Fixes
* get_me support for visualstudio.com urls ([ffd3c8a](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/ffd3c8a34bcee1856911e5eed7b719d524c25fef))
## [0.1.36](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.35...mcp-server-azure-devops-v0.1.36) (2025-05-07)
### Bug Fixes
* implement pagination for list-pull-requests to prevent infinite loop ([#196](https://github.com/Tiberriver256/mcp-server-azure-devops/issues/196)) ([e3d7f32](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/e3d7f321f11241bd7b45a4f0e6810509cc8c01c1))
## [0.1.35](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.34...mcp-server-azure-devops-v0.1.35) (2025-05-07)
### Bug Fixes
* update creatorId and reviewerId to require UUIDs instead of allowing emails ([09e82ef](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/09e82ef5e7dfdcd07d1851450ea8c488ea8bb82a))
* use default project for code search when no projectId is specified ([#202](https://github.com/Tiberriver256/mcp-server-azure-devops/issues/202)) ([3bf118f](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/3bf118f45b4222bbfaf888deb67d546b87afc2fe))
## [0.1.34](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.33...mcp-server-azure-devops-v0.1.34) (2025-05-02)
### Features
* add update-pull-request tool to tool-definitions and implement reviewer management ([b7b5398](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/b7b539813baadb84e15022fdb93d24f440491d94))
## [0.1.33](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.32...mcp-server-azure-devops-v0.1.33) (2025-04-28)
### Bug Fixes
* add guidance for HTML formatting in multi-line text fields ([#188](https://github.com/Tiberriver256/mcp-server-azure-devops/issues/188)) ([25751cd](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/25751cd0d7cb8919a7bca80d0796784935f0fbed)), closes [#179](https://github.com/Tiberriver256/mcp-server-azure-devops/issues/179)
## [0.1.32](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.31...mcp-server-azure-devops-v0.1.32) (2025-04-26)
### Features
* add get_pull_request_comments ([2b7fb3a](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/2b7fb3a885466c633d2d2dfdd8906cc9573483d9))
* add_pull_request_comment ([1df6161](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/1df616161835e11c0039bc344ccdc57742f79507))
## [0.1.31](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.30...mcp-server-azure-devops-v0.1.31) (2025-04-23)
### Features
* **pull-requests:** implement list-pull-requests functionality ([3f8cac4](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/3f8cac448e2adacaddeb069bc0116b8526577624))
* **wikis:** add create and update wiki functionalities ([27edd6d](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/27edd6d7786748548f4a0123ff19be43b30265c4))
### Bug Fixes
* **pull-requests:** update repository name environment variable ([d2fde5f](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/d2fde5f94280f08056f94b613a673d4bbe9c0192))
## [0.1.30](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.29...mcp-server-azure-devops-v0.1.30) (2025-04-21)
### Features
* **wikis:** implement `get_wiki_page` tool ([7ba5fd7](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/7ba5fd7830fefa17c014aa2b80f0bad04d8fcbf7))
* **wikis:** implement `get_wikis` tool ([3120479](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/3120479b5c31bfaeb50a507791056066f33b6534))
## [0.1.29](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.28...mcp-server-azure-devops-v0.1.29) (2025-04-19)
### Features
* **pipelines:** implement trigger-pipeline functionality ([e9ba71b](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/e9ba71bfeb2c3a2dc0e1e314698a453d5995d099))
## [0.1.28](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.27...mcp-server-azure-devops-v0.1.28) (2025-04-17)
### Features
* **pipeline:** implement get-pipeline functionality ([#166](https://github.com/Tiberriver256/mcp-server-azure-devops/issues/166)) ([e307340](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/e3073401e141b566191be16ed4f9b7925c2849eb))
## [0.1.27](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.26...mcp-server-azure-devops-v0.1.27) (2025-04-16)
### Features
* **pipeline:** implement list-pipelines ([#161](https://github.com/Tiberriver256/mcp-server-azure-devops/issues/161)) ([89ce473](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/89ce4732ba754632540ffb45ceae323f9675c023)), closes [#94](https://github.com/Tiberriver256/mcp-server-azure-devops/issues/94)
## [0.1.26](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.25...mcp-server-azure-devops-v0.1.26) (2025-04-15)
### Features
* **getWorkItem:** enhance get_work_item to include all available fields ([3810660](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/38106600f04842a44e5e5b6e824716ebb6f69e61))
* support default project and organization in all tools ([5beca06](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/5beca063057bdbc2dd869c865fb01e0d311c8917))
### Bug Fixes
* return actual field information from get_project_details tool ([64a030a](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/64a030a8c14fd1f9e7f871ae409f0dded23dbe98))
## [0.1.25](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.24...mcp-server-azure-devops-v0.1.25) (2025-04-11)
### Features
* create pull request ([ab9c255](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/ab9c2554ea82a497dead8131a6479ba6fe7c5ba8))
## [0.1.24](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.23...mcp-server-azure-devops-v0.1.24) (2025-04-10)
### Bug Fixes
* add missing minimatch module ([ee1ffa3](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/ee1ffa34afb0da9cdac31da140c17dbd9c589c2b))
## [0.1.23](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.22...mcp-server-azure-devops-v0.1.23) (2025-04-10)
### Features
* **repositories:** add get_all_repositories_tree tool for viewing multi-repository file structure ([adbe206](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/adbe206300d55ba06063c675492b3a8153b688f7))
* support default project and organization in all tools ([96d61bd](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/96d61bd1098146dfafd1faf7dade1a37725cd7b7))
## [0.1.22](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.21...mcp-server-azure-devops-v0.1.22) (2025-04-08)
### Bug Fixes
* allow parameterless tools to be called without arguments ([9ce88c3](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/9ce88c3afd4454b8a65392a98e7e2ffb45192584))
## [0.1.21](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.20...mcp-server-azure-devops-v0.1.21) (2025-04-08)
### Features
* add get-file-content feature to access repository content ([a282f75](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/a282f75383ffc362e5b2d1ecbccebb0047e21571))
* restore get_file_content tool and update documentation ([f71013a](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/f71013a962fb5fbe5d121eaf7f1901e58cf70482))
## [0.1.20](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.19...mcp-server-azure-devops-v0.1.20) (2025-04-06)
### Bug Fixes
* add explicit permissions to workflow file ([ae85b95](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/ae85b953d2467538e42d8c6853b93e1af3c8ed51))
* refine WIQL query in integration test ([eb32e43](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/eb32e43a9064485d29661bcae99a987e3b863464))
* remove schema validation for parameterless tools ([031a71d](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/031a71d71083649216e5b67eb6d67c18c78702bd))
## [0.1.19](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.18...mcp-server-azure-devops-v0.1.19) (2025-04-05)
### Bug Fixes
* package.json & package-lock.json to reduce vulnerabilities ([2fb1e72](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/2fb1e725120edc75c9897bc81f57381c20ad880a))
## [0.1.18](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.17...mcp-server-azure-devops-v0.1.18) (2025-04-05)
### Bug Fixes
* getMe profile bug ([ceca909](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/ceca909beaa74b0dd150ce1688a498281fd0b9e8))
## [0.1.17](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.16...mcp-server-azure-devops-v0.1.17) (2025-04-05)
### Features
* implement get_me tool ([2a3849d](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/2a3849da063f6ce0877dd672992a8bc19f88230e))
## [0.1.16](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.15...mcp-server-azure-devops-v0.1.16) (2025-04-05)
### Features
* limit search results to 10 when includeContent is true ([827e4e6](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/827e4e65be353125f5ae595b7e68d80f614f8c07))
* make projectId optional in search features for organization-wide search ([1ca1e0e](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/1ca1e0e146bf880d367078b02a2ddaebf6f54a2a))
### Bug Fixes
* correct [Object Object] display in search_code includeContent ([bdabd6b](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/bdabd6bbeb3f60347c37499bdcb621f5c206dfe0))
* resolve parameter conflict in getItemContent function ([38d624c](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/38d624c10dcfad26bab6d04a9290ad05097f5052))
* simplify content handling in search_code to properly process ReadableStream ([136a90a](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/136a90a94f446e2c4227d87286b8d71ef8223212))
### Performance Improvements
* optimize git hooks with lint-staged ([ba953d8](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/ba953d84706893d56a82573c8d9e8ecdf3b09591))
## [0.1.15](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.14...mcp-server-azure-devops-v0.1.15) (2025-04-02)
### Bug Fixes
* search_work_items authentication with Azure Identity ([cdb2e72](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/cdb2e722ee3abf6be465adcad7dc294f7c623103))
## [0.1.14](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.13...mcp-server-azure-devops-v0.1.14) (2025-04-02)
### Bug Fixes
* add zod-to-json-schema dependency and remove unused packages from package-lock.json ([c9c117f](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/c9c117fd388e228c1116d9249698d931557877b7))
## [0.1.13](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.12...mcp-server-azure-devops-v0.1.13) (2025-04-02)
### Features
* add 'expand' option to get_work_item ([6bee365](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/6bee365d9b37f7e197eaff03065e713ab0ee1c5f))
* Add npm publish to release.yml ([50d0368](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/50d0368c090adc39a9b3ece67d198cabcd18c6ce))
* add pre-commit hook for prettier and eslint ([1b4ddff](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/1b4ddff90e3c3ab9954d041398d224f03c632f63))
* enhance GitHub release notes with changelog content ([2fb275d](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/2fb275d38acbc9c092584573a549466ccd5482bc))
* implement automated release workflow ([9e5a5df](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/9e5a5dfacdd87ca933ed02efbd0aa8035239332d))
* implement get_project_details core functionality ([6d93d98](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/6d93d9820c4bd3ce8bc257d05ff04b39d1370a19)), closes [#101](https://github.com/Tiberriver256/mcp-server-azure-devops/issues/101)
* implement get_repository_details core functionality ([dcef80b](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/dcef80b922ef338f6d3704ab30f59c1b126c70ee))
* implement manage work item link handler ([72cd641](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/72cd6419cf804eb0d72d5ba7763ad5b46bc35650))
* implement search_wiki handler with tests ([286598c](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/286598c47052ade3b6a524938046b3e3b9341b3a))
* implement search_work_items handler with tests ([e244658](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/e2446587e6f82fb7e2dbfe47d2d034ecfdfc3189))
* **search:** add code search functionality for Azure DevOps repos ([0680102](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/068010236b10d8ed444ec01bd6820b27c5c9dcdc))
### Bug Fixes
* add bin field to make package executable with npx ([2d3d5fa](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/2d3d5fa31a9ba741c4a85d7ef21d72ff46270695))
* add build step to workflow and ensure dist files are included in package ([6e12d3c](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/6e12d3ca666937c7b24c7c5d8b161fbb8e34798c))
* add parent-child relationship support for createWorkItem ([31d5efe](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/31d5efef49c162772e64eabd1e4012d8143dc270))
* add tag_name parameter to GitHub release action ([68cfa43](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/68cfa43839c5975cdf9c2ec8a5348ace6138d1c2))
* improve cross-platform CLI compatibility for Windows ([0f6ed3f](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/0f6ed3fe7c72ba63ec5485047ce52e06278457ab))
* make AZURE_DEVOPS_AUTH_METHOD parameter case-insensitive ([9bbf53f](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/9bbf53ffcc1a9170e6ba038fee182da0621be777))
* only request max 200 by default ([296de35](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/296de3584346bd05c14dec3b39dff9a5ec0036a5))
* resolve npm publish authentication and package content issues ([96e91d0](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/96e91d04ec620ad77fc35fea31c2b7795fb73d9e))
* restore tests/setup.ts to fix test suite ([5e23eab](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/5e23eab1228f3949c431f1b8509ad5fbf829e528))
* revert to direct execution of index.js to fix main module detection ([82efa90](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/82efa90852f56db3a0b028ec50eb5230072da88a))
* Typo in release.yaml workflow ([e0de15f](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/e0de15fd220ef2141466cf0530383921ed99253d))
## [0.1.12](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/mcp-server-azure-devops-v0.1.11...mcp-server-azure-devops-v0.1.12) (2025-04-02)
### Features
* add 'expand' option to get_work_item ([6bee365](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/6bee365d9b37f7e197eaff03065e713ab0ee1c5f))
* Add npm publish to release.yml ([50d0368](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/50d0368c090adc39a9b3ece67d198cabcd18c6ce))
* add pre-commit hook for prettier and eslint ([1b4ddff](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/1b4ddff90e3c3ab9954d041398d224f03c632f63))
* enhance GitHub release notes with changelog content ([2fb275d](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/2fb275d38acbc9c092584573a549466ccd5482bc))
* implement automated release workflow ([9e5a5df](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/9e5a5dfacdd87ca933ed02efbd0aa8035239332d))
* implement get_project_details core functionality ([6d93d98](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/6d93d9820c4bd3ce8bc257d05ff04b39d1370a19)), closes [#101](https://github.com/Tiberriver256/mcp-server-azure-devops/issues/101)
* implement get_repository_details core functionality ([dcef80b](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/dcef80b922ef338f6d3704ab30f59c1b126c70ee))
* implement manage work item link handler ([72cd641](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/72cd6419cf804eb0d72d5ba7763ad5b46bc35650))
* implement search_wiki handler with tests ([286598c](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/286598c47052ade3b6a524938046b3e3b9341b3a))
* implement search_work_items handler with tests ([e244658](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/e2446587e6f82fb7e2dbfe47d2d034ecfdfc3189))
* **search:** add code search functionality for Azure DevOps repos ([0680102](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/068010236b10d8ed444ec01bd6820b27c5c9dcdc))
### Bug Fixes
* add bin field to make package executable with npx ([2d3d5fa](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/2d3d5fa31a9ba741c4a85d7ef21d72ff46270695))
* add build step to workflow and ensure dist files are included in package ([6e12d3c](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/6e12d3ca666937c7b24c7c5d8b161fbb8e34798c))
* add parent-child relationship support for createWorkItem ([31d5efe](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/31d5efef49c162772e64eabd1e4012d8143dc270))
* add tag_name parameter to GitHub release action ([68cfa43](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/68cfa43839c5975cdf9c2ec8a5348ace6138d1c2))
* improve cross-platform CLI compatibility for Windows ([0f6ed3f](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/0f6ed3fe7c72ba63ec5485047ce52e06278457ab))
* make AZURE_DEVOPS_AUTH_METHOD parameter case-insensitive ([9bbf53f](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/9bbf53ffcc1a9170e6ba038fee182da0621be777))
* only request max 200 by default ([296de35](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/296de3584346bd05c14dec3b39dff9a5ec0036a5))
* resolve npm publish authentication and package content issues ([96e91d0](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/96e91d04ec620ad77fc35fea31c2b7795fb73d9e))
* restore tests/setup.ts to fix test suite ([5e23eab](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/5e23eab1228f3949c431f1b8509ad5fbf829e528))
* revert to direct execution of index.js to fix main module detection ([82efa90](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/82efa90852f56db3a0b028ec50eb5230072da88a))
* Typo in release.yaml workflow ([e0de15f](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/e0de15fd220ef2141466cf0530383921ed99253d))
### [0.1.11](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/v0.1.10...v0.1.11) (2025-04-01)
### Features
* **search:** add code search functionality for Azure DevOps repos ([0680102](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/068010236b10d8ed444ec01bd6820b27c5c9dcdc))
### [0.1.10](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/v0.1.9...v0.1.10) (2025-04-01)
### Features
* add 'expand' option to get_work_item ([6bee365](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/6bee365d9b37f7e197eaff03065e713ab0ee1c5f))
### Bug Fixes
* only request max 200 by default ([296de35](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/296de3584346bd05c14dec3b39dff9a5ec0036a5))
### [0.1.9](https://github.com/Tiberriver256/mcp-server-azure-devops/compare/v0.1.8...v0.1.9) (2025-03-31)
### Features
* add pre-commit hook for prettier and eslint ([1b4ddff](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/1b4ddff90e3c3ab9954d041398d224f03c632f63))
* implement manage work item link handler ([72cd641](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/72cd6419cf804eb0d72d5ba7763ad5b46bc35650))
### Bug Fixes
* add parent-child relationship support for createWorkItem ([31d5efe](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/31d5efef49c162772e64eabd1e4012d8143dc270))
* make AZURE_DEVOPS_AUTH_METHOD parameter case-insensitive ([9bbf53f](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/9bbf53ffcc1a9170e6ba038fee182da0621be777))
* restore tests/setup.ts to fix test suite ([5e23eab](https://github.com/Tiberriver256/mcp-server-azure-devops/commit/5e23eab1228f3949c431f1b8509ad5fbf829e528))
### [0.1.8](https://github.com/Tiberriver256/azure-devops-mcp/compare/v0.1.7...v0.1.8) (2025-03-26)
### Bug Fixes
* revert to direct execution of index.js to fix main module detection ([82efa90](https://github.com/Tiberriver256/azure-devops-mcp/commit/82efa90852f56db3a0b028ec50eb5230072da88a))
### [0.1.7](https://github.com/Tiberriver256/azure-devops-mcp/compare/v0.1.6...v0.1.7) (2025-03-26)
### Bug Fixes
* add build step to workflow and ensure dist files are included in package ([6e12d3c](https://github.com/Tiberriver256/azure-devops-mcp/commit/6e12d3ca666937c7b24c7c5d8b161fbb8e34798c))
### [0.1.6](https://github.com/Tiberriver256/azure-devops-mcp/compare/v0.1.5...v0.1.6) (2025-03-26)
### Bug Fixes
* improve cross-platform CLI compatibility for Windows ([0f6ed3f](https://github.com/Tiberriver256/azure-devops-mcp/commit/0f6ed3fe7c72ba63ec5485047ce52e06278457ab))
### [0.1.5](https://github.com/Tiberriver256/azure-devops-mcp/compare/v0.1.4...v0.1.5) (2025-03-26)
### Bug Fixes
* add bin field to make package executable with npx ([2d3d5fa](https://github.com/Tiberriver256/azure-devops-mcp/commit/2d3d5fa31a9ba741c4a85d7ef21d72ff46270695))
### [0.1.4](https://github.com/Tiberriver256/azure-devops-mcp/compare/v0.1.3...v0.1.4) (2025-03-26)
### Bug Fixes
* resolve npm publish authentication and package content issues ([96e91d0](https://github.com/Tiberriver256/azure-devops-mcp/commit/96e91d04ec620ad77fc35fea31c2b7795fb73d9e))
### [0.1.3](https://github.com/Tiberriver256/azure-devops-mcp/compare/v0.1.2...v0.1.3) (2025-03-26)
### Features
* Add npm publish to release.yml ([50d0368](https://github.com/Tiberriver256/azure-devops-mcp/commit/50d0368c090adc39a9b3ece67d198cabcd18c6ce))
### Bug Fixes
* Typo in release.yaml workflow ([e0de15f](https://github.com/Tiberriver256/azure-devops-mcp/commit/e0de15fd220ef2141466cf0530383921ed99253d))
### [0.1.2](https://github.com/Tiberriver256/azure-devops-mcp/compare/v0.1.1...v0.1.2) (2025-03-26)
### Bug Fixes
* add tag_name parameter to GitHub release action ([68cfa43](https://github.com/Tiberriver256/azure-devops-mcp/commit/68cfa43839c5975cdf9c2ec8a5348ace6138d1c2))
### 0.1.1 (2025-03-26)
### Features
* enhance GitHub release notes with changelog content ([2fb275d](https://github.com/Tiberriver256/azure-devops-mcp/commit/2fb275d38acbc9c092584573a549466ccd5482bc))
* implement automated release workflow ([9e5a5df](https://github.com/Tiberriver256/azure-devops-mcp/commit/9e5a5dfacdd87ca933ed02efbd0aa8035239332d))
## 0.1.0 (2025-03-26)
### Features
* enhance GitHub release notes with changelog content ([dcaf554](https://github.com/Tiberriver256/azure-devops-mcp/commit/dcaf5542fc08cbb9bd665623d305ae7879758f4e))
* implement automated release workflow ([6fbf41e](https://github.com/Tiberriver256/azure-devops-mcp/commit/6fbf41e5a52c4db054355d4aced33744f6b1a6eb))
```
--------------------------------------------------------------------------------
/docs/tools/pull-requests.md:
--------------------------------------------------------------------------------
```markdown
# Azure DevOps Pull Requests Tools
This document describes the tools available for working with Azure DevOps Pull Requests.
## create_pull_request
Creates a new pull request in a specific Git repository.
### Description
The `create_pull_request` tool creates a new pull request in a specified Azure DevOps Git repository. It allows you to propose changes from a source branch to a target branch, add a title, description, reviewers, and link to work items. Pull requests are a key part of code review and collaboration workflows in Azure DevOps.
### Parameters
```json
{
"projectId": "MyProject", // Required: The ID or name of the project
"repositoryId": "MyRepo", // Required: The ID or name of the repository
"title": "Update feature X", // Required: The title of the pull request
"sourceRefName": "refs/heads/feature-branch", // Required: The source branch name
"targetRefName": "refs/heads/main", // Required: The target branch name
"description": "This PR implements feature X", // Optional: The description of the pull request
"reviewers": ["[email protected]"], // Optional: List of reviewer email addresses or IDs
"isDraft": true, // Optional: Whether the pull request should be created as a draft
"workItemRefs": [123, 456] // Optional: List of work item IDs to link to the pull request
}
```
| Parameter | Type | Required | Description |
| --------------- | -------- | -------- | -------------------------------------------------------------- |
| `projectId` | string | Yes | The ID or name of the project containing the repository |
| `repositoryId` | string | Yes | The ID or name of the repository to create the pull request in |
| `title` | string | Yes | The title of the pull request |
| `sourceRefName` | string | Yes | The source branch name (e.g., "refs/heads/feature-branch") |
| `targetRefName` | string | Yes | The target branch name (e.g., "refs/heads/main") |
| `description` | string | No | The description of the pull request |
| `reviewers` | string[] | No | List of reviewer email addresses or IDs |
| `isDraft` | boolean | No | Whether the pull request should be created as a draft |
| `workItemRefs` | number[] | No | List of work item IDs to link to the pull request |
### Response
The tool returns a `PullRequest` object containing:
- `pullRequestId`: The unique identifier of the created pull request
- `status`: The status of the pull request (active, abandoned, completed)
- `createdBy`: Information about the user who created the pull request
- `creationDate`: The date and time when the pull request was created
- `title`: The title of the pull request
- `description`: The description of the pull request
- `sourceRefName`: The source branch name
- `targetRefName`: The target branch name
- `mergeStatus`: The merge status of the pull request
- And various other fields and references
Example response:
```json
{
"repository": {
"id": "repo-guid",
"name": "MyRepo",
"url": "https://dev.azure.com/organization/MyProject/_apis/git/repositories/MyRepo",
"project": {
"id": "project-guid",
"name": "MyProject"
}
},
"pullRequestId": 42,
"codeReviewId": 42,
"status": 1,
"createdBy": {
"displayName": "John Doe",
"id": "user-guid",
"uniqueName": "[email protected]"
},
"creationDate": "2023-01-01T12:00:00Z",
"title": "Update feature X",
"description": "This PR implements feature X",
"sourceRefName": "refs/heads/feature-branch",
"targetRefName": "refs/heads/main",
"mergeStatus": 1,
"isDraft": true,
"reviewers": [
{
"displayName": "Jane Smith",
"id": "reviewer-guid",
"uniqueName": "[email protected]",
"voteResult": 0
}
],
"url": "https://dev.azure.com/organization/MyProject/_apis/git/repositories/MyRepo/pullRequests/42"
}
```
### Error Handling
The tool may throw the following errors:
- ValidationError: If required parameters are missing or invalid
- AuthenticationError: If authentication fails
- PermissionError: If the user doesn't have permission to create a pull request
- ResourceNotFoundError: If the project, repository, or specified branches don't exist
- GitError: For Git-related errors (e.g., conflicts, branch issues)
- GeneralError: For other unexpected errors
Error messages will include details about what went wrong and suggestions for resolution.
### Example Usage
```typescript
// Basic example - create a PR from feature branch to main
const pr = await mcpClient.callTool('create_pull_request', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
title: 'Add new feature',
sourceRefName: 'refs/heads/feature-branch',
targetRefName: 'refs/heads/main',
});
console.log(`Created PR #${pr.pullRequestId}: ${pr.url}`);
// Create a draft PR with description and reviewers
const draftPr = await mcpClient.callTool('create_pull_request', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
title: 'WIP: Refactor authentication code',
description:
'# Work in Progress\n\nRefactoring authentication code to use the new identity service.',
sourceRefName: 'refs/heads/auth-refactor',
targetRefName: 'refs/heads/develop',
isDraft: true,
reviewers: ['[email protected]', '[email protected]'],
});
console.log(`Created draft PR #${draftPr.pullRequestId}`);
// Create a PR linked to work items
const linkedPr = await mcpClient.callTool('create_pull_request', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
title: 'Fix bugs in payment processor',
sourceRefName: 'refs/heads/bugfix/payment',
targetRefName: 'refs/heads/main',
workItemRefs: [1234, 1235, 1236],
});
console.log(`Created PR #${linkedPr.pullRequestId} linked to work items`);
```
## list_pull_requests
Lists pull requests in a specific Git repository with optional filtering.
### Description
The `list_pull_requests` tool retrieves pull requests from a specified Azure DevOps Git repository. It supports filtering by status (active, completed, abandoned), creator, reviewer, and source/target branches. This tool is useful for monitoring code review progress, identifying pending PRs, and automating PR-related workflows.
### Parameters
```json
{
"projectId": "MyProject", // Required: The ID or name of the project
"repositoryId": "MyRepo", // Required: The ID or name of the repository
"status": "active", // Optional: The status of pull requests to return (active, completed, abandoned, all)
"creatorId": "a8a8a8a8-a8a8-a8a8-a8a8-a8a8a8a8a8a8", // Optional: Filter by creator ID (must be a UUID)
"reviewerId": "b9b9b9b9-b9b9-b9b9-b9b9-b9b9b9b9b9b9", // Optional: Filter by reviewer ID (must be a UUID)
"sourceRefName": "refs/heads/feature-branch", // Optional: Filter by source branch name
"targetRefName": "refs/heads/main", // Optional: Filter by target branch name
"top": 10, // Optional: Maximum number of pull requests to return (default: 10)
"skip": 0 // Optional: Number of pull requests to skip for pagination
}
```
| Parameter | Type | Required | Description |
| --------------- | ------ | -------- | ----------------------------------------------------------------------------------- |
| `projectId` | string | Yes | The ID or name of the project containing the repository |
| `repositoryId` | string | Yes | The ID or name of the repository to list pull requests from |
| `status` | string | No | The status of pull requests to return: "active", "completed", "abandoned", or "all" |
| `creatorId` | string | No | Filter pull requests by creator ID (must be a UUID) |
| `reviewerId` | string | No | Filter pull requests by reviewer ID (must be a UUID) |
| `sourceRefName` | string | No | Filter pull requests by source branch name |
| `targetRefName` | string | No | Filter pull requests by target branch name |
| `top` | number | No | Maximum number of pull requests to return |
### Response
The tool returns an object containing:
- `count`: The number of pull requests returned
- `value`: An array of `PullRequest` objects
- `hasMoreResults`: A boolean indicating if there are more results available
- `warning`: A message with pagination guidance (only present when hasMoreResults is true)
Each pull request in the `value` array contains:
- `pullRequestId`: The unique identifier of the pull request
- `title`: The title of the pull request
- `status`: The status of the pull request (active, abandoned, completed)
- `createdBy`: Information about the user who created the pull request
- `creationDate`: The date and time when the pull request was created
- `sourceRefName`: The source branch name
- `targetRefName`: The target branch name
- And various other fields and references
Example response:
```json
{
"count": 2,
"value": [
{
"repository": {
"id": "repo-guid",
"name": "MyRepo",
"project": {
"id": "project-guid",
"name": "MyProject"
}
},
"pullRequestId": 42,
"codeReviewId": 42,
"status": 1,
"createdBy": {
"displayName": "John Doe",
"uniqueName": "[email protected]"
},
"creationDate": "2023-01-01T12:00:00Z",
"title": "Update feature X",
"description": "This PR implements feature X",
"sourceRefName": "refs/heads/feature-branch",
"targetRefName": "refs/heads/main",
"mergeStatus": 3,
"isDraft": false,
"url": "https://dev.azure.com/organization/MyProject/_apis/git/repositories/MyRepo/pullRequests/42"
},
{
"repository": {
"id": "repo-guid",
"name": "MyRepo",
"project": {
"id": "project-guid",
"name": "MyProject"
}
},
"pullRequestId": 43,
"codeReviewId": 43,
"status": 1,
"createdBy": {
"displayName": "Jane Smith",
"uniqueName": "[email protected]"
},
"creationDate": "2023-01-02T14:30:00Z",
"title": "Fix bug in login flow",
"description": "This PR fixes a critical bug in the login flow",
"sourceRefName": "refs/heads/bugfix/login",
"targetRefName": "refs/heads/main",
"mergeStatus": 3,
"isDraft": false,
"url": "https://dev.azure.com/organization/MyProject/_apis/git/repositories/MyRepo/pullRequests/43"
}
],
"hasMoreResults": false
}
```
### Error Handling
The tool may throw the following errors:
- ValidationError: If required parameters are missing or invalid
- AuthenticationError: If authentication fails
- PermissionError: If the user doesn't have permission to list pull requests
- ResourceNotFoundError: If the project or repository doesn't exist
- GeneralError: For other unexpected errors
Error messages will include details about what went wrong and suggestions for resolution.
### Example Usage
```typescript
// List all active pull requests in a repository
const activePRs = await mcpClient.callTool('list_pull_requests', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
status: 'active',
});
console.log(`Found ${activePRs.count} active pull requests`);
// List pull requests created by a specific user (using their UUID)
const userPRs = await mcpClient.callTool('list_pull_requests', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
creatorId: 'a8a8a8a8-a8a8-a8a8-a8a8-a8a8a8a8a8a8',
});
console.log(`Found ${userPRs.count} pull requests created by this user`);
// List pull requests targeting a specific branch
const mainPRs = await mcpClient.callTool('list_pull_requests', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
targetRefName: 'refs/heads/main',
});
console.log(`Found ${mainPRs.count} pull requests targeting main branch`);
// Paginate through pull requests
const page1 = await mcpClient.callTool('list_pull_requests', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
top: 10,
skip: 0,
});
// Check if there are more results and get the next page
let page2 = { count: 0, value: [] };
if (page1.hasMoreResults) {
page2 = await mcpClient.callTool('list_pull_requests', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
top: 10,
skip: 10,
});
}
console.log(`Retrieved ${page1.count + page2.count} pull requests in 2 pages`);
```
### Pagination
The `list_pull_requests` tool supports pagination to handle large result sets. By default, results are limited to 10 pull requests per request to prevent performance issues.
#### Pagination Parameters
- `top`: Maximum number of pull requests to return (default: 10)
- `skip`: Number of pull requests to skip for pagination
#### Example: Paginating through all pull requests
```typescript
// Get first page (10 items)
const firstPage = await mcpClient.callTool('list_pull_requests', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
});
// Check if there are more results
if (firstPage.hasMoreResults) {
// Get second page
const secondPage = await mcpClient.callTool('list_pull_requests', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
skip: 10,
});
// Continue until no more results
if (secondPage.hasMoreResults) {
const thirdPage = await mcpClient.callTool('list_pull_requests', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
skip: 20,
});
}
}
```
#### Handling Large Repositories
When working with repositories that have many pull requests, it's recommended to use pagination to avoid performance issues. The `list_pull_requests` tool now limits results to 10 by default to prevent issues with very large responses.
If you need to process all pull requests, use the pagination pattern shown above to iterate through the results in manageable chunks.
### Implementation Details
The `list_pull_requests` tool:
1. Establishes a connection to Azure DevOps using the provided credentials
2. Retrieves the Git API client
3. Constructs a search criteria object based on the provided filters
4. Maps status strings to Azure DevOps PullRequestStatus enum values
5. Makes the API call to retrieve the pull requests with pagination parameters
6. Determines if there are more results available
7. Returns an enhanced response object with count, value, hasMoreResults, and warning
8. Handles errors and provides meaningful error messages
This implementation provides a robust and flexible way to retrieve pull requests from Azure DevOps repositories while preventing infinite loop issues.
## get_pull_request_comments
Gets comments and comment threads from a specific pull request.
### Description
The `get_pull_request_comments` tool retrieves comment threads and their associated comments from a specific pull request in an Azure DevOps Git repository. It allows you to get all comments or filter for a specific thread, and supports options for including deleted comments and limiting the number of results. This tool is useful for reviewing feedback on code changes, monitoring discussions, and integrating pull request comments into external workflows.
### Parameters
```json
{
"projectId": "MyProject", // Required: The ID or name of the project
"repositoryId": "MyRepo", // Required: The ID or name of the repository
"pullRequestId": 42, // Required: The ID of the pull request
"threadId": 123, // Optional: The ID of a specific thread to retrieve
"includeDeleted": false, // Optional: Whether to include deleted comments
"top": 50 // Optional: Maximum number of threads to return
}
```
| Parameter | Type | Required | Description |
| ---------------- | ------- | -------- | ------------------------------------------------------------------------------ |
| `projectId` | string | Yes | The ID or name of the project containing the repository |
| `repositoryId` | string | Yes | The ID or name of the repository containing the pull request |
| `pullRequestId` | number | Yes | The ID of the pull request to get comments from |
| `threadId` | number | No | The ID of a specific thread to retrieve (if omitted, all threads are returned) |
| `includeDeleted` | boolean | No | Whether to include deleted comments in the results |
| `top` | number | No | Maximum number of comment threads to return |
### Response
The tool returns an array of `GitPullRequestCommentThread` objects, each containing:
- `id`: The unique identifier of the thread
- `status`: The status of the thread (active, fixed, closed, etc.)
- `threadContext`: Information about the location of the thread in the code (file path, line numbers)
- `comments`: An array of comments within the thread
- And various other fields and references
Each comment in the thread contains:
- `id`: The unique identifier of the comment
- `content`: The text content of the comment
- `commentType`: The type of comment (code change, general, etc.)
- `author`: Information about the user who created the comment
- `publishedDate`: The date and time when the comment was published
- `filePath`: The path of the file the comment is associated with (if any)
- `leftFileStart`: The start position in the left file (object with `line` and `offset`), or null
- `leftFileEnd`: The end position in the left file (object with `line` and `offset`), or null
- `rightFileStart`: The start position in the right file (object with `line` and `offset`), or null
- `rightFileEnd`: The end position in the right file (object with `line` and `offset`), or null
- And various other fields and references
Example response:
```json
[
{
"id": 123,
"status": 1,
"threadContext": {
"filePath": "/src/app.ts",
"rightFileStart": {
"line": 10,
"offset": 5
},
"rightFileEnd": {
"line": 10,
"offset": 15
}
},
"comments": [
{
"id": 456,
"content": "This variable name is not descriptive enough.",
"commentType": 1,
"author": {
"displayName": "Jane Smith",
"id": "user-guid",
"uniqueName": "[email protected]"
},
"publishedDate": "2023-04-15T14:30:00Z",
"filePath": "/src/app.ts",
"rightFileStart": { "line": 10, "offset": 5 },
"rightFileEnd": { "line": 10, "offset": 15 },
"leftFileStart": undefined,
"leftFileEnd": undefined
},
{
"id": 457,
"parentCommentId": 456,
"content": "Good point, I'll rename it to be more descriptive.",
"commentType": 1,
"author": {
"displayName": "John Doe",
"id": "user-guid-2",
"uniqueName": "[email protected]"
},
"publishedDate": "2023-04-15T14:35:00Z",
"filePath": "/src/app.ts",
"rightFileStart": { "line": 10, "offset": 5 },
"rightFileEnd": { "line": 10, "offset": 15 },
"leftFileStart": undefined,
"leftFileEnd": undefined
}
],
"isDeleted": false
},
{
"id": 124,
"status": 2,
"comments": [
{
"id": 458,
"content": "Can you add more validation here?",
"commentType": 1,
"author": {
"displayName": "Jane Smith",
"id": "user-guid",
"uniqueName": "[email protected]"
},
"publishedDate": "2023-04-15T14:40:00Z",
"filePath": null,
"rightFileStart": undefined,
"rightFileEnd": undefined,
"leftFileStart": undefined,
"leftFileEnd": undefined
}
],
"isDeleted": false
}
]
```
### Error Handling
The tool may throw the following errors:
- ValidationError: If required parameters are missing or invalid
- AuthenticationError: If authentication fails
- PermissionError: If the user doesn't have permission to access the pull request comments
- ResourceNotFoundError: If the project, repository, pull request, or thread doesn't exist
- GeneralError: For other unexpected errors
Error messages will include details about what went wrong and suggestions for resolution.
### Example Usage
```typescript
// Get all comments from a pull request
const comments = await mcpClient.callTool('get_pull_request_comments', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
pullRequestId: 42,
});
// Get comments with file path and line number information
comments.forEach(thread => {
thread.comments?.forEach(comment => {
if (comment.filePath && comment.rightFileStart && comment.rightFileEnd) {
console.log(`Comment on ${comment.filePath}:${comment.rightFileStart.line}-${comment.rightFileEnd.line}: ${comment.content}`);
} else {
console.log(`General comment: ${comment.content}`);
}
});
});
// Get a specific thread by ID
const thread = await mcpClient.callTool('get_pull_request_comments', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
pullRequestId: 42,
threadId: 123,
});
// Get comments with pagination
const firstPage = await mcpClient.callTool('get_pull_request_comments', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
pullRequestId: 42,
top: 10,
});
```
### Implementation Details
The `get_pull_request_comments` tool:
1. Establishes a connection to Azure DevOps using the provided credentials
2. Retrieves the Git API client
3. Gets the comment threads from the pull request
4. For each thread:
- Extracts file path and line number information from the thread context
- Adds these fields to each comment in the thread
- Uses rightFileStart.line for line number if available, falls back to leftFileStart.line
5. Returns the transformed threads with enhanced comment information
6. Handles errors and provides meaningful error messages
This implementation provides a robust way to retrieve and analyze pull request comments from Azure DevOps repositories, with enhanced file and line number information for better code review integration.
## add_pull_request_comment
Adds a comment to a pull request, either as a reply to an existing comment or as a new thread.
### Description
The `add_pull_request_comment` tool allows you to create new comments in pull requests in Azure DevOps. You can either:
1. Add a reply to an existing comment thread
2. Create a new thread with a comment in the general discussion
3. Create a new thread with a comment on a specific file at a specific line
This tool is useful for providing feedback on pull requests, engaging in code review discussions, and automating comment workflows.
### Parameters
```json
{
"projectId": "MyProject", // Required: The ID or name of the project
"repositoryId": "MyRepo", // Required: The ID or name of the repository
"pullRequestId": 42, // Required: The ID of the pull request
"content": "This looks good, let's merge!", // Required: The content of the comment
"threadId": 123, // Optional: The ID of the thread to add the comment to (for replying)
"parentCommentId": 456, // Optional: The ID of the parent comment (for threaded replies)
"filePath": "/src/app.ts", // Optional: The path of the file to comment on (for file comments)
"lineNumber": 42, // Optional: The line number to comment on (for file comments)
"status": "active" // Optional: The status to set for a new thread (active, fixed, wontFix, closed, pending)
}
```
| Parameter | Type | Required | Description |
| ----------------- | ------ | -------- | ------------------------------------------------------------------------------------------------ |
| `projectId` | string | Yes | The ID or name of the project containing the repository |
| `repositoryId` | string | Yes | The ID or name of the repository containing the pull request |
| `pullRequestId` | number | Yes | The ID of the pull request to comment on |
| `content` | string | Yes | The text content of the comment |
| `threadId` | number | No | The ID of an existing thread to add the comment to. Required when replying to an existing thread |
| `parentCommentId` | number | No | ID of the parent comment when replying to a specific comment in a thread |
| `filePath` | string | No | The path of the file to comment on (for creating a new thread on a file) |
| `lineNumber` | number | No | The line number to comment on (for creating a new thread on a file) |
| `status` | string | No | The status to set for a new thread: "active", "fixed", "wontFix", "closed", or "pending" |
### Response
When adding a comment to an existing thread, the tool returns an object containing:
- `comment`: The created comment object with details like ID, content, and author
When creating a new thread with a comment, the tool returns an object containing:
- `comment`: The created comment object
- `thread`: The created thread object with details like ID, status, and context
Example response for replying to an existing thread:
```json
{
"comment": {
"id": 101,
"content": "I agree with the suggestion",
"commentType": 1,
"parentCommentId": 100,
"author": {
"displayName": "John Doe",
"id": "user-guid",
"uniqueName": "[email protected]"
},
"publishedDate": "2023-05-15T10:23:45Z"
}
}
```
Example response for creating a new thread on a file:
```json
{
"comment": {
"id": 200,
"content": "This variable name should be more descriptive",
"commentType": 1,
"author": {
"displayName": "John Doe",
"id": "user-guid",
"uniqueName": "[email protected]"
},
"publishedDate": "2023-05-15T10:30:12Z"
},
"thread": {
"id": 50,
"status": 1,
"threadContext": {
"filePath": "/src/app.ts",
"rightFileStart": {
"line": 42,
"offset": 1
},
"rightFileEnd": {
"line": 42,
"offset": 1
}
},
"comments": [
{
"id": 200,
"content": "This variable name should be more descriptive",
"commentType": 1,
"author": {
"displayName": "John Doe",
"id": "user-guid",
"uniqueName": "[email protected]"
},
"publishedDate": "2023-05-15T10:30:12Z"
}
]
}
}
```
### Error Handling
The tool may throw the following errors:
- ValidationError: If required parameters are missing or invalid
- AuthenticationError: If authentication fails
- PermissionError: If the user doesn't have permission to comment on the pull request
- ResourceNotFoundError: If the project, repository, pull request, or thread doesn't exist
- GeneralError: For other unexpected errors
Error messages will include details about what went wrong and suggestions for resolution.
### Example Usage
```typescript
// Reply to an existing thread in a pull request
const reply = await mcpClient.callTool('add_pull_request_comment', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
pullRequestId: 42,
threadId: 123,
content: 'I agree with the suggestion, let me implement this change.',
});
console.log(`Created reply with ID ${reply.comment.id}`);
// Reply to a specific comment in a thread
const threadedReply = await mcpClient.callTool('add_pull_request_comment', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
pullRequestId: 42,
threadId: 123,
parentCommentId: 456,
content: 'Specifically addressing your point about error handling.',
});
console.log(`Created threaded reply with ID ${threadedReply.comment.id}`);
// Create a new general discussion thread in a pull request
const newThread = await mcpClient.callTool('add_pull_request_comment', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
pullRequestId: 42,
content:
"Overall this looks good, but let's discuss the error handling approach.",
});
console.log(`Created new thread with ID ${newThread.thread.id}`);
// Create a comment on a specific file and line
const fileComment = await mcpClient.callTool('add_pull_request_comment', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
pullRequestId: 42,
content: 'This variable name should be more descriptive.',
filePath: '/src/app.ts',
lineNumber: 42,
});
console.log(
`Created file comment with ID ${fileComment.comment.id} in thread ${fileComment.thread.id}`,
);
// Create a comment with thread status
const statusComment = await mcpClient.callTool('add_pull_request_comment', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
pullRequestId: 42,
content: "There's an edge case not handled here.",
filePath: '/src/app.ts',
lineNumber: 87,
status: 'active',
});
console.log(`Created active thread with ID ${statusComment.thread.id}`);
```
### Implementation Details
The `add_pull_request_comment` tool:
1. Establishes a connection to Azure DevOps using the provided credentials
2. Retrieves the Git API client
3. Creates the comment object with the provided content
4. Determines whether to add a comment to an existing thread or create a new thread:
- For existing threads, it calls `createComment` to add a comment to the thread
- For new threads, it creates a thread object and calls `createThread` to create a new thread with the comment
5. For file comments, it adds file path and line information to the thread context
6. Maps status strings to the appropriate CommentThreadStatus enum values
7. Returns the created comment or thread information
8. Handles errors and provides meaningful error messages
This implementation provides a flexible way to add comments to pull requests, supporting both regular discussion comments and code review feedback.
## update_pull_request
Updates an existing pull request with new properties, links work items, and manages reviewers.
### Description
The `update_pull_request` tool allows you to update various aspects of an existing pull request in Azure DevOps. You can modify the title, description, status, draft state, add or remove linked work items, and add or remove reviewers. This tool is useful for automating pull request workflows, updating PR details based on new information, and managing the review process.
### Parameters
```json
{
"projectId": "MyProject", // Required: The ID or name of the project
"repositoryId": "MyRepo", // Required: The ID or name of the repository
"pullRequestId": 42, // Required: The ID of the pull request to update
"title": "Updated PR Title", // Optional: The updated title of the pull request
"description": "Updated PR description", // Optional: The updated description
"status": "active", // Optional: The updated status (active, abandoned, completed)
"isDraft": false, // Optional: Whether to mark (true) or unmark (false) as draft
"addWorkItemIds": [123, 456], // Optional: Work item IDs to link to the PR
"removeWorkItemIds": [789], // Optional: Work item IDs to unlink from the PR
"addReviewers": ["[email protected]"], // Optional: Reviewers to add
"removeReviewers": ["[email protected]"], // Optional: Reviewers to remove
"additionalProperties": {} // Optional: Additional properties to update
}
```
| Parameter | Type | Required | Description |
| ---------------------- | -------- | -------- | ------------------------------------------------------------ |
| `projectId` | string | Yes | The ID or name of the project containing the repository |
| `repositoryId` | string | Yes | The ID or name of the repository containing the pull request |
| `pullRequestId` | number | Yes | The ID of the pull request to update |
| `title` | string | No | The updated title of the pull request |
| `description` | string | No | The updated description of the pull request |
| `status` | string | No | The updated status: "active", "abandoned", or "completed" |
| `isDraft` | boolean | No | Whether to mark (true) or unmark (false) the PR as a draft |
| `addWorkItemIds` | number[] | No | Array of work item IDs to link to the pull request |
| `removeWorkItemIds` | number[] | No | Array of work item IDs to unlink from the pull request |
| `addReviewers` | string[] | No | Array of reviewer email addresses or IDs to add |
| `removeReviewers` | string[] | No | Array of reviewer email addresses or IDs to remove |
| `additionalProperties` | object | No | Additional properties to update on the pull request |
### Response
The tool returns the updated `PullRequest` object containing:
- `pullRequestId`: The unique identifier of the updated pull request
- `title`: The title of the pull request (updated if provided)
- `description`: The description of the pull request (updated if provided)
- `status`: The status of the pull request (active, abandoned, completed)
- `isDraft`: Whether the pull request is a draft
- And various other fields and references, including updated reviewers and work item references
Example response:
```json
{
"repository": {
"id": "repo-guid",
"name": "MyRepo",
"url": "https://dev.azure.com/organization/MyProject/_apis/git/repositories/MyRepo",
"project": {
"id": "project-guid",
"name": "MyProject"
}
},
"pullRequestId": 42,
"codeReviewId": 42,
"status": 1,
"createdBy": {
"displayName": "John Doe",
"id": "user-guid",
"uniqueName": "[email protected]"
},
"creationDate": "2023-01-01T12:00:00Z",
"title": "Updated PR Title",
"description": "Updated PR description",
"sourceRefName": "refs/heads/feature-branch",
"targetRefName": "refs/heads/main",
"mergeStatus": 3,
"isDraft": false,
"reviewers": [
{
"displayName": "Jane Smith",
"id": "reviewer-guid",
"uniqueName": "[email protected]",
"voteResult": 0
}
],
"url": "https://dev.azure.com/organization/MyProject/_apis/git/repositories/MyRepo/pullRequests/42",
"workItemRefs": [
{
"id": "123",
"url": "https://dev.azure.com/organization/MyProject/_apis/wit/workItems/123"
},
{
"id": "456",
"url": "https://dev.azure.com/organization/MyProject/_apis/wit/workItems/456"
}
]
}
```
### Error Handling
The tool may throw the following errors:
- ValidationError: If required parameters are missing or invalid
- AuthenticationError: If authentication fails
- PermissionError: If the user doesn't have permission to update the pull request
- ResourceNotFoundError: If the project, repository, or pull request doesn't exist
- GeneralError: For other unexpected errors
Error messages will include details about what went wrong and suggestions for resolution.
### Example Usage
```typescript
// Update the title and description of a pull request
const updatedPR = await mcpClient.callTool('update_pull_request', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
pullRequestId: 42,
title: 'Updated PR Title',
description: 'This PR has been updated to add new features',
});
console.log(`Updated PR: ${updatedPR.title}`);
// Mark a pull request as completed
const completedPR = await mcpClient.callTool('update_pull_request', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
pullRequestId: 42,
status: 'completed',
});
console.log(
`PR status: ${completedPR.status === 3 ? 'Completed' : 'Not completed'}`,
);
// Convert a draft PR to a normal PR
const readyPR = await mcpClient.callTool('update_pull_request', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
pullRequestId: 42,
isDraft: false,
});
console.log(`PR is draft: ${readyPR.isDraft ? 'Yes' : 'No'}`);
// Add and remove work items from a PR
const workItemPR = await mcpClient.callTool('update_pull_request', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
pullRequestId: 42,
addWorkItemIds: [123, 456],
removeWorkItemIds: [789],
});
console.log(
`PR now has ${workItemPR.workItemRefs?.length || 0} linked work items`,
);
// Add and remove reviewers
const reviewersPR = await mcpClient.callTool('update_pull_request', {
projectId: 'MyProject',
repositoryId: 'MyRepo',
pullRequestId: 42,
addReviewers: ['[email protected]', '[email protected]'],
removeReviewers: ['[email protected]'],
});
console.log(`PR now has ${reviewersPR.reviewers?.length || 0} reviewers`);
```
### Implementation Details
The `update_pull_request` tool:
1. Establishes a connection to Azure DevOps using the provided credentials
2. Retrieves the Git API client
3. Gets the current pull request to verify it exists
4. Creates an update object with only the properties that are being updated:
- Basic properties (title, description, isDraft)
- Status (active, abandoned, completed)
- Any additional properties provided
5. Updates the pull request with the provided changes
6. If specified, handles adding and removing work item associations:
- Adds work items by creating links between the PR and work items
- Removes work items by deleting links between the PR and work items
7. If specified, handles adding and removing reviewers:
- Adds reviewers by creating reviewer references
- Removes reviewers by deleting reviewer references
8. Gets the final updated pull request to return all changes
9. Handles errors and provides meaningful error messages
This implementation provides a comprehensive way to update pull requests in Azure DevOps repositories, supporting all common update scenarios.
## get_pull_request_changes
Retrieves the list of files changed in a pull request, including unified diff patches for each file and the latest policy evaluation status.
### Parameters
```json
{
"projectId": "MyProject",
"repositoryId": "MyRepo",
"pullRequestId": 42
}
```
### Response
Returns an object with:
- `changes`: The raw change entries from Azure DevOps for the latest iteration
- `evaluations`: Policy evaluation records for the pull request
- `files`: Array of changed files with their unified diffs
Each file entry has the shape:
```json
{
"path": "src/app.ts",
"patch": "@@ -1,2 +1,2 @@\n-old\n+new\n"
}
```
## get_pull_request_checks
Summarises the latest status checks (builds, validations, custom checks) and policy evaluations applied to a pull request, including the pipeline/run identifiers you need to investigate failures.
### Parameters
```json
{
"projectId": "MyProject",
"repositoryId": "MyRepo",
"pullRequestId": 42
}
```
### Response
Returns an object with two arrays:
- `statuses`: Check runs reported through the PR status API. Each entry includes the check `state`, description, status context (`name`/`genre`), and a `pipeline` object with any discovered `pipelineId`, `definitionId`, `runId`/`buildId`, and `targetUrl`.
- `policyEvaluations`: Policy evaluation records (e.g., build validations, required reviews). Each entry includes policy metadata, whether it is blocking, the evaluation status, a friendly `displayName`, and a `pipeline` object mirroring the identifiers above when the policy is backed by a pipeline.
Example response (trimmed):
```json
{
"statuses": [
{
"id": 17,
"state": "failed",
"description": "CI build",
"context": { "name": "CI", "genre": "continuous-integration" },
"pipeline": {
"pipelineId": 55,
"runId": 123,
"targetUrl": "https://dev.azure.com/org/project/_apis/pipelines/55/runs/123?view=results"
}
}
],
"policyEvaluations": [
{
"evaluationId": "eval-1",
"status": "rejected",
"displayName": "CI Build",
"isBlocking": true,
"pipeline": {
"definitionId": 987,
"buildId": 456,
"targetUrl": "https://dev.azure.com/org/project/_build/results?buildId=456"
}
}
]
}
```
Use the surfaced `pipelineId` and `runId` values with the pipeline tools (`get_pipeline_run`, `pipeline_timeline`, `get_pipeline_log`, etc.) to drill into the specific validation that is blocking the pull request.
```