Repository navigation
Releases: eXoz00rd/AzureMCP
Release list
v0.2.1 — no cookies carried between HTTP callers
A security fix for the HTTP server. Upgrade every deployment that serves more than one user.
Security
- The server no longer keeps cookies from Azure DevOps. Over HTTP every caller shares one pooled connection handler, and in 0.2.0 it stored the cookies Azure DevOps set and sent them with later requests from other callers, next to those callers' own PATs. Each request now carries its caller's PAT and nothing another caller left behind. A new end-to-end test calls as two users in turn and fails if any request carries a cookie issued to someone else (#64)
stdio — the NuGet tool used by Copilot, Claude Code, and other local clients — serves a single user and was not affected.
Upgrading
- Docker:
docker pull ghcr.io/exoz00rd/azuremcp:0.2.1and recreate the container. Deployments followinglatestor0.2pick it up on their next pull - Helm:
helm upgradeto chart0.2.1 - Open WebUI: the plugin is unchanged; nothing to do
62 tools, 470 tests.
Full changelog: v0.2.0...v0.2.1
v0.2.0 — the server as a container beside Open WebUI, with each user's own PAT
The server now runs as its own container next to Open WebUI. It serves MCP over Streamable HTTP, holds no PAT of its own, and every request carries the caller's own PAT, so Azure DevOps attributes every comment, vote, and queued build to the person who asked. stdio stays the default: Copilot, Claude Code, and every existing client keep working unchanged.
Added
- Streamable HTTP transport —
ADOS_TRANSPORT=httpserves a stateless MCP endpoint behind a shared bearer token. The guard runs on the endpoint routing selects, rejects unknown browser origins, and allows anonymous access only on loopback (#55) - Each caller's own PAT — every HTTP request carries its caller's PAT in
X-Azure-DevOps-Pat.ADOS_PATis refused over HTTP, so no request can fall back to a shared identity (#56, #61) - Health endpoint and container logging —
/healthzanswers probes without a token, and a healthy start logs nothing (#57, #63) - Container image —
ghcr.io/exoz00rd/azuremcp:0.2.0forlinux/amd64andlinux/arm64on the chiseled ASP.NET 10 runtime: non-root, no shell, signed with cosign, with a build provenance attestation and an SBOM (#58) - Helm chart —
oci://ghcr.io/exoz00rd/charts/azuremcpwith a hardened pod, aNetworkPolicyadmitting only Open WebUI, and an internal certificate authority from a ConfigMap that keeps the public roots (#59)
Changed
- The Open WebUI plugin calls the server over HTTP instead of downloading and starting a binary inside Open WebUI. Its valves are now the server URL, the server's token, and the timeout; the collection URL and certificate authority moved to the server. The self-contained linux-x64 binary is no longer attached (#60)
- The NuGet package needs the ASP.NET Core runtime in every mode, stdio included. The .NET 10 SDK already ships it (#55)
Upgrading from 0.1.3 with Open WebUI
The 0.1.3 plugin started the server inside Open WebUI; this one needs the server running beside it. Deploy the image or the chart first (Running over HTTP), then replace the plugin's code with azure_devops_openwebui.py from this release and set its valves: server_url (for example http://azuremcp:8080/mcp) and server_token. Replacing the code of the existing tool keeps the PAT each user already entered; a newly created tool starts without them.
Assets
| File | Purpose |
|---|---|
azure_devops_openwebui.py |
the Open WebUI plugin, generated from the tools this release registers |
62 tools, 469 tests.
Full changelog: v0.1.3...v0.2.0
v0.1.3 — Open WebUI plugin with per-user PATs, clearer connection errors
Open WebUI can now use this server. The release ships a tool plugin that runs inside Open WebUI, starts the server on demand, and passes each user their own PAT — one instance serves many users without sharing a credential.
Added
- Open WebUI plugin (
azure_devops_openwebui.py) — generated from the tools this server registers, so it never drifts from them. It downloads the self-contained server below, verifies its SHA-256 before running it, and starts it for the duration of a single call with the calling user's own PAT taken from Open WebUI's per-user valves (#49, #51) - Support for an internal certificate authority — paste its PEM into the plugin's
ca_certificatevalve and it is merged with the container's system roots into the trust bundle handed to the server. Certificate validation is never disabled (#52)
Changed
- A server that cannot be reached is now explained instead of surfacing a raw socket or SSL failure. The message names the collection and what to verify. An untrusted certificate is reported on the first attempt, because retrying it can only produce the same answer (#53)
Assets
| File | Purpose |
|---|---|
azure_devops_openwebui.py |
the Open WebUI plugin, with this release's download URL and checksum already set |
AzureDevOpsServer.Mcp-linux-x64 |
self-contained server the plugin downloads on first use |
AzureDevOpsServer.Mcp-linux-x64.sha256 |
checksum of that binary |
Using it with Open WebUI
- As an administrator, open Workspace → Tools → +, paste
azure_devops_openwebui.py, and save - Open the tool's Valves and set
collection_url(plusca_certificatewhen the server uses an internal authority) - Grant access to the users or groups that should see the tool
- Each user opens Integrations → Tools → Valves in a chat and enters their own PAT
Requires Open WebUI 0.11.x on linux-x64, and outbound access to this release from the Open WebUI container.
62 tools, 416 tests.
Full changelog: v0.1.2...v0.1.3
v0.1.2 — richer work item reads, safer writes, clearer errors
Ten fixes and additions since v0.1.1, focused on work item reads/writes and truncation/error reporting.
Changed
- Breaking:
update_work_item,create_work_item,link_work_item, andadd_work_item_attachmentnow return a minimalWorkItemWriteResult(id, rev, changed fields, success) instead of the fullWorkItem.
Added
includeRelationsonget_work_itemandget_work_itemsfetches relations without requiring a fullfieldsexpansion.expectedRevisiononupdate_work_itemlets a caller require a specific revision before writing; a mismatch is reported with the current revision instead of silently overwriting a concurrent change.descriptionFormatonget_work_item,get_work_items, andget_work_item_revisions(htmldefault,text) strips markup and decodes entities from rich-text fields.
Fixed
- Eight list tools reported no truncation when a result exactly filled its cap.
list_branches,list_commits,list_pull_requests,list_my_pull_requests,list_releases,list_release_approvals,list_builds, andget_work_item_revisionsnow request one extra item and report truncation the same waylist_repository_itemsandlist_work_item_commentsalready did. get_work_itemsfailed with an opaque server error on an oversized id batch, and project pagination had no upper bound and could loop forever on a malformed continuation token. Both are now bounded client-side with a clear error.- Authentication failures collapsed every 401/203 response into one generic message. It now reports the actual request URI, HTTP status, and the server's offered
WWW-Authenticateschemes, without ever including theAuthorizationheader or the PAT.
Known issues
- The write-path changes above (
expectedRevision, the minimal write result shape) are verified only against stub Azure DevOps handlers in this release, not yet against a real Azure DevOps Server.
62 tools, 391 tests.
Full changelog: v0.1.1...v0.1.2
v0.1.1 — safer votes, real comment ids, streamed responses
Five fixes and one API correction since v0.1.0, plus release/CI hygiene.
Changed
- Breaking:
add_work_item_commentnow posts through_apis/wit/workItems/{id}/commentsinstead of writing toSystem.History, and returns aWorkItemComment(real id, version) instead of the wholeWorkItem. It also accepts an optionalprojectparameter, matchinglist_work_item_comments.
Added
get_work_item_commentreads a single work item comment by id.
Fixed
vote_on_pull_requestsilently cleared the reviewer's required flag. The PUT only sent{ vote }, and that endpoint replaces the whole reviewer resource. The client now looks up the reviewer's currentisRequiredbefore voting and includes it in the request.- Unsafe HTTP methods (POST/PATCH/PUT/DELETE) were retried automatically on transient Azure DevOps failures, which could create duplicate work items, comments, releases, attachments, or queued builds when a request succeeded but its response was lost. Only GET still retries.
- Repository file content was fully buffered before
maxCharscould limit it. Large files now stream through a byte-level JSON decoder instead of being materialized in full first. - Build logs stream instead of buffering the whole response.
- The NuGet package version is now the single source for the MCP manifest version, so the two can no longer disagree.
An end-to-end smoke test now covers the stdio MCP transport, and CI enforces a test coverage threshold.
Known issues
add_work_item_commentandget_work_item_comment(above) are verified only against stub Azure DevOps handlers in this release, not yet against a real Azure DevOps Server.
62 tools, 263 tests.
Full changelog: v0.1.0...v0.1.1
v0.1.0 — first stable release
The first non-preview release. Nine previews landed 60 tools, toolset/read-only configuration, and on-premises-specific error handling; this one is a compatibility fix found through real on-premises use.
Fixed
create_or_update_wiki_pagefailed with405 Method Not Allowedagainst some on-premises Azure DevOps Server installations. The page-version lookup that runs before every write sent an HTTPHEADrequest, and not every on-prem server acceptsHEADon that route — the client never got as far as sending thePUT. The lookup now usesGETinstead, which is confirmed to work, withIf-Matchsemantics unchanged.
60 tools, 185 tests.
Full changelog: v0.1.0-preview.9...v0.1.0
v0.1.0-preview.9 — pull request/work item links and correct optional-parameter schemas
Closes the pull request ↔ work item gap and fixes a schema bug that made every optional tool parameter look required to MCP clients.
Added
link_pull_request_to_work_itembuilds thevstfsartifact URL from the pull request itself and creates theArtifactLinkrelation, so linking no longer requires constructing the URL by handlink_work_itemaccepts an explicitartifactLinkNameand infers it from knownvstfsURLs when omitted- Azure DevOps error responses now reach the caller with their real status and message —
AzureDevOpsClientExceptionderives fromMcpExceptioninstead of being wrapped in a genericArgumentException
Fixed
- Every optional tool parameter was marked
requiredin the generated JSON schema. Nullable parameters had no default value in the C# signature, so the schema generator listed them as required regardless of their type — a strict MCP client could demand a value for a parameter that was meant to be optional. Nullable parameters (and injected cancellation tokens) now default tonull, and a test asserts this holds across every toolset. - Dropped a stale note claiming the repository is private
60 tools, 185 tests.
Full changelog: v0.1.0-preview.8...v0.1.0-preview.9
v0.1.0-preview.8 — toolsets, read-only mode, better ergonomics
Fifty-nine tools had become a cost rather than a feature: the tool list weighs about 34 KB in every request, and clients cap how many tools they accept. This release makes the surface configurable and the server easier for a model to use correctly.
Added
ADOS_TOOLSETSexposes only the areas a team uses (projects,workitems,queries,repositories,pullrequests,builds,releases,wiki).workitems,pullrequestsdrops the list from 59 tools to 27. An unknown name fails at startup with the list of valid ones.ADOS_READ_ONLY=trueremoves every write tool, leaving 40 read-only tools — for agents that may look at Azure DevOps but not change it, without relying on PAT scopes alone.- MCP
instructionssent on connect: the configured collection, the default project, whether the server is read-only, and how to use the tools well (field lists for work items, timeline before logs, raise a limit instead of assuming something is missing, and do not perform write actions unasked). - Output schemas on all tools, so clients receive structured results instead of opaque JSON.
Fixed
query_work_itemsdid not work in v0.1.0-preview.7. Its attributes decorated a private helper method, so the registered tool returned the default project name instead of running the WIQL query, and the real method was never registered. The tool count stayed the same, which is why smoke tests missed it.- Errors now carry the Azure DevOps message (for example
TF401019: The Git repository ... does not exist.) instead of the full error envelope withtypeKey,errorCode, andeventId.
169 tests.
Full changelog: v0.1.0-preview.7...v0.1.0-preview.8
v0.1.0-preview.7 — wiki writes, work item depth, release gates
Closes the remaining write gaps outside Git. Git writes are deliberately left out: local git tooling does that better, and the agent already has it.
Added
- Wiki:
create_or_update_wiki_pagehandles both creating and replacing a page, sendingIf-Matchwith the page ETag only when the page already exists - Work items:
list_work_item_comments(reads the discussion, not just appends to it),get_work_item_revisions,link_work_item(parent, child, related, predecessor, successor, or a raw relation such asArtifactLinkfor commits and pull requests),add_work_item_attachment(uploads text content and links it in one call) - Pull requests:
update_pull_request(title, description, auto-complete),add_pull_request_reviewerandremove_pull_request_reviewer, accepting an identity id, an account name, orme - Releases:
list_release_approvals,update_release_approval, anddeploy_release_environment— deployment automation now gets past approval gates - Projects:
get_projectwith process template and version control type
Configuration
ADOS_API_VERSION_WIT_COMMENTS overrides the API version for the work item comments endpoint, which is still preview on on-premises servers.
59 tools, 150 tests.
Known issue
query_work_items is broken in this version: its attributes decorated a private helper, so the tool returned the project name instead of running the WIQL query. Fixed in v0.1.0-preview.8 — upgrade if you use that tool.
Full changelog: v0.1.0-preview.6...v0.1.0-preview.7
v0.1.0-preview.6 — pull request insight
Makes pull requests fully answerable: the server could already cast a vote, but could not tell you who approved anything.
Added
list_my_pull_requests— pull requests across every repository of a project, withcreatedByMeandassignedToMefilters resolved from the signed-in identityget_pull_request_policies— policy evaluations (required builds, minimum reviewers, linked work items) with status and blocking flag; explains why a pull request cannot be completedlist_pull_request_work_items— work items linked to a pull requestreply_to_pull_request_thread— replies inside an existing thread instead of starting a new oneset_pull_request_thread_status— resolves threads as fixed, wontFix, closed, byDesign, or pending
Changed
- Pull requests now return reviewer votes,
mergeStatus,isDraft, creation and closed dates, and the repository reference. These come from the same response the server already fetched, so nothing extra is requested.
47 tools, 119 tests.
Full changelog: v0.1.0-preview.5...v0.1.0-preview.6