Big News: Socket Selected for OpenAI's Cybersecurity Grant Program.Details
Socket
Book a DemoSign in
Socket

@levnikolaevich/hex-line-mcp

Package Overview
Dependencies
Maintainers
1
Versions
46
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@levnikolaevich/hex-line-mcp

Hash-verified file editing MCP + token efficiency hook for AI coding agents. 9 tools: inspect_path, read, edit, write, grep, outline, verify, changes, bulk_replace.

latest
Source
npmnpm
Version
1.26.0
Version published
Maintainers
1
Created
Source

hex-line-mcp

Hash-verified file editing MCP + token efficiency hook for AI coding agents.

npm downloads license node

Every line carries an FNV-1a content hash. Every edit must present those hashes back -- proving the agent is editing what it thinks it's editing. No stale context, no silent corruption. Hashing works on normalized logical text; writes preserve the file's existing line endings and trailing-newline shape.

By default, mutating tools stay inside the current project root. If you intentionally need to edit a temp or external path, pass allow_external: true on edit_file, write_file, or bulk_replace.

Features

9 MCP Tools

Core day-to-day tools:

  • read_file
  • edit_file
  • grep_search
  • outline
  • verify
  • bulk_replace

Advanced / occasional:

  • write_file
  • inspect_path
  • changes
ToolDescriptionKey Feature
read_fileRead file with progressive disclosure, optional edit-ready metadata, and automatic graph hints when availableMinimal plain discovery by default, explicit edit_ready for verified edits
edit_fileRevision-aware anchor edits (set_line, replace_lines, insert_after, replace_between)Batched same-file edits + conservative auto-rebase
write_fileCreate new file or overwrite, auto-creates parent dirsPath validation, no hash overhead
grep_searchSearch with ripgrep, summary-first discovery, and optional edit-ready hunkssummary by default, capped content mode with explicit allow_large_output escape hatch
outlineAST-based structural overview with hash anchors via tree-sitter WASM. Supports JavaScript/TypeScript, Python, C#, PHP, and fence-aware markdown headings95% token reduction, direct edit anchors
verifyCheck if held checksums / revision are still currentStaleness check without full re-read
inspect_pathUnified file-or-directory inspectionMinimal tree discovery by default, capped pattern-mode lists with refine hints
changesCompare file against git ref, shows added/removed/modified symbolsAST-level semantic diff with risk/provenance preview
bulk_replaceSearch-and-replace across multiple files inside an explicit root pathCompact summary (default) or capped diffs via format, dry_run, max_files

Hooks (SessionStart + PreToolUse + PostToolUse)

EventTriggerAction
PreToolUseRead/Edit/Write/Grep/Glob on project text scopeAdvises hex-line by default for project-scoped text files and file discovery; explicit hooks.mode: "blocking" hard redirects. Built-in tools stay available for binary/media, plan files in Plan Mode, and text paths outside the current project root
PreToolUseBash with dangerous commandsBlocks rm -rf /, git push --force, etc. Agent must confirm with user
PostToolUseBash with 50+ lines outputRTK: deduplicates, truncates, shows filtered summary to Claude as feedback
SessionStartSession beginsInjects a short bootstrap hint; defers to the active output style when hex-line style is enabled

Bash Redirects

PreToolUse also intercepts project-scoped file inspection Bash commands: cat, type, Get-Content, head, tail, ls, dir, tree, find, Get-ChildItem, stat, wc, Get-Item, grep, rg, findstr, Select-String, sed -i. Targeted inspection pipelines receive advisory hints by default and are hard redirected only in explicit blocking mode; Git/build/test/docker/network and stdin-filter pipelines remain allowed.

Install

MCP Server

npm i -g @levnikolaevich/hex-line-mcp
claude mcp add -s user hex-line -- hex-line-mcp

ripgrep is bundled via @vscode/ripgrep — no manual install needed for grep_search.

Requires Node.js >= 20.19.0.

Hooks

Hooks and output style are auto-synced on every MCP server startup. The server compares installed files with bundled versions and updates only when content differs. First run after npm i -g triggers full install automatically.

Hooks are written to global ~/.claude/settings.json with absolute path to hook.mjs. Output style is installed to ~/.claude/output-styles/hex-line.md and activated if no other style is set. To activate manually: /config > Output style > hex-line.

No extra manual setup is required after install. The startup sync uses the current Node runtime and a stable hook path under ~/.claude/hex-line, so the hook command survives spaces in the home directory on Windows, macOS, and Linux.

Validation

Use the normal package checks:

npm test
npm run lint
npm run check

For the full MCP workspace regression pass from the repository root, run the package test scripts explicitly:

npm --prefix mcp --workspace hex-common test
npm --prefix mcp --workspace hex-line-mcp test
npm --prefix mcp --workspace hex-graph-mcp test
npm --prefix mcp --workspace hex-ssh-mcp test:all

Maintainers can also run the internal scenario harness when they want reproducible repo-local workflow regressions:

npm run scenarios -- --repo /path/to/repo
npm run scenarios:diagnostic -- --repo /path/to/repo

The diagnostics run reports graph payload overhead and auto-refresh telemetry. Read those rows as engineering diagnostics, not as a compression score.

Comparative built-in vs hex-line benchmarks are maintained outside this package. External-baseline comparisons must reuse the same scenario suite and correctness contract before making broader claims.

Optional Graph Enrichment

If a project already has .hex-skills/codegraph/index.db, hex-line automatically adds lightweight graph hints to read_file, outline, grep_search, edit_file, and changes.

  • Graph enrichment is optional. If .hex-skills/codegraph/index.db is missing, stale, or unreadable, hex-line falls back to standard behavior silently.
  • Graph enrichment is project-deterministic. hex-line only uses the graph database that belongs to the resolved current project scope.
  • Nested projects do not inherit graph hints from a parent repo index once a nested project boundary is detected.
  • better-sqlite3 is optional. If it is unavailable, hex-line still works without graph hints.
  • read_file only emits the top-line Graph: header in verbosity=full.
  • grep_search only emits line-level graph annotations in output=content when editReady=true. summary, files, count, and discovery-only content search stay graph-free.
  • Grep annotations are capped and count-suffixes are deduplicated so the first label keeps the counts and later labels stay short.
  • read_file, outline, and grep_search stay compact: they only surface high-signal local facts such as api, framework entrypoints, callers, flow, and clone hints.
  • edit_file and changes surface the deeper review layer: external callers, downstream return/property flow, clone peers, public API risk, framework entrypoint risk, and same-name sibling warnings when present.
  • Both tools now expose a short top-level preview before the detailed sections: payload_sections, graph_enrichment, count fields, and provenance_summary.
  • Stale graph data never changes correctness. hex-line suppresses stale hints, schedules a best-effort reindexFile(...) for a stale file, and escalates to one background indexProject(...) when several files go stale inside the burst window.
  • The threshold-crossing file still keeps its point refresh so a short stale burst does not create a blind gap before the project refresh finishes.
  • edit_file may still use stale graph context as same-response advisory metadata when the file was just edited, but stale graph never gates the edit protocol itself.
  • npm run scenarios:diagnostic -- --with-graph prints graph payload overhead plus an auto-refresh probe line with suppressions, file_refresh, project_refresh, and threshold_hits.

hex-line does not read hex-graph internals directly anymore. The integration uses a small read-only contract exposed by hex-graph-mcp:

  • hex_line_symbols
  • hex_line_line_facts
  • hex_line_edit_impacts
  • hex_line_edit_impact_facts
  • hex_line_clone_siblings

Tools Reference

Common Workflows

Local code edit in one file

  • outline for large code files
  • read_file for the exact range you need
  • edit_file with all known hunks in one call

Follow-up edit on the same file

  • Carry revision from the earlier read_file or edit_file
  • Pass it back as base_revision
  • Use verify before delayed or mixed-tool follow-up edits
  • If the server returns retry_edit, retry_edits, retry_checksum, or retry_plan, reuse those directly

Rewrite a long block

Use replace_between inside edit_file when you know stable start/end anchors and want to replace a large function, class, or config block without reciting the old body.

Literal rename / refactor

Use bulk_replace for text rename patterns across one or more files inside a known project root or directory scope. Pass path explicitly. In normal agent workflows that scope should be auto-filled from the current project root, not typed manually. Returns compact summary by default; pass format: "full" for capped diffs. Do not use it as a substitute for structured block rewrites.

read_file

Read a file with progressive disclosure. Default mode is discovery-first: plain partial lines, low token cost, and optional continuation hints. When you need verified edits, pass edit_ready: true with verbosity: "full" to get canonical read_range blocks with anchors and checksums. Directories go through inspect_path.

ParameterTypeRequiredDescription
file_pathstringyesFile path
file_pathsstring[]noArray of file paths to read (batch mode)
offsetnumbernoStart line, 1-indexed (default: 1)
limitnumbernoMax lines to return (default: 200 for discovery, 2000 for edit-ready, 0 = all)
rangesarraynoExplicit line ranges, e.g. [{ "start": 10, "end": 30 }]
plainbooleannoOmit hashes, output lineNum|content instead
verbosityenumnominimal, compact, or full
edit_readybooleannoInclude hash/checksum edit protocol blocks explicitly

Default output is discovery-first:

File: lib/search.mjs
meta: 282 lines, 10.2KB, 2 hours ago
continuation: {"kind":"offset","offset":4,"limit":200}

1|import { resolve } from "node:path";
2|import { readFileSync } from "node:fs";
3|...

Explicit edit-ready output:

File: lib/search.mjs
meta: 282 lines, 10.2KB, 2 hours ago
revision: rev-12-a1b2c3d4
file: 1-282:beefcafe
eol: lf
trailing_newline: true

block: read_range
span: 1-3
eol: lf
trailing_newline: true
ab.1    import { resolve } from "node:path";
cd.2    import { readFileSync } from "node:fs";
ef.3    ...
checksum: 1-3:f7e2a1b0

edit_file

Edit using revision-aware hash-verified anchors. Prefer one batched call per file. For text rename use bulk_replace.

ParameterTypeRequiredDescription
file_pathstringyesFile to edit
editsstringyesJSON array of edit operations (see below)
dry_runbooleannoPreview changes without writing
restore_indentbooleannoAuto-fix indentation to match anchor context (default: false)
base_revisionstringnoPrior revision from read_file / edit_file for same-file follow-up edits
conflict_policyenumnoconservative or strict (default: conservative)
allow_externalbooleannoAllow editing a path outside the current project root

Edit operations (JSON array):

[
  {"set_line": {"anchor": "ab.12", "new_text": "replacement line"}},
  {"replace_lines": {"start_anchor": "ab.10", "end_anchor": "cd.15", "new_text": "...", "range_checksum": "10-15:a1b2c3d4"}},
  {"insert_after": {"anchor": "ab.20", "text": "inserted line"}},
  {"replace_between": {"start_anchor": "ab.30", "end_anchor": "cd.80", "new_text": "...", "boundary_mode": "inclusive"}}
]

Discipline:

  • Never invent range_checksum. Copy it from read_file or grep_search(output_mode:"content").
  • First mutation in a file: prefer grep_search for narrow targets, or outline -> read_file(ranges) for structural edits.
  • Prefer 1-2 hunks on the first pass. Once edit_file returns a fresh revision, continue from that state as base_revision.
  • hex-line preserves existing file line endings on write; repo-level line-ending cleanup should be a separate deliberate operation, not a side effect of edit_file.

Result footer includes:

  • status: OK | AUTO_REBASED | CONFLICT
  • reason: ... as the canonical machine-readable cause for the current status
  • revision: ...
  • summary: ... with edited line span / diff counts on successful edits
  • payload_sections: ... so callers know which detailed sections follow
  • graph_enrichment: unavailable + graph_fix: ... when the project graph is missing or out of sync (silent when graph is healthy)
  • ⚠ Semantic impact: and ⚠ N clone(s): blocks emitted directly when graph-backed review data is available
  • changed_ranges: ... when relevant
  • recovery_ranges: ... with the narrowest recommended read_file ranges for retry
  • next_action: ... as the canonical immediate choice: apply_retry_edit, apply_retry_batch, or reread_then_retry
  • remapped_refs: ... when stale anchors were uniquely relocated
  • retry_checksum: ... on local conflicts, narrowed to the exact target range when possible
  • retry_edit: ... when the server can synthesize a ready-to-retry edit skeleton from current local state
  • retry_edits: ... on conservative batch conflicts when every conflicted edit can be retried directly
  • suggested_read_call: ... when rereading is the safest next step
  • retry_plan: ... with a compact machine-readable next-call plan
  • summary: ... and snippet: ... instead of long prose blocks on conflicts
  • edit_conflicts: N on conservative multi-edit preflight conflicts

write_file

Create a new file or overwrite an existing one. Creates parent directories automatically.

ParameterTypeRequiredDescription
file_pathstringyesFile path
contentstringyesFile content
allow_externalbooleannoAllow writing a path outside the current project root

Search file contents using ripgrep. Default mode is summary for discovery. Use content with edit_ready: true when you need canonical search_hunk blocks for verified edits. files and count stay plain list modes.

ParameterTypeRequiredDescription
patternstringyesSearch pattern (regex by default, literal if literal:true)
pathstringnoDirectory or file to search (default: cwd)
globstringnoGlob filter, e.g. "*.ts"
typestringnoFile type filter, e.g. "js", "py"
output_modeenumnoOutput format: "summary" (default), "content", "files_with_matches", "count"
case_insensitivebooleannoIgnore case
smart_casebooleannoCI when lowercase, CS when uppercase (-S)
literalbooleannoLiteral string search, no regex (-F)
multilinebooleannoPattern can span multiple lines (-U)
contextnumbernoSymmetric context lines around matches (-C)
context_beforenumbernoContext lines BEFORE match (-B)
context_afternumbernoContext lines AFTER match (-A)
limitnumbernoMax matches per file (default: 20 for summary, 100 for content)
head_limitnumbernoTotal match events across all files; multiline matches count as 1 (default: 50 for summary, 200 for content, 1000 for files_with_matches/count, 0 = unlimited)
plainbooleannoOmit hash tags inside block entries, return lineNum|content
edit_readybooleannoPreserve hash/checksum search hunks in content mode
allow_large_outputbooleannoBypass the default content-mode block/char caps when you intentionally need a larger payload

summary mode returns counts, top files, and a few plain snippets. content mode returns canonical search_hunk blocks with per-hunk checksums enabling direct replace_lines from grep results without intermediate read_file.

  • Default content mode is intentionally capped to keep discovery cheap. When truncation happens, the diagnostic block includes shown_matches, file_count, truncated, next_action, and suggested_refine_call.
  • Treat allow_large_output: true as an explicit override for review/debug workflows, not as the normal discovery path.

outline

AST-based structural outline with hash anchors for direct edit_file usage. Supports JavaScript/TypeScript, Python, C#, PHP, and fence-aware markdown heading navigation (.md/.mdx). Each entry includes a hash tag for immediate anchor use without intermediate read_file.

ParameterTypeRequiredDescription
file_pathstringyesSource file path

Supported languages: JavaScript (.js, .mjs, .cjs, .jsx), TypeScript (.ts, .tsx), Python (.py), C# (.cs), and PHP (.php) via tree-sitter WASM.

Not for .json, .yaml, .txt -- use read_file directly for those.

verify

Check if range checksums from prior read/search blocks are still valid, optionally relative to a prior base_revision. Returns a deterministic verification report with canonical status, summary, next_action, and compact entry lines.

ParameterTypeRequiredDescription
file_pathstringyesFile path
checksumsstring[]yesArray of checksum strings, e.g. ["1-50:f7e2a1b0"]
base_revisionstringnoPrior revision to compare against latest state

Example output:

status: STALE
reason: checksums_stale
revision: rev-17-deadbeef
summary: valid=0 stale=1 invalid=0
next_action: reread_ranges
base_revision: rev-16-feedcafe
changed_ranges: 10-12(replace)
suggested_read_call: {"tool":"mcp__hex-line__read_file","arguments":{"file_path":"/repo/file.ts","ranges":["10-12"]}}

entry: 1/1 | status: STALE | span: 10-12 | checksum: 10-12:oldc0de0 | current_checksum: 10-12:newc0de0 | next_action: reread_range | summary: content changed since checksum capture

inspect_path

Inspect a file or directory path without guessing which low-level tool to call first.

ParameterTypeRequiredDescription
pathstringyesFile or directory path
patternstringnoGlob filter on names (e.g. "*-mcp", "*.mjs"). Returns flat match list instead of tree
typestringno"file", "dir", or "all" (default). Like find -type f/d
max_depthnumbernoMax recursion depth (default: 2 for discovery, or 20 in pattern mode)
max_entriesnumbernoMax entries to show in pattern mode before truncation metadata is returned (default: 60, 0 = unlimited)
gitignorebooleannoRespect root .gitignore patterns (default: true). Nested .gitignore not supported
formatstringno"compact" = shorter path view. "full" = include sizes / metadata where available
verbosityenumnominimal, compact, or full
  • For regular files it returns compact metadata: size, line count when cheap, modification time, type, and binary flag.
  • For directories it returns a gitignore-aware tree.
  • With pattern, it switches to flat match mode and works as the preferred replacement for find / recursive ls.
  • Broad pattern mode is capped by default and returns match_count, shown_count, truncated, next_action, and suggested_refine_call so the caller can narrow path before asking for more.

Hook

The unified hook (hook.mjs) handles five Claude hook events:

PreToolUse: Tool Redirect

Advises built-in Read, Edit, Write, Grep, and Glob on project-scoped text workflows to use hex-line. Missing or malformed hook state defaults to advisory mode; set .hex-skills/environment_state.json to hooks.mode: "blocking" to hard-route covered calls. Binary/media files (images, PDFs, notebooks, archives, executables, fonts, media), plan markdown files in Plan Mode, and text paths outside the current project root stay on built-in tools.

PreToolUse: Bash Redirect + Dangerous Blocker

Intercepts project-scoped Bash file inspection commands (cat, type, Get-Content, head, tail, ls, dir, tree, find, Get-ChildItem, stat, wc, Get-Item, grep, rg, findstr, Select-String, sed -i, etc.) and advises hex-line tools by default. Explicit blocking mode hard redirects covered cases. Dangerous commands (rm -rf /, git push --force, git reset --hard, DROP TABLE, chmod 777, mkfs, dd) are always blocked.

PostToolUse: RTK Output Filter

Triggers on Bash tool output exceeding 50 lines. Pipeline:

  • Detect command type -- npm install, test, build, pip install, git verbose, or generic
  • Normalize -- replaces UUIDs, timestamps, IPs, hex values, large numbers with placeholders
  • Deduplicate -- collapses identical normalized lines with (xN) counts
  • Truncate -- keeps first 15 + last 15 lines, omits the middle

SessionStart: Bootstrap Hint

Injects a compact startup reminder. If the hex-line output style is active, the hook emits only a minimal bootstrap hint plus ToolSearch('+hex-line read edit') fallback. Otherwise it injects the short preferred read/edit workflow directly, including the scope rule: use file paths for file tools and the current project root for repo-wide tools such as bulk_replace.

Hook policy constants in lib/hook-policy.mjs:

ConstantDefaultPurpose
LINE_THRESHOLD50Minimum lines to trigger filtering
HEAD_LINES15Lines to keep from start
TAIL_LINES15Lines to keep from end

SessionStart: Tool Preferences

Injects a short operational workflow into agent context at session start. If schemas are not loaded yet, it includes the ToolSearch('+hex-line read edit') fallback. Primary flow stays outline -> read_file -> edit_file -> verify, with targeted reads over full-file reads.

PreToolUse: Plan Mode Enforcement

When permission_mode === "plan", blocks mutating hex-line tools (edit_file, write_file, bulk_replace) with a hard deny. Read-only tools pass through normally. This enforces plan mode for MCP tools that bypass the built-in Edit/Write permission layer.

ConfigChange: Cache Invalidation

Invalidates cached hook mode and hex-line disabled flag when settings change mid-session. Dispatches before the isHexLineDisabled() check so that toggling hex-line on/off mid-session takes effect without restart.

PermissionDenied: Observability

Logs when Claude denies a tool call after the hook delivered a redirect hint. Reads data.reason for hex-line tool mentions and Bash denials. Observability only — no action taken.

Architecture

hex-line-mcp/
  server.mjs          MCP server (stdio transport, 9 tools)
  hook.mjs            Unified hook (PreToolUse + PostToolUse + SessionStart)
  package.json
  lib/
    hook-policy.mjs   Shared hook policy: redirects, thresholds, danger patterns
    setup.mjs         Startup autosync for hook + output style
    read.mjs          File reading with hash annotation
    edit.mjs          Anchor-based edits, diff output
    search.mjs        ripgrep wrapper with hash-annotated results
    outline.mjs       tree-sitter WASM AST outline
    verify.mjs        Range checksum verification
    info.mjs          File metadata (size, lines, mtime, type)
    tree.mjs          Directory tree with .gitignore support
    inspect-path.mjs  Unified file/directory inspection
    changes.mjs       Semantic git diff via AST
    bulk-replace.mjs  Multi-file search-and-replace
    setup.mjs         Claude hook installation + output style setup
    format.mjs        Output formatting utilities
    security.mjs      Path validation, binary detection, size limits
    @levnikolaevich/hex-common/
      text-protocol/hash.mjs   Shared FNV-1a hashing and checksum protocol
      output/normalize.mjs     Shared output normalization helpers

Hash Format

ab.42    const x = calculateTotal(items);
  • ab -- 2-char FNV-1a tag derived from content (whitespace-normalized)
  • 42 -- line number (1-indexed)
  • Tab separator, then original content
  • Tag alphabet: abcdefghijklmnopqrstuvwxyz234567 (32 symbols, bitwise selection)

Range Checksums

checksum: 1-50:f7e2a1b0

FNV-1a accumulator over all line hashes in the range (little-endian byte feed). Detects changes to any line, even ones not being edited.

Security

  • Path canonicalization via realpathSync (resolves symlinks)
  • Binary file detection (null byte scan in first 8KB)
  • 10 MB file size limit
  • Write path validation (ancestor directory must exist)
  • Directory restrictions delegated to Claude Code sandbox

FAQ

Does it work without Claude Code?

Yes. hex-line-mcp is a standard MCP server (stdio transport). It works with any MCP-compatible client -- Claude Code, Gemini CLI, Codex CLI, or custom integrations. Hook installation is Claude-specific; Gemini/Codex use MCP Tool Preferences guidance instead.

What happens if a hash is stale?

The edit is rejected with an error showing which lines changed since the last read. The agent must re-read the affected range and retry. This prevents silent overwrites from stale context.

Is outline available for all file types?

Outline works on JavaScript/TypeScript, Python, C#, PHP, and markdown heading navigation (.md/.mdx, fenced code blocks ignored). For JSON, YAML, and text files use read_file directly. Each outline entry includes a hash anchor (tag.line-range: symbol) for direct use in edit_file.

How does the RTK filter work?

The PostToolUse hook normalizes Bash output (replaces UUIDs, timestamps, IPs with placeholders), deduplicates identical lines, and truncates to first 15 + last 15 lines. The filtered summary is shown to Claude as stderr feedback via exit code 2.

Can I disable the built-in tool blocking?

Yes. The supported runtime bypass is .hex-skills/environment_state.json -> { "hooks": { "mode": "advisory" } }, which downgrades project text redirects to advice. To remove the hook entirely, delete the hex-line hook entries from ~/.claude/settings.json. To disable the MCP server for one project, add hex-line to ~/.claude.json -> projects.{cwd}.disabledMcpServers.

Hex Family

PackagePurposenpm
hex-line-mcpLocal file editing with hash verification + hooksnpm
hex-ssh-mcpRemote file editing over SSHnpm
hex-graph-mcpCode knowledge graph with AST indexingnpm

License

MIT

Keywords

mcp

FAQs

Package last updated on 16 Apr 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts