Skip to content

Commit dfee3a8

Browse files
authored
feat: interactive OAuth flow added (#368)
PR adds OAuth interactive authentication flow as a default token retrieval mechanism. Original credentials flows are kept but need to be opted-in via command line args. This is still WIP. ClientID needs to be replaced with a "ADO trusted" app once it is available. Readme and Troubleshooting need to be updated as well. ## GitHub issue number ## **Associated Risks** ## ✅ **PR Checklist** - [ ] **I have read the [contribution guidelines](https://github.com/microsoft/azure-devops-mcp/blob/main/CONTRIBUTING.md)** - [ ] **I have read the [code of conduct guidelines](https://github.com/microsoft/azure-devops-mcp/blob/main/CODE_OF_CONDUCT.md)** - [ ] Title of the pull request is clear and informative. - [ ] 👌 Code hygiene - [ ] 🔭 Telemetry added, updated, or N/A - [ ] 📄 Documentation added, updated, or N/A - [ ] 🛡️ Automated tests added, or N/A ## 🧪 **How did you test it?** Manually via inspector, all authentication options
1 parent 6fd5798 commit dfee3a8

30 files changed

+575
-262
lines changed

README.md

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -152,16 +152,7 @@ For the best experience, use Visual Studio Code and GitHub Copilot. See the [get
152152

153153
1. Install [VS Code](https://code.visualstudio.com/download) or [VS Code Insiders](https://code.visualstudio.com/insiders)
154154
2. Install [Node.js](https://nodejs.org/en/download) 20+
155-
3. Install [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest)
156-
4. Open VS Code in an empty folder
157-
158-
### Azure Login
159-
160-
Ensure you are logged in to Azure DevOps via the Azure CLI:
161-
162-
```sh
163-
az login
164-
```
155+
3. Open VS Code in an empty folder
165156

166157
### Installation
167158

@@ -232,7 +223,7 @@ Click "Select Tools" and choose the available tools.
232223

233224
![configure mcp server tools](./docs/media/configure-mcp-server-tools.gif)
234225

235-
Open GitHub Copilot Chat and try a prompt like `List ADO projects`.
226+
Open GitHub Copilot Chat and try a prompt like `List ADO projects`. The first time an ADO tool is executed browser will open prompting to login with your Microsoft account. Please ensure you are using credentials matching selected Azure DevOps organization.
236227

237228
> 💥 We strongly recommend creating a `.github\copilot-instructions.md` in your project. This will enhance your experience using the Azure DevOps MCP Server with GitHub Copilot Chat.
238229
> To start, just include "`This project uses Azure DevOps. Always check to see if the Azure DevOps MCP server has a tool relevant to the user's request`" in your copilot instructions file.

docs/GETTINGSTARTED.md

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,12 @@ Before you begin, make sure you have:
2020

2121
1. Install [VS Code](https://code.visualstudio.com/download) or [VS Code Insiders](https://code.visualstudio.com/insiders)
2222
2. Install [Node.js](https://nodejs.org/en/download) 20+
23-
3. Install [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest)
24-
4. Open VS Code in an empty folder
23+
3. Open VS Code in an empty folder
2524

2625
### For Visual Studio 2022
2726

2827
1. Install [VS Studio 2022 version 17.14](https://learn.microsoft.com/en-us/visualstudio/releases/2022/release-history) or later
29-
2. Install [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest)
30-
3. Open a project in Visual Studio
31-
32-
### Azure CLI Login
33-
34-
Ensure you are logged in to Azure DevOps via the Azure CLI:
35-
36-
```sh
37-
az login
38-
```
28+
2. Open a project in Visual Studio
3929

4030
## 🍕 Installation Options
4131

@@ -219,12 +209,6 @@ Replace `Contoso` with your own organization name
219209

220210
### ✴️ Using MCP Server with Claude Desktop
221211

222-
Ensure you are logged in to Azure DevOps using the Azure CLI:
223-
224-
```sh
225-
az login
226-
```
227-
228212
Open Claude Desktop and navigate to **File > Settings > Developer**. Click **Edit Config**.
229213

230214
![Configuring MCP servers in Claude Desktop](../docs/media/claude-desktop-getting-started-1.png)

docs/TROUBLESHOOTING.md

Lines changed: 62 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,6 @@
3131

3232
1. **npm Authentication Issues for Remote Access**
3333
If you encounter authentication errors:
34-
- Ensure you are logged in to Azure DevOps using the `az` CLI:
35-
36-
```pwsh
37-
az login
38-
```
39-
4034
- Verify your npm configuration:
4135

4236
```pwsh
@@ -54,7 +48,67 @@
5448

5549
## Authentication Issues
5650

57-
### Multi-Tenant Authentication Problems
51+
### GitHub Codespaces
52+
53+
Due to limitations of the environment default OAuth option is not available in Codespace.
54+
Make sure you authenticate via
55+
56+
```sh
57+
az login
58+
```
59+
60+
in the terminal before using MCP tools.
61+
62+
And in case there are authorization/access errors when using the tools please check the [Multi-Tenant Authentication Problems guide](#multi-tenant-authentication-problems-when-using-azcli)
63+
64+
### OAuth
65+
66+
Recent switch to OAuth flow is supposed to simplify authentication against ADO APIs and remove additional software dependency.
67+
68+
It is however possible that strict tenant admin policies prevent users from successfully logging in using OAuth flow. In that case consider falling back to AZ CLI.
69+
70+
#### Symptoms
71+
72+
Upon ADO tool execution browser opens a tab/window and after login attempt an error text is displayed:
73+
74+
```
75+
Error occurred: ...
76+
```
77+
78+
#### Solution
79+
80+
Try using Azure login context instead:
81+
82+
1. Install [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest) and **log in**:
83+
84+
```sh
85+
az login
86+
```
87+
88+
2. **Configure the MCP server** with the azcli authentication option by updating your `.vscode/mcp.json`.
89+
90+
```json
91+
{
92+
"inputs": [
93+
{
94+
"id": "ado_org",
95+
"type": "promptString",
96+
"description": "Azure DevOps organization name (e.g. 'contoso')"
97+
}
98+
],
99+
"servers": {
100+
"ado": {
101+
"type": "stdio",
102+
"command": "npx",
103+
"args": ["-y", "@azure-devops/mcp", "${input:ado_org}", "--authentication", "azcli"]
104+
}
105+
}
106+
}
107+
```
108+
109+
3. **Restart VS Code** completely to ensure the MCP server picks up the new configuration.
110+
111+
### Multi-Tenant Authentication Problems when using azcli
58112

59113
If you encounter authentication errors like `TF400813: The user 'xxx' is not authorized to access this resource`, you may be experiencing multi-tenant authentication issues.
60114

@@ -100,7 +154,7 @@ The MCP server may be authenticating with a different tenant than your Azure Dev
100154
"ado": {
101155
"type": "stdio",
102156
"command": "npx",
103-
"args": ["-y", "@azure-devops/mcp", "${input:ado_org}", "--tenant", "${input:ado_tenant}"]
157+
"args": ["-y", "@azure-devops/mcp", "${input:ado_org}", "--authentication", "azcli", "--tenant", "${input:ado_tenant}"]
104158
}
105159
}
106160
}
@@ -137,44 +191,3 @@ The MCP server may be authenticating with a different tenant than your Azure Dev
137191
4. **When prompted**, enter:
138192
- Your Azure DevOps organization name
139193
- The tenant ID from step 1
140-
141-
### Dev Container and WSL Authentication Issues
142-
143-
If the tenant configuration solution above doesn't resolve your authentication issues, and you're working in a **Dev Container** or **WSL (Windows Subsystem for Linux)** environment, the root cause may be different.
144-
145-
#### Dev Container/WSL Symptoms
146-
147-
- Same authorization errors as above (`TF400813: The user 'xxx' is not authorized to access this resource`)
148-
- Tenant ID configuration didn't resolve the issue
149-
- You're using VS Code with Dev Containers or WSL
150-
- MCP server is configured in User Settings (global) rather than workspace settings
151-
152-
#### Dev Container/WSL Root Cause
153-
154-
When MCP servers are configured in **User Settings** (global configuration), they inherit the environment context from the **host machine**, including `az login` authentication settings. In Dev Container or WSL scenarios, this means:
155-
156-
- The MCP server uses the host machine's Azure authentication
157-
- Any `az login` performed inside the Dev Container or WSL environment is ignored
158-
- There may be a mismatch between the authentication context the MCP server expects and your development environment
159-
160-
#### Dev Container/WSL Solution
161-
162-
1. **Verify your MCP configuration location**:
163-
- Check if your MCP server is configured in User Settings (global) vs Workspace Settings
164-
- User Settings: Run `MCP: Open User Configuration` from Command Palette
165-
- Workspace Settings: Check for `.vscode/mcp.json` in your project
166-
167-
2. **For User Settings (Global) MCP configuration**:
168-
- Ensure you are logged into Azure from the **host machine** (not inside the Dev Container/WSL)
169-
- Run `az login` on the host Windows machine (outside of WSL/Dev Container)
170-
- Do NOT run `az login` inside the Dev Container or WSL environment
171-
- Restart VS Code completely
172-
173-
3. **Alternative: Use Workspace Settings instead**:
174-
- Move your MCP server configuration from User Settings to Workspace Settings
175-
- Create/update `.vscode/mcp.json` in your project
176-
- This allows the MCP server to use the authentication context from within the Dev Container/WSL environment
177-
178-
4. **For Dev Containers specifically**:
179-
- Consider configuring MCP servers directly in your `devcontainer.json` file using the `customizations.vscode.mcp` section
180-
- This ensures the MCP server runs within the containerized environment with the correct context

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@azure-devops/mcp",
3-
"version": "2.1.0",
3+
"version": "2.2.0",
44
"description": "MCP server for interacting with Azure DevOps",
55
"license": "MIT",
66
"author": "Microsoft Corporation",

src/auth.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { AzureCliCredential, ChainedTokenCredential, DefaultAzureCredential, TokenCredential } from "@azure/identity";
2+
import { AccountInfo, AuthenticationResult, PublicClientApplication } from "@azure/msal-node";
3+
import open from "open";
4+
5+
const scopes = ["499b84ac-1321-427f-aa17-267ca6975798/.default"];
6+
7+
class OAuthAuthenticator {
8+
static clientId = "0d50963b-7bb9-4fe7-94c7-a99af00b5136";
9+
static defaultAuthority = "https://login.microsoftonline.com/common";
10+
11+
private accountId: AccountInfo | null;
12+
private publicClientApp: PublicClientApplication;
13+
14+
constructor(tenantId?: string) {
15+
this.accountId = null;
16+
this.publicClientApp = new PublicClientApplication({
17+
auth: {
18+
clientId: OAuthAuthenticator.clientId,
19+
authority: tenantId ? `https://login.microsoftonline.com/${tenantId}` : OAuthAuthenticator.defaultAuthority,
20+
},
21+
});
22+
}
23+
24+
public async getToken(): Promise<string> {
25+
let authResult: AuthenticationResult | null = null;
26+
if (this.accountId) {
27+
try {
28+
authResult = await this.publicClientApp.acquireTokenSilent({
29+
scopes,
30+
account: this.accountId,
31+
});
32+
} catch (error) {
33+
authResult = null;
34+
}
35+
}
36+
if (!authResult) {
37+
authResult = await this.publicClientApp.acquireTokenInteractive({
38+
scopes,
39+
openBrowser: async (url) => {
40+
open(url);
41+
},
42+
});
43+
this.accountId = authResult.account;
44+
}
45+
46+
if (!authResult.accessToken) {
47+
throw new Error("Failed to obtain Azure DevOps OAuth token.");
48+
}
49+
return authResult.accessToken;
50+
}
51+
}
52+
53+
function createAuthenticator(type: string, tenantId?: string): () => Promise<string> {
54+
switch (type) {
55+
case "azcli":
56+
case "env":
57+
if (type !== "env") {
58+
process.env.AZURE_TOKEN_CREDENTIALS = "dev";
59+
}
60+
let credential: TokenCredential = new DefaultAzureCredential(); // CodeQL [SM05138] resolved by explicitly setting AZURE_TOKEN_CREDENTIALS
61+
if (tenantId) {
62+
// Use Azure CLI credential if tenantId is provided for multi-tenant scenarios
63+
const azureCliCredential = new AzureCliCredential({ tenantId });
64+
credential = new ChainedTokenCredential(azureCliCredential, credential);
65+
}
66+
return async () => {
67+
const result = await credential.getToken(scopes);
68+
if (!result) {
69+
throw new Error("Failed to obtain Azure DevOps token. Ensure you have Azure CLI logged or use interactive type of authentication.");
70+
}
71+
return result.token;
72+
};
73+
74+
default:
75+
const authenticator = new OAuthAuthenticator(tenantId);
76+
return () => {
77+
return authenticator.getToken();
78+
};
79+
}
80+
}
81+
export { createAuthenticator };

0 commit comments

Comments
 (0)