# PerspectiveGraph (oci · ghcr.io/luiacuaniello/perspectivegraph)

Read-only attack-path tools: reachable routes to sensitive assets, and what a fix would cut.

- Trust score: 62/100 (medium)
- Change this week: +40
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-10-17

## Components

- oci · `ghcr.io/luiacuaniello/perspectivegraph`: 62/100 (this document), [markdown](https://verifymcp.io/servers/luiacuaniello-perspectivegraph/ghcr-io-luiacuaniello-perspectivegraph.md), [page](https://verifymcp.io/servers/luiacuaniello-perspectivegraph/ghcr-io-luiacuaniello-perspectivegraph)

## Channel facts

- Registry: `oci`
- Package: `ghcr.io/luiacuaniello/perspectivegraph`
- Version: `v1.38.1`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-10-17.

- **Supply Chain Security**: 8/100
  - No malware scan is available for this kind of package: the supply-chain vendors we use do not cover it. This is a permanent gap in our coverage, not a finding about the package.
  - CVE check failed: a known advisory affects this package; its severity couldn't be graded.
  - Install-script risk not yet assessed.
  - Dependency health could not be checked: this image's dependency list comes from an SBOM its publisher attached. It names packages and versions but not whether each is deprecated, still maintained or linked to its source, so there is nothing we can fairly grade.
- **Provenance & Transparency**: 100/100
  - Source repository is publicly reachable at the declared URL.
  - Cryptographically verified build provenance (signed, bound to luiacuaniello/perspectivegraph).
  - Clear OSI-approved license (Apache-2.0).
  - Actively maintained (last published 2 days ago).
  - Publishes a security disclosure policy (SECURITY.md).
- **Schema Quality & AI Usability**: 73/100
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 1387 tokens (~173/item across 8 items; 8 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 57/100
  - Stability observed for 17 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 100/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 100% of tool parameters carry a description.
  - Structured output schemas are declared (100% of tools); any adoption earns full credit.
- **Tool Safety**: 100/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - We read all 8 captured tool definition(s), and no name or description among them implies an irreversible operation.
  - An AI judge read all 8 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.

## Install

### How do I install the PerspectiveGraph MCP server?

PerspectiveGraph runs locally as a container image, launched with docker run --rm -i -e API_TOKEN ghcr.io/luiacuaniello/perspectivegraph:v1.38.1. Ready-made configuration for Claude, Cursor, VS Code, Codex and 3 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add luiacuaniello-perspectivegraph -- docker run --rm -i -e API_TOKEN ghcr.io/luiacuaniello/perspectivegraph:v1.38.1
```

This image reads API_TOKEN. Set it in your client's env block for this server; docker run -e passes it through to the container.

### Cursor

```json
{
  "mcpServers": {
    "luiacuaniello-perspectivegraph": {
      "command": "docker",
      "args": [
        "run",
        "--rm",
        "-i",
        "-e",
        "API_TOKEN",
        "ghcr.io/luiacuaniello/perspectivegraph:v1.38.1"
      ]
    }
  }
}
```

This image reads API_TOKEN. Set it in your client's env block for this server; docker run -e passes it through to the container.

### VS Code

```json
{
  "servers": {
    "luiacuaniello-perspectivegraph": {
      "command": "docker",
      "args": [
        "run",
        "--rm",
        "-i",
        "-e",
        "API_TOKEN",
        "ghcr.io/luiacuaniello/perspectivegraph:v1.38.1"
      ]
    }
  }
}
```

This image reads API_TOKEN. Set it in your client's env block for this server; docker run -e passes it through to the container.

### Codex

```bash
codex mcp add luiacuaniello-perspectivegraph -- docker run --rm -i -e API_TOKEN ghcr.io/luiacuaniello/perspectivegraph:v1.38.1
```

This image reads API_TOKEN. Set it in your client's env block for this server; docker run -e passes it through to the container.

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "luiacuaniello-perspectivegraph": {
      "type": "local",
      "command": [
        "docker",
        "run",
        "--rm",
        "-i",
        "-e",
        "API_TOKEN",
        "ghcr.io/luiacuaniello/perspectivegraph:v1.38.1"
      ],
      "enabled": true
    }
  }
}
```

This image reads API_TOKEN. Set it in your client's env block for this server; docker run -e passes it through to the container.

### Hermes

```yaml
mcp_servers:
  luiacuaniello-perspectivegraph:
    command: "docker"
    args: ["run", "--rm", "-i", "-e", "API_TOKEN", "ghcr.io/luiacuaniello/perspectivegraph:v1.38.1"]
```

This image reads API_TOKEN. Set it in your client's env block for this server; docker run -e passes it through to the container.

### Netclaw

```json
{
  "McpServers": {
    "luiacuaniello-perspectivegraph": {
      "Transport": "stdio",
      "Command": "docker",
      "Arguments": [
        "run",
        "--rm",
        "-i",
        "-e",
        "API_TOKEN",
        "ghcr.io/luiacuaniello/perspectivegraph:v1.38.1"
      ]
    }
  }
}
```

This image reads API_TOKEN. Set it in your client's env block for this server; docker run -e passes it through to the container.

### Other

```json
{
  "mcpServers": {
    "luiacuaniello-perspectivegraph": {
      "command": "docker",
      "args": [
        "run",
        "--rm",
        "-i",
        "-e",
        "API_TOKEN",
        "ghcr.io/luiacuaniello/perspectivegraph:v1.38.1"
      ]
    }
  }
}
```

This image reads API_TOKEN. Set it in your client's env block for this server; docker run -e passes it through to the container.

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-10-17 (score 62, +1)

No change was recorded against any check on this day. Stability & Change Management went from 53 to 57. That category is still filling its 30-day observation window: 16 days of observed history at the previous scan, 17 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-10-15 (score 61, +39)

- [security improvement] Injection markers: unverified → pass
- [functional regression] Schema quality: 118 → 173
- [functional improvement] Tool coverage: unverified → 100
- [functional improvement] Stability: unverified → 0.50
- [functional improvement] MCP protocol: unverified → pass
- [functional] First check of Tool coverage: 100

### 2026-10-14 (score 22, 0)

- [functional] Package version: v1.38.0 → v1.38.1
- [functional] Package version: v1.31.0 → v1.38.0

### 2026-10-12 (score 22, 0)

- [functional improvement] Security disclosure: unverified → pass
- [functional] Package version: v1.37.0 → v1.38.0
- [functional] Package version: v1.31.0 → v1.37.0

### 2026-10-11 (score 22, 0)

- [functional regression] Security disclosure: pass → unverified
- [functional] Package version: v1.32.0 → v1.37.0

### 2026-10-07 (score 22, −35)

- [security regression] Stability: 0.13 → unverified
- [security regression] Tool safety: pass → unverified
- [functional regression] Capabilities: pass → unverified
- [functional regression] Tool coverage: 100 → unverified
- [functional] First check of Schema quality: unverified
- [functional] Package version: v1.31.0 → v1.32.0

### 2026-10-04 (score 57, +1)

- [security regression] Tool safety: pass → unverified
- [security regression] Stability: 0.10 → unverified
- [functional regression] Capabilities: pass → unverified
- [functional regression] Tool coverage: 100 → unverified
- [functional] First check of Schema quality: unverified
- [functional] Package version: v1.30.0 → v1.31.0

### 2026-10-03 (score 56, 0)

- [functional] Package version: v1.29.1 → v1.30.0

## MCP tools (8)

### `get_posture` (~82 tokens)

Summarize the environment: how many attack routes are open, how many are runtime-confirmed, how many assets and relationships are mapped, and which sensitive assets an attacker can currently reach. Start here to orient before enumerating anything: it also gives the names the other tools take - the sensitive assets routes_to_target accepts and the applications `app` arguments accept.

Output parameters:

- `applications` (array|null): The application names this environment knows: the values `app` arguments accept.
- `posture` (object|null): Counts for the whole environment.
- `riskSimulation` (object|null): The environment's overall risk, simulated over every route at once.

### `list_attack_paths` (~272 tokens)

List the ranked routes from internet exposure to a sensitive asset, highest triage priority first. `score` is the modelled end-to-end exploit probability and `priority` (0-100, banded P1/P2/P3) is the triage order that also weighs corroboration and target sensitivity. IMPORTANT: these probabilities are expert estimates, not measurements calibrated against real outcomes - call get_score_trust before presenting any of them as a probability, and prefer the ranking over the absolute values. It returns one page: when `nextOffset` is not null more routes exist, and passing it as `offset` returns the next ones. Routes an analyst has suppressed are listed too, marked `suppressed`.

Input parameters:

- `app` (string): Restrict to one application, by a name from get_posture's `applications`: a repository slug or the value of a cloud resource's `app` tag, e.g. 'payments-api'. The match is exact, and a name the envir…
- `limit` (integer): How many routes to return, priority-first.
- `offset` (integer): How many routes to skip from the top of the ranking: the `nextOffset` of the previous page. Leave it out for the first page.

Output parameters:

- `attackPaths` (array|null): The routes, highest priority first.
- `nextOffset` (integer|null): Pass as `offset` for the next page. Null when this page is the last.
- `offset` (integer): How many routes were skipped before this page.

### `explain_attack_path` (~143 tokens)

Give the full kill chain for one route: every hop, the relationship type, that hop's probability, where the probability came from (kev/epss/runtime are observed evidence; cvss/severity/heuristic are estimates), and the MITRE ATT&CK technique. Use this before explaining or acting on a route - the hop provenance is what tells you which parts of the story are evidence and which are assumption.

Input parameters:

- `path_id` (string, required): The `id` of a route from list_attack_paths. An id lasts as long as its route: one that has since been closed is reported as no longer open, and list_attack_paths gives the current ones.

Output parameters:

- `confidence` (number|null): How far the score can be trusted, 0-1: the mean confidence of its hops.
- `confidenceLabel` (string|null): The same as a band: high, medium or low.
- `correlatedHops` (boolean|null): True when two or more hops rest on the same kind of evidence.
- `id` (string|null): The route's id, as asked for.
- `mixtureScore` (number|null): The score averaged over attacker profiles, weighted by how likely each is.
- `nodes` (array|null): The assets on the route, entry point first, target last.
- `posteriorMean` (number|null): The score with the uncertainty of each hop and the mix of attacker capabilities taken into account, 0-1.
- `priority` (number|null): Triage priority, 0-100: the score blended with corroboration, target sensitivity and how many routes share the entry point. This is the order of the list.
- `priorityFactors` (array|null): The reasons behind the priority, human-readable.
- `priorityLabel` (string|null): Priority band: P1, P2 or P3. P1 is what to fix first.
- `priorityReason` (string|null): One sentence saying why the route is in its band, when a fact put it there; null when the blended number did.
- `profileScores` (array|null): The score against each attacker profile.
- `remediations` (array|null): Ways to close the route.
- `runtimeConfirmed` (boolean|null): True when a runtime alert sits on the route.
- `score` (number|null): End-to-end probability that an attacker completes the route, 0-1. A modelled estimate, not a measured rate: see get_score_trust.
- `scoreCiHigh` (number|null): High end of the same interval.
- `scoreCiLow` (number|null): Low end of the 90% credible interval around posteriorMean. A wide interval means the score rests on soft inputs.
- `scoreUpperBound` (number|null): The score if the hops fail or succeed together rather than independently: the weakest hop's probability.
- `steps` (array|null): The hops, in order. Each is one relationship an attacker crosses.
- `suppressed` (boolean|null): True when an analyst has triaged the route off the board (accepted risk, false positive). It still exists, but do not present it as open work.

### `routes_to_target` (~214 tokens)

Enumerate the k best distinct routes that reach a named sensitive asset. Answers 'how many ways in are there, and do they share a choke point' - which single-path views hide. Cutting a hop that every route traverses removes them all; cutting one that appears in a single route removes one. Each route comes with its hops, ready to hand to simulate_fix. It returns the best `k` and has no further page.

Input parameters:

- `from` (string): Optional entry point to start from, by name or node id. Omit to consider every internet-exposed entry point.
- `k` (integer): How many distinct routes to return, best first. Fewer routes come back when fewer exist.
- `target` (string, required): The sensitive asset to reach, by name or node id: a `name` under get_posture's crownJewels (e.g. 'account-admin (effective)'), or an `id` from search_assets. A target nothing reaches returns an empty…

Output parameters:

- `kShortestPaths` (array|null): The distinct routes to the target, most likely first. Empty when nothing reaches it.

### `list_fixes` (~139 tokens)

Return the remediation plan: the fewest changes that remove the most risk, choke points first, each with the share of critical-path risk it eliminates and how many routes it cuts. This is usually the right answer to 'what should we do' - a hundred routes typically collapse into a handful of changes.

Input parameters:

- `app` (string): Restrict to one application, by a name from get_posture's `applications`: a repository slug or the value of a cloud resource's `app` tag, e.g. 'payments-api'. The match is exact, and a name the envir…

Output parameters:

- `remediationPlan` (array|null): The changes, the one that removes the most risk first.

### `simulate_fix` (~155 tokens)

Ask what actually happens if specific relationships are cut: re-runs the whole simulation with those edges removed and reports how many routes disappear and how the compromise probability moves. This is the tool to reach for before recommending a change - it is a deterministic counterfactual over the real graph, not an estimate, so it settles 'would this help' instead of arguing about it. It changes nothing: the graph, the environment and every recorded decision stay as they are, so it needs no confirmation and can be repeated freely.

Input parameters:

- `cuts` (array, required): Relationships to remove. Take each from a step of explain_attack_path (its from/to), or pass the `cut` of one of that route's remediations as it is.

Output parameters:

- `whatIf` (object|null): The same environment with the cuts applied, compared with it as it is.

### `search_assets` (~167 tokens)

Full-text search across indexed assets and findings by name, CVE id, or keyword. Use it to resolve a name a human mentioned into the node ids the other tools take. It needs OpenSearch on the deployment: where that is off it answers with an error saying so, never with an empty list, and get_posture and list_attack_paths are then where names come from. It returns the best `size` matches and has no further page: narrow the query instead.

Input parameters:

- `query` (string, required): Text matched against asset and finding names, labels, ids, severities and CWEs, e.g. 'log4j', 'PII', 'CVE-2021-44228'.
- `size` (integer): Maximum number of matches to return, best match first.

Output parameters:

- `search` (array): The matches, best first. Empty when nothing matches.

### `get_score_trust` (~215 tokens)

Report how well the engine's probabilities have matched reality, measured against recorded red-team or BAS outcomes: the verdict (well-calibrated / calibrated-on-average / overconfident / underconfident / insufficient-data; calibrated-on-average means only the average matches, so no individual score may be quoted as a probability), the predicted-versus-observed rates, and what to do about the gap. Call this before quoting any score as a probability. If it reports insufficient-data, the numbers are expert estimates and must be presented as the model's own estimate, not as odds. It also reports discrimination - whether the score, and separately the triage Priority order, put confirmed paths above refuted ones (AUC with a 95% interval). Do not present the ranking as evidence of which path is most dangerous unless priorityDiscrimination reads 'discriminates'; 'insufficient-data' or 'indistinguishable-from-chance' means the order has not been shown to beat a coin, and must be said so.

Output parameters:

- `calibration` (object|null): The scores compared with the recorded red-team and BAS outcomes.
- `validation` (object|null): What happened to the routes that were tested.

## Diagnostics

Captured diagnostic sections: Provenance, Vulnerabilities. The full working is on the page: https://verifymcp.io/servers/luiacuaniello-perspectivegraph/ghcr-io-luiacuaniello-perspectivegraph#diagnostics

## Score history

- 2026-10-17: 62
- 2026-10-16: 61
- 2026-10-15: 61
- 2026-10-14: 22
- 2026-10-13: 22
- 2026-10-12: 22
- 2026-10-11: 22
- 2026-10-07: 22
- 2026-10-04: 57
- 2026-10-03: 56
- 2026-10-02: 56
- 2026-10-01: 55
- 2026-09-30: 55

## Common questions

### What is the PerspectiveGraph MCP server?

PerspectiveGraph is an MCP server listed in the public MCP registry as io.github.luiacuaniello/perspectivegraph. Read-only attack-path tools: reachable routes to sensitive assets, and what a fix would cut. This page covers its container image (ghcr.io/luiacuaniello/perspectivegraph).

### Is the PerspectiveGraph MCP server safe to use?

PerspectiveGraph scores 62 out of 100 on VerifyMCP. We recorded 1 known advisory against it as of 17 October 2026. Its build provenance is signed and verified. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the PerspectiveGraph MCP server expose?

PerspectiveGraph exposes 8 tools: get_posture, list_attack_paths, explain_attack_path, routes_to_target, list_fixes, and 3 more. Their descriptions and schemas cost roughly 1,387 tokens of context every time the server is loaded.

### Is the PerspectiveGraph MCP server still maintained?

PerspectiveGraph is still listed as active in the MCP registry. We last reached this channel on 17 October 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

### What licence is the PerspectiveGraph MCP server under?

PerspectiveGraph declares the Apache-2.0 licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.

## Links

- GitHub Container Registry: https://ghcr.io/luiacuaniello/perspectivegraph
- Repository: https://github.com/luiacuaniello/perspectivegraph
- Changelog RSS feed: https://verifymcp.io/servers/luiacuaniello-perspectivegraph/ghcr-io-luiacuaniello-perspectivegraph.xml
- Changelog JSON feed: https://verifymcp.io/servers/luiacuaniello-perspectivegraph/ghcr-io-luiacuaniello-perspectivegraph.json
- HTML version of this page: https://verifymcp.io/servers/luiacuaniello-perspectivegraph/ghcr-io-luiacuaniello-perspectivegraph
