@azure-devops/mcp 1.2.0-daily.20250715 β†’ 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,20 +5,20 @@ Easily install the Azure DevOps MCP Server for VS Code or VS Code Insiders:
5
5
  [![Install with NPX in VS Code](https://img.shields.io/badge/VS_Code-Install_AzureDevops_MCP_Server-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=ado&config=%7B%20%22type%22%3A%20%22stdio%22%2C%20%22command%22%3A%20%22npx%22%2C%20%22args%22%3A%20%5B%22-y%22%2C%20%22%40azure-devops%2Fmcp%22%2C%20%22%24%7Binput%3Aado_org%7D%22%5D%7D&inputs=%5B%7B%22id%22%3A%20%22ado_org%22%2C%20%22type%22%3A%20%22promptString%22%2C%20%22description%22%3A%20%22Azure%20DevOps%20organization%20name%20%20%28e.g.%20%27contoso%27%29%22%7D%5D)
6
6
  [![Install with NPX in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install_AzureDevops_MCP_Server-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=ado&quality=insiders&config=%7B%20%22type%22%3A%20%22stdio%22%2C%20%22command%22%3A%20%22npx%22%2C%20%22args%22%3A%20%5B%22-y%22%2C%20%22%40azure-devops%2Fmcp%22%2C%20%22%24%7Binput%3Aado_org%7D%22%5D%7D&inputs=%5B%7B%22id%22%3A%20%22ado_org%22%2C%20%22type%22%3A%20%22promptString%22%2C%20%22description%22%3A%20%22Azure%20DevOps%20organization%20name%20%20%28e.g.%20%27contoso%27%29%22%7D%5D)
7
7
 
8
- This TypeScript project defines the **local** MCP server for Azure DevOps, enabling you to perform a wide range of Azure DevOps tasks directly from your code editor.
8
+ This TypeScript project provides a **local** MCP server for Azure DevOps, enabling you to perform a wide range of Azure DevOps tasks directly from your code editor.
9
9
 
10
- > 🚨 **Public Preview:** This project is in public preview. You can expect that the tools will change before general availability.
10
+ > 🚨 **Public Preview:** This project is in public preview. Tools and features may change before general availability.
11
11
 
12
- ## πŸ“„ Table of contents
12
+ ## πŸ“„ Table of Contents
13
13
 
14
14
  1. [πŸ“Ί Overview](#-overview)
15
15
  2. [πŸ† Expectations](#-expectations)
16
- 3. [βš™οΈ Supported tools](#️-supported-tools)
17
- 4. [πŸ”Œ Installation & getting started](#-installation--getting-started)
16
+ 3. [βš™οΈ Supported Tools](#️-supported-tools)
17
+ 4. [πŸ”Œ Installation & Getting Started](#-installation--getting-started)
18
18
  5. [πŸ”¦ Usage](#-usage)
19
19
  6. [πŸ“ Troubleshooting](#-troubleshooting)
20
- 7. [🎩 Samples & best practices](#-samples--best-practices)
21
- 8. [πŸ™‹β€β™€οΈ Frequently asked questions](#️-frequently-asked-questions)
20
+ 7. [🎩 Samples & Best Practices](#-samples--best-practices)
21
+ 8. [πŸ™‹β€β™€οΈ Frequently Asked Questions](#️-frequently-asked-questions)
22
22
  9. [πŸ“Œ Contributing](#-contributing)
23
23
 
24
24
  ## πŸ“Ί Overview
@@ -37,9 +37,9 @@ The Azure DevOps MCP Server brings Azure DevOps context to your agents. Try prom
37
37
 
38
38
  ## πŸ† Expectations
39
39
 
40
- The Azure DevOps MCP Server is built from tools that are concise, simple, focused, and easy to use. Each designed for a specific scenario. We intentionally avoid complex tools that try to do too much. The goal is to provide a thin abstraction layer over the REST APIs, making data access straightforward and letting the language model handle the complex reasoning.
40
+ The Azure DevOps MCP Server is built from tools that are concise, simple, focused, and easy to useβ€”each designed for a specific scenario. We intentionally avoid complex tools that try to do too much. The goal is to provide a thin abstraction layer over the REST APIs, making data access straightforward and letting the language model handle complex reasoning.
41
41
 
42
- ## βš™οΈ Supported tools
42
+ ## βš™οΈ Supported Tools
43
43
 
44
44
  Interact with these Azure DevOps services:
45
45
 
@@ -61,32 +61,32 @@ Interact with these Azure DevOps services:
61
61
  - **wit_list_backlogs**: Retrieve a list of backlogs for a given project and team.
62
62
  - **wit_list_backlog_work_items**: Retrieve a list of backlogs for a given project, team, and backlog category.
63
63
  - **wit_get_work_item**: Get a single work item by ID.
64
- - **wit_get_work_items_batch_by_ids**: Retrieves a list of work items by IDs in batch.
64
+ - **wit_get_work_items_batch_by_ids**: Retrieve a list of work items by IDs in batch.
65
65
  - **wit_update_work_item**: Update a work item by ID with specified fields.
66
66
  - **wit_create_work_item**: Create a new work item in a specified project and work item type.
67
- - **wit_list_work_item_comments**: Retrieves a list of comments for a work item by ID.
68
- - **wit_get_work_items_for_iteration**: Retrieves a list of work items for a specified iteration.
69
- - **wit_add_work_item_comment**: Add comment to a work item by ID.
70
- - **wit_add_child_work_items**: Create one or many child work items of a specific work item type for the given parent Id
67
+ - **wit_list_work_item_comments**: Retrieve a list of comments for a work item by ID.
68
+ - **wit_get_work_items_for_iteration**: Retrieve a list of work items for a specified iteration.
69
+ - **wit_add_work_item_comment**: Add a comment to a work item by ID.
70
+ - **wit_add_child_work_items**: Create one or more child work items of a specific work item type for the given parent ID.
71
71
  - **wit_link_work_item_to_pull_request**: Link a single work item to an existing pull request.
72
72
  - **wit_get_work_item_type**: Get a specific work item type.
73
73
  - **wit_get_query**: Get a query by its ID or path.
74
74
  - **wit_get_query_results_by_id**: Retrieve the results of a work item query given the query ID.
75
75
  - **wit_update_work_items_batch**: Update work items in batch.
76
- - **wit_close_and_link_workitem_duplicates**: Close duplicate work items by id.
77
76
  - **wit_work_items_link**: Link work items together in batch.
78
77
 
79
- #### Deprecated tools
78
+ #### Deprecated Tools
80
79
 
81
- - **wit_add_child_work_item**: Replaced by `wit_add_child_work_items` so that you can create one or many child items per call.
80
+ - **wit_add_child_work_item**: Replaced by `wit_add_child_work_items` to allow creating one or more child items per call.
81
+ - **wit_close_and_link_workitem_duplicates**: This tool is no longer needed. Finding and marking duplicates can be done with other tools.
82
82
 
83
83
  ### πŸ“ Repositories
84
84
 
85
85
  - **repo_list_repos_by_project**: Retrieve a list of repositories for a given project.
86
86
  - **repo_list_pull_requests_by_repo**: Retrieve a list of pull requests for a given repository.
87
- - **repo_list_pull_requests_by_project**: Retrieve a list of pull requests for a given project Id or Name.
87
+ - **repo_list_pull_requests_by_project**: Retrieve a list of pull requests for a given project ID or name.
88
88
  - **repo_list_branches_by_repo**: Retrieve a list of branches for a given repository.
89
- - **repo_list_my_branches_by_repo**: Retrieve a list of my branches for a given repository Id.
89
+ - **repo_list_my_branches_by_repo**: Retrieve a list of your branches for a given repository ID.
90
90
  - **repo_list_pull_requests_by_commits**: List pull requests associated with commits.
91
91
  - **repo_list_pull_request_threads**: Retrieve a list of comment threads for a pull request.
92
92
  - **repo_list_pull_request_thread_comments**: Retrieve a list of comments in a pull request thread.
@@ -94,49 +94,53 @@ Interact with these Azure DevOps services:
94
94
  - **repo_get_branch_by_name**: Get a branch by its name.
95
95
  - **repo_get_pull_request_by_id**: Get a pull request by its ID.
96
96
  - **repo_create_pull_request**: Create a new pull request.
97
- - **repo_update_pull_request_status**: Update status of an existing pull request to active or abandoned.
97
+ - **repo_update_pull_request_status**: Update the status of an existing pull request to active or abandoned.
98
98
  - **repo_update_pull_request_reviewers**: Add or remove reviewers for an existing pull request.
99
99
  - **repo_reply_to_comment**: Replies to a specific comment on a pull request.
100
100
  - **repo_resolve_comment**: Resolves a specific comment thread on a pull request.
101
101
  - **repo_search_commits**: Searches for commits.
102
+ - **repo_create_pull_request_thread**: Creates a new comment thread on a pull request.
102
103
 
103
104
  ### πŸ›°οΈ Builds
104
105
 
105
- - **build_get_definitions**: Retrieves a list of build definitions for a given project.
106
- - **build_get_definition_revisions**: Retrieves a list of revisions for a specific build definition.
107
- - **build_get_builds**: Retrieves a list of builds for a given project.
108
- - **build_get_log**: Retrieves the logs for a specific build.
106
+ - **build_get_definitions**: Retrieve a list of build definitions for a given project.
107
+ - **build_get_definition_revisions**: Retrieve a list of revisions for a specific build definition.
108
+ - **build_get_builds**: Retrieve a list of builds for a given project.
109
+ - **build_get_log**: Retrieve the logs for a specific build.
109
110
  - **build_get_log_by_id**: Get a specific build log by log ID.
110
111
  - **build_get_changes**: Get the changes associated with a specific build.
111
- - **build_run_build**: Triggers a new build for a specified definition.
112
- - **build_get_status**: Fetches the status of a specific build.
113
- - **build_update_build_stage**: Updates the stage of a specific build.
112
+ - **build_run_build**: Trigger a new build for a specified definition.
113
+ - **build_get_status**: Fetch the status of a specific build.
114
+ - **build_update_build_stage**: Update the stage of a specific build.
114
115
 
115
116
  ### πŸš€ Releases
116
117
 
117
- - **release_get_definitions**: Retrieves a list of release definitions for a given project.
118
- - **release_get_releases**: Retrieves a list of releases for a given project.
118
+ - **release_get_definitions**: Retrieve a list of release definitions for a given project.
119
+ - **release_get_releases**: Retrieve a list of releases for a given project.
119
120
 
120
121
  ### πŸ§ͺ Test Plans
121
122
 
122
- - **testplan_create_test_plan**: Creates a new test plan in the project.
123
- - **testplan_create_test_case**: Creates a new test case work item.
124
- - **testplan_add_test_cases_to_suite**: Adds existing test cases to a test suite.
123
+ - **testplan_create_test_plan**: Create a new test plan in the project.
124
+ - **testplan_create_test_case**: Create a new test case work item.
125
+ - **testplan_add_test_cases_to_suite**: Add existing test cases to a test suite.
125
126
  - **testplan_list_test_plans**: Retrieve a paginated list of test plans from an Azure DevOps project. Allows filtering for active plans and toggling detailed information.
126
- - **testplan_list_test_cases**: Gets a list of test cases in the test plan.
127
- - **testplan_show_test_results_from_build_id**: Gets a list of test results for a given project and build ID.
127
+ - **testplan_list_test_cases**: Get a list of test cases in the test plan.
128
+ - **testplan_show_test_results_from_build_id**: Get a list of test results for a given project and build ID.
128
129
 
129
130
  ### πŸ”Ž Search
130
131
 
131
- - **search_code**: Get the code search results for a given search text.
132
+ - **search_code**: Get code search results for a given search text.
132
133
  - **search_wiki**: Get wiki search results for a given search text.
133
134
  - **search_workitem**: Get work item search results for a given search text.
134
135
 
135
- ## πŸ”Œ Installation & getting started
136
+ ## πŸ”Œ Installation & Getting Started
136
137
 
137
138
  Clone the repository, install dependencies, and add it to your MCP client configuration.
138
139
 
139
- ### Visual Studio Code & GitHub Copilot
140
+ [VS Code and GitHub Copilot](#%EF%B8%8F-visual-studio-code--github-copilot)<br/>
141
+ [Visual Studio 2022 and GitHub Copilot](#%EF%B8%8F-visual-studio-2022--github-copilot)
142
+
143
+ ### ➑️ Visual Studio Code & GitHub Copilot
140
144
 
141
145
  For the best experience, use Visual Studio Code and GitHub Copilot.
142
146
 
@@ -157,51 +161,51 @@ az login
157
161
 
158
162
  ### Installation
159
163
 
160
- #### ✨ One-Click install
164
+ #### ✨ One-Click Install
161
165
 
162
166
  [![Install with NPX in VS Code](https://img.shields.io/badge/VS_Code-Install_AzureDevops_MCP_Server-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=ado&config=%7B%20%22type%22%3A%20%22stdio%22%2C%20%22command%22%3A%20%22npx%22%2C%20%22args%22%3A%20%5B%22-y%22%2C%20%22%40azure-devops%2Fmcp%22%2C%20%22%24%7Binput%3Aado_org%7D%22%5D%7D&inputs=%5B%7B%22id%22%3A%20%22ado_org%22%2C%20%22type%22%3A%20%22promptString%22%2C%20%22description%22%3A%20%22Azure%20DevOps%20organization%20name%20%20%28e.g.%20%27contoso%27%29%22%7D%5D)
163
167
  [![Install with NPX in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install_AzureDevops_MCP_Server-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=ado&quality=insiders&config=%7B%20%22type%22%3A%20%22stdio%22%2C%20%22command%22%3A%20%22npx%22%2C%20%22args%22%3A%20%5B%22-y%22%2C%20%22%40azure-devops%2Fmcp%22%2C%20%22%24%7Binput%3Aado_org%7D%22%5D%7D&inputs=%5B%7B%22id%22%3A%20%22ado_org%22%2C%20%22type%22%3A%20%22promptString%22%2C%20%22description%22%3A%20%22Azure%20DevOps%20organization%20name%20%20%28e.g.%20%27contoso%27%29%22%7D%5D)
164
168
 
165
169
  After installation, select GitHub Copilot Agent Mode and refresh the tools list. Learn more about Agent Mode in the [VS Code Documentation](https://code.visualstudio.com/docs/copilot/chat/chat-agent-mode).
166
170
 
167
- #### 🧨 Installing from public feed (recommended)
171
+ #### 🧨 Install from Public Feed (Recommended)
168
172
 
169
- This installation method is the easiest for all users using Visual Studio Code.
173
+ This installation method is the easiest for all users of Visual Studio Code.
170
174
 
171
175
  πŸŽ₯ [Watch this quick start video to get up and running in under two minutes!](https://youtu.be/EUmFM6qXoYk)
172
176
 
173
177
  ##### Steps
174
178
 
175
- 1. In your project, add a `.vscode\mcp.json` file and add the following:
176
-
177
- ```json
178
- {
179
- "inputs": [
180
- {
181
- "id": "ado_org",
182
- "type": "promptString",
183
- "description": "Azure DevOps organization name (e.g. 'contoso')"
184
- }
185
- ],
186
- "servers": {
187
- "ado": {
188
- "type": "stdio",
189
- "command": "npx",
190
- "args": ["-y", "@azure-devops/mcp", "${input:ado_org}"]
191
- }
192
- }
193
- }
194
- ```
195
-
196
- 2. Save the file, then click 'Start`
197
-
198
- <img src="./docs/media/start-mcp-server.gif" alt="start mcp server" width="250"/>
179
+ 1. In your project, add a `.vscode\mcp.json` file with the following content:
180
+
181
+ ```json
182
+ {
183
+ "inputs": [
184
+ {
185
+ "id": "ado_org",
186
+ "type": "promptString",
187
+ "description": "Azure DevOps organization name (e.g. 'contoso')"
188
+ }
189
+ ],
190
+ "servers": {
191
+ "ado": {
192
+ "type": "stdio",
193
+ "command": "npx",
194
+ "args": ["-y", "@azure-devops/mcp", "${input:ado_org}"]
195
+ }
196
+ }
197
+ }
198
+ ```
199
+
200
+ 2. Save the file, then click 'Start'.
201
+
202
+ <img src="./docs/media/start-mcp-server.gif" alt="start mcp server" width="250"/>
199
203
 
200
204
  3. In chat, switch to [Agent Mode](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode).
201
205
  4. Click "Select Tools" and choose the available tools.
202
- 5. We strongly recommend that you create a `.github\copilot-instructions.md` in your project and copy and paste the contents from this [copilot-instructions.md](./.github/copilot-instructions.md) file. This will enhance your experience using the Azure DevOps MCP Server with GitHub Copilot Chat.
206
+ 5. We strongly recommend creating a `.github\copilot-instructions.md` in your project and copying the contents from this [copilot-instructions.md](./.github/copilot-instructions.md) file. This will enhance your experience using the Azure DevOps MCP Server with GitHub Copilot Chat.
203
207
 
204
- #### πŸ› οΈ Installing from source (dev mode)
208
+ #### πŸ› οΈ Install from Source (Dev Mode)
205
209
 
206
210
  This installation method is recommended for advanced users and contributors who want immediate access to the latest updates from the main branch. It is ideal if you are developing new tools, enhancing existing features, or maintaining a custom fork.
207
211
 
@@ -211,39 +215,100 @@ This installation method is recommended for advanced users and contributors who
211
215
 
212
216
  1. Clone the repository.
213
217
  2. Install dependencies:
214
- ```sh
215
- npm install
216
- ```
218
+
219
+ ```sh
220
+ npm install
221
+ ```
222
+
217
223
  3. Edit or add `.vscode/mcp.json`:
218
224
 
219
- ```json
220
- {
221
- "inputs": [
222
- {
223
- "id": "ado_org",
224
- "type": "promptString",
225
- "description": "Azure DevOps organization's name (e.g. 'contoso')"
226
- }
227
- ],
228
- "servers": {
229
- "ado": {
230
- "type": "stdio",
231
- "command": "mcp-server-azuredevops",
232
- "args": ["${input:ado_org}"]
233
- }
234
- }
235
- }
236
- ```
237
-
238
- 4. Start the Azure DevOps MCP Server
239
-
240
- <img src="./docs/media/start-mcp-server.gif" alt="start mcp server" width="250"/>
225
+ ```json
226
+ {
227
+ "inputs": [
228
+ {
229
+ "id": "ado_org",
230
+ "type": "promptString",
231
+ "description": "Azure DevOps organization's name (e.g. 'contoso')"
232
+ }
233
+ ],
234
+ "servers": {
235
+ "ado": {
236
+ "type": "stdio",
237
+ "command": "mcp-server-azuredevops",
238
+ "args": ["${input:ado_org}"]
239
+ }
240
+ }
241
+ }
242
+ ```
243
+
244
+ 4. Start the Azure DevOps MCP Server.
245
+
246
+ <img src="./docs/media/start-mcp-server.gif" alt="start mcp server" width="250"/>
241
247
 
242
248
  5. In chat, switch to [Agent Mode](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode).
243
249
  6. Click "Select Tools" and choose the available tools.
244
- 7. We strongly recommend that you create a `.github\copilot-instructions.md` in your project and copy and paste the contents from this [copilot-instructions.md](./.github/copilot-instructions.md) file. This will help your experience when it comes to using the Azure DevOps MCP Server in GitHub Copilot Chat.
250
+ 7. We strongly recommend creating a `.github\copilot-instructions.md` in your project and copying the contents from this [copilot-instructions.md](./.github/copilot-instructions.md) file. This will help you get the best experience using the Azure DevOps MCP Server in GitHub Copilot Chat.
251
+
252
+ See the [How To](./docs/HOWTO.md) section for details.
253
+
254
+ ### ➑️ Visual Studio 2022 & GitHub Copilot
255
+
256
+ For the best experience, use Visual Studio Code and GitHub Copilot πŸ‘†.
257
+
258
+ ### Prerequisites
259
+
260
+ 1. Install [VS Studio 2022 version 17.14](https://learn.microsoft.com/en-us/visualstudio/releases/2022/release-history) or later
261
+ 2. Install [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest)
262
+ 3. Open a project in Visual Studio.
263
+
264
+ ### Azure Login
265
+
266
+ Ensure you are logged in to Azure DevOps via the Azure CLI:
267
+
268
+ ```sh
269
+ az login
270
+ ```
271
+
272
+ #### 🧨 Install from Public Feed (Recommended)
273
+
274
+ This installation method is the easiest for all users of Visual Studio 2022.
275
+
276
+ πŸŽ₯ [Watch this quick start video to get up and running in under two minutes!](https://youtu.be/nz_Gn-WL7j0)
277
+
278
+ ##### Steps
279
+
280
+ 1. Add a `.mcp.json` file to the solution folder with the following content:
281
+
282
+ ```json
283
+ {
284
+ "inputs": [
285
+ {
286
+ "id": "ado_org",
287
+ "type": "promptString",
288
+ "description": "Azure DevOps organization name (e.g. 'contoso')"
289
+ }
290
+ ],
291
+ "servers": {
292
+ "ado": {
293
+ "type": "stdio",
294
+ "command": "npx",
295
+ "args": ["-y", "@azure-devops/mcp", "${input:ado_org}"]
296
+ }
297
+ }
298
+ }
299
+ ```
300
+
301
+ 2. Save the file.
302
+ 3. Add your organization name by clicking on the `input` option.
303
+
304
+ <img src="./docs/media/start-mcp-server-from-vs.png" alt="start mcp server from visual studio 2022" width="250"/>
305
+
306
+ 4. Open Copilot chat and switch to [Agent Mode](https://learn.microsoft.com/en-us/visualstudio/ide/copilot-agent-mode?view=vs-2022).
307
+ 5. Click the "Tools" icon and choose the available tools.
308
+
309
+ <img src="./docs/media/set-tools-from-vs.png" alt="set tools to use in visual studio 2022" width="250"/>
245
310
 
246
- See [How To](./docs/HOWTO.md) section for details
311
+ 6. We strongly recommend creating a `.github\copilot-instructions.md` in your project and copying the contents from this [copilot-instructions.md](./.github/copilot-instructions.md) file. This will enhance your experience using the Azure DevOps MCP Server with GitHub Copilot Chat.
247
312
 
248
313
  ## πŸ”¦ Usage
249
314
 
@@ -263,23 +328,23 @@ See [How To](./docs/HOWTO.md) section for details
263
328
  3. Select desired `ado` tools.
264
329
  4. Try prompts like "List ADO projects".
265
330
 
266
- For more details, see [Visual Studio MCP Servers documentation](https://learn.microsoft.com/en-us/visualstudio/ide/mcp-servers?view=vs-2022) and [Getting Started Video](https://www.youtube.com/watch?v=oPFecZHBCkg).
331
+ For more details, see [Visual Studio MCP Servers documentation](https://learn.microsoft.com/en-us/visualstudio/ide/mcp-servers?view=vs-2022) and the [Getting Started Video](https://www.youtube.com/watch?v=oPFecZHBCkg).
267
332
 
268
333
  ## πŸ“ Troubleshooting
269
334
 
270
335
  See the [Troubleshooting guide](./docs/TROUBLESHOOTING.md) for help with common issues and logging.
271
336
 
272
- ## 🎩 Samples & best practices
337
+ ## 🎩 Samples & Best Practices
273
338
 
274
339
  Find sample prompts and best practices in our [How-to Guide](./docs/HOWTO.md).
275
340
 
276
- ## πŸ™‹β€β™€οΈ Frequently asked questions
341
+ ## πŸ™‹β€β™€οΈ Frequently Asked Questions
277
342
 
278
343
  For answers to common questions about the Azure DevOps MCP Server, see the [Frequently Asked Questions](./docs/FAQ.md).
279
344
 
280
345
  ## πŸ“Œ Contributing
281
346
 
282
- We welcome contributions! During preview, please file Issues for bugs, enhancements, or documentation improvements.
347
+ We welcome contributions! During preview, please file issues for bugs, enhancements, or documentation improvements.
283
348
 
284
349
  See our [Contributions Guide](./CONTRIBUTING.md) for:
285
350
 
@@ -288,7 +353,7 @@ See our [Contributions Guide](./CONTRIBUTING.md) for:
288
353
  - πŸ“ Code style & testing
289
354
  - πŸ”„ Pull request process
290
355
 
291
- ## 🀝 Code of conduct
356
+ ## 🀝 Code of Conduct
292
357
 
293
358
  This project follows the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
294
359
  For questions, see the [FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [open@microsoft.com](mailto:open@microsoft.com).
package/dist/index.js CHANGED
@@ -4,17 +4,33 @@
4
4
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
5
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
6
  import * as azdev from "azure-devops-node-api";
7
- import { DefaultAzureCredential } from "@azure/identity";
7
+ import { AzureCliCredential, ChainedTokenCredential, DefaultAzureCredential } from "@azure/identity";
8
+ import yargs from "yargs";
9
+ import { hideBin } from "yargs/helpers";
8
10
  import { configurePrompts } from "./prompts.js";
9
11
  import { configureAllTools } from "./tools.js";
10
12
  import { UserAgentComposer } from "./useragent.js";
11
13
  import { packageVersion } from "./version.js";
12
- const args = process.argv.slice(2);
13
- if (args.length === 0) {
14
- console.error("Usage: mcp-server-azuredevops <organization_name>");
15
- process.exit(1);
16
- }
17
- export const orgName = args[0];
14
+ // Parse command line arguments using yargs
15
+ const argv = yargs(hideBin(process.argv))
16
+ .scriptName("mcp-server-azuredevops")
17
+ .usage("Usage: $0 <organization> [options]")
18
+ .version(packageVersion)
19
+ .command("$0 <organization>", "Azure DevOps MCP Server", (yargs) => {
20
+ yargs.positional("organization", {
21
+ describe: "Azure DevOps organization name",
22
+ type: "string",
23
+ });
24
+ })
25
+ .option("tenant", {
26
+ alias: "t",
27
+ describe: "Azure tenant ID (optional, required for multi-tenant scenarios)",
28
+ type: "string",
29
+ })
30
+ .help()
31
+ .parseSync();
32
+ export const orgName = argv.organization;
33
+ const tenantId = argv.tenant;
18
34
  const orgUrl = "https://dev.azure.com/" + orgName;
19
35
  async function getAzureDevOpsToken() {
20
36
  if (process.env.ADO_MCP_AZURE_TOKEN_CREDENTIALS) {
@@ -23,8 +39,16 @@ async function getAzureDevOpsToken() {
23
39
  else {
24
40
  process.env.AZURE_TOKEN_CREDENTIALS = "dev";
25
41
  }
26
- const credential = new DefaultAzureCredential(); // CodeQL [SM05138] resolved by explicitly setting AZURE_TOKEN_CREDENTIALS
42
+ let credential = new DefaultAzureCredential(); // CodeQL [SM05138] resolved by explicitly setting AZURE_TOKEN_CREDENTIALS
43
+ if (tenantId) {
44
+ // Use Azure CLI credential if tenantId is provided for multi-tenant scenarios
45
+ const azureCliCredential = new AzureCliCredential({ tenantId });
46
+ credential = new ChainedTokenCredential(azureCliCredential, credential);
47
+ }
27
48
  const token = await credential.getToken("499b84ac-1321-427f-aa17-267ca6975798/.default");
49
+ if (!token) {
50
+ throw new Error("Failed to obtain Azure DevOps token. Ensure you have Azure CLI logged in or another token source setup correctly.");
51
+ }
28
52
  return token;
29
53
  }
30
54
  function getAzureDevOpsClient(userAgentComposer) {
@@ -1,6 +1,6 @@
1
1
  // Copyright (c) Microsoft Corporation.
2
2
  // Licensed under the MIT License.
3
- import { apiVersion } from "../utils.js";
3
+ import { apiVersion, getEnumKeys, safeEnumConvert } from "../utils.js";
4
4
  import { BuildQueryOrder, DefinitionQueryOrder } from "azure-devops-node-api/interfaces/BuildInterfaces.js";
5
5
  import { z } from "zod";
6
6
  import { StageUpdateType } from "azure-devops-node-api/interfaces/BuildInterfaces.js";
@@ -22,7 +22,10 @@ function configureBuildTools(server, tokenProvider, connectionProvider) {
22
22
  repositoryType: z.enum(["TfsGit", "GitHub", "BitbucketCloud"]).optional().describe("Type of repository to filter build definitions"),
23
23
  name: z.string().optional().describe("Name of the build definition to filter"),
24
24
  path: z.string().optional().describe("Path of the build definition to filter"),
25
- queryOrder: z.nativeEnum(DefinitionQueryOrder).optional().describe("Order in which build definitions are returned"),
25
+ queryOrder: z
26
+ .enum(getEnumKeys(DefinitionQueryOrder))
27
+ .optional()
28
+ .describe("Order in which build definitions are returned"),
26
29
  top: z.number().optional().describe("Maximum number of build definitions to return"),
27
30
  continuationToken: z.string().optional().describe("Token for continuing paged results"),
28
31
  minMetricsTime: z.coerce.date().optional().describe("Minimum metrics time to filter build definitions"),
@@ -37,7 +40,7 @@ function configureBuildTools(server, tokenProvider, connectionProvider) {
37
40
  }, async ({ project, repositoryId, repositoryType, name, path, queryOrder, top, continuationToken, minMetricsTime, definitionIds, builtAfter, notBuiltAfter, includeAllProperties, includeLatestBuilds, taskIdFilter, processType, yamlFilename, }) => {
38
41
  const connection = await connectionProvider();
39
42
  const buildApi = await connection.getBuildApi();
40
- const buildDefinitions = await buildApi.getDefinitions(project, name, repositoryId, repositoryType, queryOrder, top, continuationToken, minMetricsTime, definitionIds, path, builtAfter, notBuiltAfter, includeAllProperties, includeLatestBuilds, taskIdFilter, processType, yamlFilename);
43
+ const buildDefinitions = await buildApi.getDefinitions(project, name, repositoryId, repositoryType, safeEnumConvert(DefinitionQueryOrder, queryOrder), top, continuationToken, minMetricsTime, definitionIds, path, builtAfter, notBuiltAfter, includeAllProperties, includeLatestBuilds, taskIdFilter, processType, yamlFilename);
41
44
  return {
42
45
  content: [{ type: "text", text: JSON.stringify(buildDefinitions, null, 2) }],
43
46
  };
@@ -70,7 +73,11 @@ function configureBuildTools(server, tokenProvider, connectionProvider) {
70
73
  continuationToken: z.string().optional().describe("Token for continuing paged results"),
71
74
  maxBuildsPerDefinition: z.number().optional().describe("Maximum number of builds per definition"),
72
75
  deletedFilter: z.number().optional().describe("Filter for deleted builds (see QueryDeletedOption enum)"),
73
- queryOrder: z.nativeEnum(BuildQueryOrder).default(BuildQueryOrder.QueueTimeDescending).optional().describe("Order in which builds are returned"),
76
+ queryOrder: z
77
+ .enum(getEnumKeys(BuildQueryOrder))
78
+ .default("QueueTimeDescending")
79
+ .optional()
80
+ .describe("Order in which builds are returned"),
74
81
  branchName: z.string().optional().describe("Branch name to filter builds"),
75
82
  buildIds: z.array(z.number()).optional().describe("Array of build IDs to retrieve"),
76
83
  repositoryId: z.string().optional().describe("Repository ID to filter builds"),
@@ -78,7 +85,7 @@ function configureBuildTools(server, tokenProvider, connectionProvider) {
78
85
  }, async ({ project, definitions, queues, buildNumber, minTime, maxTime, requestedFor, reasonFilter, statusFilter, resultFilter, tagFilters, properties, top, continuationToken, maxBuildsPerDefinition, deletedFilter, queryOrder, branchName, buildIds, repositoryId, repositoryType, }) => {
79
86
  const connection = await connectionProvider();
80
87
  const buildApi = await connection.getBuildApi();
81
- const builds = await buildApi.getBuilds(project, definitions, queues, buildNumber, minTime, maxTime, requestedFor, reasonFilter, statusFilter, resultFilter, tagFilters, properties, top, continuationToken, maxBuildsPerDefinition, deletedFilter, queryOrder, branchName, buildIds, repositoryId, repositoryType);
88
+ const builds = await buildApi.getBuilds(project, definitions, queues, buildNumber, minTime, maxTime, requestedFor, reasonFilter, statusFilter, resultFilter, tagFilters, properties, top, continuationToken, maxBuildsPerDefinition, deletedFilter, safeEnumConvert(BuildQueryOrder, queryOrder), branchName, buildIds, repositoryId, repositoryType);
82
89
  return {
83
90
  content: [{ type: "text", text: JSON.stringify(builds, null, 2) }],
84
91
  };
@@ -168,7 +175,7 @@ function configureBuildTools(server, tokenProvider, connectionProvider) {
168
175
  project: z.string().describe("Project ID or name to update the build stage for"),
169
176
  buildId: z.number().describe("ID of the build to update"),
170
177
  stageName: z.string().describe("Name of the stage to update"),
171
- status: z.nativeEnum(StageUpdateType).describe("New status for the stage"),
178
+ status: z.enum(getEnumKeys(StageUpdateType)).describe("New status for the stage"),
172
179
  forceRetryAllJobs: z.boolean().default(false).describe("Whether to force retry all jobs in the stage."),
173
180
  }, async ({ project, buildId, stageName, status, forceRetryAllJobs }) => {
174
181
  const connection = await connectionProvider();
@@ -177,7 +184,7 @@ function configureBuildTools(server, tokenProvider, connectionProvider) {
177
184
  const token = await tokenProvider();
178
185
  const body = {
179
186
  forceRetryAllJobs: forceRetryAllJobs,
180
- state: status.valueOf(),
187
+ state: safeEnumConvert(StageUpdateType, status),
181
188
  };
182
189
  const response = await fetch(endpoint, {
183
190
  method: "PATCH",
@@ -2,6 +2,7 @@
2
2
  // Licensed under the MIT License.
3
3
  import { ReleaseDefinitionExpands, ReleaseDefinitionQueryOrder, ReleaseExpands, ReleaseStatus, ReleaseQueryOrder } from "azure-devops-node-api/interfaces/ReleaseInterfaces.js";
4
4
  import { z } from "zod";
5
+ import { getEnumKeys, safeEnumConvert } from "../utils.js";
5
6
  const RELEASE_TOOLS = {
6
7
  get_release_definitions: "release_get_definitions",
7
8
  get_releases: "release_get_releases",
@@ -10,12 +11,18 @@ function configureReleaseTools(server, tokenProvider, connectionProvider) {
10
11
  server.tool(RELEASE_TOOLS.get_release_definitions, "Retrieves list of release definitions for a given project.", {
11
12
  project: z.string().describe("Project ID or name to get release definitions for"),
12
13
  searchText: z.string().optional().describe("Search text to filter release definitions"),
13
- expand: z.nativeEnum(ReleaseDefinitionExpands).default(ReleaseDefinitionExpands.None).describe("Expand options for release definitions"),
14
+ expand: z
15
+ .enum(getEnumKeys(ReleaseDefinitionExpands))
16
+ .default("None")
17
+ .describe("Expand options for release definitions"),
14
18
  artifactType: z.string().optional().describe("Filter by artifact type"),
15
19
  artifactSourceId: z.string().optional().describe("Filter by artifact source ID"),
16
20
  top: z.number().optional().describe("Number of results to return (for pagination)"),
17
21
  continuationToken: z.string().optional().describe("Continuation token for pagination"),
18
- queryOrder: z.nativeEnum(ReleaseDefinitionQueryOrder).default(ReleaseDefinitionQueryOrder.NameAscending).describe("Order of the results"),
22
+ queryOrder: z
23
+ .enum(getEnumKeys(ReleaseDefinitionQueryOrder))
24
+ .default("NameAscending")
25
+ .describe("Order of the results"),
19
26
  path: z.string().optional().describe("Path to filter release definitions"),
20
27
  isExactNameMatch: z.boolean().optional().default(false).describe("Whether to match the exact name of the release definition. Default is false."),
21
28
  tagFilter: z.array(z.string()).optional().describe("Filter by tags associated with the release definitions"),
@@ -26,7 +33,7 @@ function configureReleaseTools(server, tokenProvider, connectionProvider) {
26
33
  }, async ({ project, searchText, expand, artifactType, artifactSourceId, top, continuationToken, queryOrder, path, isExactNameMatch, tagFilter, propertyFilters, definitionIdFilter, isDeleted, searchTextContainsFolderName, }) => {
27
34
  const connection = await connectionProvider();
28
35
  const releaseApi = await connection.getReleaseApi();
29
- const releaseDefinitions = await releaseApi.getReleaseDefinitions(project, searchText, expand, artifactType, artifactSourceId, top, continuationToken, queryOrder, path, isExactNameMatch, tagFilter, propertyFilters, definitionIdFilter, isDeleted, searchTextContainsFolderName);
36
+ const releaseDefinitions = await releaseApi.getReleaseDefinitions(project, searchText, safeEnumConvert(ReleaseDefinitionExpands, expand), artifactType, artifactSourceId, top, continuationToken, safeEnumConvert(ReleaseDefinitionQueryOrder, queryOrder), path, isExactNameMatch, tagFilter, propertyFilters, definitionIdFilter, isDeleted, searchTextContainsFolderName);
30
37
  return {
31
38
  content: [{ type: "text", text: JSON.stringify(releaseDefinitions, null, 2) }],
32
39
  };
@@ -37,7 +44,11 @@ function configureReleaseTools(server, tokenProvider, connectionProvider) {
37
44
  definitionEnvironmentId: z.number().optional().describe("ID of the definition environment to filter releases"),
38
45
  searchText: z.string().optional().describe("Search text to filter releases"),
39
46
  createdBy: z.string().optional().describe("User ID or name who created the release"),
40
- statusFilter: z.nativeEnum(ReleaseStatus).optional().default(ReleaseStatus.Active).describe("Status of the releases to filter (default: Active)"),
47
+ statusFilter: z
48
+ .enum(getEnumKeys(ReleaseStatus))
49
+ .optional()
50
+ .default("Active")
51
+ .describe("Status of the releases to filter (default: Active)"),
41
52
  environmentStatusFilter: z.number().optional().describe("Environment status to filter releases"),
42
53
  minCreatedTime: z.coerce
43
54
  .date()
@@ -53,10 +64,18 @@ function configureReleaseTools(server, tokenProvider, connectionProvider) {
53
64
  .optional()
54
65
  .default(() => new Date())
55
66
  .describe("Maximum created time for releases (default: now)"),
56
- queryOrder: z.nativeEnum(ReleaseQueryOrder).optional().default(ReleaseQueryOrder.Ascending).describe("Order in which to return releases (default: Ascending)"),
67
+ queryOrder: z
68
+ .enum(getEnumKeys(ReleaseQueryOrder))
69
+ .optional()
70
+ .default("Ascending")
71
+ .describe("Order in which to return releases (default: Ascending)"),
57
72
  top: z.number().optional().describe("Number of releases to return"),
58
73
  continuationToken: z.number().optional().describe("Continuation token for pagination"),
59
- expand: z.nativeEnum(ReleaseExpands).optional().default(ReleaseExpands.None).describe("Expand options for releases"),
74
+ expand: z
75
+ .enum(getEnumKeys(ReleaseExpands))
76
+ .optional()
77
+ .default("None")
78
+ .describe("Expand options for releases"),
60
79
  artifactTypeId: z.string().optional().describe("Filter releases by artifact type ID"),
61
80
  sourceId: z.string().optional().describe("Filter releases by artifact source ID"),
62
81
  artifactVersionId: z.string().optional().describe("Filter releases by artifact version ID"),
@@ -69,7 +88,7 @@ function configureReleaseTools(server, tokenProvider, connectionProvider) {
69
88
  }, async ({ project, definitionId, definitionEnvironmentId, searchText, createdBy, statusFilter, environmentStatusFilter, minCreatedTime, maxCreatedTime, queryOrder, top, continuationToken, expand, artifactTypeId, sourceId, artifactVersionId, sourceBranchFilter, isDeleted, tagFilter, propertyFilters, releaseIdFilter, path, }) => {
70
89
  const connection = await connectionProvider();
71
90
  const releaseApi = await connection.getReleaseApi();
72
- const releases = await releaseApi.getReleases(project, definitionId, definitionEnvironmentId, searchText, createdBy, statusFilter, environmentStatusFilter, minCreatedTime, maxCreatedTime, queryOrder, top, continuationToken, expand, artifactTypeId, sourceId, artifactVersionId, sourceBranchFilter, isDeleted, tagFilter, propertyFilters, releaseIdFilter, path);
91
+ const releases = await releaseApi.getReleases(project, definitionId, definitionEnvironmentId, searchText, createdBy, safeEnumConvert(ReleaseStatus, statusFilter), environmentStatusFilter, minCreatedTime, maxCreatedTime, safeEnumConvert(ReleaseQueryOrder, queryOrder), top, continuationToken, safeEnumConvert(ReleaseExpands, expand), artifactTypeId, sourceId, artifactVersionId, sourceBranchFilter, isDeleted, tagFilter, propertyFilters, releaseIdFilter, path);
73
92
  return {
74
93
  content: [{ type: "text", text: JSON.stringify(releases, null, 2) }],
75
94
  };