Skip to main content
Glama

Dependency Security MCP

Dependency Security MCP is a small, production-oriented Model Context Protocol server for OWASP Dependency-Check vulnerability scanning. It exposes three narrow tools:

  • start_dependency_scan

  • get_scan_status

  • get_scan_report

It does not expose shell execution, arbitrary filesystem access, repository mutation, remediation, package manager commands, or unrestricted OWASP CLI arguments.

Architecture

flowchart TD
    LangGraph --> Client[MCP Client]
    Client --> Server[Dependency Security MCP]
    Server --> ScanService
    Server --> ReportService
    ScanService --> Scanner[DependencyScanner]
    ReportService --> Scanner
    Scanner --> OWASP[OWASP Dependency-Check]

The MCP layer is intentionally thin. Tool functions validate and serialize request and response data, then call application services. Services depend on repository and scanner abstractions, so a later OSV scanner, dependency resolver, version provider, or remediation service can be added without changing the MCP tool contracts.

Related MCP server: Dependency-Track MCP Server

Requirements

  • Python 3.12+

  • OWASP Dependency-Check CLI available as dependency-check

  • The official MCP Python SDK v2

Install Python dependencies:

python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

The project uses the current v2 server style:

from mcp.server import MCPServer

Installing OWASP Dependency-Check

Install Dependency-Check from the OWASP project and ensure the dependency-check command is on PATH. You can also point the server at a custom executable:

export OWASP_DEPENDENCY_CHECK_PATH=/opt/dependency-check/bin/dependency-check.sh

Configuration

Copy .env.example values into your environment:

export MCP_SERVER_NAME=dependency-security-mcp
export OWASP_DEPENDENCY_CHECK_PATH=dependency-check
export SCAN_OUTPUT_ROOT=/tmp/dependency-security-mcp
export ALLOWED_REPOSITORY_ROOTS=/workspace/repos
export SCAN_TIMEOUT_SECONDS=1800
export LOG_LEVEL=INFO

ALLOWED_REPOSITORY_ROOTS is a comma-separated allowlist. Requested repositories are resolved with Path.resolve() and must exist, be directories, and live below one configured root.

Running

Run with stdio for local development:

uv run mcp dev src/dependency_security_mcp/server.py

Run with Streamable HTTP for production-style serving:

uv run mcp run src/dependency_security_mcp/server.py --transport streamable-http

Open the MCP Inspector:

uv run mcp dev src/dependency_security_mcp/server.py

MCP Tools

start_dependency_scan

Starts an OWASP Dependency-Check scan asynchronously and returns immediately after scheduling.

Request:

{
  "repository_path": "/workspace/repos/payment-service",
  "project_name": "payment-service"
}

Response:

{
  "scan_id": "4f8b3dfd-e4f7-40ec-b31f-df3d1992c544",
  "scanner": "OWASP_DEPENDENCY_CHECK",
  "status": "RUNNING",
  "project_name": "payment-service",
  "started_at": "2026-10-03T07:00:00Z"
}

get_scan_status

Request:

{
  "scan_id": "4f8b3dfd-e4f7-40ec-b31f-df3d1992c544"
}

Response:

{
  "scan_id": "4f8b3dfd-e4f7-40ec-b31f-df3d1992c544",
  "status": "COMPLETED",
  "scanner": "OWASP_DEPENDENCY_CHECK",
  "started_at": "2026-10-03T07:00:00Z",
  "completed_at": "2026-10-03T07:03:15Z",
  "error": null
}

get_scan_report

Running response:

{
  "scan_id": "4f8b3dfd-e4f7-40ec-b31f-df3d1992c544",
  "status": "RUNNING",
  "message": "Scan has not completed yet."
}

Completed response:

{
  "scan_id": "4f8b3dfd-e4f7-40ec-b31f-df3d1992c544",
  "scanner": "OWASP_DEPENDENCY_CHECK",
  "project_name": "payment-service",
  "repository_path": "/workspace/repos/payment-service",
  "status": "COMPLETED",
  "dependency_count": 147,
  "vulnerable_dependency_count": 3,
  "vulnerability_count": 5,
  "findings": []
}

Example Client Flow

from mcp import Client


async with Client("http://localhost:8000/mcp") as client:
    start = await client.call_tool(
        "start_dependency_scan",
        {
            "repository_path": "/workspace/repos/payment-service",
            "project_name": "payment-service",
        },
    )
    scan_id = start.structured_content["scan_id"]

    while True:
        status = await client.call_tool("get_scan_status", {"scan_id": scan_id})
        if status.structured_content["status"] in {"COMPLETED", "FAILED", "CANCELLED"}:
            break

    report = await client.call_tool("get_scan_report", {"scan_id": scan_id})
    print(report.structured_content)

Docker

Build:

docker build -t dependency-security-mcp .

Run with a read-only repository mount:

docker run --rm \
  -v /repos:/workspace/repos:ro \
  -e ALLOWED_REPOSITORY_ROOTS=/workspace/repos \
  dependency-security-mcp

The image runs as a non-root user and writes scan output under SCAN_OUTPUT_ROOT.

Security Model

  • Never executes arbitrary user commands.

  • Never uses shell=True.

  • Validates repository paths by resolving them before allowlist checks.

  • Restricts scans to configured roots.

  • Server controls output directories.

  • Enforces scan timeouts and process termination.

  • Validates scanner exit codes.

  • Returns structured client-safe errors.

  • Does not expose environment variables, raw shell access, arbitrary filesystem APIs, or arbitrary OWASP arguments.

The caller decides when and which allowed repository to scan. The MCP server decides whether the path is allowed, which executable and arguments are used, where reports are stored, how long the scan may run, and how reports are normalized.

Tests

Run unit tests:

pytest

Run lint:

ruff check .

The real OWASP integration test is opt-in:

RUN_OWASP_INTEGRATION_TESTS=true pytest tests/integration

Roadmap

The architecture is ready for additional narrow capabilities later:

  • Maven, Gradle, and npm dependency resolution

  • OSV scanning

  • Dependency version lookup

  • Suggested dependency fixes

  • Controlled dependency updates

  • Build/test verification

Those capabilities are intentionally not implemented in this first version.

Available Tools

3 tools
get_scan_reportB

Get the normalized vulnerability report for a completed scan.

ParametersJSON Schema
NameRequiredDescriptionDefault
scan_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

B3.3/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden. It notes the scan must be 'completed' but says nothing about error behavior for incomplete scans, required permissions/auth, whether results are cached or paginated, or freshness of the report.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single, front-loaded sentence with no filler. The verb and resource lead immediately, and nothing redundant is included.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-value explanation is unnecessary. But for a retrieval tool with no annotations, the description is thin on preconditions, failure modes, and report scope ('normalized' is left undefined).

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and there is one required parameter (scan_id). The description implies the report is keyed to a scan but adds no format, source, or validity detail for scan_id beyond what the schema's name/type already convey.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Get') and resource ('normalized vulnerability report') scoped to a completed scan. It is distinguishable from get_scan_status (status vs. report) and start_dependency_scan (initiates vs. retrieves), though it does not name those siblings explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'for a completed scan' implies a precondition (the scan must have finished), which is useful usage context. However, it offers no explicit when-to-use guidance, no alternatives, and no statement of what to do if the scan is still running.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_scan_statusC

Get status for a dependency vulnerability scan.

ParametersJSON Schema
NameRequiredDescriptionDefault
scan_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

C2.7/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden, and it discloses almost nothing: not whether status is polled, what states are returned, whether the scan_id must come from start_dependency_scan, or whether the call is cheap/safe to repeat. It only restates the operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single short sentence with no filler and the verb-resource pairing front-loaded. It is efficient, though brevity here shades into under-specification rather than disciplined conciseness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be described, but the description still omits the essentials for correct invocation: where scan_id comes from, typical polling behavior, and how this differs from the report tool. For a tool with a sibling pair this thin, more context is warranted.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% for the single required scan_id parameter, and the description adds only the weak implication that the id identifies a dependency vulnerability scan. It does not explain the id's origin or format, so it fails to compensate for the coverage gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Get) and resource (status for a dependency vulnerability scan), which is meaningfully narrower than the sibling get_scan_report. It does not, however, explicitly distinguish itself from get_scan_report or start_dependency_scan, so an agent must infer the status-vs-report split.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No when-to-use guidance, no mention of alternatives, and no indication that this is typically polled after start_dependency_scan. The description offers nothing about when this tool is the right choice versus get_scan_report.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

start_dependency_scanB

Start an OWASP Dependency-Check scan for an allowed repository path.

ParametersJSON Schema
NameRequiredDescriptionDefault
project_nameNo
repository_pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

B3/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description must carry the full behavioral burden. It mentions starting an OWASP Dependency-Check scan but says nothing about whether the scan is asynchronous, whether the call blocks, what permissions are required, what happens when the path is not allowed, or how the caller should proceed afterward. The output schema covers return values, but operational behavior remains largely undisclosed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single, front-loaded sentence with no filler. Every part of the sentence earns its place and conveys the core action and target resource efficiently.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The output schema exists, so return-value explanation is not required. Still, for a scan-starting mutation tool with no annotations, the description is too thin: it omits async/polling behavior, permission requirements, and the meaning of the optional project_name parameter. An agent would need to guess important operational details.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description should compensate. It mentions the required repository_path and adds that it must be an 'allowed' path, which is some useful context. However, it completely omits the optional project_name parameter, leaving half the parameters undocumented in both the schema and the description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific verb and resource: 'Start an OWASP Dependency-Check scan.' This clearly separates it from siblings like get_scan_status and get_scan_report, which handle status and reporting. It is clear enough for selection, though it does not explicitly name or contrast the siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: the agent can infer this tool begins a scan for a repository. The phrase 'for an allowed repository path' hints at a precondition, but there is no explicit when-to-use guidance, no mention of alternatives, and no indication of when not to call it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv0.1.0
    • First observedget_scan_report
    • First observedget_scan_status
    • First observedstart_dependency_scan

TDQS

A3.5/5.0

Scored across 3 tools

Disambiguation5/5

Each tool targets a distinct phase of the scan lifecycle: start a scan, poll its status, and retrieve the completed report. There is no functional overlap, and the descriptions clearly differentiate status polling from report retrieval.

Naming Consistency5/5

All tool names follow a consistent snake_case verb_noun pattern (start_dependency_scan, get_scan_status, get_scan_report). The shared 'get_scan_' prefix for the two retrieval tools reinforces predictability.

Tool Count5/5

Three tools are well-scoped for a focused dependency scanning service: initiate, monitor, and fetch results. The set contains no redundant or filler tools, and the count sits comfortably in the typical 3-15 range.

Completeness4/5

The core lifecycle (start → status → report) is fully covered, but there is no way to list existing scans or cancel a running scan. These are minor gaps that agents can work around by retaining scan IDs, but they limit multi-scan management.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    Not graded
    maintenance
    Provides tools for autonomous CVE detection, enrichment, and remediation across managed repositories using GHSA and NVD data. It enables automated triage and pull request creation for dependency fixes based on configurable severity policies.
    -
  • A
    license
    Not graded
    quality
    F
    maintenance
    Enables auditing npm, pip, and other package dependencies for known CVEs via the OSV database, with tools to scan manifests, query individual packages, and integrate into CI/CD workflows.
    396 npm
    MIT