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.

GNO MCP in Claude Desktop

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:

  1. Client LLM uses gno_context for one bounded evidence handoff, or gno_query plus bounded reads for manual retrieval.
  2. Client LLM synthesizes directly, or calls gno_ask with literal verify: true when it needs a closed-evidence verification contract.
  3. 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:

ToolUse WhenFollow-up
gno_contextOne deterministic, token-budgeted evidence bundle for an agent goalCite exact evidence spans; state unresolved gaps
gno_context_verifyReusing a saved Capsule after sources or runtime configuration may have changedRebuild only when the receipt reports drift
gno_askA local answer whose claims must be classified against one closed CapsuleSend literal verify: true; retain gaps/abstention
gno_searchExact phrases, filenames, identifiers, error messages, known symbolsgno_get around result line
gno_vsearchConceptual similarity where exact wording may differgno_get or gno_multi_get top results
gno_queryDefault choice; mixed lexical + semantic + reranked retrievalgno_multi_get for top URIs
gno_query_diagnoseImportant target doc is missing or you need stage-by-stage retrieval evidenceAdjust filters/query mode, then retry gno_query
gno_getOne known gno:// URI, #docid, or collection/pathUse fromLine + lineCount first
gno_sectionCreate/resolve a durable section target; cite only exact/recoveredFollow citation lines with gno_get
gno_multi_getBatch several top result refs or glob-matched docsKeep maxBytes bounded
gno_peekCheap counts, backlog, recent files, or whether gno serve --detach is upSame peek@1.0 snapshot as gno peek --json
gno_statusResults look stale, vector search fails, or embeddings may be missingRun 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: explicit relevant, irrelevant, or missing_expected feedback
  • gno_trace_export: deterministic aggregate agentic-receipt
  • gno_trace_delete: one trace plus owned records
  • gno_trace_purge: every local receipt; requires confirm: 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_get shows effective policy, provenance, durable revision, and diagnostic version.
  • gno_egress_check explains an exact action/destination/caller/content-class decision without performing the action.
  • gno_egress_policy_set is 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|status inspect content-free local receipts; gno_egress_audit_delete|purge are write-enabled local cleanup controls.
  • gno_audit runs 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:

OperationBearer/transport authMCP write opt-inCollection destination policy
Local list/showTransport-dependentNoNo network export
Local label/delete/purgeTransport-dependentYes on MCPNo network export
Loopback aggregate exportLoopback admissionYes on MCPLocal-file/process allowed
LAN or remote aggregate exportRequiredYeslan 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.

ProfileRead toolsWith --enable-write adds
full (default)all 34all 19 write tools
coregno_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

ClientInstall CommandScope
Claude Desktopgno mcp installUser
Claude Codegno mcp install --target claude-codeUser, Project
Cursorgno mcp install --target cursorUser, Project
Zedgno mcp install --target zedUser
Windsurfgno mcp install --target windsurfUser
OpenCodegno mcp install --target opencodeUser, Project
Ampgno mcp install --target ampUser
LM Studiogno mcp install --target lmstudioUser
LibreChatgno mcp install --target librechat --scope projectProject
Codexgno mcp install --target codexUser, Project

Note: Warp terminal requires manual UI configuration. See Warp MCP docs.

Raycast AI Integration

GNO in Raycast AI

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

  1. Open Raycast → Search "Install MCP Server"
  2. Configure:
    • Name: gno
    • Command: the absolute Bun executable from the dry-run JSON
    • Arguments: copy the full generated argument array; append --enable-write only for write-enabled mode

Where to Use GNO

Once installed, @gno works anywhere in Raycast AI:

ModeAccessBest For
Quick AIPress Tab in Raycast, or assign hotkeyFast one-off queries, floating overlay
AI ChatSearch "AI Chat" or assign hotkey (e.g., ⌥J)Extended research, conversation history
AI CommandsCustom commands with @gnoRepeatable 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: gno instead 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 serve NOT 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

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:

  1. Rephrase the query (free, often effective)
  2. Then try thorough: true for 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 query
  • intent: semantic/vector-focused reformulation
  • hyde: hypothetical passage for vector retrieval
  • Validation: text is trimmed and must be non-empty; at most one hyde entry 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 to true; set false (or noGraph: 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_ask accepts the same opt-in, including verified mode, without changing canonical Capsule bytes.

Migration notes (retrieval v2):

  • Existing gno_query calls remain valid with no payload changes required.
  • intent is complementary to queryModes: use intent for background context, queryModes for caller-supplied lexical/semantic expansions.
  • queryModes is optional and only needed when your client wants explicit retrieval intent control.
  • If queryModes is set, generated expansion is skipped for that query and the provided entries are used directly.
  • The query string itself may also be a multi-line structured query document using term:, intent:, and hyde: 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.

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)).

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:

  1. Retrieves embeddings for all chunks of the source document
  2. Computes the average embedding
  3. Searches for nearest neighbors using sqlite-vec
  4. 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_changes accepts since, collection, and bounded limit. It returns retained metadata-only changes with opaque cursor and retention disclosure.
  • gno_diff accepts ref and optional opaque change. It reports structural history availability without returning or reconstructing source bodies.
  • gno_impact accepts ref plus 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_ask does only with literal verify: true and abstains below complete substantive-claim support
  • Collection names are case-insensitive
  • Search tools support tagsAll/tagsAny for 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

  1. Search: "Find documents about API authentication"
  2. Review results and scores
  3. Get full content of relevant docs
  4. Ask follow-up questions with context

Environment Variables

Configure MCP server behavior with environment variables:

VariableEffect
HF_HUB_OFFLINE=1Offline mode: use cached models only, fail if missing
GNO_NO_AUTO_DOWNLOAD=1Disable auto-download but allow explicit gno models pull
GNO_VERBOSE=1Enable 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 --pattern filters)

  • Use specific collections for faster searches

  • Pre-download models: gno models pull --all Collection boundary tools:

  • gno_egress_policy_get shows effective policy, provenance, durable revision, and diagnostic version.

  • gno_egress_check explains an exact action/destination/caller/content-class decision without performing the action.

  • gno_egress_policy_set is 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|status inspect content-free local receipts; gno_egress_audit_delete|purge are 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.