noyalib-mcp 0.0.5

Model Context Protocol server exposing noyalib's lossless YAML editing to AI agents
Documentation

Contents


Install

cargo install noyalib-mcp

For environments without a Rust toolchain (the typical AI-agent deployment shape):

# npm wrapper — auto-downloads the matching binary on first run,
# caches under ~/.cache/noyalib-mcp/<version>/.
npx noyalib-mcp

# Container — multi-arch (linux/amd64, linux/arm64).
docker run --rm -i ghcr.io/sebastienrousseau/noyalib-mcp:latest

Both consume the same signed binary attached to every GitHub Release. See Verification for the verify commands.


Quick Start

The server speaks JSON-RPC 2.0 over stdio with newline-delimited frames, per the MCP specification. A typical agent launches the binary as a child process, sends initialize, then dispatches tool calls:

{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"agent","version":"0.0.1"}}}
{"jsonrpc":"2.0","method":"notifications/initialized"}
{"jsonrpc":"2.0","id":2,"method":"tools/list"}
{"jsonrpc":"2.0","id":3,"method":"tools/call",
 "params":{"name":"format","arguments":{"yaml":"a:1\nb:2\n"}}}

Why this approach?

AI agents that edit YAML configuration today regex-replace and corrupt comments, indentation, and document structure. The same agent fixing a port number in a Kubernetes manifest can shift every comment by a line, reorder sibling keys, or strip trailing whitespace that a downstream linter cared about.

noyalib's CST does the edits losslessly — a set("server.port", "9090") rewrites only the byte span of the 8080 scalar; the surrounding comments and indentation pass through untouched. This server is the protocol shim that lets MCP-aware clients drive that engine safely:

  • Lossless mutation. tools/call set returns a document byte-identical to the input outside the touched span.
  • Surgical reads. tools/call get walks the dotted path and returns just the value, not the whole tree.
  • Schema validation. tools/call validate --schema runs the same JSON Schema 2020-12 engine noyavalidate ships.
  • Stdio transport. Standard MCP. Works with every spec-compliant client.

Connect

Claude Desktop / Claude Code

claude mcp add noyalib $(which noyalib-mcp)

Cursor

~/.cursor/mcp.json:

{
  "mcpServers": {
    "noyalib": {
      "command": "noyalib-mcp"
    }
  }
}

Zed

~/.config/zed/settings.json:

{
  "context_servers": {
    "noyalib": {
      "command": { "path": "noyalib-mcp" }
    }
  }
}

Continue.dev

~/.continue/config.json:

{
  "experimental": {
    "modelContextProtocolServers": [
      { "transport": { "type": "stdio", "command": "noyalib-mcp" } }
    ]
  }
}

Any other MCP-aware client

Point at the binary; the transport is stdio with newline- delimited JSON-RPC 2.0.


Tools exposed

The v0.0.1 server registers two file-oriented tools — both operate on a YAML file at file: <path>, not on inline source strings, so an agent's edits land on disk losslessly:

Tool Arguments Returns
noyalib_get { file: string, path: string } The raw source fragment at the dotted/indexed path (e.g. server.host, items[0].name). No re-quoting; no canonicalisation.
noyalib_set { file: string, path: string, value: string } The file rewritten via the lossless CST so only the touched span changes; comments, blank lines, and sibling formatting survive byte-for-byte. The value is a YAML fragment (0.0.2, "hello", [1, 2, 3]); a parse failure leaves the file unchanged.

Each tool's full input schema lives in the response to tools/list. The server also handles the standard initialize / initialized / notifications/cancelled lifecycle.

Format / parse / validate are not exposed as MCP tools today — they're available via the noya-cli binaries (noyafmt, noyavalidate) and the noyalib library API. Promotion to first-class MCP tools is on the v0.0.2+ roadmap.


Examples

Agent-driving demos under crates/noyalib-mcp/examples/:

Script What it shows
handshake.sh initializetools/list smoke test. Confirms the binary speaks the protocol and announces the expected tools.
format-call.sh tools/call format on a poorly-spaced document. Demonstrates that comments + indentation pass through the CST formatter unchanged.
set-then-get.sh Round-trip the mutation surface: set rewrites server.port, get reads it back. Surgical edit; surrounding bytes untouched.
chmod +x crates/noyalib-mcp/examples/*.sh
crates/noyalib-mcp/examples/handshake.sh | jq -c .

POSIX-shell only — no jq, no node dependencies. Pipe through jq -c . if you want pretty-printed JSON responses.


Verification

The npm wrapper and the GHCR image both consume the signed binary attached to every GitHub Release. To verify the underlying binary before trusting it:

COSIGN_EXPERIMENTAL=1 cosign verify-blob \
  --certificate-identity-regexp 'https://github.com/sebastienrousseau/noyalib/' \
  --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
  --certificate <artefact>.pem \
  --signature   <artefact>.sig \
  <artefact>

The npm wrapper additionally carries an npm provenance attestation:

npm view noyalib-mcp provenance

Full cookbook: pkg/VERIFY.md.


When not to use noyalib-mcp

  • You don't trust your AI agent with filesystem access at all. noyalib-mcp doesn't read or write files itself — every operation takes the YAML document as a string argument and returns the result as a string. The agent decides what to do with the result. If the agent has filesystem access, it can persist the response wherever it wants.
  • You need a sandboxed schema registry. noyalib-mcp accepts schemas as inline strings in tools/call validate; it does not fetch schemas from URLs. If your workflow needs network-resolved schemas, the agent is responsible for fetching the schema first and passing the bytes.

Compatibility

MSRV: Rust 1.75.0 stable — same floor as the core noyalib library. The MCP wire surface is text-only JSON-RPC and pulls no nightly-only deps. CI verifies the floor on every PR via the Per-crate MSRV workflow job. The bump policy lives in doc/POLICIES.md.

Tier-1 platforms (CI-verified each PR): aarch64-apple-darwin, x86_64-unknown-linux-gnu, x86_64-pc-windows-msvc. The binary writes via atomic file replacement on every platform — on Windows via MoveFileExW(MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH) semantics.


Documentation


License

Dual-licensed under Apache 2.0 or MIT, at your option.