MCP server (Claude / Cursor)

Connect Claude, Cursor, or any MCP-compatible client to DevUpdate.io, via the hosted endpoint with OAuth, or by running the server locally.

The DevUpdate.io MCP server exposes your tracked sources, releases, available dependency upgrades, and open security issues as tools that any Model Context Protocol-compatible client can call. The most common uses: have your agent run a full dependency audit ("are we exposed to anything right now?"), ask "is this update safe?" and have the model check the actual diff analysis before answering, or have it work through your available upgrades and resolve the safe ones. The division of labor is deliberate: your agent brings the codebase, we bring verified dependency knowledge, and your code never reaches our servers.

There are two ways to connect:

  • The hosted server (recommended): point your client at https://api.devupdate.io/mcp and sign in. No install, no config files.
  • Local (stdio): run the server yourself with an API token, for air-gapped setups or if you'd rather no traffic flow through our hosted endpoint.

Both expose the same tools, on every tier including the free one: the free tier's 2 lockfiles (a frontend and a backend, i.e. a full repo) get the full audit/upgrade surface; paid tiers extend it across unlimited lockfiles. The MCP-and-skills setup you commit to a repo works for every collaborator regardless of their plan.

Working with Claude Code or another coding agent? Pair the server with the downloadable agent skills: one-file playbooks for the full audit (devupdate-audit), safe upgrades (devupdate-dependency-upgrades), and security triage when no clean fix exists (devupdate-security-triage).

What the server gives you #

Five tools for the model to call, kept deliberately few so a crowded MCP client (many connectors at once) doesn't ration DevUpdate's tools out of the audit path:

  • list_sources: your tracked sources, with last release and risk band. Pass query to find sources by name instead of listing hundreds.
  • get_updates: release intelligence across your sources, with AI summaries, risk scores, and breaking-change lists. Scope it with source_id (one source), query (search by term), since / min_risk (recent or high-risk only), or omit everything for "what changed lately". Long section text is truncated per release and marked as such, except around a query match, which is always shown; get_upgrades with upgrade_ids renders the four decision-relevant sections deeper still.
  • get_security_issues: the audit entry point, covering every OSV/GHSA advisory affecting a pinned version, independent of whether an upgrade exists. Includes the two cases upgrade tools structurally drop (vulnerable at the latest release; fix unreleased), a fix_status triage key (fix_available when a released fix is reachable, linking the upgrade that delivers it once ingested, fix_blocked naming the parent constraint standing in front of the advisory's own lowest fix (a parent that merely blocks the jump to latest doesn't count), fix_unreleased when no released fix is reachable above the pin, checked against the registry's published set, or kept conservatively when that lookup is unavailable), and the advisory's own workaround text, verbatim, when one is documented. No dismissal: unresolved issues keep listing by design.
  • get_upgrades: available dependency upgrades in one call. A per-lockfile rollup (counts of upgradeable / direct vs. transitive / blocked-by-parent / major / security / high-risk / not-monitored) leads the per-package list (pinned → latest, major / security / breaking / direct / transitive / blocked flags, OSV/GHSA advisory ids with fix versions, the parent constraint behind blocked upgrades, each with its (id: N) tag), optionally filtered by lockfile, minimum risk level, or to include dismissed ones. Where anything is blocked, a blocked-upgrade levers section sits between the two: the distinct parent packages holding those upgrades back, ranked by how many each gates, with the ones that are themselves upgradeable marked as such. Hundreds of blocked transitive pins usually trace back to a handful of parents, so that section is normally the shortest route to clearing most of them; pass blocked_by to list exactly what one parent gates. Pass upgrade_ids instead for release-by-release detail across each upgrade's exact (pinned, latest] range: the call to make before taking a major or breaking upgrade.
  • dismiss_upgrades: snooze upgrades you've decided to defer, until a newer version appears - by lockfile or specific upgrade ids.

One token, all your lockfiles, across repos. Your MCP credential authenticates a whole DevUpdate.io account, not a single repository, so get_upgrades and get_security_issues return every lockfile the account monitors (except any you've hidden; see below) even when your agent is working inside one repo. To keep them straight, each lockfile is labeled with its origin, repo: owner/name:path when it's connected to GitHub, or manual upload when it isn't, so an agent can tell which findings belong to the repo it's in and which belong to a different project on the same account. Pass lockfile_id to scope a call to a single lockfile. (This is display scope, not a security boundary: cross-account isolation is enforced separately; see Privacy → tenant isolation.)

Want a lockfile monitored in the web app but kept out of your AI agents' reach entirely? Each lockfile has an Available to AI agents toggle (its card's overflow menu, and the lockfile detail page). Turn it off and that lockfile is excluded from the get_upgrades and get_security_issues tools and their rollup counts, while it keeps syncing and showing on your dashboard. See Per-lockfile agent visibility below for exactly how far the boundary reaches.

Upgrade risk levels are priorities, most urgent first: critical means a registry advisory (OSV/GHSA, the same data npm audit / pip-audit read) affects your pinned version and its fix ships in the range, with the advisory ids included so an agent can verify; high means a confirmed breaking signal: a major jump or documented breaking changes; medium means suspicion without confirmation: undocumented changes detected via diff, security-flavored release notes with no matching advisory, an advisory whose fix is not in the range, or a release scoring 40+; low is routine catch-up. See Available upgrades for the full model, including how offered versions are validated against the package's registry and how parent-blocked upgrades are detected.

Responses are bounded, and say when they are. A large account can hold hundreds of lagging pins, and a tool result that overflows the model's context costs more than it delivers: the agent loses the answer, or spends its remaining budget paging the text back out of a file. So every list these tools return is capped, ordered worst-first (risk then security for upgrades, severity for issues) so a cut takes the routine tail, and every capped list states how many rows it left out and how to reach them. The counts never shrink: rollups, totals, and the lever tallies are computed over everything in scope, so a short list is never a quiet all-clear. To see a slice in full, narrow it: lockfile_id for one project, risk_level to raise the floor, blocked_by for one parent's set, query on list_sources.

get_upgrades and dismiss_upgrades replace the old get_alerts and mark_alerts_read tools, from the move off reactive lockfile alerts; get_upgrades also folds in the former get_lockfile_upgrade_summary, get_available_upgrades, and get_upgrade_details, and get_updates the former get_source_updates / get_dependency_changes / search_updates; fewer, denser tools survive client-side tool rationing better.

Every tool except dismiss_upgrades is read-only. The audit flow starts with get_security_issues (severity-first, fix_status decides the resolution path), then get_upgrades unfiltered, whose rollup heads the list, so a filtered-empty list is never mistaken for "up to date"; pass upgrade_ids for release-by-release detail before anything major or breaking. Then resolve the safe ones. After bumping a dependency you usually don't need dismiss_upgrades at all. The next sync auto-resolves the upgrade; use it only to snooze an upgrade you're deferring. The agent skills package these flows so you don't have to prompt them every time.

The hosted endpoint speaks streamable HTTP at:

https://api.devupdate.io/mcp

Authentication is standard MCP OAuth: your client discovers our authorization server automatically, opens a browser window, and you approve the connection on a consent screen, with no tokens to copy. Each connected client appears under Settings → Connected AI Clients, where you can revoke it at any time.

Prefer not to do the browser dance (CI, scripts)? The endpoint also accepts your API token directly as a bearer header: Authorization: Bearer du_….

claude.ai and Claude Desktop #

Add a custom connector (Settings → Connectors → Add custom connector) and paste https://api.devupdate.io/mcp. Claude walks you through the OAuth sign-in; the DevUpdate tools then show up in the tools menu.

Claude Code #

One command, then authenticate via /mcp:

claude mcp add --transport http devupdate https://api.devupdate.io/mcp

To share the server with everyone working in a repository, check this .mcp.json into the project root instead, where each developer authenticates once via /mcp:

{
  "mcpServers": {
    "devupdate": {
      "type": "http",
      "url": "https://api.devupdate.io/mcp"
    }
  }
}

To make it a complete one-commit setup for the whole team, add the three agent skills alongside it, so every session (including Claude Code web sessions) loads the audit / upgrade / triage playbooks automatically:

for skill in devupdate-audit devupdate-dependency-upgrades devupdate-security-triage; do
  mkdir -p .claude/skills/$skill
  curl -fsSL -o .claude/skills/$skill/SKILL.md https://devupdate.io/skills/$skill/SKILL.md
done

Commit the .mcp.json and the .claude/skills/ files together. Every collaborator (on any tier, including the free one) then gets the same server and playbooks, and authenticates the server once via /mcp on first use. (More on the skills, and setup for non-Claude clients, in Agent skills.)

For non-interactive use, skip OAuth and pass an API token:

claude mcp add --transport http devupdate https://api.devupdate.io/mcp \
  --header "Authorization: Bearer du_<your-token>"

Claude Code on the web #

Web sessions run in a sandboxed cloud container whose outbound traffic is allowlisted by hostname, so the route you pick decides whether you touch that allowlist at all:

  • As a connector (nothing to configure): add DevUpdate.io in the web UI (paste the URL above, complete the OAuth sign-in). Connector traffic travels through Anthropic's servers rather than the session's own network, so the environment's allowed domains never come into it.
  • From a committed .mcp.json (two domains to allow): the container itself talks to api.devupdate.io over the session network, so the environment has to allow it. The same goes for the curl that downloads the agent skills, which comes from devupdate.io.

Allowed domains for cloud sandboxes #

Committing the .mcp.json (or downloading the skills with curl) means the session's own network carries the traffic, so the environment needs both of these. Open the environment selector at claude.ai/code (the cloud icon in the row above the message box), edit the environment, set Network access to Custom, and list them in Allowed domains, one per line:

devupdate.io
*.devupdate.io

Both lines, because a leading *. matches subdomains only. *.devupdate.io covers the MCP endpoint at api.devupdate.io; the bare devupdate.io covers the apex, which serves the skill files at https://devupdate.io/skills/…/SKILL.md and the pages those skills link to. The default Trusted level does not include either: it covers package registries, GitHub, and cloud SDKs, and nothing of ours. (Full network access reaches us as well, at the cost of allowing everything else too.)

Leave Also include default list of common package managers checked while you're at it. An upgrade session edits a manifest and then installs, so it still needs npm, PyPI, and the rest of the default list; unchecking it allows only what you typed.

What a blocked domain looks like, so nobody misreads it as an outage. The MCP server fails to connect, or its tools return transport errors, DNS failures, or proxy 403s, in a session where everything else works. A curl for a SKILL.md comes back empty or refused. That is the sandbox declining the hostname, and no amount of retrying or re-authorizing fixes it: add the two domains above, or connect DevUpdate.io as a connector instead. The devupdate-audit skill carries this same check in its preflight, so an agent running the audit in a locked-down sandbox diagnoses it rather than reporting us down.

The same applies wherever a sandbox allowlists egress by hostname: routines, Claude Tag sessions, a self-hosted runner, or CI. Allow both devupdate.io and *.devupdate.io, or connect through a channel that doesn't use the sandbox's network.

Cursor #

Cursor's MCP config lives at ~/.cursor/mcp.json:

{
  "mcpServers": {
    "devupdate": {
      "url": "https://api.devupdate.io/mcp"
    }
  }
}

Cursor opens the OAuth consent flow on first use.

Running the server locally (stdio) #

The same server ships as an npm package and runs over stdio with an API token from Settings → API tokens. The config shape is identical for Claude Desktop (claude_desktop_config.json), Claude Code (.mcp.json), and Cursor (~/.cursor/mcp.json):

{
  "mcpServers": {
    "devupdate": {
      "command": "npx",
      "args": ["-y", "@devupdate/mcp-server"],
      "env": {
        "DEVUPDATE_TOKEN": "<your-token>"
      }
    }
  }
}

In a shared repo, use "DEVUPDATE_TOKEN": "${DEVUPDATE_TOKEN}" and have each developer export the variable, so the raw token never lands in version control. Restart the client to pick up the new server.

Env-var naming differs by artifact: the npm package reads DEVUPDATE_TOKEN, while the Python server run from source (python -m app.mcp) reads DEVUPDATE_API_TOKEN. The configs above are for the npm package.

Don't paste a raw token into a config file you commit. Anything pushed to a repository (including from a Claude Code web session) is out of your hands; if a token leaks, revoke it from Settings → API tokens and provision a new one.

Security model #

  • OAuth connections are scoped. A connected client gets exactly two scopes, shown on the consent screen: mcp:read (your sources, release analyses, available upgrades, and security issues) and mcp:alerts:write (dismiss upgrade notices). The issued tokens cannot reach any other API surface, not settings, not billing, not account data beyond your basic profile.
  • The tool surface is deliberately narrow in both modes: read your sources, releases, upgrades, and security issues, plus dismiss_upgrades. No client can upload lockfiles, add or remove sources, or touch billing.
  • Everything is revocable. OAuth clients are listed under Settings → Connected AI Clients and can be disconnected individually, and their tokens stop working immediately. API tokens are revoked from the API tokens page with the same effect.
  • Each tool call is logged on our side for audit, and consent grants and revocations land in your account's security audit trail.
  • OAuth access tokens are short-lived (1 hour) and refreshed automatically by your client; refresh tokens rotate on every use, and a replayed refresh token revokes the whole connection as a precaution.

Per-lockfile agent visibility #

Each lockfile has an Available to AI agents toggle (default on). Turning it off keeps the lockfile fully monitored in the web app (it still syncs, and its upgrades and security issues still show on your dashboard), but removes it from the MCP surface: the get_upgrades, get_security_issues, and dismiss_upgrades tools and the rollup counts all behave as if it isn't there (and it's dropped from the underlying /lockfiles REST endpoint the tools read; there is no list_lockfiles tool). It's the knob for "monitor this project for me, but don't let my connected agents roam it."

Where the boundary is enforced:

  • Connected AI clients (the hosted server): enforced at the API. For an OAuth (duo_) connection, or any request arriving over the hosted /mcp endpoint, hidden lockfiles are filtered out in the database query. A connected client can't reach them even if it calls the underlying REST endpoint directly. The toggle is not just cosmetic tool formatting.
  • The self-hosted stdio server: honored by the tools. The stdio server authenticates with your own full-access API token, which the API can't distinguish from your other programmatic use, so the filter there is applied by the MCP tools themselves. The practical effect is the same (hidden lockfiles don't appear), and it's your own machine and token.
  • Not a limit on your own raw API token. The toggle governs the MCP surface, not your du_ API token used directly against the REST API; that key is your full-access credential by design. It is not a way to partition your own account from yourself.

This is a per-account display/scope preference: which of your lockfiles your agents see. It is distinct from, and layered on top of, the cross-account tenant isolation described in Privacy → tenant isolation.

A common pattern: ask the model to "check DevUpdate before suggesting package updates." Configure your AI assistant's system prompt to call get_updates before recommending an upgrade; it'll cite real risk data instead of guessing. For full upgrade sessions, the downloadable skill is the packaged version of this idea.