ghul.mcp 2.1.27

Prefix Reserved
dotnet tool install --global ghul.mcp --version 2.1.27
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local ghul.mcp --version 2.1.27
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=ghul.mcp&version=2.1.27
                    
nuke :add-package ghul.mcp --version 2.1.27
                    

ghul-mcp

MCP (Model Context Protocol) server for the ghūl programming language. It drives the ghūl compiler's analysis mode to answer semantic queries — diagnostics, hover, definition, references, symbol search — so AI coding agents can query ghūl code by meaning instead of searching it as text.

Written in ghūl, consuming the ghul.analysis.protocol client library.

Status

Working. Multi-project routing: every semantic tool takes an optional project argument (absolute path to a ghūl project directory). Absent uses the server's --default-project. The server keeps a pool of analyser sessions (up to 8) keyed by canonical path and reaps least-recently-used entries above the cap, so multiple git worktrees under one Claude session can each stay warm.

Tools:

  • Whole-project: diagnostics (errors and warnings). A large result comes back as a summary - counts by severity, a by-code and top-files breakdown, every error in full - which you narrow with file, severity, code, or exclude_codes.
  • File-scoped: inlays (the narrowing / flow annotations the editor shows inline for one file - where a value is narrowed and where a narrowing is killed); optional code filter.
  • Position-based: hover, definition, references, implementations.
  • Name-based: symbols (substring search), hover_of, definition_of, references_of, implementations_of (resolve a name and return the answer, or the candidate list when a name is shared).
  • Type-based: members (list the members of a type expression - works for ghūl-declared and imported types including System.*).

All lines and columns are 1-based, matching compiler diagnostics.

Every analyser-backed result starts with a context line naming the project directory and the ghul.compiler version that answered, so a query routed to the wrong project - or served by a session warmed on a superseded pin - is visible in the result itself.

The server drives the target project's own pinned ghul.compiler tool in analysis mode, seeds it with the project's assembly references and source contents, and re-sends any file whose on-disk timestamp moved before answering each query - results always reflect what is on disk. A locally packed dev compiler (0.0.0-*, from dotnet pack -p:Version=0.0.0-local-<slug>.1 installed into the project's manifest) is accepted regardless of the minimum version - it is built from current source, so its analysis protocol is current too.

Install as a .NET tool

Published as ghul.mcp on NuGet. Add it to any project's local tool manifest:

dotnet new tool-manifest      # if the project has no .config/dotnet-tools.json yet
dotnet tool install --local ghul.mcp

Usage

Point the server at a ghūl project directory (its dotnet tools must be restored; the assemblies list is generated automatically on first use):

dotnet ghul-mcp --default-project path/to/project

Registering with Claude Code:

claude mcp add ghul -- dotnet ghul-mcp --default-project <project-dir>

Pool host

One analyser per project, shared by every client. The MCP server holds no analyser of its own: each tool call routes to the target project's pool host, a Unix-socket serve mode of this same binary, and the host keeps the project's analyser warm. A shell script - the Claude Code edit hook, say - feeds edits to the same host, so the analyser an editor session keeps current is the one queries are answered from, and the first full compile is paid once per project rather than once per client session:

dotnet ghul-mcp --pool-host /tmp/ghul-pool.sock --project path/to/project

Callers never launch the host by hand: every client - hook or MCP server - discovers a running host through the project-keyed socket path (/tmp/ghul-mcp-pool-<md5 of the project path>.sock) and connects to it, or starts one if nothing is listening. A client meeting a host from an incompatible ghul-mcp build (the hello handshake carries a protocol version) shuts it down as best it can and starts a fresh one.

The wire shape is newline-delimited JSON, one request per line: a hello handshake first, then call (a tool name and its arguments, answered with the same rendered, stamped text the MCP tool returns), edit (a file relative to the project, answered with that file's diagnostics), info, release, heap_check and shutdown. Connections are served serially; warm requests are milliseconds.

The host exits once it has gone --pool-host-idle-timeout seconds without a connection (default 1800; 0 waits indefinitely), unlinking its socket on the way out. A warm analyser holds the project's sources in memory, so one left over from an editing session that ended hours ago costs hundreds of megabytes to answer nothing. The MCP server propagates its own --pool-host-idle-timeout to the hosts it spawns.

A caller decides whether to launch a host by connecting, not by testing whether the socket file exists. A host killed outright cannot unlink its socket, and the file it leaves behind is indistinguishable from a live one; treating existence as proof of life leaves the socket dead until the file is removed by hand. On a refused connection, unlink the socket and relaunch.

Observability

pool_status (an MCP tool, or dotnet ghul-mcp --pool-status from a shell) sweeps every /tmp/ghul-mcp-pool-*.sock, asks each host for its status, and reports per project: the host pid, uptime and idle time, connection and request counters split by op, host and analyser memory, and the analyser's compiler, pid and source count. Sockets nothing answers are reported as stale. Discovery is the directory scan - the socket per project is the registry - so one call sees hosts used by other sessions, by the edit hook, and left behind by dead hosts alike.

The shared query log (~/.local/state/ghul-mcp/query-log.jsonl) records the host side too: every edit a hook feeds an analyser, and every failed op, one JSON line each alongside the MCP tool dispatches, carrying the host's pid so the two producers can be told apart.

Query log

The server appends one JSON line per tools/call dispatch to a query log: timestamp, pid, tool name, raw arguments, status (ok, error, unknown-tool, invalid-request), elapsed milliseconds, result size, and the first 300 characters of the result text. Analyser failures - spawn failures, timeouts, restart loops - surface as error entries carrying the exception message, so the log answers "is this server actually working reliably, and are its answers useful?" after the fact.

The log defaults to $XDG_STATE_HOME/ghul-mcp/query-log.jsonl (falling back to ~/.local/state/ghul-mcp/query-log.jsonl), shared by every server instance - entries carry the pid to tell sessions apart. --query-log <path> redirects it; --no-query-log disables it. At startup a log past 10 MB is rotated to <path>.prev. A logging failure never breaks the server: it disables the log for the rest of the run and reports once on stderr.

Build and test

dotnet tool restore
./tests/smoke.sh

Issues

View open issues or raise a new one.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last Updated
2.1.27 62 8/31/2026
2.1.26 56 8/31/2026
2.1.25 62 8/30/2026
2.1.24 63 8/30/2026
2.1.23 61 8/30/2026
2.1.22 60 8/30/2026
2.1.21 63 8/29/2026
2.1.20 61 8/29/2026
2.1.19 69 8/27/2026
2.1.18 88 8/26/2026
2.1.17 83 8/26/2026
2.1.16 88 8/26/2026
2.1.15 89 8/26/2026
2.1.14 80 8/26/2026
2.1.13 88 8/24/2026
2.1.12 88 8/24/2026
2.1.11 93 8/24/2026
2.1.10 92 8/23/2026
2.1.9 91 8/23/2026
2.1.8 95 8/23/2026
Loading failed