ai-context-nas
Provides tools for searching, reading, and writing notes in an Obsidian vault stored as Markdown files on the NAS.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ai-context-nasrecall the latest decisions on the API endpoints"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
AI context and memory on UGREEN NAS
Private, project-scoped context for Claude Code, Codex CLI, Hermes, and other MCP clients. The UGREEN app on Windows manages the separate NAS; the Linux containers run on the NAS.
Status: slim gateway and private HTTPS are running on the ARM64 UGREEN NAS using published Docker Hub images. Live Windows-to-NAS MCP, graph retrieval, access checks, note/memory persistence after a container stop/start, and a stopped-snapshot backup/restore passed. Astra reviewed the implementation. Per-app client setup, automatic backup scheduling, and a NAS reboot test remain. See validation.
Container editions
Public images are published under joweenflores/ai-context-nas on Docker Hub. Release status and verified architecture/digests are recorded in validation; a tag is usable only after publication is confirmed.
Tag | Includes | Use |
| Authenticated MCP, graph artifact retrieval, Markdown, SQLite ICM, backup tools | Default persistent gateway; import or separately index graphs |
| Everything in slim plus Graphify AST parsers and Git | One-shot indexing, repository sync, or an all-in-one gateway |
Both variants use the same data layout, authentication, and six MCP tools. Slim deliberately omits Graphify extraction and Git; it can query existing Graphify artifacts. Standard also uses a small Debian Python base; the edition difference is installed tools. TLS is a separate joweenflores/ai-context-tls:0.1.0 image. Upstream components retain their own licenses; MIT covers this project's code.
After preparing folders, use docker compose up --no-build --pull always -d gateway tls to pull images. Compose defaults to slim for gateway/maintenance and standard for the operations indexer. To run the standard gateway, set CONTEXT_VARIANT=standard in .env. Pin release digests for repeatable deployments. Local builds remain available with docker compose --profile operations build.
Related MCP server: obsidian-vault-mcp
What runs
Two persistent containers: the slim Python MCP gateway and Caddy for private HTTPS. The gateway reads real Graphify artifacts and invokes the real ICM CLI, serializing access to a separate SQLite database for each project. Graphify indexing is a short-lived operator job. The Obsidian vault is ordinary Markdown on the NAS; open it using Obsidian Desktop over an authenticated SMB share.
The gateway is useful here because native Graphify MCP does not provide the restricted vault tools or the combined project access policy. It exposes six tools: graph_query, note_search, note_read, note_write, memory_recall, and memory_store. Hermes is a separate client/container. No embeddings, vector service, extra memory database, Docker socket, or privileged containers are needed.
See architecture, verified software, security, and client configurations.
1. Discover the NAS
In the UGREEN Windows app, connect to your NAS and open its settings and Docker application. Record the model, CPU architecture, installed RAM, UGOS version, the free space in your intended shared folder, and existing Docker projects/ports. Windows SMB drive letters are not Linux storage paths.
If SSH is enabled for your account, run sh scripts/discover.sh on the NAS. It is read-only. Confirm Compose v2 or newer and Linux AMD64 or ARM64. Obtain the local path of a dedicated shared folder from UGOS storage/share details or the NAS terminal; do not assume /volume1. Existing reverse proxies, VPNs, and port conflicts must be reviewed before enabling access. Never replace an existing project called ai-context without inspecting it.
The NAS inspected through UGOS in Chrome is a DH4300 Plus with RK3588C ARM64, 8 GB RAM, and UGOS 1.20.0.0142. SSH was refused; deployment uses the authenticated Docker Projects interface and a dedicated folder in the writable Docker share. Existing arr-stack and cloudflared projects are left untouched. See validation for the current acceptance state. Other installations must discover their own paths, ports, and account ownership.
2. Prepare the project folder
Clone this public repository. Contributions are welcome under the MIT license; see CONTRIBUTING.md. Keep live data out of Git. You can prepare the folder on Windows, then transfer it using the UGREEN app, or prepare it directly on the NAS.
This preparation requires Python 3.12 and the locked dependencies. On a machine with Python and uv:
uv sync --frozenUse .venv/bin/python on Linux/macOS and .venv\Scripts\python.exe in PowerShell for the following python commands. Add that environment's Scripts/bin folder to PATH when indexing locally.
python -m scripts.manage init --uid 10001 --gid 10001
python -m scripts.manage register --project myapp --url https://github.com/OWNER/REPO.git
python -m scripts.manage client --name codex-windows --projects myapp --write
python -m scripts.manage client --name claude-mac --projects myapp --write
python -m scripts.manage client --name hermes --projects myappUse the UID/GID of your intended non-root NAS folder owner instead of 10001 when known. scripts/setup.sh detects the current NAS account; scripts/Setup.ps1 can prepare files from Windows. The initializer rejects existing nonempty folders that lack this project's marker. Registration is explicit and never scans NAS files.
Each client receives a different random token, stored locally under .secrets/CLIENT.env. clients.json stores token hashes, project allowlists, and write permissions. Do not paste those values into Git or chat. Retain the .secrets directory when transferring the deployment folder; it is intentionally excluded from the repository.
Edit .env for the NAS:
DATA_ROOT=./runtime
PUID=10001
PGID=10001
BIND_ADDRESS=10.10.10.2
HTTPS_PORT=8443
CONTEXT_HOST=context.nas.internal
MAX_CONTEXT_TOKENS=2000
BACKUP_KEEP=14The IP is an example based on discovered SMB mappings; confirm it still identifies your NAS. Relative ./runtime means local storage beside compose.yaml, provided that folder is on the NAS. An absolute DATA_ROOT must be a verified NAS Linux path. Initialization on Windows writes a Windows absolute path: change it before transferring. Set PUID/PGID to the NAS account with read/write access to the folder. Configuration files must be readable by that account, and .secrets/clients.json must be readable only by the owner. Runtime folders must belong to that UID/GID. UGOS ACLs also need to allow that account to access the vault through SMB.
The default bind address is loopback. Deliberately set the NAS's private IP after checking ports/firewall rules. There is no router port-forwarding step.
3. Build and start using UGOS Docker Projects
Copy the project folder to the dedicated NAS share, including
.env,.secrets,config, and initializedruntimefolders. Exclude your Windows.venv, caches, and.git.For UGOS's browser editor, use a rendered configuration containing the two runtime services, relative NAS folder mounts, explicit NAS UID/GID and private IP, and published image digests from images.json. Omit service
buildentries and the unusedx-runtimeextension; one-shot operations stay in the source Compose file. Do not put raw bearer tokens in the editor.Open Docker → Project in Chrome, select the dedicated project folder, and import or paste that deployment configuration. Redeploy → Pull the latest image → Deploy was verified on UGOS 1.20.0.0142. Confirm both gateway and TLS are running, then perform the remote checks below. The project uses two continuous containers; standard indexing remains a separate operation.
When NAS terminal/SSH access is available, the equivalent source-build workflow is:
docker compose config --quiet docker compose --profile operations build gateway tls indexer docker compose up -d gateway tls docker compose ps docker compose logs --tail 50 gateway tls sh scripts/health-check.shGateway should be healthy, and Caddy starts after it. An empty/invalid credentials file intentionally prevents startup. Actual readiness requires the functional checks below. The tested GUI deployment preserved the Compose secret mount and all runtime restrictions.
Building ICM from locked Rust source can temporarily require substantially more RAM and storage than running the stack. Build once on a compatible machine if the NAS cannot handle it, then transfer the built image using docker save/docker load. Test ARM64 natively before relying on it; multi-architecture base images do not prove every dependency builds there.
4. HTTPS and private client access
Provide private DNS or hosts-file resolution for context.nas.internal to the NAS private IP. Caddy creates a private CA and serves HTTPS at https://context.nas.internal:8443/mcp. Its root certificate is under runtime/tls/caddy/pki/authorities/local/root.crt. Export only that public root certificate and trust it on each client; protect root.key and the rest of the TLS directory. For Python-based clients, configure their trusted CA bundle as needed. Do not disable certificate verification.
Allow port 8443 only from your LAN/VPN clients in the NAS firewall. If Tailscale or another private VPN is already available, use its private IP and DNS. VPN setup and actual firewall rules are operator tasks until NAS access is available. The gateway itself has no published port. Caddy's admin endpoint is disabled.
Follow client configurations for Codex, Claude Code, Hermes, and generic MCP clients. Restart the gateway after changing .secrets/clients.json because credentials are loaded on startup. Revoke a client by removing its entry, then restart.
5. Register and refresh repository graphs
For a controlled NAS clone, execute synchronization on the NAS host, where Git credentials are managed by the NAS account:
python -m scripts.manage sync --project myapp
docker compose --profile operations run --rm --no-deps indexer python -m scripts.manage index --project myappIf the host has no Python, prepare/synchronize the clone on a trusted development machine and copy it into runtime/repositories/myapp, then run the indexer on the NAS. Never mount an arbitrary PC repository path on the NAS expecting it to exist. Do not embed GitHub tokens in clone URLs. Private SSH clones require separately configured host keys and credentials on the syncing host. The job only fast-forwards clean clones; it will stop on local changes or divergent branches. It does not initialize submodules or Git LFS.
The indexer gets source repositories read-only. It stages a sanitized source copy and excludes symlinks, Git metadata, dependency/build folders, .env*, keys, .secrets/.ssh/cloud credential folders, and common credential filenames. Graphify performs code-only AST extraction without LLM calls. Review code for embedded secrets before registering it: filename exclusions cannot identify secrets hardcoded inside source code. Large repositories may exceed the job's temporary storage/resource limit; split them or prebuild artifacts on a development machine.
Each successful index publishes graph.json atomically and records its SHA-256, source commit (or an explicit unknown/packed-ref marker), timestamp, and Graphify version. Graphify reuses eligible cached extraction output where its own incremental rules permit. The sanitized temporary root can cause full re-extraction; no incremental speedup is promised. Retrieval reports freshness so stale indexes can be recognized.
For a development-machine artifact:
# On the development machine, using Graphify 0.9.91:
graphify extract /path/to/repo --code-only --no-cluster --out /path/to/export
# Output is /path/to/export/graphify-out/graph.json (the extra folder is intentional).
python -m scripts.manage register --project imported-project
python -m scripts.manage import-graph --project imported-project --artifact /path/to/export/graphify-out/graph.jsonImport into the deployment's data root, then transfer that project's graph folder if importing on another machine. Raw Graphify nodes/edges and version-1 node-link exports are accepted; unsupported explicit schema versions fail. Imported source revision is marked unknown. Create client permissions for newly registered projects deliberately.
6. Knowledge and memory policy
Open runtime/obsidian as a vault through an authenticated NAS SMB share in Obsidian Desktop. There is no Obsidian server container. Templates are under obsidian/Templates and copied into the live vault during initialization. Place each project's notes in Projects/PROJECT/; gateway access remains inside that root, even if humans also use shared top-level Architecture/Development folders. Copy an approved shared convention into a project when that client needs it.
Agents create or update only Projects/PROJECT/Agents/NAME.md. Updates require the exact SHA-256 from note_read. Notes without the agent ownership frontmatter must be edited by a human. Avoid simultaneous SMB editing of the same agent-owned file: atomic replacement and optimistic hash checks detect ordinary conflicts, but SMB editors do not participate in the gateway lock.
Retrieve only context needed for the task. Prefer current code, verified documentation, active architecture decisions, relevant memories, then historical notes. Graph traversal, result count, query length, request bytes, and returned context are bounded. The gateway conservatively caps serialized result bytes using the configured token budget as a byte ceiling; it does not claim to implement a model-specific tokenizer. Truncated results are marked and retain source references.
memory_store requires a write-enabled token and verified=true. Store decisions/outcomes after checking them; do not capture every conversation. ICM enforces exact-content deduplication per topic. Each project has its own database, so project isolation does not depend on topic naming. Run one gateway worker/replica only; never attach another ICM service or CLI writer to these databases while the gateway is active.
7. Backups and recovery
Run sh scripts/backup.sh from a NAS scheduler during a quiet maintenance window. It briefly stops this stack, restarts it on exit, and retains the newest BACKUP_KEEP archives. Have humans close the SMB vault during the snapshot; the script cannot lock desktop editors. Operator index/import/backup jobs are mutually excluded by a lock file.
Example NAS cron entry, after replacing the path with the verified project location:
15 3 * * * cd /verified/local/path/ai-context-nas && sh scripts/backup.sh >> backups/schedule.log 2>&1This is an installation example; no NAS schedule has been created. Use UGOS's task scheduler if available and set its timezone deliberately. Archives include SQLite databases made using the SQLite Online Backup API, graph artifacts/freshness metadata, the vault, project registry/configuration, and TLS identity. They do not include repository clones, which can be synchronized again, or client tokens and .env. Keep encrypted off-device copies of those secrets and the pinned repo revision separately. Protect backup archives because they include memories and CA private keys.
To test restoration into a separate folder:
docker compose --profile operations run --rm --no-deps maintenance python -m scripts.manage restore --archive /backups/context-TIMESTAMP.tar.gz --target /data/restore-testRestoration verifies archive paths, file checksums, and SQLite integrity and refuses to replace nonempty data. To recover on another machine: obtain this pinned repository/image and secrets, initialize an empty local data root, restore into a new staging folder, stop gateway/TLS, copy restored graphs, icm, obsidian, and tls to the empty live root and restored config to the project config directory, set ownership, validate Compose, start, and run acceptance checks. Keep the previous data intact until those checks pass. Do not copy an active SQLite DB file directly.
8. Acceptance checks before relying on the NAS
Use the gateway from a real remote client to index a fixture, query a symbol and dependency, create/read an agent note, and store/recall a verified memory. Test invalid tokens, a read-only client's attempted write, and a request for another project. Refresh the source index and confirm the changed symbol. Restart the gateway container and verify the same note and memory remain. Restart the NAS in an approved window and repeat. Stop/start the gateway to test recovery. Back up, restore into staging, and recall a known restored memory using an isolated test instance.
Measure latency from the remote client, docker stats --no-stream, and du -sh runtime/*. These measurements must come from your NAS; local fixture timing is not a NAS performance estimate. Record results in validation.
Developer checks:
uv sync --frozen
# Set ICM_BINARY to a checksum-verified 0.11.4 native binary to enable real memory tests.
python -m pytest -q
docker compose --env-file .env.example config --quietSee troubleshooting for common failures. Preserve data and logs before upgrading pins; re-run tests and restoration after changes.
Available Tools
10 toolsget_communityB
Get all nodes in a community by community ID.
| Name | Required | Description | Default |
|---|---|---|---|
| community_id | Yes | Community ID (0-indexed by size) | |
| project_path | No | Absolute path to a project directory containing graphify-out/graph.json. Optional — defaults to the graph this server was started with. | |
| token_budget | No | Max output tokens |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It implies a read operation but does not mention side effects, permissions, output truncation, or what happens with the token_budget parameter.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence with no wasted words. It is appropriately sized for a simple retrieval tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool has no output schema and no annotations, the description is minimally sufficient but leaves gaps. It does not explain what a 'community' represents, how the output is structured, or how token_budget affects the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all three parameters (community_id, project_path, token_budget) are documented in the schema itself. The description only references community_id and adds no meaningful semantics beyond the schema, which is the baseline expectation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Get') and resource ('all nodes in a community') plus the required key ('by community ID'). It is clear and actionable, but it does not differentiate this tool from siblings like get_neighbors or query_graph that might also return graph nodes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit guidance on when to use this tool versus alternatives, nor any exclusions or prerequisites. The usage context is only implied by the tool name and description.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_neighborsC
Get all direct neighbors of a node with edge details.
| Name | Required | Description | Default |
|---|---|---|---|
| label | No | ||
| node_id | No | Alias for label (node id) | |
| project_path | No | Absolute path to a project directory containing graphify-out/graph.json. Optional — defaults to the graph this server was started with. | |
| token_budget | No | Max output tokens | |
| relation_filter | No | Optional: filter by relation type |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses that edge details are returned, but says nothing about read-only nature, truncation behavior from token_budget, what happens on missing nodes, or permissions. For a parameterless-required traversal tool with zero annotation coverage this is a real gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One front-loaded sentence with no filler. It is efficient, though the brevity borders on under-specification rather than pure conciseness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No annotations and no output schema, with 5 parameters whose interactions (label vs node_id alias, default graph resolution, token_budget truncation) go unexplained in the description. An agent can guess at invocation but cannot predict return shape limits or edge-case behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 80%, so the schema already documents label, node_id, project_path, token_budget, and relation_filter. The description adds only the implied notion of 'direct' traversal depth and edge detail richness, and does not clarify the label vs node_id aliasing ambiguity — but baseline 3 is warranted given high schema coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Get') and resource ('all direct neighbors of a node'), plus the payload characteristic ('with edge details'). It is distinguishable from siblings like get_node (single node) and shortest_path (multi-hop), though it doesn't explicitly contrast with query_graph.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance on when to use this versus get_node, query_graph, or shortest_path, and no exclusions or prerequisites. The agent must infer that 'direct' means depth-1 traversal from the name alone.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_nodeC
Get full details for a specific node by label or ID.
| Name | Required | Description | Default |
|---|---|---|---|
| label | No | Node label or ID to look up | |
| node_id | No | Alias for label (node id) | |
| project_path | No | Absolute path to a project directory containing graphify-out/graph.json. Optional — defaults to the graph this server was started with. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full disclosure burden. 'Get' implies a read, but it says nothing about behavior when a node is not found, whether the result is cached or scoped, or how the project_path default interacts with the lookup.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with no wasted words. It is efficiently sized, though its brevity is partly a symptom of thin content rather than deliberate compression.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no annotations and no output schema, the description should explain what 'full details' actually contains and how project_path changes the target graph. Neither is covered, leaving an agent unable to predict the response shape.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents all three parameters. The description's 'by label or ID' merely echoes what the schema says and adds no syntax, format, or precedence detail beyond it.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get full details for a specific node') and indicates the two lookup keys (label or ID). It does not explicitly differentiate from siblings like query_graph or get_neighbors, but the single-node detail scope is clear enough to infer.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No explicit when-to-use or when-not-to-use guidance, and no mention of alternatives such as query_graph for search or get_neighbors for traversal. Usage is only implied by 'for a specific node'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_pr_impactA
Get detailed graph impact for a specific PR: which files it changes, which knowledge-graph communities are affected, and how many nodes are touched. Use this to assess merge risk or check for overlap with your current work.
| Name | Required | Description | Default |
|---|---|---|---|
| repo | No | GitHub repo (owner/repo). Defaults to current repo. | |
| pr_number | Yes | PR number to analyse | |
| project_path | No | Absolute path to a project directory containing graphify-out/graph.json. Optional — defaults to the graph this server was started with. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so description carries full burden. It describes the tool's function but does not disclose side effects, rate limits, or whether it is read-only. More behavioral context needed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with key information. No wasted words, efficient and clear.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema and 3 parameters, description covers main output aspects (files, communities, nodes). Could benefit from more detail on return format, but sufficient for core purpose.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline 3. Description does not add extra meaning to parameters beyond what schema already provides. No additional detail on defaults or usage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool gets detailed graph impact for a specific PR, listing what it provides (files changed, communities affected, nodes touched). It distinguishes from siblings by focusing on PR impact rather than general graph queries.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states 'Use this to assess merge risk or check for overlap with your current work,' giving clear context. Does not explicitly mention when not to use, but siblings provide alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
god_nodesC
Return the most connected nodes - the core abstractions of the knowledge graph.
| Name | Required | Description | Default |
|---|---|---|---|
| top_n | No | ||
| project_path | No | Absolute path to a project directory containing graphify-out/graph.json. Optional — defaults to the graph this server was started with. | |
| exclude_hubs_percentile | No | Suppress nodes whose degree exceeds this percentile (0-100) of the degree distribution, matching cluster()'s hub exclusion |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. Beyond implying a read-only ranking by connectivity, it discloses nothing about ordering, how many nodes come back, whether degrees are returned, or what happens when the graph is empty — all material for an unannotated tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One front-loaded sentence with no filler. It is efficient, though its brevity is under-specification rather than true economy — the length is fine but the content budget is underused.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no annotations, no output schema, and three parameters (one undocumented in the schema), the description should say more about result shape and the hub-exclusion behavior. As written an agent knows the gist but not enough to invoke it confidently or interpret the output.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 67%, and the description mentions no parameters at all. Notably top_n has no schema description and the description doesn't compensate; 'most connected' vaguely relates to exclude_hubs_percentile but doesn't explain that it suppresses top-degree nodes.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Return the most connected nodes') plus an interpretive gloss ('the core abstractions of the knowledge graph'), which tells an agent what kind of result to expect. It doesn't explicitly contrast with siblings like graph_stats or query_graph, but the resource is distinct enough to separate it.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: an agent can infer this is for getting a high-level map of the graph's hubs. There is no statement of when to prefer this over graph_stats or query_graph, and no mention of prerequisites or when results are misleading (e.g. dense graphs).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
graph_statsA
Return summary statistics: node count, edge count, communities, confidence breakdown.
| Name | Required | Description | Default |
|---|---|---|---|
| project_path | No | Absolute path to a project directory containing graphify-out/graph.json. Optional — defaults to the graph this server was started with. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must fully disclose behavior. It states it returns read-only summary statistics, but lacks details on performance (e.g., costly for large graphs), side effects, or prerequisites (e.g., graph must be loaded). This is insufficient for a tool with zero annotation coverage.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence that is concise and front-loaded with the verb 'return'. Every word adds value, no filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema and no annotations, the description lists four return fields but omits details like data format, ordering, or whether the confidence breakdown is per community or overall. It is minimally complete but could be richer.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the parameter 'project_path' is well-described in the schema. The tool description adds no additional semantic meaning beyond the schema, but since the schema already covers it, a baseline score of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description uses verb 'return' and lists specific items (node count, edge count, communities, confidence breakdown), clearly distinguishing it from siblings like 'get_community' (returns a specific community) or 'shortest_path' (pathfinding). It precisely states the tool's purpose.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no guidance on when to use this tool vs alternatives (e.g., 'get_community' for a specific community). It is implied that for summary statistics one uses this tool, but explicit when-to-use or when-not-to-use is missing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_prsA
List open GitHub PRs with CI status, review state, and graph impact (which communities each PR touches, blast radius). Use this before starting work to check if a PR already covers the area you're about to change.
| Name | Required | Description | Default |
|---|---|---|---|
| base | No | Base branch to filter PRs by (auto-detected if omitted) | |
| repo | No | GitHub repo (owner/repo). Defaults to current repo. | |
| project_path | No | Absolute path to a project directory containing graphify-out/graph.json. Optional — defaults to the graph this server was started with. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so description carries full burden. Mentions the data returned (CI status, review state, graph impact) but does not state that it is a read-only operation or disclose any side effects, auth requirements, or rate limits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no waste. First sentence clearly states purpose and outputs; second sentence gives usage context. Front-loaded and efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema and no annotations, description provides a reasonable overview. However, it lacks explanation of the output structure for 'graph impact' and does not specify pagination or filtering beyond parameters. Adequate but could be more complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so baseline is 3. Description adds minimal value beyond schema descriptions; it does not provide additional parameter details like default behavior for omitted parameters or format expectations.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description explicitly states the tool lists open GitHub PRs with CI status, review state, and graph impact. Action verb 'List' and specific resource 'open GitHub PRs' along with key data points, distinguishing it from siblings like get_pr_impact and triage_prs.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit usage context: 'Use this before starting work to check if a PR already covers the area you're about to change.' Does not explicitly mention when not to use or list alternatives, but the guidance is clear and actionable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
query_graphB
Search the knowledge graph using BFS or DFS. Returns relevant nodes and edges as text context.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | bfs=broad context, dfs=trace a specific path | bfs |
| depth | No | Traversal depth (1-6) | |
| question | Yes | Natural language question or keyword search | |
| project_path | No | Absolute path to a project directory containing graphify-out/graph.json. Optional — defaults to the graph this server was started with. | |
| token_budget | No | Max output tokens | |
| context_filter | No | Optional explicit edge-context filter, e.g. ['call', 'field'] |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so the description must carry the burden. It states the tool returns 'relevant nodes and edges as text context' but does not explain output structure, side effects, or required permissions. The description adds limited behavioral context beyond the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence, which is concise but too brief for a 6-parameter tool. It front-loads the main purpose but omits important details, making it borderline underspecified.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (6 params, no output schema, no annotations) and multiple siblings, the description is incomplete. It does not explain what 'text context' looks like, how to interpret results, or provide usage examples. Sibling tools like graph_stats are not differentiated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so baseline is 3. The tool description adds no extra meaning over the schema; it repeats the mode choices but without enriching parameter semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool searches a knowledge graph using BFS or DFS, distinguishing it from siblings like get_node (single node retrieval) and shortest_path (path-specific). The verb 'Search' and resource 'knowledge graph' are specific.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No explicit guidance on when to use BFS vs DFS, nor compared to alternative tools like get_neighbors or shortest_path. The description implies use for traversal but lacks contextual decision rules.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shortest_pathA
Find the shortest path between two concepts in the knowledge graph. Follows stored edge direction by default; set undirected=true to ignore it.
| Name | Required | Description | Default |
|---|---|---|---|
| source | Yes | Source concept label or keyword | |
| target | Yes | Target concept label or keyword | |
| max_hops | No | Maximum hops to consider | |
| undirected | No | Ignore stored edge direction when searching | |
| project_path | No | Absolute path to a project directory containing graphify-out/graph.json. Optional — defaults to the graph this server was started with. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden. It usefully discloses the default directed-traversal behavior and the undirected escape hatch, but says nothing about the return shape (path vs. node list), behavior when no path exists, or traversal cost limits beyond max_hops in the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences, zero filler, with the core purpose front-loaded and the behavioral modifier second. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 5-parameter read tool with no annotations and no output schema, the definition covers purpose and the direction flag but leaves the result format and no-path behavior unstated, which an agent would need to call and interpret it confidently.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all five parameters are already documented in the schema; the description only re-explains undirected, which the schema already covers. Baseline 3 applies when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Find the shortest path between two concepts in the knowledge graph'), which is unambiguous and distinct from siblings like get_neighbors or query_graph. It does not explicitly name which sibling to prefer in which situation, but the operation itself is clearly scoped.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage ('between two concepts') and explains the undirected toggle condition, but never says when to choose this over get_neighbors or query_graph, nor any preconditions (e.g., concepts must exist in the graph). Usage is inferable, not stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
triage_prsA
Return all actionable open PRs (correct base, not stale) with full graph impact data so you can reason about review priority, merge order, and conflict risk. Call this when the user asks 'what PRs should I review?' or 'what's ready to merge?'
| Name | Required | Description | Default |
|---|---|---|---|
| base | No | Base branch to filter PRs by (auto-detected if omitted) | |
| repo | No | GitHub repo (owner/repo). Defaults to current repo. | |
| project_path | No | Absolute path to a project directory containing graphify-out/graph.json. Optional — defaults to the graph this server was started with. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden. It explains the filtering criteria (correct base, not stale) and mentions graph impact data. However, it doesn't define 'actionable' or 'stale' precisely, nor does it disclose any side effects, rate limits, or output structure details.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description consists of two sentences: first sentence states purpose and value, second sentence gives usage guidance. It is front-loaded, concise, and contains no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description lacks output schema, so it should provide more detail on the return value. While it mentions 'full graph impact data' and reasoning use cases, it does not specify the structure or fields included, leaving the agent partially informed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already describes all three parameters (base, repo, project_path) with clear defaults. The tool description does not add additional parameter-level semantics beyond what the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses specific verbs ('return') and a clear resource ('actionable open PRs with graph impact data'). It distinguishes from sibling tools like list_prs (raw list) and get_pr_impact (single PR) by emphasizing triage and priority reasoning.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to call the tool ('when user asks what PRs to review or what's ready to merge'). It provides clear context but does not explicitly mention when not to use it or which sibling alternatives to choose.
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.
10 tool updates
v0.1.0- First observed
get_community - First observed
get_neighbors - First observed
get_node - First observed
get_pr_impact - First observed
god_nodes - First observed
graph_stats - First observed
list_prs - First observed
query_graph - First observed
shortest_path - First observed
triage_prs
TDQS
Scored across 10 tools
Most tools have clearly distinct graph or PR purposes, such as get_node vs get_neighbors vs shortest_path. The main overlap is between list_prs and triage_prs, both listing PRs, though triage_prs is narrower and adds priority-oriented impact data. get_pr_impact is distinct by targeting a specific PR.
All names use snake_case, but conventions are mixed: some are verb_noun (query_graph, get_node, list_prs), while others are noun phrases or specialized labels (god_nodes, graph_stats, shortest_path). The pattern is readable but not consistently action-first.
Ten tools is well-scoped for a read-only knowledge-graph context and PR triage server. Each tool covers a distinct query or inspection need without excessive surface area.
The surface covers graph search, node details, neighbors, communities, statistics, paths, and PR impact/triage well. A minor gap is the lack of a list_communities operation, making community IDs less discoverable before calling get_community.
Maintenance
Related MCP Connectors
Private-by-default, local-first memory/context/task orchestrator for MCP apps and agents.
OAuth-protected, read-only-by-default MCP server for provenance-labeled QuillCaddie project memory.
Personal knowledge graph as an AI memory layer over MCP - read, save, and link your memories.
Agent-native notes, tasks, dev-docs, vaults, sync & handoffs. MCP + OpenAPI dual surface.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceSelf-hosted service providing unified memory search and write operations across file-based memory, vector embeddings, and the Graphiti temporal knowledge graph, accessible via HTTP API or MCP stdio transport.3MIT
- AlicenseNot gradedqualityDmaintenanceSelf-hosted MCP server for private Obsidian vaults on GitHub, exposing tools to search, read, write, and analyze Markdown notes and their link graph.MIT
- FlicenseNot gradedqualityBmaintenanceProvides self-hosted, versioned project memory with full-text and vector search, enabling search, retrieval, upsertion, and history management of project entries via MCP tools.-
- AlicenseBqualityCmaintenanceProvides AI agents with durable, searchable project memory, session notes, skills, and bounded context packs over MCP while leaving orchestration to the client.15MIT