Back to Discover

scripthold

connector

zoster81

Secure encoding-aware local workspace runtime for AI agents

View on GitHub
0 starsSynced Aug 17, 2026

Install to Claude Code

/plugin marketplace add zoster81/scripthold

README

Scripthold — Secure MCP Server for Local Workspaces

Test Suite CodeQL golangci-lint Go Release License: GPL-3.0 MCP Registry Platforms Text encodings Source providers

Code from the web. Work locally. Recover safely.

Scripthold is a Model Context Protocol (MCP) server that gives web, desktop, and CLI agents controlled access to explicitly authorized local workspaces. It reads and writes legacy text safely, exposes deterministic repository-oriented workflows, supports authenticated Streamable HTTP as well as stdio, and can optionally run durable asynchronous local tasks.

AI clients see Настройки — not ???? or Íàñòðîéêè.

Scripthold detects encodings from bytes and decoded-text evidence rather than filenames, presents text to the MCP client as UTF-8, and preserves or deliberately converts encoding, BOM, and line endings through bounded-memory and durable filesystem operations.

  • 36 tools and 3 guided prompts over one authoritative catalog in Scripthold 3.0.0.
  • 168 registered encodings, including UTF-32 LE/BE and broad portable legacy coverage; automatic detection remains intentionally more conservative than explicit codec support.
  • 101 active source-intelligence providers across programming languages, dialects, DSLs, document/config formats, and composites, with capability-specific evidence and fail-closed ambiguity.
  • Secure filesystem boundaries with resolved-root containment, deterministic traversal, Windows reparse/junction handling, staged mutation, conflict detection, and no-replace creation.
  • Verified change workflows with deterministic fingerprints, one-shot edit approval, strict patch packages, persistent backup integration, and typed verification.
  • Offline backup recovery with deterministic persisted review plans, immutable source evidence, fully verified reconstruction into a separate staged destination, mandatory full audit, no-replace promotion, and path-free provenance.
  • Durable asynchronous execution with idempotent admission, an owner-only task store, bounded queue/logs, independent supervisor/worker/executor lifecycle, recovery, logical locks, and cancellation.
  • Fail-closed Streamable HTTP with bearer authentication, loopback defaults, exact Host/Origin checks, bounded resources, no CORS, and explicit TLS/proxy requirements for non-loopback exposure.

Scripthold was built with Scripthold.

Lineage: Scripthold originated from the original mcp-file-tools project, created by Dimitar Grigorov, and retains its GPL-3.0 lineage and permanent attribution. See Project Direction.

Current release and development state

Scripthold 3.0.0 is the current public release. It exposes 36 tools, 3 guided prompts, 168 registered encodings, and 101 active source-intelligence providers. The GitHub Release publishes six raw binaries, six platform archives, and checksums.txt; GitHub-only workflows add MCPB bundles and the MCP Registry publication for io.github.zoster81/scripthold.

The 3.0.0 release line contains the completed R23-R27 work and exposes 36 tools. R27 completed on 2026-08-16 with 101 active source-analysis providers across 103 registry rows; Dockerfile and Make remain auxiliary inactive metadata. source_symbols provides bounded declaration/navigation workflows, while source_query adds structural search, supported project relations, bounded fingerprint-verified context, and coherent process-local incremental generations. Capability claims are provider-specific and mechanically projected in docs/LANGUAGE_CAPABILITIES.md; ambiguous formats fail closed, and no external parser/compiler/LSP runtime or persistent on-disk code index is required.

No milestone after R27 is active by default; Scripthold 3.0.0 publishes the completed R23-R27 release scope. Current milestone state belongs in docs/ROADMAP.md, concise completed history in docs/ROADMAP_HISTORY.md, and the R23-R27 subsystem contracts in docs/MCP_MUTATION_SURFACE.md, docs/SAFE_FILESYSTEM_OPERATIONS.md, docs/SOURCE_INTELLIGENCE.md, docs/BACKUP_RECOVERY.md, and docs/MULTILANGUAGE_CODE_INTELLIGENCE.md.

Quality and security

The push-event Test Suite is the exact-commit release-candidate gate. It covers Windows/Linux/macOS native regression and race testing, Go vet, standalone Staticcheck, the repository's focused golangci-lint policy, govulncheck, deterministic fuzz checks, six supported-target cross-builds, workflow/shell validation, and native/container smoke before the aggregate Release candidate job can pass.

CodeQL adds Go code scanning on main pushes, a weekly schedule, and manual runs. Vulnerability reporting and responsible-disclosure guidance are in SECURITY.md. Secret scanning, allowed-root confinement, durable mutation/backup invariants, encoding safety, and transport security remain part of the repository's normal verification model rather than badge-only claims.

Transport and authorization model

TransportTypical useSecurity boundaryRoots behavior
stdioLocal MCP clients and secure tunnel bridgesClient configuration plus operating-system process boundaryStartup directories are authoritative; dynamic client roots are accepted only when startup roots are empty
Streamable HTTPPersistent localhost services, containers, trusted proxies, explicitly secured remote servicesBearer token on every MCP request; loopback by default; TLS or trusted proxy boundary for non-loopbackStartup directories are immutable and shared by all requests; HTTP clients cannot mutate roots

Both transports use the same BuildServer path and expose the same tools, prompts, limits, encoding behavior, error model, and execution policy.

Allowed directories are a process-wide authorization boundary. Sessions separate protocol lifecycle and cancellation; they are not per-agent filesystem ACLs. If two agents require technical isolation, run separate Scripthold processes with narrower roots and, for concurrent Git writes, separate checkouts or worktrees.

MCP 2026-07-28 is supported through the stable Go SDK. Native HTTP serves stateless modern requests beside retained stateful legacy sessions under the same outer authentication, Host/Origin, resource, logging, and execution controls. See docs/MCP_2026_07_28_ADOPTION.md and docs/HTTP_SECURITY.md.

Tool catalog

File and directory operations

  • read_text_file — stream decoded text with bounded output and optional line numbers.
  • read_multiple_files — deterministic bounded batch reads with per-file status.
  • write_whole_file — replace complete file contents through the shared encoder.
  • edit_file — read-only exact edit preview with approval fingerprints and a one-shot capability.
  • edit_file_apply — apply only the exact prepared edit identified by previewId.
  • patch_package — read-only inspect/dry-run/verify for declared multi-file edits.
  • patch_package_apply — apply only a prepared patch-package capability.
  • list_directory — list directory entries with filtering and deterministic sorting.
  • tree — compact .gitignore-aware deterministic tree output.
  • get_file_info — read file or directory metadata.
  • filesystem_package — read-only bounded preparation for coordinated no-replace create/copy/move/delete filesystem changes.
  • filesystem_package_apply — apply one prepared filesystem package by one-shot previewId.
  • search_files — bounded .gitignore-aware glob search.
  • source_symbols — bounded read-only source outline, digest, find, and fingerprint-bound show navigation.
  • source_query — bounded R27 read-only structural search, supported project relations, and fingerprint-verified task-context assembly.
  • fingerprint_paths — deterministic SHA-256 state fingerprints.
  • verify_state — bounded typed JSON/text/Git-diff/fingerprint checks.
  • backup_store — read-only status/history/compare/audit plus restore/GC preparation for the optional persistent store.
  • backup_restore_apply — apply one prepared original-target restore.
  • backup_gc_apply — apply one prepared generation-bound backup GC plan.
  • grep_text_files — paged regex search with deterministic partial-coverage reporting.

Encoding and service tools

Durable task execution

  • task_run — durably enqueue idempotent shell or script work.
  • task_list — page/filter persistent task metadata.
  • task_get — inspect current/terminal task state and bounded lifecycle history.
  • task_logs — read bounded stdout/stderr with absolute cursors.
  • task_cancel — cancel queued work or terminate a running process tree.

The detailed schemas, outputs, limits, and examples are authoritative in TOOLS.md. internal/toolcatalog/catalog.json is the source of truth for runtime tool metadata.

Encoding support

list_encodings is authoritative for canonical names, aliases, and capability metadata. Scripthold 3.0.0 exposes 168 canonical read/write encodings across Unicode, IBM/DOS/EBCDIC, ISO-8859, Windows, classic Mac/KOI8/other single-byte families, and East Asian/stateful multibyte families.

The production runtime remains pure Go. Additional mappings and state machines derived from pinned GNU libiconv evidence are checked in and require no libiconv/GCC dependency during ordinary build or execution. UTF-32 LE/BE are full text encodings with strict scalar validation; generic byte-order-unspecified utf-32 remains intentionally rejected. See docs/GLOBAL_ENCODING_COVERAGE.md for the completed R22 contract.

Installation

Choose stdio when the MCP client should own the child process or a secure bridge expects a local command. Choose Streamable HTTP for a persistent authenticated service. Both expose the same public behavior.

Use a published release

Scripthold-named releases use raw binary names of the form scripthold_<os>_<arch> (with .exe on Windows) and matching platform archives. Historical 2.0.0 predates the rename and retains its original asset names.

For reproducible installations, use a specific semantic release rather than @main or an assumed historical asset name. Verify the published asset against checksums.txt before installation.

Build from source

git clone https://github.com/zoster81/scripthold.git
cd scripthold
go test ./...
go build -o scripthold ./cmd/scripthold

The module path is github.com/zoster81/scripthold.

Local stdio clients

Pass every startup-authorized directory as an argument:

{
  "mcpServers": {
    "scripthold": {
      "type": "stdio",
      "command": "C:\\Tools\\scripthold_windows_amd64.exe",
      "args": ["D:\\Projects"]
    }
  }
}

A roots-capable stdio client may provide dynamic roots only when the process starts without directory arguments. MCP_STDIO_LEGACY_HANDSHAKE=1 exists only for legacy bridges that probe discovery and repeat an equivalent legacy initialization on one persistent child; leave it disabled for normal modern clients.

Native Streamable HTTP

HTTP requires exactly one bearer-token source. A minimal loopback PowerShell start is:

$tokenPath = Join-Path $env:TEMP "scripthold.token"
$bytes = New-Object byte[] 32
$rng = [System.Security.Cryptography.RandomNumberGenerator]::Create()
try { $rng.GetBytes($bytes) } finally { $rng.Dispose() }
[System.IO.File]::WriteAllText($tokenPath, [Convert]::ToBase64String($bytes), [System.Text.UTF8Encoding]::new($false))

$env:MCP_HTTP_TOKEN_FILE = $tokenPath
$env:MCP_HTTP_ADDR = "127.0.0.1:8765"
.\scripthold_windows_amd64.exe --transport=streamable-http D:\Projects

The MCP endpoint is http://127.0.0.1:8765/mcp; /healthz and /readyz expose minimal liveness/readiness status. The token must be sent as Authorization: Bearer <token> on every MCP request. Do not put tokens in command-line arguments, URLs, cookies, or query parameters.

Non-loopback listeners require explicit opt-in plus TLS or an explicitly trusted proxy boundary. Browser CORS is not enabled. See docs/HTTP_SECURITY.md before exposing HTTP beyond loopback.

OpenAI Secure MCP Tunnel

The repository includes sanitized PowerShell examples for tunnel and local topologies:

ExampleTopology
start-local-stdio.ps1One foreground local stdio server.
start-local-http.ps1One authenticated HTTP server; loopback by default.
start-openai-tunnel-stdio-plus-local-http.ps1Tunnel to a dedicated stdio child plus an independent local HTTP process.
start-openai-tunnel-http-plus-local-stdio.ps1Tunnel to authenticated HTTP plus an independent local stdio child.

Copy an example outside the Git checkout before replacing placeholders. Never commit Runtime API keys, Tunnel IDs, bearer tokens, or private state paths. The tunnel setup uses OpenAI's official tunnel-client; consult the official client documentation for current OpenAI control-plane requirements.

The example launchers keep task_run execution disabled by default. Script and shell execution remain separate authorizations, and HTTP additionally requires MCP_HTTP_ENABLE_EXECUTION=1.

Container image

The repository Dockerfile builds a statically linked binary and runs as unprivileged UID/GID 10001. The image is transport-neutral.

docker build --build-arg VERSION=dev -t scripthold:dev .

docker run --rm -i \
  --read-only \
  --cap-drop=ALL \
  --security-opt=no-new-privileges \
  --tmpfs /tmp:rw,noexec,nosuid,size=64m \
  --mount type=bind,source=/absolute/project,target=/data \
  scripthold:dev --transport=stdio /data

The mounted directory must be accessible to UID/GID 10001. HTTP containers should mount token/TLS files read-only, publish only the intended port, and preserve the security contract in docs/HTTP_SECURITY.md.

Security model

  • File tools access only explicitly authorized roots after canonical path resolution.
  • Recursive operations do not follow escaping symlinks, junctions, or other reparse points.
  • Mutations stage and revalidate before commit; initially missing destinations use no-replace creation. Single-file mutators classify the bounded actual target state after failures that may occur beyond the commit boundary instead of reporting preview-predicted changes as fact.
  • Failed MCP tool calls preserve stable error metadata/text; tools with structured output also expose errorCode and human-readable message there, retaining any existing partial-state evidence.
  • The optional backup store must be a separate non-overlapping owner-only authority and is inaccessible to ordinary file tools.
  • task_run is disabled by default. Script tasks validate/fingerprint the script and execute an owner-only matching snapshot; shell tasks validate the logical shell name before durable admission, confine only the working directory, and otherwise run with the executor identity's operating-system permissions.
  • HTTP adds authentication, Host/Origin, proxy/TLS, resource, logging, and execution boundaries; it is not a replacement for operating-system isolation.

Detailed contracts: HTTP security, verified changes, persistent backups, offline backup diagnostics, R23 mutation surface, R24 safe filesystem operations, R25 source intelligence, R26 backup recovery, and durable tasks.

Configuration

The most important process-wide variables are summarized below. Subsystem documents contain the precise security and lifecycle semantics.

VariablePurposeDefault
MCP_TRANSPORTstdio or streamable-http; CLI --transport takes precedence.stdio
MCP_DEFAULT_ENCODINGEncoding for newly created files when no encoding is supplied.utf-8
MCP_MAX_FILE_BYTESFull-document source-size limit.67108864
MCP_MAX_DECODED_CHARACTERSMaximum decoded characters returned by read_text_file.16777216
MCP_MAX_LINE_BYTESMaximum decoded UTF-8 bytes in one line.16777216
MCP_MAX_BATCH_FILESMaximum items in bounded batch/path-list operations.256
MCP_MAX_MATCHESServer maximum for grep matches.10000
MCP_MAX_OUTPUT_BYTESAggregate structured/text output budget.67108864
MCP_SOURCE_MAX_FILESR25 source files considered per request before stricter global ceilings.256
MCP_SOURCE_MAX_AGGREGATE_BYTESAggregate raw source bytes selected by one source-intelligence request.67108864
MCP_SOURCE_MAX_FILE_BYTESPer-file source-intelligence byte ceiling.8388608
MCP_SOURCE_MAX_SYMBOLSRetained source-symbol ceiling per request/analyzer budget.10000
MCP_SOURCE_MAX_CONCURRENCYBounded source-analysis worker count.4
MCP_SOURCE_MAX_REQUEST_SECONDSSource-intelligence request deadline.30
MCP_SOURCE_MAX_OUTPUT_BYTESSource-intelligence structured output budget before the global output ceiling.16777216
MCP_SOURCE_MAX_RESULTSR27 retained search/relation result ceiling.10000
MCP_SOURCE_MAX_GRAPH_NODESR27 graph-node ceiling.5000
MCP_SOURCE_MAX_GRAPH_EDGESR27 graph-edge ceiling.20000
MCP_SOURCE_MAX_GRAPH_DEPTHR27 graph traversal depth ceiling.8
MCP_SOURCE_MAX_CONTEXT_BYTESR27 task-context byte budget.1048576
MCP_SOURCE_MAX_CONTEXT_ITEMSR27 retained context-item ceiling.256
MCP_SOURCE_MAX_INDEX_PROJECTSR27 retained process-local index-scope ceiling.4
MCP_SOURCE_MAX_INDEX_GENERATIONSR27 retained generations per index scope.2
MCP_MAX_FILESYSTEM_PACKAGE_OPERATIONSMaximum operations in one filesystem-package-v1 manifest.256
MCP_MAX_FILESYSTEM_PACKAGE_BYTESMaximum prepared filesystem-package manifest size.16777216
MCP_MAX_FILESYSTEM_RECURSIVE_ENTRIESMaximum entries in one exact recursive copy/delete scope.100000
MCP_MAX_FILESYSTEM_RECURSIVE_DEPTHMaximum exact recursive copy/delete depth.128
MCP_MAX_FILESYSTEM_AGGREGATE_BYTESMaximum aggregate source bytes in one filesystem package.1073741824
MCP_MAX_FILESYSTEM_STAGING_BYTESMaximum aggregate bytes staged before filesystem-package commit.1073741824
MCP_MAX_FILESYSTEM_PACKAGE_PREVIEWSMaximum retained filesystem-package preview capabilities.16
MCP_MAX_FILESYSTEM_PACKAGE_PREVIEW_BYTESMaximum aggregate retained preview state.134217728
MCP_FILESYSTEM_PACKAGE_PREVIEW_TTL_SECONDSFilesystem-package preview lifetime.900
MCP_MEMORY_THRESHOLDDeprecated fallback for file/output byte limits.unset
MCP_HTTP_ADDRHTTP listen address.127.0.0.1:8765
MCP_HTTP_PATHMCP endpoint path./mcp
MCP_HTTP_TOKEN_FILE / MCP_HTTP_TOKENMutually exclusive HTTP bearer-token sources.unset
MCP_HTTP_ALLOWED_HOSTSAdditional exact Host values.listener-derived
MCP_HTTP_ALLOWED_ORIGINSExact accepted Origin values; no CORS headers are emitted.empty
MCP_HTTP_ALLOW_NON_LOOPBACKRequired opt-in for non-loopback binding.disabled
MCP_HTTP_TLS_CERT_FILE / MCP_HTTP_TLS_KEY_FILEDirect HTTPS certificate/key pair.unset
MCP_HTTP_TRUSTED_PROXY_CIDRSImmediate trusted proxy networks.empty
MCP_HTTP_MAX_BODY_BYTESPer-POST body limit.16777216
MCP_HTTP_MAX_INFLIGHT_BODY_BYTESAggregate concurrent POST-body reservation.67108864
MCP_HTTP_MAX_CONCURRENT_REQUESTSConcurrent non-SSE HTTP handlers.64
MCP_HTTP_SESSION_TIMEOUTLegacy stateful session idle timeout.15m
MCP_HTTP_ENABLE_EXECUTIONAdditional HTTP-only execution gate.disabled
MCP_BACKUP_STORE_DIREnables the dedicated persistent backup store.unset
MCP_BACKUP_DEFAULT_POLICYDefault persistent pre-state policy for approval-bound edit/package/BOM/encoding mutations: disabled or required.disabled
MCP_TASK_STORE_DIREnables the owner-only durable task registry.unset
MCP_ENABLE_RUN_SCRIPTAuthorizes task_run kind=script.disabled
MCP_ENABLE_SHELLAuthorizes unrestricted task_run kind=shell.disabled
MCP_ENABLE_EXECUTIONAuthorizes both task kinds.disabled

Backup limits, task-store limits, edit/package preview limits, and the full HTTP configuration contract are documented in docs/PERSISTENT_BACKUP_LIFECYCLE.md, docs/DURABLE_TASKS.md, TOOLS.md, and docs/HTTP_SECURITY.md.

Typical uses

  • Read and safely modify legacy source/configuration files without changing their encoding accidentally.
  • Search mixed-encoding repositories with explicit partial-coverage evidence.
  • Navigate heterogeneous repositories across 101 active source providers, query supported project relations, and assemble bounded source context without loading complete projects into the model.
  • Preview and approve edits or multi-file patch packages against deterministic fingerprints.
  • Keep approval-bound persistent backups and restore a selected original target safely.
  • Recover trustworthy records from a damaged backup store offline into a separate audited destination without modifying the source evidence.
  • Run long builds/tests through durable tasks without tying process lifetime to one MCP request.
  • Serve the same workspace tools through local stdio, authenticated HTTP, containers, or a secure tunnel bridge.

Example:

User: Read config.ini and change the title to "Настройки".
Assistant: read_text_file (cp1251) -> edit_file preview preserving cp1251 -> explicit approval -> edit_file_apply(previewId)

Development and contribution

Prerequisite Go version is declared by go.mod. The full local quality gate also uses the repository-pinned golangci-lint policy.

go mod verify
go test ./...
golangci-lint run ./...
go build -o scripthold ./cmd/scripthold

Contributor workflow is in CONTRIBUTING.md. Coding agents should read the root AGENTS.md and the nearest scoped guide. Reusable verification is in docs/DEVELOPMENT_CHECKLIST.md, current planning in docs/ROADMAP.md, and publication in docs/PUBLISHING.md.

The intentional 1.8-to-2.0 breaking changes remain documented in docs/MIGRATION_2.0.md. The Scripthold 3.0.0 R23-R27 surface evolution is documented in docs/MIGRATION_3.0.md and the completed subsystem contracts.

License

GPL-3.0 — see LICENSE.

Rendered live from zoster81/scripthold's GitHub README — not stored, always reflects the source repo.

6 Install Methods

NameDescriptionCategorySource
mcpb packageInstall via mcpb (stdio transport)mcp-serverhttps://github.com/zoster81/scripthold/releases/download/v3.0.0/scripthold_windows_amd64.mcpb
mcpb packageInstall via mcpb (stdio transport)mcp-serverhttps://github.com/zoster81/scripthold/releases/download/v3.0.0/scripthold_windows_arm64.mcpb
mcpb packageInstall via mcpb (stdio transport)mcp-serverhttps://github.com/zoster81/scripthold/releases/download/v3.0.0/scripthold_linux_amd64.mcpb
mcpb packageInstall via mcpb (stdio transport)mcp-serverhttps://github.com/zoster81/scripthold/releases/download/v3.0.0/scripthold_linux_arm64.mcpb
mcpb packageInstall via mcpb (stdio transport)mcp-serverhttps://github.com/zoster81/scripthold/releases/download/v3.0.0/scripthold_darwin_amd64.mcpb
mcpb packageInstall via mcpb (stdio transport)mcp-serverhttps://github.com/zoster81/scripthold/releases/download/v3.0.0/scripthold_darwin_arm64.mcpb

0 Comments

Login required
Log in to post a comment or update on this repo.

No comments yet — be the first to share an update.