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:
- Configure MCP in Claude settings:
{
"mcpServers": {
"geode": {
"command": "geode",
"args": ["mcp", "serve", "--host", "localhost", "--port", "3141"]
}
}
}
- 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:
Verify Geode is installed:
which geode geode --versionTest server manually:
geode lsp --helpCheck permissions:
ls -la $(which geode)Review IDE logs for error messages
No Completions or Hover
Symptom: Code completion or hover not working
Solutions:
Verify file extension is recognized:
- Use
.gql,.gcypher, or.cypher
- Use
Check LSP client is attached:
- Neovim:
:LspInfo - VS Code: Check LSP output panel
- Neovim:
Verify server capabilities:
-- Neovim: Print capabilities :lua print(vim.inspect(vim.lsp.get_active_clients()[1].server_capabilities))Restart LSP client:
- Neovim:
:LspRestart - VS Code: Reload window
- Neovim:
Diagnostics Not Updating
Symptom: Syntax errors not showing or outdated
Solutions:
Verify text synchronization mode:
{ "textDocumentSync": 1 // Full sync mode }Check document version numbers are incrementing
Force document refresh:
- Save file (triggers didSave)
- Close and reopen file
Review LSP server logs for errors
High CPU Usage
Symptom: LSP server consuming excessive CPU
Solutions:
Check for very large files (> 10,000 lines)
- Parser may be slow on large inputs
Disable unnecessary features:
{ "gql.diagnostics.enable": false // Disable real-time checking }Increase debounce time in IDE:
{ "editor.quickSuggestionsDelay": 500 // VS Code }
Memory Leaks
Symptom: LSP server memory usage growing over time
Solutions:
Restart LSP server periodically
- Neovim:
:LspRestart
- Neovim:
Close unused documents:
- Server maintains state for all open files
Report issue with reproduction steps
Future Enhancements
Planned Features
Short-term:
- Document formatting (pretty-print GQL)
- Go-to-definition for variables
- Symbol outline (document structure)
- Find references
Long-term:
- Semantic highlighting (textDocument/semanticTokens)
- Code actions (quick fixes, refactorings)
- Signature help for functions
- Inlay hints for types
- Call hierarchy
- Type hierarchy
- Rename refactoring
- 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:
- Type keyword prefix:
MAT→MATCH - Use trigger characters:
n.→ property suggestions - Function completion:
cou→count() - 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 mappingsgql.vim- Vim-style syntax highlighting
See editors/README.md for complete setup instructions.
Next Steps
Explore More:
- REPL Advanced Features - Interactive shell
- Testing Strategies - Test your queries
- Query Performance Tuning - Optimize queries
Related Topics:
- GQL Guide - Learn GQL syntax
- API Reference - Complete function list
- Schema Design - Graph modeling
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