azure-devops-attachment-mcp-server
This server lets AI assistants manage work item attachments on an on-premise Azure DevOps Server through MCP tools.
List attachments on a work item (name, size, comment, created date, id, URL).
Add/upload a local file and attach it to a work item, with optional custom file name and comment.
Delete/remove an attachment by GUID or unique file name (removes only the work item link).
Download an attachment to a local directory by GUID or unique file name, without overwriting existing files.
Configure via environment variables: collection URL, PAT, default project, API version, download directory, and insecure TLS option.
Works with Azure DevOps Server 2019/2020/2022 and supports simple uploads up to 130 MB.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@azure-devops-attachment-mcp-server List the attachments on work item 4711."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
azure-devops-attachment-mcp-server
An MCP server (stdio) that lets AI assistants manage work item attachments on on-premise Azure DevOps Server (2019 / 2020 / 2022, formerly TFS) through the REST API, authenticated with a Personal Access Token.
It exposes four tools:
Tool | What it does |
| Lists the attachments of a work item (name, size, comment, date, id, URL). |
| Uploads a local file and attaches it to a work item. |
| Removes an attachment from a work item by id or unique file name. |
| Saves an attachment to a local directory and returns the path. |
No extra dependencies beyond the MCP SDK and zod: it uses Node's built-in fetch, so npx starts fast.
Requirements
Node.js 20 or newer.
A Personal Access Token (PAT) for the collection with the Work Items (Read & Write) scope.
Network access from the machine running the MCP server to the Azure DevOps Server.
Related MCP server: Azure DevOps MCP Server
Quick start
Add the server to your MCP client configuration. The generic JSON form (Claude Desktop, Cursor, Windsurf,
VS Code mcp.json and most other clients accept it):
{
"mcpServers": {
"azure-devops-attachments": {
"type": "stdio",
"command": "npx",
"args": ["-y", "azure-devops-attachment-mcp-server"],
"env": {
"AZURE_DEVOPS_URL": "https://tfs.company.local/tfs/DefaultCollection",
"AZURE_DEVOPS_PAT": "<your personal access token>",
"AZURE_DEVOPS_PROJECT": "MyProject"
}
}
}
}Claude Code:
claude mcp add azure-devops-attachments \
-e AZURE_DEVOPS_URL=https://tfs.company.local/tfs/DefaultCollection \
-e AZURE_DEVOPS_PAT=<your personal access token> \
-e AZURE_DEVOPS_PROJECT=MyProject \
-- npx -y azure-devops-attachment-mcp-serverThen ask your assistant things like:
"List the attachments on work item 4711."
"Attach
./reports/perf.xlsxto bug 4711 with the comment 'perf run 2026-09'.""Download the attachment
spec.pdffrom work item 4711 into~/Downloads.""Remove the attachment
old-log.txtfrom work item 4711."
Configuration
All configuration is passed through environment variables.
Variable | Required | Default | Description |
| yes | Collection URL, e.g. | |
| yes | Personal Access Token. Sent only as a Basic auth header to | |
| no | Default team project for the attachment endpoints. The work item's own project takes precedence when known. | |
| no |
| REST |
| no | process cwd | Directory where |
| no |
| Set to |
The server exits with code 1 and a message naming the missing variable when the configuration is incomplete.
Tools
Every tool returns a short human-readable summary plus structuredContent matching the documented shape.
Errors come back as tool errors (isError: true) with an actionable message, for example which environment
variable to check after an HTTP 401.
list_attachments
Input | Type | Notes |
| integer | Required. |
Returns { workItemId, workItemRev, count, attachments[] } where each attachment has
{ id, name, size, comment, createdDate, url, relationIndex }. size is null when the server does not
report it (older servers or migrated data).
add_attachment
Input | Type | Notes |
| integer | Required. |
| string | Required. Absolute or cwd-relative path of a local file (max 130 MB). |
| string | Optional. Name stored on the server; defaults to the file's base name. |
| string | Optional. Comment shown next to the attachment. |
| string | Optional. Team project for the upload; defaults to the work item's project, then |
Returns { workItemId, workItemRev, attachment: { id, name, size, url, comment } }.
delete_attachment
Input | Type | Notes |
| integer | Required. |
| GUID | One of |
| string | Exact file name; rejected with the candidate ids when several attachments share it. |
Returns { workItemId, workItemRev, removed: { id, name, relationIndex }, note }. Only the link between the
work item and the file is removed; Azure DevOps has no REST endpoint that deletes the stored file itself
(this is also what the web UI does).
download_attachment
Input | Type | Notes |
| integer | Required. |
| GUID | One of |
| string | Exact file name; must be unique on the work item. |
| string | Optional. Local file name; defaults to the server-side name (sanitized). |
| string | Optional. Defaults to |
| string | Optional. Team project for the download URL. |
Returns { id, name, path, size, workItemId } with the absolute path of the saved file. Existing files are
never overwritten: a (1), (2), ... suffix is added instead.
How it maps to the REST API
Tool | Calls |
list |
|
add |
|
delete |
|
download |
|
Details that matter on-premise:
Work items are addressed at collection level, so a work item in any project of the collection works.
Download URLs are rebuilt from
AZURE_DEVOPS_URLinstead of trusting the host inside the relation URL, which on some servers points at an internal name.X-TFS-FedAuthRedirect: Suppressis sent so a rejected PAT yields a clear 401 instead of a sign-in page.A failed
test /rev(concurrent edit) triggers exactly one refetch-and-retry.
Limitations
Simple uploads only: files above 130 MB (chunked upload) are rejected with a clear message.
PAT authentication only; NTLM / Windows integrated authentication is not supported.
Deleting removes the attachment link; the blob stays on the server (no API exists to purge it).
stdio transport only.
Security notes
The PAT is used solely as a Basic auth header for requests to
AZURE_DEVOPS_URLand never appears in logs, tool output or error messages.Everything the server logs goes to stderr; stdout is reserved for the MCP protocol.
Downloaded file names are sanitized (path separators,
.., control characters) and files are written only inside the requested output directory.AZURE_DEVOPS_ALLOW_INSECURE_TLS=truedisables certificate verification for the whole process. Use it only on trusted networks; adding your CA viaNODE_EXTRA_CA_CERTSis the safer option.
Troubleshooting
Symptom | Likely cause |
| PAT invalid, expired, created in another collection, or missing the Work Items (Read & Write) scope. |
| Same as above, or |
| Self-signed certificate: set |
| Wrong host in |
| Wrong id, or the PAT owner cannot read that work item. |
| Pass |
Run npx @modelcontextprotocol/inspector npx -y azure-devops-attachment-mcp-server with the environment
variables set to try the tools interactively.
Development
npm install
npm run typecheck # tsc --noEmit over src and tests
npm test # vitest (builds dist/ first so the bin tests use the real entry point)
npm run build # emits dist/
npm run inspect # MCP Inspector against dist/index.jsTests run against a fake fetch; no Azure DevOps Server is needed. See docs/design.md
for the design notes.
Releasing
Bump
versioninpackage.jsonand commit.Tag it:
git tag v<version> && git push --tags.The
Publish to npmworkflow builds, tests and publishes with provenance. It needs anNPM_TOKENrepository secret (an npm automation token).
License
Available Tools
4 toolsadd_attachmentAdd an attachment to a work itemA
Upload a local file and attach it to a work item (adds an AttachedFile relation). Simple upload limit: 130 MB. Returns the attachment id and the work item's new revision.
Inputs: filePath (required), workItemId (required), comment, project, +1 more. Returns: attachment, workItemId, workItemRev
delete_attachmentDelete a work item attachmentADestructive
Remove an attachment from a work item by attachment id or by a file name that is unique on the work item. Only the link is removed; Azure DevOps has no API to delete the stored file.
Inputs: workItemId (required), name, attachmentId. Returns: note, removed, workItemId, workItemRev
download_attachmentDownload a work item attachmentA
Download a work item attachment to a local directory by attachment id or unique file name. Existing files are never overwritten (a " (n)" suffix is added). Returns the absolute path of the saved file.
Inputs: workItemId (required), name, project, fileName, +2 more. Returns: id, name, path, size, +1 more
list_attachmentsList work item attachmentsARead-onlyIdempotent
List the file attachments of an Azure DevOps work item: name, size, comment, created date, attachment id (GUID) and URL.
Inputs: workItemId (required). Returns: count, workItemId, attachments, workItemRev
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 4 tools
Each tool performs a clearly distinct action on attachments: list, upload, delete, and download. There is no overlap in purpose, and the descriptions reinforce the boundaries.
All tool names follow a consistent verb_noun snake_case pattern: list_attachments, add_attachment, delete_attachment, download_attachment. The only minor variation is singular versus plural attachment, but it reads naturally and does not cause confusion.
Four tools is exactly the right scope for an attachment management server: list, add, delete, and download. There is no redundancy or unnecessary bloat.
The tool set covers the full actionable lifecycle for work item attachments: enumerate, add, remove the link, and retrieve the file. Update is not applicable since attachments are immutable, so there are no meaningful gaps.
Maintenance
Related MCP Connectors
File uploads for AI agents. Upload, list, and manage files. No signup required.
Manage files and folders directly from your workspace. Read and write files, list directories, cre…
- DNS-DATA RemoteDeprecatedcom.dns-data
Connect AI assistants to authorized Windows and macOS devices for files, commands, and management.
Remote Desktop Commander: use files, terminal and processes on your own computers from any AI app.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables natural language interaction with Azure DevOps to manage work items, projects, and Git commit links via the REST API. It supports comprehensive operations including creating, searching, batch updating work items, and managing attachments.22 npmMIT
- AlicenseNot gradedqualityCmaintenanceEnables AI assistants to interact with Azure DevOps APIs for managing projects, work items, repositories, pull requests, and pipelines through natural language.51 npm1MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to interact with Azure DevOps APIs for managing projects, work items, repositories, pull requests, pipelines, and more through natural language.14,175 npmMIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to interact with Azure DevOps for managing work items, repositories, wikis, and automating development workflows.MIT