FossID
Preview release. This extension is in active development. You need a FossID scan server URL and user token to use it — if you are not yet a FossID customer, use FossID: Request Access from the Command Palette to request access.
VS Code extension for software composition analysis. Bridges the
FossID MCP server — which scans codebases for
open-source components, licenses, and CVEs — with any MCP-compatible chat
client (Claude Code, GitHub Copilot, Cursor, Windsurf, Cline, Continue),
and adds editor-UI tools so the LLM can surface findings directly in your
editor.
What you get
Two MCP servers, both spawned and supervised by the extension:
- fossid-mcp (17 tools) — scanning, graph queries, compliance analysis,
SBOM generation. The bundled
fossid-mcp Rust binary, run as a
long-lived HTTP subprocess on 127.0.0.1.
- fossid-editor (6 tools) — editor actions the LLM calls to render
findings inline:
- open_file — open a file at a specific range
- show_diff — native side-by-side diff (e.g., canonical license vs
tampered file)
- highlight_ranges — colored decorations with hover messages
- show_diagnostics — Problems panel entries with finding identity,
metadata, and verification annotations
- clear_diagnostics / clear_highlights — explicit purge
Plus auto-revalidation on save: each diagnostic can carry a
verification annotation describing how to check resolution. On file
save, the extension runs the check and drops resolved findings —
no LLM round-trip for the common case. Five verification methods:
text-absent, text-present, tool-empty, tool-match (deterministic),
and llm (asks the user's chat model to judge).
Install
- Obtain
fossid-vscode-<version>.vsix (built via ./scripts/build-vsix.sh
or downloaded from a GitHub release — the VSIX bundles the fossid-mcp
binary for the target platform).
- In VS Code: Extensions view →
... menu → Install from VSIX… →
select the file. Reload when prompted.
- A welcome notification appears: click Set Up.
- Enter your FossID server URL and API token. Done.
After credentials are stored, the extension spawns fossid-mcp and the
in-process fossid-editor server on 127.0.0.1, then writes
workspace-scoped MCP configs:
<workspace>/.vscode/mcp.json — Copilot
<workspace>/.mcp.json — Claude Code
Both files contain only the HTTP URLs the extension is currently bound to.
Credentials never touch disk — they live in VS Code's SecretStorage and
are injected into the subprocess's environment at spawn time.
Recommended: add both files to your workspace's .gitignore. The
embedded port is per-machine and changes across restarts when the
ephemeral fallback kicks in, so committing them creates merge churn for
teammates. The first time the extension writes them, you'll see a
one-time notification with a button to copy the lines for your .gitignore.
.vscode/mcp.json
.mcp.json
VS Code's MCP panel auto-trusts and starts the new servers on activation
(no manual "Start Server" click required for trusted workspaces).
Usage
In your chat client (Claude Code, Copilot Agent Mode, Cursor, etc.):
- "Scan this workspace for open-source components and show me the risk overview."
- "Analyze LICENSE with local_license_analysis and highlight any modifications."
- "Find files with GPL-3.0 copyleft and push them to the Problems panel."
- "Show a diff between the canonical MIT text and my LICENSE file."
The LLM chains scanning tools (fossid-mcp) with editor tools (fossid-editor)
transparently. Byte-accurate highlighting: tools accept startByte/endByte
directly from scan output — no line-counting needed.
Lifecycle
- Activation — both servers come up. Workspace configs are written
(when a folder is open) and any orphan
fossid-ide entries from earlier
versions get scrubbed. VS Code's MCP layer is nudged into auto-starting
the new entries.
- Credential rotation —
Sign Out followed by Sign In (or any change
to fossid.host / fossid.token in SecretStorage) tears down the
subprocess and respawns it with the new env, then surfaces a
notification asking your chat client to reconnect.
- Crash recovery — unexpected subprocess exit triggers a restart with
short backoff (0/500/2000 ms); ≥3 exits inside 30 s and the extension
surfaces the failure in the FossID output channel rather than looping.
- Two windows — each VS Code window owns its own subprocess on its
own port, with its own workspace-scoped configs. State is per-window;
killing one doesn't affect the other.
- Reload —
deactivate() shuts down the subprocess; the next
activation re-spawns and re-syncs the workspace MCP configs. Workspace
files are intentionally not scrubbed on reload because two windows on
the same folder share a single .vscode/mcp.json, and a sibling
closing must not wipe a still-live entry.
- Uninstall — VS Code's hook timing is subtle. Per the maintainers
(#155561),
vscode:uninstall fires before VS Code removes the extension on
disk, which happens at app restart — not at the moment you click
Uninstall and not on a window reload. On macOS, closing the window
does not quit the app; you need Cmd+Q. The recommended path:
- Run
FossID: Clean Up Workspace Configs first. Stops the
subprocess and scrubs .vscode/mcp.json + .mcp.json for the
current workspace synchronously. Then uninstall normally. This
is the deterministic path and doesn't depend on hook timing.
- If you skip step 1, the bundled
vscode:uninstall hook fires
at next full app restart. It SIGTERMs any tracked subprocess
PIDs, scrubs every workspace the extension touched (tracked in
<globalStorage>/state.json), and removes the bundled skill
folder (~/.claude/skills/fossid-editor/).
- If the hook didn't fire (or you want to clean up without
restarting VS Code), the script can be invoked directly:
node ~/.vscode/extensions/fossid.fossid-vscode-*/out/uninstall.js.
That's effectively what (2) does, just without depending on VS
Code's queue.
Commands
| Command |
Purpose |
FossID: Set Up |
First-run wizard: prompts for server URL + token; subsequent runs of the extension write configs auto. |
FossID: Sign In |
Update stored credentials (triggers a subprocess restart with the new env). |
FossID: Sign Out |
Clear stored credentials and stop the subprocess. |
FossID: Copy MCP URL |
Quick-pick: copy the fossid-editor URL, fossid-mcp URL, or both as a JSON snippet. |
FossID: Clean Up Workspace Configs |
Pre-uninstall scrub — removes our entries from .vscode/mcp.json and .mcp.json and stops the subprocess. |
Settings
| Setting |
Default |
Purpose |
fossid.port |
39814 |
Preferred port for the in-process fossid-editor server. Falls back to ephemeral on collision. |
fossid.mcpPort |
39815 |
Preferred port for the fossid-mcp subprocess. Falls back to ephemeral on collision. |
Architecture
The extension runs two MCP servers:
- fossid-editor — in-process, inside the VS Code extension host. SSE
transport on
http://127.0.0.1:<fossid.port>/sse. Tool handlers have
full access to vscode.window / vscode.languages — that's how they
open diffs, paint decorations, and manage diagnostics.
- fossid-mcp — subprocess, spawned with
fossid-mcp http --host 127.0.0.1 --port <fossid.mcpPort>. Streamable HTTP transport on
http://127.0.0.1:<port>/mcp. Credentials injected via
FOSSID_HOST / FOSSID_TOKEN environment variables at spawn time;
never written to any config file. Supervised by the extension:
restart on crash, SIGTERM/SIGKILL on shutdown.
One subprocess per VS Code window — every connected agent in that window
shares the same ScanGraph, so Claude Code and Copilot reading the same
workspace see the same scan state.
Both servers bind to 127.0.0.1 only; no remote network exposure.
| Client |
Works? |
| Claude Code (VS Code extension) |
✓ tested |
| GitHub Copilot Chat (Agent Mode) |
✓ (pick any model: Claude, GPT, Gemini) |
| Cursor |
✓ (VS Code fork, same MCP) |
| Windsurf |
✓ expected (untested) |
| Cline / Continue.dev |
✓ (MCP-compatible) |
| Claude Desktop / CLI |
scanning tools only (no editor UI) |
Build from source
Two developer workflows, pick whichever fits. Both end with a
packaged .vsix in the repo root; the only difference is where the
fossid-mcp binary comes from.
Default: release-artifact download
npm install
npm run fetch-mcp # downloads binary for the current platform
npm run package # packages .vsix
fetch-mcp reads MCP_VERSION (repo root, single-line version pin),
pulls the matching asset from fossid-ab/fossid-mcp's GitHub Release,
verifies its SHA-256 against the release's SHA256SUMS, and writes
it to bin/fossid-mcp[.exe]. Requires gh CLI + auth (gh auth login locally, GH_TOKEN in CI). Bumping the binary version is a
one-line edit to MCP_VERSION.
Escape hatch: build from a sibling checkout
For devs iterating on the Rust side:
npm install
npm run fetch-mcp:local # cargo build --release in ../fossid-mcp
npm run package
# or the all-in-one:
./scripts/build-vsix.sh # fetch-mcp:local + package + summary
Defaults to ../fossid-mcp; override with FOSSID_MCP_PATH=/path
or pass the path as an argument.
Note on the CI build
.github/workflows/build.yml's build job runs npm run fetch-mcp
per matrix platform — same script you'd run locally. No Rust
toolchain in CI, no cross-compile, no private fossid-mcp checkout.
Bumping MCP_VERSION in a PR exercises the new binary end-to-end.
Releases
This project uses changesets
for versioning and changelog generation. Workflow:
- Land your PR with a changeset describing the change:
npm run changeset # interactive: pick bump level + write entry
The CI's Changeset Check workflow fails any PR that touches src/**
without a changeset (apply the no-changeset label to bypass for
docs-only or chore PRs).
- Merging to
main opens or updates a "Version Packages" PR with the
pending bump and CHANGELOG additions. Review and merge it when ready
to ship.
- Merging the Version Packages PR pushes a
vX.Y.Z git tag, which
triggers build.yml to package per-platform .vsix artifacts and
attach them to a GitHub Release.
A streamable-HTTP interop check against the bundled Claude Code lives at
scripts/spike-streamable-http.sh — re-run it any time MCP_VERSION or
the Claude CLI version changes.
Testing
Unit tests live alongside source as foo.test.ts next to foo.ts.
Run with:
npm run test:unit # one-shot
npm run test:unit:watch # watch mode
npm run test:unit:coverage # with v8 coverage
Unit tests run in a Node environment only — no VS Code host, no Rust
binary, no live FossID backend. Modules that import * as vscode from 'vscode' are served via a minimal shim at test/__mocks__/vscode.ts
(aliased in vitest.config.ts).
Extension-host tests live in test/suite/*.test.ts and run inside a
real VS Code instance (Mocha-style, suite/test globals). Verify
activation, command registration, and configuration contributions:
npm run test:e2e # downloads VS Code on first run, caches in .vscode-test/
On Linux CI, prefix with xvfb-run -a to supply a virtual display.
MCP integration tests live in test/integration/mcp/*.test.ts and
boot the real in-process MCP server on an ephemeral loopback port,
connect an @modelcontextprotocol/sdk client via SSE, and exercise
each registered tool:
npm run test:integration
A meta-test enumerates the server's registered tools and asserts
each one has a corresponding <tool>.test.ts file — adding a new
tool without a test fails the suite.
The fossid-mcp subprocess module (src/mcpSubprocess.test.ts) drives
the real bundled binary via it.skipIf(!hasBinary) — it skips when
bin/fossid-mcp isn't present, runs the full spawn/EADDRINUSE/dispose
suite when it is.
License
See LICENSE.