MCP Integration
September 5, 2026 · View on GitHub
Use GNO as a local MCP server for Claude Desktop, Cursor, Zed, Windsurf, Amp, Raycast, and other AI clients that need grounded access to your own documents.
Full specification: See spec/mcp.md for complete tool and resource schemas.

Cancellation
Protocol request cancellation and connection loss propagate into each request's retrieval, expansion, generation and verification stages, including remote HTTP inference. Canceled requests cannot publish a late successful or partial result. Queued cancellation removes only the caller's work; an active native operation retains capacity until settlement or controlled child exit.
An accepted asynchronous indexing/embedding job owns its lifetime after returning a job ID. Closing the accepting transport does not cancel that persistent job. Owner-initiated job cancellation stops further inference retries and checkpoint publication; interrupted work is reported as failed under the existing job schema, with unfinished backlog left pending. Finite shutdown orchestration is a separate lifecycle boundary.
Filtered retrieval limits
Search candidate budgets apply after supported owner filters (collection, path, tags, dates, author, categories and exclusions). Semantic retrieval and hybrid retrieval also select matching-language chunks before their budgets; standalone lexical language remains reserved. A nearby out-of-scope vector cannot displace an eligible hit. Caller scope intersects user filters; empty allowlists deny all. Whole-document exclusions inspect every chunk, including other languages; hybrid exclusions also inspect author and category metadata.
Results can remain shorter than the requested limit after score thresholds, deduplication or limited eligible coverage. Ranking/fusion and output schemas are unchanged. This correction does not change independent natural-language memory recall matching.
Project hints and trust
Retrieval tools accept optional projectHints arrays with at most 16 strings.
Hints are opaque, untrusted caller metadata: MCP does not interpret them as
paths, probe the filesystem, reflect them in results, or apply a project
affinity boost. This deliberate zero-affinity behavior differs from trusted
local CLI cwd/--project-root resolution. Omit the field for byte-compatible
existing behavior. MCP diagnose therefore preserves the closed
query-diagnose@1.0 payload and omits affinity; only trusted local CLI
diagnose can emit the closed, redacted query-diagnose@1.1 affinity metadata.
Overview
MCP (Model Context Protocol) allows AI assistants to access external tools and
resources. GNO registers 34 tools in default read-only mode and 53 when writes
are explicitly enabled (the default full profile; the opt-in core profile
advertises 7 read tools plus 2 write tools, see Tool Profiles):
- Tools (read): gno_context, gno_context_verify, gno_ask, gno_recall, gno_search, gno_vsearch, gno_query, gno_query_diagnose, gno_get, gno_section, gno_multi_get, gno_peek, gno_status, gno_audit, gno_egress_policy_get, gno_egress_check, gno_egress_audit_list, gno_egress_audit_show, gno_egress_audit_status, gno_changes, gno_diff, gno_impact, gno_trace_list, gno_trace_show, gno_list_tags, gno_links, gno_backlinks, gno_similar, gno_graph, gno_graph_query, gno_graph_neighbors, gno_graph_path
- Tools (write, opt-in): gno_egress_policy_set, gno_egress_audit_delete, gno_egress_audit_purge, gno_trace_label, gno_trace_export, gno_trace_delete, gno_trace_purge, gno_remember, gno_capture, gno_add_collection, gno_sync, gno_embed, gno_index, gno_remove_collection, gno_clear_collection_embeddings, gno_create_folder, gno_rename_note, gno_move_note, gno_duplicate_note
- Tools (jobs, read): gno_job_status, gno_list_jobs
- Resources: Access documents via
gno://collection/path
Design: Retrieval First, Verified Synthesis by Explicit Opt-In
GNO's raw MCP tools remain retrieval-focused: they return search results,
exact evidence, and document content for the client LLM to synthesize.
gno_ask is the one explicit synthesis surface. It rejects calls unless
verify is the literal boolean true, builds a closed Context Capsule,
generates against only that retained evidence, classifies every substantive
claim, and abstains unless support coverage is 100%. Write tools enable
collection management but do not perform synthesis.
Why keep raw retrieval primary? Claude, Codex, and other AI agents may use more capable models and need direct control over evidence selection. An additional local synthesis call can be:
- Slower (extra LLM call)
- Lower quality (local models < Claude/GPT-4)
- Redundant (the client LLM can synthesize directly)
Intended workflow:
- Client LLM uses
gno_contextfor one bounded evidence handoff, orgno_queryplus bounded reads for manual retrieval. - Client LLM synthesizes directly, or calls
gno_askwith literalverify: truewhen it needs a closed-evidence verification contract. - The caller retains exact evidence spans and explicit gaps either way.
Verified synthesis classifies support against one Capsule and its recorded freshness state. It does not prove that the retained corpus is complete, that the sources are true, or that a supported claim is universally factual.
Agent Retrieval Playbook
For tasks that need a complete, bounded evidence handoff, start with
gno_context. It compiles exact line spans, provenance hashes, coverage gaps,
omission counts, and capability fallbacks into one deterministic Capsule. Use
gno_context_verify before reusing a saved Capsule. GNO does not save Capsules
implicitly.
Balanced and thorough gno_context, gno_query, and gno_ask retrieval use
bounded graph expansion by default. Set graph: false or noGraph: true, or
use fast mode, for an explicit graph-free request.
For gno_context, MCP text is the compact, versioned
gno-context-agent-v1 projection delivered once to the model. The complete
canonical Capsule remains in structuredContent for application clients. The
projection retains exact spans, gaps, budget state, retrieval fingerprints,
model identities, and exact omission totals/reason counts. Its documented
compact tuples avoid repeating descriptive field names; absent sparse omission
reasons mean zero. It also retains adversarially escaped title/heading metadata,
explicit egress state, context-to-evidence bindings, and configured guidance
under an untrusted_data/hard_delimited marker. Active-token Capsules carry
their estimator and tokenizer fingerprint with the exact used-token count. The
complete omission audit remains in structuredContent.
Hosts that expose structuredContent to the model must account for it in
addition to text; GNO's promotion benchmark targets hosts that expose the MCP
text content and keep structured data application-side.
For interactive lookup and manual retrieval control, start with gno_query. It
combines BM25, vector search, and reranking, then returns uri, docid,
snippets, and line anchors for follow-up retrieval.
Use the narrower tools when the request is explicit:
| Tool | Use When | Follow-up |
|---|---|---|
gno_context | One deterministic, token-budgeted evidence bundle for an agent goal | Cite exact evidence spans; state unresolved gaps |
gno_context_verify | Reusing a saved Capsule after sources or runtime configuration may have changed | Rebuild only when the receipt reports drift |
gno_ask | A local answer whose claims must be classified against one closed Capsule | Send literal verify: true; retain gaps/abstention |
gno_search | Exact phrases, filenames, identifiers, error messages, known symbols | gno_get around result line |
gno_vsearch | Conceptual similarity where exact wording may differ | gno_get or gno_multi_get top results |
gno_query | Default choice; mixed lexical + semantic + reranked retrieval | gno_multi_get for top URIs |
gno_query_diagnose | Important target doc is missing or you need stage-by-stage retrieval evidence | Adjust filters/query mode, then retry gno_query |
gno_get | One known gno:// URI, #docid, or collection/path | Use fromLine + lineCount first |
gno_section | Create/resolve a durable section target; cite only exact/recovered | Follow citation lines with gno_get |
gno_multi_get | Batch several top result refs or glob-matched docs | Keep maxBytes bounded |
gno_peek | Cheap counts, backlog, recent files, or whether gno serve --detach is up | Same peek@1.0 snapshot as gno peek --json |
gno_status | Results look stale, vector search fails, or embeddings may be missing | Run write-enabled gno_index or gno_embed |
With private retrieval tracing enabled, gno_search, gno_vsearch,
gno_query, gno_get, gno_context, and gno_ask return the random receipt identity in
top-level _meta.gno.retrievalTrace.traceId. Model-visible content and
structuredContent stay unchanged. Pass that value as optional traceId to
gno_get to link the exact opened line range to the original retrieval.
Disabled tracing omits _meta and performs no trace work.
Use gno_trace_list for metadata-only history and gno_trace_show for one
explicit bounded detail read. History never includes replay query/goal text.
The following mutations are available only when the server starts with
--mcp-enable-write or gateway.enableWrite: true:
gno_trace_label: explicitrelevant,irrelevant, ormissing_expectedfeedbackgno_trace_export: deterministic aggregateagentic-receiptgno_trace_delete: one trace plus owned recordsgno_trace_purge: every local receipt; requiresconfirm: true
HTTP MCP rejects those tool names before dispatch when writes are disabled. Bearer authentication alone never authorizes them. Handlers also enforce the write flag, so direct or future transports cannot bypass the boundary. Relevant/irrelevant targets must match recorded evidence; missing-expected accepts a content-free document identity. Export rejects open/missing traces and preserves all terminal outcomes without implicit negative feedback.
Collection boundary tools use the same policy contract on every transport:
gno_egress_policy_getshows effective policy, provenance, durable revision, and diagnostic version.gno_egress_checkexplains an exact action/destination/caller/content-class decision without performing the action.gno_egress_policy_setis write-enabled; relaxation requires the exact collection, current policy, durable revision, target policy, and explicit acknowledgement. Stale and replayed confirmations fail closed.gno_egress_audit_list|show|statusinspect content-free local receipts;gno_egress_audit_delete|purgeare write-enabled local cleanup controls.gno_auditruns an offline read-only workspace integrity report; it is not an egress receipt-management tool.
Collection policy never replaces bearer authentication or the MCP write flag. Trace export resolves exact trace lineage and checks policy before creating or reusing an export receipt.
Source availability (collections[].sourceAvailability: any | local) is
configured on the collection and is not an egress tool. Sync/index job
receipts may include CLOUD_PLACEHOLDER, CLOUD_PARTIAL, DATALESS_DIRECTORY,
or SOURCE_AVAILABILITY_* codes under local mode. Distinct from
egressPolicy. Evidence-qualified for tested macOS File Provider layouts only
(see Configuration).
gno_audit
gno_audit returns the same versioned report as CLI gno audit for links,
provenance, freshness, or all. Optional collections, paths, and tags
scope the scan. maxFindings is 1–1000; exact totals and truncation remain in
the report. maxAgeDays, orphanRoots, and orphanIgnorePrefixes are explicit
run policy, not persisted configuration.
The tool is annotated read-only, destructive-false, and idempotent, and the implementation independently performs only query-only SQLite and source reads. Cancellation returns partial/inconclusive evidence. Missing or unreadable sources are unavailable—not healthy. Stable finding IDs can be diffed across runs, but GNO stores no audit baseline and offers no repair/apply action in v1. The response can contain local paths/headings/evidence, so apply the same local disclosure judgment as other retrieval tools.
Trace management intentionally keeps three independent decisions:
| Operation | Bearer/transport auth | MCP write opt-in | Collection destination policy |
|---|---|---|---|
| Local list/show | Transport-dependent | No | No network export |
| Local label/delete/purge | Transport-dependent | Yes on MCP | No network export |
| Loopback aggregate export | Loopback admission | Yes on MCP | Local-file/process allowed |
| LAN or remote aggregate export | Required | Yes | lan or remote as applicable |
An authenticated caller with writes disabled receives WRITE_DISABLED before
trace lookup or policy evaluation. A write-enabled caller whose destination is
outside the current trace lineage policy receives content-free
EGRESS_DENIED; no export manifest is created or reused. Loopback REST
inspection, explicit label/delete, and full purge remain local controls and do
not grant permission for a later LAN or remote export. Missing IDs and denials
never echo trace IDs, queries, goals, evidence references, local paths, target
URLs, or receipt content.
For ambiguous terms, pass intent instead of stuffing extra words into query:
{
"query": "python",
"intent": "programming language, not the animal"
}
For structured retrieval, use queryModes to combine typed strategies:
{
"query": "API rate limiting",
"queryModes": [
{ "mode": "term", "text": "token bucket" },
{ "mode": "intent", "text": "HTTP middleware throttling" },
{
"mode": "hyde",
"text": "A design note describing request throttling with per-client refill windows."
}
]
}
When a search result includes line, fetch a bounded range first:
{
"ref": "gno://work/service.ts",
"fromLine": 120,
"lineCount": 40
}
Use gno_multi_get after search/query when several top documents are needed. Pass the result uri or docid values as refs, and cap maxBytes to avoid flooding the client context.
Structured gno_search, gno_vsearch, and gno_query results may also contain
context. This is user-configured guidance resolved for that exact uri and
docid, ordered global → collection → broad-to-specific path prefix. Apply it
when interpreting the result, but cite the retrieved source content—not the
guidance—as evidence. Results without matching configuration omit the field.
Security Model
Write Tool Gating
Write tools are disabled by default. Enable with:
gno mcp --enable-write
# or
GNO_MCP_ENABLE_WRITE=1 gno mcp
Without this flag, the 34 read-only retrieval, verified-synthesis, memory
recall, trace, graph, egress, status, and job-inspection tools are available.
Enabling writes adds 19 mutation tools (including gno_remember), for 53
total. Those counts describe the default full profile; see
Tool Profiles for the slim core surface.
Tool Profiles
Every advertised tool definition is context an agent pays for each session.
The core profile advertises only the tools the
playbook routes to; full (the default) keeps
today's whole surface, byte-for-byte.
| Profile | Read tools | With --enable-write adds |
|---|---|---|
full (default) | all 34 | all 19 write tools |
core | gno_query, gno_search, gno_get, gno_multi_get, gno_context, gno_changes, gno_recall (7) | gno_capture, gno_remember |
Write tools stay behind --enable-write in both profiles; a profile never
widens the write gate. gno_job_status is not in core because neither core
write is asynchronous. Both profiles speak both protocol revisions
(2025-11-25 and 2026-07-28) on stdio and the resident HTTP endpoint; see
Resident HTTP Transport for how a client's
revision is negotiated.
The two profiles also describe their tools differently. full serves the
original description strings unchanged. core serves each of its nine tools a
short micro-instruction that says when to call it, what it runs, and what
comes back, with the bounds the caller has to respect (line anchors for
gno_get, maxBytes for gno_multi_get, the 8-fact / 512-token gno_recall
budget, the separate embedding step after gno_capture). The descriptions
match the retrieval order in the playbook:
gno_query first, gno_search for exact words, gno_get /
gno_multi_get to read, gno_context for one bounded evidence handoff,
gno_changes for what changed, gno_recall / gno_remember for facts. Input
schemas are identical across profiles.
# stdio
gno mcp --tool-profile core
gno mcp --tool-profile core --enable-write
# resident gateway (serve or daemon)
gno daemon --mcp-tool-profile core
# ~/.config/gno/index.yml - resident gateway default
gateway:
toolProfile: core
Precedence is CLI flag, then gateway.toolProfile, then full. The profile
is read when the listener starts; restart gno mcp, gno serve, or
gno daemon to change it. Tools outside the active profile are unknown to the
server (JSON-RPC -32602), not hidden.
The default stays full for now: core is opt-in, and flipping the default
is a separate follow-up that waits on dogfood evidence (agents running on
core across real sessions with the playbook's routing holding). Pick the
profile once per harness at install time with
gno mcp install --tool-profile core; the generated stdio registration then
starts gno mcp --tool-profile core (plus --enable-write when requested),
and gno mcp status reports the profile each registration carries.
Collection Root Validation
gno_add_collection rejects dangerous paths:
/(root filesystem)~alone (entire home directory)- System directories (
/etc,/usr,/bin,/var,/System,/Library) - Hidden config dirs (
~/.config,~/.local,~/.ssh,~/.gnupg)
Client Approval
MCP clients prompt for tool approval. Review parameters before confirming write operations.
Resident HTTP Transport
gno serve and gno daemon expose the same tools and resources at /mcp
over Streamable HTTP. Stdio remains supported for clients configured with
gno mcp. Both transports speak two protocol revisions from one tool
registry: MCP 2025-11-25 clients (the initialize handshake, stateful
sessions over HTTP) keep working unchanged, and MCP 2026-07-28 clients
negotiate natively (server/discover, per-request _meta envelope,
sessionless HTTP - no Mcp-Session-Id). Modern requests must carry the
MCP-Protocol-Version and Mcp-Method headers (Mcp-Name on tools/call
and resource reads); unsupported revisions, missing or mismatched headers, and
malformed envelopes are rejected with a 400 JSON-RPC error rather than
served. Both transports are served by @modelcontextprotocol/server 2.x;
advertised tool schemas carry the JSON Schema 2020-12 $schema stamp. The
exact routing and error table is in spec/mcp.md (Protocol Revisions).
Local defaults are intentionally narrow: literal 127.0.0.1, exact Host and
present Origin checks for the selected port, and read-only tools. The boundary
uses Bun's actual socket peer and ignores all forwarded-address headers.
# Safe loopback defaults
gno serve
gno daemon --port 3000
# Explicit LAN bind: use the headless daemon; all three controls are mandatory
gno daemon --host 0.0.0.0 \
--mcp-token-file ~/.config/gno/mcp-token \
--mcp-allowed-host workstation.local:3000 \
--mcp-allowed-origin https://trusted-client.example
gno serve stays loopback-only because its Web UI and REST API share the HTTP
listener. The daemon is the supported surface for authenticated non-loopback
MCP access.
The token file is created with a random 256-bit token when an explicitly
configured path does not exist. On POSIX it must remain mode 0600 or stricter.
Never pass the token on the command line; clients send
Authorization: Bearer <token>. Rotation, deletion, invalid contents, or
permission relaxation invalidates authenticated sessions.
Authentication does not authorize writes. Set gateway.enableWrite: true or
pass --mcp-enable-write separately. Without that opt-in, HTTP calls to write
tools return a redacted HTTP 403 before SDK dispatch.
Collection policy is checked separately on every tool and resource request,
using the current socket peer even when a client reuses an existing session.
local_only content can leave only through loopback; lan content additionally
permits an authenticated private-network peer; remote is required for an
authenticated public peer. A bearer token never overrides policy, and
--mcp-enable-write never overrides either control. Policy failures return a
redacted EGRESS_DENIED response before a tool/resource reads indexed content.
Requests and sessions are bounded. Boundary responses are stable and contain no
peer, allowlist, path, token, Authorization header, query, or document content:
401 unauthenticated, 403 forbidden, 413 oversized body, 429 pressure, and 503
shutdown/credential/runtime unavailability. See
mcp-http-error.
GET /api/resident/status exposes the same redacted lifecycle snapshot used by
the Web/Desktop Health Center, gno_status, and detached process status:
mode, uptime, listener port, admission/shutdown state, session/request/queue
counts, model lease/load counters, job counts, and content/index generations.
On a non-loopback daemon listener it passes through the same Host, Origin,
bearer, socket-peer, and collection-policy checks as /mcp.
Resident client example
Point Streamable HTTP clients at:
http://127.0.0.1:3000/mcp
Start one resident owner, then connect as many isolated clients as the configured session limit allows:
gno serve
# or, without the browser:
gno daemon --no-sync-on-start
Each HTTP session owns its SDK server/transport state. Stores, jobs, watcher, model leases, and generation counters remain resident and shared. Resumable event delivery is not advertised in this release.
Migrating from stdio-only MCP
Existing gno mcp install entries remain valid and continue to launch stdio.
No forced migration: use stdio for clients that manage local subprocesses, or
configure the resident /mcp URL for clients that support Streamable HTTP.
Do not run serve and daemon together against one data directory; the second
owner fails startup instead of opening a competing store/model lifecycle.
Job Session Lifetime
Jobs are stored in memory and tied to the MCP server process:
- Job IDs are only valid within the same running server
- Polling after server restart returns NOT_FOUND
- Different MCP processes cannot query each other's jobs
Quick Install
For a new corpus, prove retrieval and install the selected handoff directly:
gno setup ~/notes --name notes --connector cursor-mcp
gno setup ~/notes --name notes --connector codex-skill
Repeat --connector for multiple targets. Supported setup IDs are
claude-code-skill, claude-desktop-mcp, cursor-mcp, codex-skill,
opencode-skill, openclaw-skill, and hermes-skill. MCP targets run a
bounded retrieval smoke after lexical proof. Skill targets are installed but
report target_runtime_unverifiable; setup cannot execute the agent runtime.
Existing entries are reused without overwrite, and malformed files are
preserved.
Setup may install an MCP command a client launches later, but setup itself
never starts, contacts, or attaches to stdio MCP or resident /mcp.
Connector follow-up can return completed_with_actions with exit 0 while
lexical setup remains proven.
Use the CLI to install GNO as an MCP server:
# Read-only (default)
gno mcp install # Claude Desktop (default)
gno mcp install --target cursor # Cursor
gno mcp install --target zed # Zed
gno mcp install --target windsurf # Windsurf
gno mcp install --target opencode # OpenCode
gno mcp install --target amp # Amp
gno mcp install --target lmstudio # LM Studio
gno mcp install --target librechat --scope project # LibreChat
gno mcp install --target claude-code # Claude Code CLI
gno mcp install --target codex # OpenAI Codex CLI
# Slim core profile (7 read tools; add --enable-write for capture and remember)
gno mcp install --target claude-code --tool-profile core
gno mcp install --target cursor --tool-profile core --enable-write --force
--tool-profile accepts core or full. Omit it and the registration is
unchanged from earlier releases (no flag written, full at runtime). Rerun
with --force to switch an existing registration; nothing migrates on its
own.
Every install pins the workspace that was active when the command ran. The
generated entry uses the absolute Bun executable, run, the current installed
package's absolute src/index.ts, then --index <active> and
--config <absolute> before mcp. It also stores absolute GNO_DATA_DIR and
GNO_CACHE_DIR values (env, or OpenCode's environment). This keeps desktop
clients on the same index, config, database, and model cache even when they do
not inherit your shell environment. Codex uses its native
~/.codex/config.toml or project .codex/config.toml tables. Run
gno mcp install --dry-run --json to inspect the exact command, arguments, and
workspace values before writing them. If the target already has GNO configured,
add --force to preview the replacement without writing it.
JSON client configs are edited as JSONC, preserving comments, trailing commas,
and unrelated layout. For OpenCode and Amp, GNO reuses an existing supported
.jsonc alternate instead of creating a duplicate .json config.
# Write-enabled
gno mcp install --enable-write # Claude Desktop (default)
gno mcp install --target cursor --enable-write # Cursor
⚠️ Write-enabled mode allows AI to create documents, add collections, and trigger reindexing. Review tool calls before approving.
Scope Options
Some clients support project-level configuration:
gno mcp install --target cursor --scope project # .cursor/mcp.json
gno mcp install --target codex --scope project # .codex/config.toml
gno mcp install --target opencode --scope project # opencode.json
gno mcp install --target librechat --scope project # librechat.yaml
Other Commands
gno mcp status # Show installation status for all targets
gno mcp uninstall --target X # Remove GNO from a target
Supported Clients
| Client | Install Command | Scope |
|---|---|---|
| Claude Desktop | gno mcp install | User |
| Claude Code | gno mcp install --target claude-code | User, Project |
| Cursor | gno mcp install --target cursor | User, Project |
| Zed | gno mcp install --target zed | User |
| Windsurf | gno mcp install --target windsurf | User |
| OpenCode | gno mcp install --target opencode | User, Project |
| Amp | gno mcp install --target amp | User |
| LM Studio | gno mcp install --target lmstudio | User |
| LibreChat | gno mcp install --target librechat --scope project | Project |
| Codex | gno mcp install --target codex | User, Project |
Note: Warp terminal requires manual UI configuration. See Warp MCP docs.
Raycast AI Integration

Use GNO directly in Raycast AI with @gno mentions. Works in both Quick AI and AI Chat.
Requires: Raycast Pro subscription (for AI features), or 50 free messages for non-Pro users
Docs: Raycast AI · MCP Support
Setup
Option 1: Clipboard Auto-Fill
Run gno mcp install --dry-run --json, substitute its absolute values into this
JSON, then open Raycast → "Install MCP Server". Raycast auto-fills from the
clipboard. Raycast is a manual target; --target raycast is not supported.
Read-only:
{
"mcpServers": {
"gno": {
"command": "/absolute/path/to/bun",
"args": [
"run",
"/absolute/path/to/@gmickel/gno/src/index.ts",
"--index",
"default",
"--config",
"/absolute/path/to/index.yml",
"mcp"
],
"env": {
"GNO_DATA_DIR": "/absolute/path/to/data",
"GNO_CACHE_DIR": "/absolute/path/to/cache"
}
}
}
}
Write-enabled:
{
"mcpServers": {
"gno": {
"command": "/absolute/path/to/bun",
"args": [
"run",
"/absolute/path/to/@gmickel/gno/src/index.ts",
"--index",
"default",
"--config",
"/absolute/path/to/index.yml",
"mcp",
"--enable-write"
],
"env": {
"GNO_DATA_DIR": "/absolute/path/to/data",
"GNO_CACHE_DIR": "/absolute/path/to/cache"
}
}
}
}
Option 2: Manual UI
- Open Raycast → Search "Install MCP Server"
- Configure:
- Name:
gno - Command: the absolute Bun executable from the dry-run JSON
- Arguments: copy the full generated argument array; append
--enable-writeonly for write-enabled mode
- Name:
Where to Use GNO
Once installed, @gno works anywhere in Raycast AI:
| Mode | Access | Best For |
|---|---|---|
| Quick AI | Press Tab in Raycast, or assign hotkey | Fast one-off queries, floating overlay |
| AI Chat | Search "AI Chat" or assign hotkey (e.g., ⌥J) | Extended research, conversation history |
| AI Commands | Custom commands with @gno | Repeatable workflows |
Quick AI appears as a floating window above your apps, ideal for quick lookups:
@gno what's in my notes about TypeScript generics?
AI Chat is a full window with sidebar and history, better for research sessions:
@gno which model scored highest on gmickel-bench
The AI will call GNO tools (gno_query, gno_get) and synthesize answers from your documents.
Example Queries
@gno search for notes about authentication
@gno what documents mention API design?
@gno how many collections do I have?
@gno find my meeting notes from last week
@gno get the contents of my project README
Write examples (requires write-enabled mode):
@gno create a note about todays meeting
@gno add my ~/Projects/docs folder
@gno refresh the notes collection
Search depth: ask for faster or more thorough searches:
@gno quick search for TypeScript errors # fast mode (~0.7s)
@gno do a thorough search for auth vulnerabilities # thorough mode (~5-8s)
The AI will pass fast: true or thorough: true to gno_query based on your request. Default mode balances speed and quality (~2-3s).
Model Quality Matters
Recommended: Claude Haiku 4.5+, Sonnet 4.5+, or GPT-4+. Raycast's Auto model selection also works well.
Smaller/weaker models may:
- Hallucinate collection names (e.g.,
collection: gnoinstead of*) - Use incorrect parameter values
- Fail to call the right tools
Requirements
- GNO installed and in PATH
- At least one collection indexed (
gno add <path>) gno serveNOT required (MCP uses stdio, accesses SQLite directly)- Restart Raycast after PATH changes
Manual Configuration
The examples below show the canonical installed command shape. Replace every
/absolute/path/to/... placeholder with values from
gno mcp install --dry-run --json; also replace default if another index is
active. Keep both absolute workspace environment values. Do not shorten the
entry to gno mcp: GUI clients may have a different PATH and do not reliably
inherit GNO_* variables.
Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
Read-only:
{
"mcpServers": {
"gno": {
"command": "/absolute/path/to/bun",
"args": [
"run",
"/absolute/path/to/@gmickel/gno/src/index.ts",
"--index",
"default",
"--config",
"/absolute/path/to/index.yml",
"mcp"
],
"env": {
"GNO_DATA_DIR": "/absolute/path/to/data",
"GNO_CACHE_DIR": "/absolute/path/to/cache"
}
}
}
}
Write-enabled:
{
"mcpServers": {
"gno": {
"command": "/absolute/path/to/bun",
"args": [
"run",
"/absolute/path/to/@gmickel/gno/src/index.ts",
"--index",
"default",
"--config",
"/absolute/path/to/index.yml",
"mcp",
"--enable-write"
],
"env": {
"GNO_DATA_DIR": "/absolute/path/to/data",
"GNO_CACHE_DIR": "/absolute/path/to/cache"
}
}
}
}
Cursor
Add to ~/.cursor/mcp.json:
Read-only:
{
"mcpServers": {
"gno": {
"command": "/absolute/path/to/bun",
"args": [
"run",
"/absolute/path/to/@gmickel/gno/src/index.ts",
"--index",
"default",
"--config",
"/absolute/path/to/index.yml",
"mcp"
],
"env": {
"GNO_DATA_DIR": "/absolute/path/to/data",
"GNO_CACHE_DIR": "/absolute/path/to/cache"
}
}
}
}
Write-enabled:
{
"mcpServers": {
"gno": {
"command": "/absolute/path/to/bun",
"args": [
"run",
"/absolute/path/to/@gmickel/gno/src/index.ts",
"--index",
"default",
"--config",
"/absolute/path/to/index.yml",
"mcp",
"--enable-write"
],
"env": {
"GNO_DATA_DIR": "/absolute/path/to/data",
"GNO_CACHE_DIR": "/absolute/path/to/cache"
}
}
}
}
Codex
Add to ~/.codex/config.toml (user) or .codex/config.toml (project):
[mcp_servers.gno]
command = "/absolute/path/to/bun"
args = ["run", "/absolute/path/to/@gmickel/gno/src/index.ts", "--index", "default", "--config", "/absolute/path/to/index.yml", "mcp"]
[mcp_servers.gno.env]
GNO_DATA_DIR = "/absolute/path/to/data"
GNO_CACHE_DIR = "/absolute/path/to/cache"
For write-enabled mode, append "--enable-write" after "mcp" in args.
gno mcp install --target codex updates only these two GNO tables and preserves
unrelated TOML and comments.
Zed
Add to ~/.config/zed/settings.json on macOS/Linux or
%APPDATA%\Zed\settings.json on Windows:
Read-only:
{
"context_servers": {
"gno": {
"command": "/absolute/path/to/bun",
"args": [
"run",
"/absolute/path/to/@gmickel/gno/src/index.ts",
"--index",
"default",
"--config",
"/absolute/path/to/index.yml",
"mcp"
],
"env": {
"GNO_DATA_DIR": "/absolute/path/to/data",
"GNO_CACHE_DIR": "/absolute/path/to/cache"
}
}
}
}
Write-enabled:
{
"context_servers": {
"gno": {
"command": "/absolute/path/to/bun",
"args": [
"run",
"/absolute/path/to/@gmickel/gno/src/index.ts",
"--index",
"default",
"--config",
"/absolute/path/to/index.yml",
"mcp",
"--enable-write"
],
"env": {
"GNO_DATA_DIR": "/absolute/path/to/data",
"GNO_CACHE_DIR": "/absolute/path/to/cache"
}
}
}
}
Windsurf
Add to ~/.codeium/windsurf/mcp_config.json:
Read-only:
{
"mcpServers": {
"gno": {
"command": "/absolute/path/to/bun",
"args": [
"run",
"/absolute/path/to/@gmickel/gno/src/index.ts",
"--index",
"default",
"--config",
"/absolute/path/to/index.yml",
"mcp"
],
"env": {
"GNO_DATA_DIR": "/absolute/path/to/data",
"GNO_CACHE_DIR": "/absolute/path/to/cache"
}
}
}
}
Write-enabled:
{
"mcpServers": {
"gno": {
"command": "/absolute/path/to/bun",
"args": [
"run",
"/absolute/path/to/@gmickel/gno/src/index.ts",
"--index",
"default",
"--config",
"/absolute/path/to/index.yml",
"mcp",
"--enable-write"
],
"env": {
"GNO_DATA_DIR": "/absolute/path/to/data",
"GNO_CACHE_DIR": "/absolute/path/to/cache"
}
}
}
}
OpenCode
Add to ~/.config/opencode/opencode.json (or the existing
~/.config/opencode/opencode.jsonc):
Read-only:
{
"mcp": {
"gno": {
"type": "local",
"command": [
"/absolute/path/to/bun",
"run",
"/absolute/path/to/@gmickel/gno/src/index.ts",
"--index",
"default",
"--config",
"/absolute/path/to/index.yml",
"mcp"
],
"environment": {
"GNO_DATA_DIR": "/absolute/path/to/data",
"GNO_CACHE_DIR": "/absolute/path/to/cache"
},
"enabled": true
}
}
}
Write-enabled:
{
"mcp": {
"gno": {
"type": "local",
"command": [
"/absolute/path/to/bun",
"run",
"/absolute/path/to/@gmickel/gno/src/index.ts",
"--index",
"default",
"--config",
"/absolute/path/to/index.yml",
"mcp",
"--enable-write"
],
"environment": {
"GNO_DATA_DIR": "/absolute/path/to/data",
"GNO_CACHE_DIR": "/absolute/path/to/cache"
},
"enabled": true
}
}
}
Amp
Add to ~/.config/amp/settings.json:
Read-only:
{
"amp.mcpServers": {
"gno": {
"command": "/absolute/path/to/bun",
"args": [
"run",
"/absolute/path/to/@gmickel/gno/src/index.ts",
"--index",
"default",
"--config",
"/absolute/path/to/index.yml",
"mcp"
],
"env": {
"GNO_DATA_DIR": "/absolute/path/to/data",
"GNO_CACHE_DIR": "/absolute/path/to/cache"
}
}
}
}
Write-enabled:
{
"amp.mcpServers": {
"gno": {
"command": "/absolute/path/to/bun",
"args": [
"run",
"/absolute/path/to/@gmickel/gno/src/index.ts",
"--index",
"default",
"--config",
"/absolute/path/to/index.yml",
"mcp",
"--enable-write"
],
"env": {
"GNO_DATA_DIR": "/absolute/path/to/data",
"GNO_CACHE_DIR": "/absolute/path/to/cache"
}
}
}
}
LM Studio
Add to ~/.lmstudio/mcp.json:
Read-only:
{
"mcpServers": {
"gno": {
"command": "/absolute/path/to/bun",
"args": [
"run",
"/absolute/path/to/@gmickel/gno/src/index.ts",
"--index",
"default",
"--config",
"/absolute/path/to/index.yml",
"mcp"
],
"env": {
"GNO_DATA_DIR": "/absolute/path/to/data",
"GNO_CACHE_DIR": "/absolute/path/to/cache"
}
}
}
}
Write-enabled:
{
"mcpServers": {
"gno": {
"command": "/absolute/path/to/bun",
"args": [
"run",
"/absolute/path/to/@gmickel/gno/src/index.ts",
"--index",
"default",
"--config",
"/absolute/path/to/index.yml",
"mcp",
"--enable-write"
],
"env": {
"GNO_DATA_DIR": "/absolute/path/to/data",
"GNO_CACHE_DIR": "/absolute/path/to/cache"
}
}
}
}
LibreChat
Add to librechat.yaml in your LibreChat project root:
Read-only:
mcpServers:
gno:
command: /absolute/path/to/bun
args:
- run
- /absolute/path/to/@gmickel/gno/src/index.ts
- --index
- default
- --config
- /absolute/path/to/index.yml
- mcp
env:
GNO_DATA_DIR: /absolute/path/to/data
GNO_CACHE_DIR: /absolute/path/to/cache
Write-enabled:
mcpServers:
gno:
command: /absolute/path/to/bun
args:
- run
- /absolute/path/to/@gmickel/gno/src/index.ts
- --index
- default
- --config
- /absolute/path/to/index.yml
- mcp
- --enable-write
env:
GNO_DATA_DIR: /absolute/path/to/data
GNO_CACHE_DIR: /absolute/path/to/cache
Other MCP Clients
Any MCP-compatible client can connect:
# Start MCP server manually (for debugging)
gno mcp
The server uses stdio transport (JSON-RPC 2.0 over stdin/stdout).
Available Tools
gno_search
BM25 keyword search.
Query: "authentication"
Collection: (optional)
since: "last month" # Optional temporal lower bound
until: "today" # Optional temporal upper bound
categories: ["meeting"] # Optional category/content-type filters
author: "gordon" # Optional author contains filter
tagsAll: ["backend"] # Optional: must have ALL tags
tagsAny: ["urgent"] # Optional: must have ANY tag
Limit: 5 (default)
Structured search results include per-result contentType and categories
fields, alongside tags, docid, uri, scores, and source metadata. Use those
fields when an agent needs to distinguish canonical typed pages from broader
category filters. File-backed hits include source.absPath. Default snippets
skip leading YAML frontmatter and prefer document prose. A frontmatter-dominated
FTS window falls back to stripped chunk prose. line follows that trimmed
display range. This display cleaning applies to gno_search, gno_vsearch,
and gno_query.
Portable export records additionally expose a bounded record object in
structured search/get/multi-get/Ask results. Read its exact locator and anchors
for citations and its adapter ID/version/configuration fingerprint for
reproducibility; use the unique uri or docid for gno_get, not the shared
container path in source.relPath.
gno_vsearch
Vector semantic search.
Query: "how to handle errors gracefully"
since: "2025-01-01"
until: "today"
categories: ["notes", "code"]
author: "gordon"
gno_query
Hybrid search (BM25 + vector).
Query: "database optimization"
intent: "postgres query latency and indexing"
candidateLimit: 12
exclude: ["hiring", "reviews"]
since: "last month"
until: "today"
categories: ["backend", "notes"]
author: "gordon"
tagsAll: ["backend", "work"] # Optional: must have ALL tags
tagsAny: ["urgent", "priority"] # Optional: must have ANY tag
queryModes:
- { mode: "term", text: "\"refresh token\" -oauth1" }
- { mode: "intent", text: "how token rotation is implemented" }
- { mode: "hyde", text: "Refresh tokens rotate on each use and old tokens are invalidated." }
explain: true
Search modes (via parameters):
- Default: Preset-aware balanced mode with bounded graph expansion. On
slim/slim-tuned, query expansion + reranking; on larger presets, reranking only by default (~2-3s) fast: true: Skip query expansion, graph expansion, and reranking (~0.7s)thorough: true: Query expansion + graph expansion + wider rerank pool (~5-8s)
Agent retry strategy: Use default mode first. If no relevant results:
- Rephrase the query (free, often effective)
- Then try
thorough: truefor better recall
Recency intent (latest, newest, recent) sorts results newest-first by canonical frontmatter date when present, with file modified time as fallback.
When queryModes is provided, GNO uses those entries directly:
term: BM25-focused phrase/keyword queryintent: semantic/vector-focused reformulationhyde: hypothetical passage for vector retrieval- Validation:
textis trimmed and must be non-empty; at most onehydeentry is allowed
Optional steering controls:
intent: disambiguating context for ambiguous queries. It steers expansion, reranking, and snippet selection without being searched directly.candidateLimit: max candidates sent to reranking. Lower it for faster responses on CPU-heavy or low-memory setups.exclude: hard-prune docs containing any excluded term in title/path/body.graph: defaults totrue; setfalse(ornoGraph: true) for BM25/vector-only retrieval.explain: include per-result scoring details. Active content-type rules add the factor, raw/base score, bounded and combined contributions, final score, rule source, and full ranking-rules fingerprint.gno_askaccepts the same opt-in, including verified mode, without changing canonical Capsule bytes.
Migration notes (retrieval v2):
- Existing
gno_querycalls remain valid with no payload changes required. intentis complementary toqueryModes: use intent for background context,queryModesfor caller-supplied lexical/semantic expansions.queryModesis optional and only needed when your client wants explicit retrieval intent control.- If
queryModesis set, generated expansion is skipped for that query and the provided entries are used directly. - The
querystring itself may also be a multi-line structured query document usingterm:,intent:, andhyde:lines. See Structured Query Syntax.
# Existing payload (still valid)
query: "auth flow"
thorough: true
# Retrieval v2 payload (explicit intent control)
query: "auth flow"
queryModes:
- { mode: "term", text: "\"refresh token\" -oauth1" }
- { mode: "intent", text: "how token rotation is implemented" }
- { mode: "hyde", text: "Refresh tokens rotate on each use and old tokens are revoked." }
# Or put the structure directly into the query field:
query: |
auth flow
term: "refresh token" -oauth1
intent: how token rotation is implemented
gno_query_diagnose
Diagnose why one target document does or does not retrieve for a query.
query: "Alice Acme"
target: "gno://notes/people/alice.md"
fast: true
graph: false
tagsAll: ["crm"]
Use this when an expected document is missing from gno_query results or when
you need evidence before changing filters, query modes, graph expansion, or
reranking. Without active auxiliary metadata, the structured response matches
the legacy query-diagnose@1.0 branch of query-diagnose.schema.json and omits
affinity. An active content-type boost uses v1.2 and includes its closed score
receipt. The response
reports target status (not_found, inactive, no_indexed_content,
filtered_out, or diagnosed), typed metadata, graph hints, chunk/line choice,
and BM25/vector/fusion/graph/rerank stage survival.
For low-latency or CPU-only checks, fast: true keeps MCP diagnose BM25-only
and avoids initializing embedding/rerank models.
gno_get
Retrieve document by ID.
ref: "abc123def456"
The response includes source metadata such as absPath, sourceHash, MIME/ext, and document capability metadata so clients can distinguish editable source files from read-only converted documents.
An indexed URI such as gno://notes/plan.md?index=research opens and reads the
named index, even when the MCP server itself is using another index. A missing
named index returns an error and is never created as a side effect.
Named indexes use 1–64 UTF-16 code units drawn from Unicode letters, marks,
numbers, internal ASCII spaces, ., _, or -. They start with a letter or
number, cannot end with a space or ., and cannot contain ... Absolute paths,
path separators, controls, and platform-invalid punctuation are rejected before
filesystem access. Case and canonically equivalent Unicode spellings share one
NFC/case-folded identity. Its 242-byte UTF-8 budget keeps the complete
index-<identity>.sqlite filename within the portable 255-byte component limit.
gno_section
Create or resolve a durable SectionTargetV1 against one indexed document.
action: "create"
ref: "gno://notes/pilot.md"
anchor: "setup" # or line: 3 — exactly one selector
action: "resolve"
ref: "gno://notes/pilot.md"
target: { schemaVersion: "1", ... }
Always registered and read-only: no document writes and no target persistence.
Uses the shared core create/resolve/transport contract. Exact/recovered results
include citation evidence (canonical URI, current anchor/title, inclusive line
range, fingerprint). Ambiguous/stale/missing omit citation and are not safe to
navigate or cite. Model-visible text includes serialized JSON plus gno_get
fromLine/lineCount follow-up guidance for navigable ranges.
gno_multi_get
Retrieve multiple documents.
refs: ["abc123", "def456"]
All refs in one call must resolve to the same index. Split mixed-index batches
into one gno_multi_get call per index.
gno_peek
Cheap read-only snapshot (peek@1.0). Same payload as gno peek --json.
One snapshot, three surfaces: CLI gno peek --json, this tool, and the skill
recipe. Do not compose status + ls + changes for this job.
Returns initialized flag, document/collection counts, embedding backlog, up to
10 recent files (with docid and absPath), and pid-file serve liveness.
serve.running is true only for gno serve --detach. A foreground serve is
not detected. There is no HTTP probe. Never initializes models or embeddings.
Uninitialized is success (initialized:false plus pinned nulls), not an error.
A subquery failure is an atomic RUNTIME error, never a half-filled snapshot.
Use this for counts/backlog/recent/serve questions; use gno_status for the
heavy health and activation payload.
Open without fetching content via gno_get: Web UI
{serveUrl}/doc?uri=<encodeURIComponent(uri)> from serve.url + uri
(optional #anchor); files via recent[].absPath or search
results[].source.absPath. If absPath is absent, show the URI tail and do
not offer file-open for that row.
gno_status
Check index health.
Returns collection counts, document totals, and health status.
The structured response also includes resident-status@1.0. HTTP clients see
the shared serve/daemon lifecycle. Stdio reports mode:"stdio",
resident:false, and no listener.
contentTypeBoost contains the effective rule IDs/factors and full ranking
fingerprint. Configured path prefixes are omitted.
gno_capture
Create a new document (requires --enable-write).
Common fields:
collection: "notes"
title: "Project Plan"
folderPath: "projects/gno" # Optional
collisionPolicy: "create_with_suffix" # Optional: error|open_existing|create_with_suffix
presetId: "project-note" # Optional: blank|project-note|research-note|decision-note|prompt-pattern|source-summary|idea-original|person|company-project|meeting
content: "# Project Plan\n" # Optional when preset provides scaffold
source:
kind: "web" # direct|web|email|meeting|chat|file|api|unknown
url: "https://example.com/source"
title: "Source page"
tags: ["project/gno"]
gno_capture writes the same structured source: frontmatter and returns the
same provenance receipt contract as CLI, REST, and SDK capture. The MCP result
also preserves legacy fields: docid, absPath, overwritten, and
serverInstanceId.
Browser-clip results may extend the shared receipt with normalized source fields
and closed source.browserClip provenance: extraction mode, exact selection
when applicable, extraction/final hashes, deterministic clip/preview digests,
browser metadata, capture time, and bounded warnings. Existing gno_capture
inputs remain compatible. For a browser clip, open_existing succeeds only
when stored clipIdentity matches; missing or different provenance returns an
explicit conflict without writing. create_with_suffix creates a distinct
note.
Collision handling checks both indexed documents and disk-only files. Use
collisionPolicy: "open_existing" to return an existing receipt without
rewriting content, create_with_suffix to create the next available filename,
or legacy overwrite: true to replace the target path and return
collisionPolicyResult: "overwritten". Capture content must be text, and
non-overwrite captures fail instead of replacing a late-arriving file.
MCP capture runs under the shared write lease and syncs the written file into
FTS before returning: a successful result always carries
sync.status: "completed" and the note is an immediate gno_search hit in the
same agent turn. If the file was written but sync failed, the tool returns the
error CAPTURE_SYNC_FAILED (naming the written path) instead of a success;
open_existing on an unindexed disk file syncs it first. The lease wait is the
v1.38 contention window (120s), after which the tool returns LOCKED without
writing. Capture does not auto-embed; run gno_embed or gno_index when
vector search should include the new note.
gno_recall
Budgeted, cited recall of current facts from a memory-managed collection
(available without --enable-write). Call it before answering about the user's
preferences, decisions, people, or prior work, and before gno_remember when
a fact may replace an earlier one.
query: "commute preference"
collection: "memory" # must have memoryManaged: true in the config
scopes: ["project:gno"] # 1-8 explicit scopes; no implicit global scope
maxFacts: 8 # Optional (default 8)
maxTokens: 512 # Optional (default 512)
The response carries only current facts (superseded records are excluded),
each with its gno:// cite, scopes, provenance, and content hash, plus a
content-free receipt (caller, session, memory ids, span hashes, digest).
Identity is mapped from the MCP session: caller is the client name from the
initialize handshake, session is the HTTP session id or the stdio server
instance id. An empty result includes a hint naming the command that stores
the first fact. The MCP adapter runs the lexical leg; retrieval.mode
reports it.
gno_remember
Store one fact with supersession semantics (requires --enable-write).
Remember is fact-granular: use gno_capture for documents and edit files
directly for existing notes.
text: "Finn prefers trams over buses."
collection: "memory"
scopes: ["project:gno"]
decision: "add" # Optional: omit for candidates only | add | supersede
predecessorUri: "gno://memory/facts/2026-09-03/mem-abc.md" # supersede only
predecessorHash: "sha256:..." # supersede only, from gno_recall
receipt: {} # Optional: the gno_recall receipt the fact derives from
derivedFrom: ["https://example.com/source"] # Optional origins
source: "Said in standup 2026-09-03" # Optional evidence
Outcomes: existing (exact duplicate, nothing written), candidates (likely
matches returned, nothing written; decide with decision), added, or
superseded. supersede checks the predecessor's hash and that it has no
successor yet; a concurrent second supersede returns
MEMORY_SUPERSEDE_CONFLICT. The fact is lexically searchable when the call
returns (sync.status: "completed").
Context fencing: text that replays a span hash from the presented receipt
returns MEMORY_FENCED_REPLAY, and a gno:// entry in derivedFrom returns
MEMORY_FENCED_DERIVED. A paraphrase without lineage cannot be fenced.
The core memory service holds the shared .mcp-write.lock lease for the write
and lexical sync; the MCP adapter takes no lock of its own, so an MCP remember
and a CLI writer serialise on one lease.
gno_rename_note / gno_move_note
Reference-safe rename and same-collection move are write-gated two-step tools.
They are unavailable unless the server starts with --enable-write; bearer
authentication does not grant mutation authority.
Preview first:
tool: gno_rename_note
action: preview
ref: gno://notes/old-note.md
name: new-note.md
tool: gno_move_note
action: preview
ref: gno://notes/new-note.md
folderPath: archive
The tool returns the canonical file-refactor-preview@1.0 plan in
structuredContent, including every examined reference, destination-only
edits, fingerprints, safety classifications, canApply, and a deterministic
lowercase SHA-256 planDigest. Do not apply when canApply is false.
Apply only the exact reviewed plan:
tool: gno_rename_note
action: apply
ref: gno://notes/old-note.md
name: new-note.md
schemaVersion: "1.0"
planDigest: <64 lowercase hex characters from preview>
confirmation: apply
confirm: true
Move uses the same apply fields plus folderPath and optional name. The
handler rebuilds the plan from current state, so stale plans fail closed.
Supported wiki and Markdown references commit atomically with the source move;
ambiguous, malformed, unsupported, read-only, occupied, cross-collection, and
truncated cases never auto-confirm. The canonical apply receipt distinguishes
applied, applied_with_sync_pending, stale_plan, conflict,
unsupported, and failed_rolled_back. If sync is pending, the filesystem
change already committed; run gno_sync or gno_index to converge the index.
gno_duplicate_note and gno_create_folder keep their existing semantics and
do not retarget inbound references. MCP tool annotations are conservative UI
hints, not authorization.
gno_add_collection
Add a folder to the index (requires --enable-write).
gno_sync
Reindex one or all collections (requires --enable-write). FTS sync only (no embedding).
gno_embed
Generate embeddings for unembedded chunks (requires --enable-write). Runs as background job.
Poll job status with gno_job_status. Fails fast if embedding model not cached.
Optional input:
collection: "notes" # limit embedding work to one collection
gno_index
Full index: sync files + generate embeddings (requires --enable-write). Runs as background job.
collection: "notes" # Optional: limit to one collection
gitPull: false # Optional: run git pull before sync
Equivalent to CLI gno index. Runs sync then embed as single job.
gno_remove_collection
Remove a collection from config (requires --enable-write). Indexed data is retained.
gno_clear_collection_embeddings
Clear stale or all embeddings for one collection (requires --enable-write).
collection: "notes"
mode: "stale" # or "all"
Use mode: "stale" to remove embeddings for models that are no longer the
active embed model for that collection. Use mode: "all" to wipe every
embedding for that collection before rebuilding.
gno_job_status
Check async job status.
gno_list_jobs
List active and recent jobs.
gno_list_tags
List all tags with document counts.
collection: "notes" # Optional: filter by collection
prefix: "project" # Optional: filter by tag prefix
Returns tags with counts for faceted filtering.
gno_links
Get outgoing links from a document.
ref: "notes/readme.md" # Document reference (URI, collection/path, or #docid)
type: "wiki" # Optional: filter by link type ("wiki" or "markdown")
Returns all outgoing links from the document, including wiki links ([[Target]]) and markdown links ([text](path.md)).
gno_backlinks
Get documents that link TO this document.
ref: "notes/target.md" # Target document reference
collection: "notes" # Optional: filter source documents by collection
Returns all documents that reference the target document. Useful for discovering related content and navigating document graphs.
gno_similar
Find semantically similar documents using vector embeddings.
ref: "notes/readme.md" # Source document reference
limit: 5 # Max results (1-50, default: 5)
threshold: 0.7 # Min similarity score (0-1)
crossCollection: false # Include docs from other collections (default: false)
Uses document embeddings to find semantically related content. The algorithm:
- Retrieves embeddings for all chunks of the source document
- Computes the average embedding
- Searches for nearest neighbors using sqlite-vec
- Returns top N similar documents (excluding the source itself)
Note: Requires documents to be embedded (gno embed or gno index). Vector search must be available (sqlite-vec installed).
gno_graph
Get knowledge graph of document connections (nodes and edges).
collection: "notes" # Optional: filter to single collection
limit: 2000 # Max nodes (1-5000, default: 2000)
edgeLimit: 10000 # Max edges (1-50000, default: 10000)
includeSimilar: false # Include similarity edges (default: false)
threshold: 0.7 # Similarity threshold (0-1, default: 0.7)
linkedOnly: true # Exclude isolated nodes (default: true)
similarTopK: 5 # Similar docs per node (1-20, default: 5)
Returns graph data with nodes (documents), links (edges), and a report with
hubs, bridge candidates, isolated documents, unresolved links, and edge-type
counts. The report also includes deterministic community summaries and node
communityId assignments when the returned graph is small enough to analyze.
Each edge also includes confidence (explicit, inferred,
ambiguous, or similarity) and audit metadata describing exact matches,
fallback matches, collision-prone matches, or similarity scores.
Successful sync reconciles references affected by target changes, including incoming references from other collections and previously unresolved links. Missing, stale, or interrupted graph state falls back to full reconciliation. An unchanged sync with current graph state skips projection; graph reads continue to use the current index. This also applies to typed graph queries and impact analysis.
Use cases:
- Explore document relationships programmatically
- Build custom visualizations
- Analyze knowledge graph structure
- Find highly connected "hub" documents
- Spot clusters/communities for agent navigation
gno_graph_query
Run bounded traversal over the typed doc_edges relationship layer from one
root document.
ref: "gno://notes/people/alice.md"
direction: "both" # "out", "in", or "both"
edgeType: "works_at" # Optional semantic edge filter
maxDepth: 2 # 1-6
maxNodes: 100 # 1-1000
frontierLimit: 100 # 1-1000
visitedLimit: 500 # 1-5000
relation is an alias for edgeType; if both are set they must match. The
structured response matches graph-query.schema.json and includes
schemaVersion, resolved root, typed nodes/edges, traversal caps,
returned counts, warnings, and truncated.
gno_graph_neighbors
Find graph neighbors for a document or graph node.
ref: "notes/readme.md" # URI, #docid, collection/path, relPath, or exact title
direction: "both" # "both", "out", or "in" (default: "both")
collection: "notes" # Optional: filter to single collection
includeSimilar: false # Optional: include similarity edges
Use this when an agent already has a seed document and needs relationship
context, nearby references, or likely missed related docs. For normal content
questions, start with gno_query; follow graph neighbors with gno_get on the
returned refs.
gno_graph_path
Find the shortest relationship path between two documents or graph nodes.
from: "notes/a.md" # Starting ref
to: "notes/b.md" # Target ref
maxDepth: 6 # Max hops (1-12, default: 6)
collection: "notes" # Optional
includeSimilar: false # Optional
Use this for "how are X and Y connected?" prompts. If either endpoint is
unknown, run gno_query first to find candidate refs, then use gno_get on
path nodes for grounded evidence.
gno_changes / gno_diff / gno_impact
These tools are always available as read-only operations; they do not require write enablement.
gno_changesacceptssince,collection, and boundedlimit. It returns retained metadata-only changes with opaque cursor and retention disclosure.gno_diffacceptsrefand optional opaquechange. It reports structural history availability without returning or reconstructing source bodies.gno_impactacceptsrefplus depth/node/edge/frontier/visited caps. It follows inbound typed, wiki, and Markdown dependencies and returns one explainable evidence path per impacted document.
Structured content uses changes@1.0, document-diff@1.0, and impact@1.0,
identical to CLI JSON, REST, and SDK results.
Persistent saved-Capsule registration management is intentionally CLI-only:
use gno context watch, watches, reverify, and unwatch. MCP
gno_context_verify verifies the supplied Capsule without registering it,
starting resident background work, or adding a write endpoint.
Resources
Access documents via GNO URIs:
gno://notes/projects/readme.md
gno://work/src/main.ts
Resource format:
gno://<collection>/<relative-path>- Non-default indexes appear as round-trip metadata:
gno://<collection>/<relative-path>?index=<name>. Document resources and read tools open that named index; mixed-index multi-get requests must be split by index.
Clarifications
- MCP loads embedding/rerank models for search tools
- Raw MCP retrieval tools do not synthesize answers;
gno_askdoes only with literalverify: trueand abstains below complete substantive-claim support - Collection names are case-insensitive
- Search tools support
tagsAll/tagsAnyfor filtering
Usage Patterns
Searching Your Notes
Ask the AI assistant:
"Search my notes for meeting decisions from last week"
The assistant will use gno_search or gno_query to find relevant documents.
Getting Document Content
Ask:
"Get the contents of my project README"
The assistant uses gno_get with the docid from search results.
Research Workflow
- Search: "Find documents about API authentication"
- Review results and scores
- Get full content of relevant docs
- Ask follow-up questions with context
Environment Variables
Configure MCP server behavior with environment variables:
| Variable | Effect |
|---|---|
HF_HUB_OFFLINE=1 | Offline mode: use cached models only, fail if missing |
GNO_NO_AUTO_DOWNLOAD=1 | Disable auto-download but allow explicit gno models pull |
GNO_VERBOSE=1 | Enable verbose logging |
Models auto-download on first use. Use these variables in CI/air-gapped environments.
Troubleshooting
"Tool not found"
Ensure GNO is installed globally:
bun install -g @gmickel/gno
which gno # Should show path
"No results"
Check that documents are indexed:
gno ls
gno status
Connection Issues
Verify MCP server works:
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | gno mcp
Should return a valid JSON-RPC response.
gno mcp status and connector installation prove configuration presence, not
that a client can retrieve. The Web Connectors page offers an explicit read-only
verification for supported installed MCP targets. It starts only the configured,
trusted local GNO command, requires gno_status and gno_search, and confirms a
collection-scoped corpus result. Package-runner/bootstrap commands such as
bunx, bun x, or npx are not accepted for this verification path.
Skill installations cannot be executed through a safe generic client hook.
They remain target_runtime_unverifiable until the owning client exposes a
read-only verification interface; installed must never be interpreted as
retrieval passed.
Debug Mode
Enable verbose logging:
GNO_VERBOSE=1 gno mcp
Performance Tips
-
Index only what you need (use
--patternfilters) -
Use specific collections for faster searches
-
Pre-download models:
gno models pull --allCollection boundary tools: -
gno_egress_policy_getshows effective policy, provenance, durable revision, and diagnostic version. -
gno_egress_checkexplains an exact action/destination/caller/content-class decision without performing the action. -
gno_egress_policy_setis write-enabled; relaxation requires the exact collection, current policy, durable revision, target policy, and explicit acknowledgement. Stale and replayed confirmations fail closed. -
gno_egress_audit_list|show|statusinspect content-free local receipts;gno_egress_audit_delete|purgeare write-enabled local cleanup controls.
Native worker lifetime
Resident and stdio MCP reuse a context-owned native inference child across calls. Model selection and outbound HTTP policy remain bound to the request's configuration snapshot and collection scope. Metadata tools do not acquire model-use leases or refresh the inference idle deadline. Native work prevents idle retirement; the five-minute default idle grace ends by retiring the child, and the next model call reloads lazily. Shutdown disposes owned children after active work drains.
Serve startup defers model-file resolution and downloads until actual inference;
empty/offline caches do not block lexical or metadata service. The first model
operation still enforces the configured offline/download and collection policy.
Existing indexes can use validated stored vector dimensions without eagerly loading
an embedding model. Capability availability is distinct from loaded-model state.
For hybrid queries, embedding/index failures retain lexical fallback but cannot
claim vectorsUsed: true unless a vector search succeeded. A real zero-match vector
search remains a successful operation. Native worker failures are contained in the
host and follow each tool's existing error or fallback contract.