Skip to main content
Glama
linked-archi-mcp

linked-archi-mcp

by linked-archi

linked-archi-mcp

An MCP server for read-only analysis of architecture knowledge graphs: ArchiMate, BPMN, C4/Structurizr, Backstage and LeanIX models converted to RDF by the Linked.Archi converters.

It is a thin adapter over the linked-archi-apm agent skills. The skills own everything that matters: the profile-resolved SPARQL template library, capability gating, read-only enforcement, provenance and the analysis patterns. This server runs their executables as subprocesses through the same versioned JSON contracts the skills use to call each other. It never imports their Python code and never re-implements a rule. That way the skills stay installable on their own, and the server can't drift from them.

A refusal is an answer, not an error. When the dataset's profile cannot support a template, the tool returns status: "refused" with the reason and an alternative. It never returns an empty result, which would read as "nothing exists".

{
  "status": "refused",
  "message": "Template 'core/dependents-direct' cannot run against profile 'linked-archi-qualified':\n  - capability 'direct_rel_triples' is False ...",
  "alternatives": ["core/dependents-qualified", "core/neighbours-qualified"]
}

What it exposes

Tool

Skill owner

What it does

dataset_connect

connect

Load the dataset and report quads, named graphs, and inputs that lost graph identity

dataset_candidates

connect

Candidate RDF files near a directory (only when client paths are allowed)

profile_list / profile_show

profile

Bundled profiles; one fully resolved profile

profile_recommend

profile

Name the profile that fits the dataset's shape

profile_verify

profile

Check a profile's claims against the dataset (verified or drift)

catalog_list / catalog_show

query

Templates gated by the profile; one template's parameters and does_not_prove

query_render

query

Template → SPARQL, without executing

query_run

query

Execute a template; result envelope with provenance and an evidence_id

query_batch

query

Several independent queries in one invocation: the dataset loads once

query_literal

query

Execute hand-written read-only SPARQL (updates, LOAD and SERVICE refused)

query_lint

query

Is this SPARQL read-only?

analyse_patterns / analyse_plan

analyse

Route a question to a pattern and get ordered steps (executes nothing)

analyse_bundle

analyse

Assemble cited results and findings into a reproducible bundle, rendered as Markdown

validate_run

validate

SHACL in-process, with target-class coverage

doctor

—

Skill locations and versions, dependencies, configured target

Every tool is annotated read-only. query_run results return at most max_rows rows, default 200. row_count always gives the full count, and rows_omitted says how many were cut.

Resources: each skill's SKILL.md and its references/**/*.md, under linked-archi://skills/<skill>/<path>. These documents explain the graph's conventions (qualified relationships, named graphs, the evidence model) and make a client a better analyst.

Prompt: investigate(question). It connects and verifies, plans, runs each step, and answers in three parts: facts, inference and unknowns.

Batching

Each tool call starts a skill process, and a local dataset is parsed once per process. query_batch runs many queries in one process, so the dataset is parsed once. On the committed sample dataset, five templates took 2.3 s as separate query_run calls and 0.5 s as one batch. On a large graph the gap widens, because the parse dominates. analyse_plan marks groups of steps that can run together as batches with status ready. Pass a manifest's queries to query_batch, giving each entry's set as parameters.

A batch is checked before any of it runs, so one refused entry refuses the whole batch. Steps that depend on an earlier result still go one at a time through query_run.

The skills' --store cached mode is also available (server flag --store), but it is not a free speed-up. It loads about 100× faster and queries about 3× slower, which helps many cheap lookups against a large unchanging graph and hurts aggregations. See the connect skill's references/store-modes.md.

Evidence and bundles

Every answered query carries an evidence_id. The server saves the query owner's envelope unchanged in a bounded, process-local store (the last 500, removed on exit). analyse_bundle takes the ids an answer rests on, in step order, plus findings split into the evidence model's five claim classes. It returns the bundle document and its Markdown rendering. The analyse skill refuses a bundle that mixes datasets or profiles, leaves out a claim class, or makes a claim that cites no step.

Source acquisition (la-source) is not exposed yet. It fetches over the network and writes a cache, which needs its own design for a server that can run over HTTP.

Related MCP server: LogicMap MCP Server

Install

Python 3.11+. The skills run as subprocesses of the server's own interpreter, so their dependencies are installed alongside it:

git clone --recurse-submodules https://github.com/linked-archi/linked-archi-mcp
cd linked-archi-mcp
pip install -e '.[all]'      # pyoxigraph for local RDF, pyshacl for validation

Where the skills come from

Resolution stops at the first match and never falls back:

  1. --skills-dir DIR

  2. $LINKED_ARCHI_SKILLS_DIR, the same variable the skills use to find each other

  3. the vendor/linked-archi-apm submodule, pinned to a released tag (currently v0.10.0)

The submodule gives development and CI a reproducible pin. To serve the skills you installed with APM instead, point the server at them:

LINKED_ARCHI_SKILLS_DIR=~/.claude/skills linked-archi-mcp --data graph.trig

doctor reports which tree was used and each skill's version. To move the pin:

git -C vendor/linked-archi-apm fetch --tags && git -C vendor/linked-archi-apm checkout vX.Y.Z

Run

stdio (local client)

linked-archi-mcp --data dist/merged.trig --profile linked-archi-default

Claude Code:

claude mcp add linked-archi -- linked-archi-mcp --data /abs/path/merged.trig

Or in any client's JSON config:

{
  "mcpServers": {
    "linked-archi": {
      "command": "linked-archi-mcp",
      "args": ["--data", "/abs/path/merged.trig"]
    }
  }
}

Over stdio, tool calls may name other files or endpoints with data / endpoint, since the client is your own agent.

Streamable HTTP

linked-archi-mcp http --port 8000 --data /srv/graph/merged.trig
# -> http://127.0.0.1:8000/mcp

Over HTTP the server is locked down by default:

  • Only the configured target. Tool calls can't name files, endpoints, shapes or profile paths, only bundled profile names. --allow-client-paths lifts this; use it only for a trusted client.

  • Token required off loopback. Binding a non-loopback address requires $LINKED_ARCHI_MCP_TOKEN, which clients send as Authorization: Bearer <token>. Behind a gateway that already authenticates, pass --insecure-no-auth instead.

  • DNS-rebinding protection. On by default for loopback binds. Add --allowed-host for the public host name when serving behind a proxy.

LINKED_ARCHI_MCP_TOKEN=$(openssl rand -hex 32) \
  linked-archi-mcp http --host 0.0.0.0 --allowed-host graph-mcp.example.org \
  --endpoint https://graph.example.org/sparql --profile linked-archi-merged

Options

Flag

Meaning

--data FILE (repeatable) / $LINKED_ARCHI_DATA

Local RDF; files merge into one dataset

--endpoint URL

HTTPS SPARQL endpoint instead

--profile

Default profile (linked-archi-default if omitted)

--catalog PATH (repeatable)

Trusted project query catalogue

--shapes FILE (repeatable)

Default SHACL shapes for validate_run

--store

memory / cached / readonly / refresh (local store mode)

--timeout-ms

Endpoint request deadline

--max-rows

Rows returned per result by default (200)

--run-timeout

Deadline for one skill invocation, seconds (120)

Develop

git submodule update --init
pip install -e '.[test]'
pytest

The tests drive the server in-process with the MCP client against the committed fixtures of the pinned skills.

License

Apache-2.0

Related MCP Connectors

Related MCP Servers