Overview

Geode provides a complete Language Server Protocol (LSP) implementation for GQL files, bringing professional IDE features to graph query development. The LSP server delivers real-time syntax checking, intelligent code completion, hover documentation, and more.

Status: Production-ready (100% implemented and tested)

What You’ll Learn

  • How to set up Geode LSP with your IDE
  • Available language features and capabilities
  • Integration guides for VS Code, Neovim, Vim, and Emacs
  • Troubleshooting common LSP issues
  • Advanced configuration options

Prerequisites

  • Geode installed (see Installation Guide )
  • Basic familiarity with your IDE’s plugin/extension system
  • For VS Code: Node.js and npm
  • For Neovim: nvim-lspconfig plugin

Starting Language Servers

Geode provides two language server modes: LSP for IDE integration and MCP for AI assistant integration.

LSP Server (Language Server Protocol)

The LSP server provides IDE features like autocomplete, hover documentation, and diagnostics.

# Start the LSP server (communicates via stdin/stdout)
geode lsp

# With verbose logging
geode lsp --verbose

# Specify log file for debugging
geode lsp --log-file=/tmp/geode-lsp.log

The LSP server is typically launched automatically by your IDE, but you can test it manually:

# Test LSP initialization
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"capabilities":{}}}' | geode lsp

MCP Server (Model Context Protocol)

The MCP server provides AI assistants (like Claude) with direct access to Geode.

# Start the MCP server
geode mcp serve

# Connect to a specific Geode instance
geode mcp serve --host localhost --port 3141

# With authentication
geode mcp serve --host localhost --port 3141 --user admin --password secret

# With verbose output
geode mcp serve --verbose

MCP Server Configuration via environment variables:

# Set connection details via environment
export GEODE_HOST=localhost
export GEODE_PORT=3141
export GEODE_USER=admin
export GEODE_PASSWORD=secret

geode mcp serve

Running Both Servers

For full development experience with both IDE support and AI assistance:

# Terminal 1: Start Geode database server
geode serve --listen 0.0.0.0:3141

# Terminal 2: Your IDE uses LSP (automatically started)
# Configure your IDE to run: geode lsp

# Terminal 3: AI assistant uses MCP
geode mcp serve --host localhost --port 3141

Claude Code Integration

To use Geode with Claude Code:

  1. Configure MCP in Claude settings:
{
  "mcpServers": {
    "geode": {
      "command": "geode",
      "args": ["mcp", "serve", "--host", "localhost", "--port", "3141"]
    }
  }
}
  1. Or use the Geode Claude plugin:
# Install the plugin
claude plugins install geode-claude-plugin

# Or run with local plugin directory
claude --plugin-dir ./geode-claude-plugin

See the Claude Code Plugin documentation for more details.

Architecture

Components

The Geode LSP implementation consists of five main components:

src/cli/lsp/
├── protocol.zig    # LSP protocol types and JSON-RPC structures
├── transport.zig   # stdio transport with Content-Length headers
├── document.zig    # Document state management
├── features.zig    # Language features (hover, completion, diagnostics)
└── server.zig      # Main LSP server implementation

Protocol Compliance

  • LSP Specification: 3.17
  • Transport: JSON-RPC 2.0 over stdin/stdout
  • Text Synchronization: Full and Incremental modes
  • Parser Integration: Uses Geode’s ISO/IEC 39075:2024 compliance parser

Server Capabilities

The LSP server advertises the following capabilities during initialization:

{
  "capabilities": {
    "textDocumentSync": 1,
    "hoverProvider": true,
    "completionProvider": {
      "triggerCharacters": [".", ":", "$"]
    },
    "diagnosticProvider": true
  }
}

Language Features

1. Diagnostics (Syntax Errors)

Real-time syntax error detection using Geode’s GQL parser:

-- Invalid syntax (missing closing parenthesis)
MATCH (n:Person
RETURN n.name

-- Error: Expected ')' at line 1, column 16

Features:

  • Instant feedback as you type
  • Line and column precision
  • Clear error messages from the parser
  • Multiple error reporting

2. Hover Documentation

Context-aware documentation for GQL keywords, functions, and types:

MATCH (n:Person)
WHERE n.age > 25
RETURN distance(n.embedding, $query, 'L2')
--     ^^^^^^^^ Hover shows: "distance(v1: VECTOR, v2: VECTOR) -> FLOAT"

Supported Items (100+ documented):

  • Keywords (40+): MATCH, RETURN, WHERE, CREATE, DELETE, MERGE, etc.
  • Functions (50+): count, sum, distance, similarity, timestamp, etc.
  • Types (15+): INTEGER, FLOAT, VECTOR, UUID, DATETIME, etc.

Example Documentation:

Hovering over distance:

distance(v1: VECTOR, v2: VECTOR, metric: STRING) -> FLOAT

Calculate distance between two vectors using the specified metric.

Supported metrics:
- 'L2' or 'euclidean': Euclidean distance
- 'cosine': Cosine distance
- 'manhattan': Manhattan (L1) distance
- 'dot': Dot product

Example:
  RETURN distance(n.embedding, $query, 'L2')

3. Code Completion

Intelligent auto-complete for GQL syntax:

MA<cursor>
-- Suggests: MATCH, MAX, MANHATTAN

RETURN co<cursor>
-- Suggests: count(), coalesce(), collect(), cos(), cosine()

WHERE n.<cursor>
-- Triggers property completion (when connected to server)

Completion Types:

  • Keywords: All GQL keywords with proper context
  • Functions: Function names with () insertion
  • Types: Data type names
  • Parameters: Variable names starting with $

Trigger Characters:

  • . - Property access
  • : - Label specification
  • $ - Parameter names

4. Document Synchronization

The LSP server maintains document state using two synchronization modes:

Full Synchronization:

  • Server receives complete document text on every change
  • Simpler implementation, suitable for smaller files
  • Default mode

Incremental Synchronization:

  • Server receives only changed text ranges
  • More efficient for large files
  • Supported but Full mode is default

IDE Integration

Visual Studio Code

Option 1: Manual Configuration

Add to your settings.json:

{
  "gql.server.enable": true,
  "gql.server.path": "/path/to/geode",
  "gql.server.args": ["lsp"],
  "gql.trace.server": "verbose"
}

Create a file type association for .gql files:

{
  "files.associations": {
    "*.gql": "gql",
    "*.gcypher": "gql",
    "*.cypher": "gql"
  }
}
Option 2: VS Code Extension

A complete VS Code extension is available in the repository:

cd editors/vscode
npm install
npm run compile
npx vsce package
# Install the .vsix file in VS Code

Extension Features:

  • TextMate grammar for syntax highlighting
  • Automatic LSP client configuration
  • Configurable server path and arguments
  • GQL language snippets
  • File icon themes

Extension Settings:

{
  "geode.lspPath": "/usr/local/bin/geode",
  "geode.lspArgs": ["lsp"],
  "geode.trace.server": "off"
}

Neovim

Using nvim-lspconfig

Create ~/.config/nvim/lua/lsp/geode.lua:

local lspconfig = require('lspconfig')
local configs = require('lspconfig.configs')

-- Define Geode LSP server
if not configs.geode then
  configs.geode = {
    default_config = {
      cmd = {'/usr/local/bin/geode', 'lsp'},
      filetypes = {'gql', 'gcypher', 'cypher'},
      root_dir = function(fname)
        return lspconfig.util.find_git_ancestor(fname) or vim.fn.getcwd()
      end,
      settings = {},
    },
  }
end

-- Set up Geode LSP
lspconfig.geode.setup{
  on_attach = function(client, bufnr)
    -- Key mappings
    local opts = { noremap=true, silent=true, buffer=bufnr }
    vim.keymap.set('n', 'gd', vim.lsp.buf.definition, opts)
    vim.keymap.set('n', 'K', vim.lsp.buf.hover, opts)
    vim.keymap.set('n', 'gi', vim.lsp.buf.implementation, opts)
    vim.keymap.set('n', '<leader>rn', vim.lsp.buf.rename, opts)
    vim.keymap.set('n', '<leader>ca', vim.lsp.buf.code_action, opts)
    vim.keymap.set('n', 'gr', vim.lsp.buf.references, opts)
    vim.keymap.set('n', '<leader>f', function()
      vim.lsp.buf.format { async = true }
    end, opts)

    -- Enable completion
    vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc')
  end,
  capabilities = require('cmp_nvim_lsp').default_capabilities(),
}

Add to init.lua:

require('lsp.geode')
File Type Detection

Add to ~/.config/nvim/ftdetect/gql.vim:

au BufRead,BufNewFile *.gql setfiletype gql
au BufRead,BufNewFile *.gcypher setfiletype gql
au BufRead,BufNewFile *.cypher setfiletype gql

Vim

Using vim-lsp plugin:

if executable('geode')
  au User lsp_setup call lsp#register_server({
    \ 'name': 'geode-lsp',
    \ 'cmd': {server_info->['geode', 'lsp']},
    \ 'allowlist': ['gql'],
    \ })
endif

" Key mappings
function! s:on_lsp_buffer_enabled() abort
  setlocal omnifunc=lsp#complete
  setlocal signcolumn=yes
  nmap <buffer> gd <plug>(lsp-definition)
  nmap <buffer> K <plug>(lsp-hover)
  nmap <buffer> <leader>rn <plug>(lsp-rename)
  nmap <buffer> [g <plug>(lsp-previous-diagnostic)
  nmap <buffer> ]g <plug>(lsp-next-diagnostic)
endfunction

augroup lsp_install
  au!
  autocmd User lsp_buffer_enabled call s:on_lsp_buffer_enabled()
augroup END

Emacs

Using lsp-mode:

(add-to-list 'lsp-language-id-configuration '(gql-mode . "gql"))

(lsp-register-client
 (make-lsp-client
  :new-connection (lsp-stdio-connection '("geode" "lsp"))
  :major-modes '(gql-mode)
  :server-id 'geode-lsp))

;; Define gql-mode (simple)
(define-derived-mode gql-mode fundamental-mode "GQL"
  "Major mode for GQL graph query language."
  (setq-local comment-start "//")
  (setq-local comment-end ""))

;; Associate file extensions
(add-to-list 'auto-mode-alist '("\\.gql\\'" . gql-mode))
(add-to-list 'auto-mode-alist '("\\.gcypher\\'" . gql-mode))
(add-to-list 'auto-mode-alist '("\\.cypher\\'" . gql-mode))

;; Start LSP in gql-mode
(add-hook 'gql-mode-hook #'lsp)

Starting the LSP Server

Command-Line Usage

# Start the LSP server (communicates via stdin/stdout)
geode lsp

# With verbose logging (to stderr)
GEODE_LSP_DEBUG=1 geode lsp 2> /tmp/geode-lsp.log

Help Information

geode lsp --help

Output:

geode lsp - Language Server Protocol server for GQL/Geode

Usage: geode lsp [options]

Description:
  Starts a Language Server Protocol (LSP) server for GQL files.
  The server communicates via JSON-RPC over stdin/stdout and provides:
    - Syntax error diagnostics
    - Hover documentation for GQL keywords, functions, and types
    - Code completion for GQL syntax
    - Document formatting

Options:
  -h, --help         Show this help message

Environment Variables

# Enable debug logging
export GEODE_LSP_DEBUG=1

# Set log file
export GEODE_LSP_LOG=/tmp/geode-lsp.log

# Set log level (debug, info, warn, error)
export GEODE_LSP_LOG_LEVEL=debug

Testing the LSP Server

Manual Testing

Create a test file test.gql:

// Sample GQL query for testing LSP features
MATCH (p:Person)-[:KNOWS]->(f:Person)
WHERE p.age > 25
RETURN p.name, f.name, distance(p.embedding, f.embedding, 'L2') AS similarity
ORDER BY similarity ASC
LIMIT 10

Start the server manually:

geode lsp

Send an initialize request (JSON-RPC):

Content-Length: 250

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "processId": null,
    "rootUri": "file:///path/to/workspace",
    "capabilities": {}
  }
}

The server responds with its capabilities:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "capabilities": {
      "textDocumentSync": 1,
      "hoverProvider": true,
      "completionProvider": {
        "triggerCharacters": [".", ":", "$"]
      }
    }
  }
}

Automated Testing

The LSP implementation includes 79 comprehensive tests:

# Run all LSP tests
zig test src/cli/lsp/test_runner.zig

# Run specific test files
zig test src/cli/lsp/protocol_test.zig   # 23 tests
zig test src/cli/lsp/document_test.zig   # 28 tests
zig test src/cli/lsp/features_test.zig   # 24 tests
zig test src/cli/lsp/server_test.zig     # 4 tests
zig test src/cli/lsp/e2e_test.zig        # 13 tests

Test Coverage:

  • Protocol structures and JSON-RPC (100%)
  • Document management and navigation (100%)
  • Language features (diagnostics, hover, completion) (100%)
  • Server lifecycle and state management (100%)
  • End-to-end workflows (100%)

Performance

Benchmarks

Syntax Highlighting:

  • Small query (< 100 chars): < 1µs
  • Medium query (< 1000 chars): < 10µs
  • Large query (< 10000 chars): < 100µs

Diagnostics (Parser):

  • Small file (< 100 lines): < 5ms
  • Medium file (< 1000 lines): < 50ms
  • Large file (< 10000 lines): < 500ms

Hover and Completion:

  • Response time: < 1ms (cached documentation)
  • First request: < 10ms (documentation loading)

Memory Usage:

  • Base server: ~12MB
  • Per document: ~1KB + document size
  • Efficient document storage with hash map lookups

Advanced Configuration

Custom Trigger Characters

Configure additional completion triggers in your IDE:

{
  "completionProvider": {
    "triggerCharacters": [".", ":", "$", "(", "["]
  }
}

Document Formatting

The LSP server supports basic document formatting:

{
  "method": "textDocument/formatting",
  "params": {
    "textDocument": {
      "uri": "file:///path/to/file.gql"
    },
    "options": {
      "tabSize": 2,
      "insertSpaces": true
    }
  }
}

Workspace Configuration

For multi-file projects, configure the workspace root:

-- Neovim: Custom root directory detection
root_dir = function(fname)
  return lspconfig.util.root_pattern('.git', 'geode.yaml')(fname)
    or lspconfig.util.find_git_ancestor(fname)
    or vim.fn.getcwd()
end

Server Logging

Enable detailed logging for debugging:

# Redirect stderr to log file
geode lsp 2> /tmp/geode-lsp.log

# Or in IDE configuration
{
  "gql.trace.server": "verbose"
}

Troubleshooting

Server Not Starting

Symptom: IDE shows “LSP server failed to start”

Solutions:

  1. Verify Geode is installed:

    which geode
    geode --version
    
  2. Test server manually:

    geode lsp --help
    
  3. Check permissions:

    ls -la $(which geode)
    
  4. Review IDE logs for error messages

No Completions or Hover

Symptom: Code completion or hover not working

Solutions:

  1. Verify file extension is recognized:

    • Use .gql, .gcypher, or .cypher
  2. Check LSP client is attached:

    • Neovim: :LspInfo
    • VS Code: Check LSP output panel
  3. Verify server capabilities:

    -- Neovim: Print capabilities
    :lua print(vim.inspect(vim.lsp.get_active_clients()[1].server_capabilities))
    
  4. Restart LSP client:

    • Neovim: :LspRestart
    • VS Code: Reload window

Diagnostics Not Updating

Symptom: Syntax errors not showing or outdated

Solutions:

  1. Verify text synchronization mode:

    {
      "textDocumentSync": 1  // Full sync mode
    }
    
  2. Check document version numbers are incrementing

  3. Force document refresh:

    • Save file (triggers didSave)
    • Close and reopen file
  4. Review LSP server logs for errors

High CPU Usage

Symptom: LSP server consuming excessive CPU

Solutions:

  1. Check for very large files (> 10,000 lines)

    • Parser may be slow on large inputs
  2. Disable unnecessary features:

    {
      "gql.diagnostics.enable": false  // Disable real-time checking
    }
    
  3. Increase debounce time in IDE:

    {
      "editor.quickSuggestionsDelay": 500  // VS Code
    }
    

Memory Leaks

Symptom: LSP server memory usage growing over time

Solutions:

  1. Restart LSP server periodically

    • Neovim: :LspRestart
  2. Close unused documents:

    • Server maintains state for all open files
  3. Report issue with reproduction steps

Future Enhancements

Planned Features

Short-term:

  1. Document formatting (pretty-print GQL)
  2. Go-to-definition for variables
  3. Symbol outline (document structure)
  4. Find references

Long-term:

  1. Semantic highlighting (textDocument/semanticTokens)
  2. Code actions (quick fixes, refactorings)
  3. Signature help for functions
  4. Inlay hints for types
  5. Call hierarchy
  6. Type hierarchy
  7. Rename refactoring
  8. Workspace symbols

Best Practices

File Organization

Organize GQL files for optimal LSP experience:

project/
├── queries/
│   ├── users.gql
│   ├── products.gql
│   └── analytics.gql
├── schemas/
│   └── graph_schema.gql
└── .git/

Query Style

Write clear, well-formatted queries:

// Good: Clear structure, proper indentation
MATCH (u:User)-[:PURCHASED]->(p:Product)
WHERE u.country = 'US'
  AND p.category = 'Electronics'
RETURN u.name, p.name, p.price
ORDER BY p.price DESC
LIMIT 10

// Avoid: Single-line, hard to read
MATCH (u:User)-[:PURCHASED]->(p:Product) WHERE u.country='US' AND p.category='Electronics' RETURN u.name,p.name,p.price ORDER BY p.price DESC LIMIT 10

Leveraging Hover

Use hover documentation to learn GQL:

// Hover over each keyword to see documentation
MATCH (n:Person)
WHERE n.age > 25
RETURN count(n) AS total

Completion Workflow

Efficient use of code completion:

  1. Type keyword prefix: MATMATCH
  2. Use trigger characters: n. → property suggestions
  3. Function completion: coucount()
  4. Parameter names: $ → parameter suggestions

Integration Examples

VS Code + GQL Workflow

{
  "files.associations": {
    "*.gql": "gql"
  },
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll": true
  },
  "gql.server.enable": true,
  "gql.server.path": "/usr/local/bin/geode",
  "gql.trace.server": "off"
}

Neovim + Treesitter + LSP

-- Complete setup with syntax highlighting and LSP
require('nvim-treesitter.configs').setup{
  ensure_installed = { "gql" },
  highlight = { enable = true },
}

require('lspconfig').geode.setup{
  on_attach = on_attach,
  capabilities = capabilities,
}

Vim + ALE (Alternative)

let g:ale_linters = {
\   'gql': ['geode-lsp'],
\}

let g:ale_fixers = {
\   'gql': ['geode-format'],
\}

Editor Plugins

Available Plugins

Complete editor integration packages are available:

Claude Code Plugin (geode-claude-plugin/):

claude /plugin install /path/to/geode-claude-plugin

Features:

  • Automatic LSP integration for Claude Code
  • MCP tools for direct Geode access
  • File extension mapping for .gql, .gcypher, .cypher, .pgql
  • Auto-installation hooks

VS Code Extension (editors/vscode/):

cd editors/vscode
npm install && npm run compile
npx vsce package

Features:

  • Full syntax highlighting with TextMate grammar
  • LSP integration via vscode-languageclient
  • Configurable settings

Neovim Configuration (editors/neovim/):

  • gql.lua - nvim-lspconfig setup with key mappings
  • gql.vim - Vim-style syntax highlighting

See editors/README.md for complete setup instructions.

Next Steps

Explore More:

Related Topics:

Community:

  • Report LSP issues on GitLab
  • Request features in discussions
  • Contribute editor plugins

Implementation: Complete (79/79 tests passing) Protocol: LSP 3.17, JSON-RPC 2.0 Parser: ISO/IEC 39075:2024 compliance Status: Production-ready