Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Noyalib logo

noyalib-mcp

Model Context Protocol server exposing noyalib's lossless YAML editing to AI agents (Claude Desktop, Claude Code, Cursor, Zed, Continue.dev, …).

Build Crates.io Docs.rs lib.rs OpenSSF Scorecard OpenSSF Best Practices


Contents


Install

cargo install noyalib-mcp

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

# npm wrapper: downloads the matching binary on first run, checks it
# against the SHA-256 in the package, caches it under
# ~/.cache/noyalib-mcp/<version>/. It refuses to run until releases
# publish per-platform archives and their digests.
npx @sebastienrousseau/noyalib-mcp

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

Split from the monorepo since v0.0.13. Prior versions shipped from sebastienrousseau/noyalib/crates/noyalib-mcp/ under the workspace-lockstep release cadence. From v0.0.13 onward noyalib-mcp lives here as its own crate, still released in strict lockstep with the parent noyalib at the same version. See ADR-0005 for the rationale and rollback recipe.

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


Requirements

  • Rust 1.89.0 or newer to build from source: rust-version in the manifest, enforced by the msrv-core CI job on every push.
  • Any tier-1 platform. CI runs the tests on Linux, macOS, and Windows with the stable, beta, and nightly toolchains; stable is the gate, beta and nightly are early warning.
  • The matching core. This crate pins noyalib at the identical =0.0.X and releases in lockstep with it; Cargo resolves that pin for you.
  • An MCP client speaking JSON-RPC 2.0 over stdio (2025-06-18 or 2026-07-28 protocol eras); the README’s Connect section lists tested hosts.

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":"2025-06-18","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

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:

  • noyalib_get — Takes { file: string, path: string }; returns the raw source fragment at the dotted/indexed path (e.g. server.host, items[0].name). No re-quoting; no canonicalisation.
  • noyalib_set — Takes { file: string, path: string, value: string }; returns 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.
  • noyalib_parse — Takes { yaml: string }; returns the JSON data model of the text (tags stripped, a stream as an array). Stateless: nothing on disk is touched.
  • noyalib_edit — Takes { yaml: string, path: string, value: string }; returns the whole text with that one value replaced losslessly. Stateless.
  • noyalib_validate — Takes { yaml: string, schema?: string }; returns valid with either the parse error (line and column) or every JSON Schema violation with its path. Stateless.

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

Command-line workflows are available through the noya-cli binaries (noyafmt, noyavalidate). Lower-level embedding uses the noyalib library API.


Examples

Agent-driving demos under examples/:

ScriptWhat it shows
handshake.shinitialize → tools/list smoke test. Confirms the binary speaks the protocol and announces the expected tools.
format-call.shtools/call format on a poorly-spaced document. Demonstrates that comments + indentation pass through the CST formatter unchanged.
set-then-get.shRound-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

GitHub Releases ship the crate archive and a CycloneDX SBOM, each with a sigstore bundle and checksums; the GHCR image is built from the tagged source. Pre-built binaries are not attached to releases yet. To verify a release artefact:

COSIGN_EXPERIMENTAL=1 cosign verify-blob \
  --certificate-identity-regexp '^https://github\.com/sebastienrousseau/noyalib-mcp/\.github/workflows/release\.yml@refs/tags/v[0-9]+\.[0-9]+\.[0-9]+$' \
  --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
  --bundle <artefact>.bundle \
  <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.89.0 stable, the floor shared across the noyalib family and the maintainer’s other Rust crates (noyalib ADR-0014). The MCP SDK alone needs 1.88.0. The MCP wire surface itself is text-only JSON-RPC and pulls no nightly-only dependencies. CI verifies the floor on every PR via the msrv-core workflow job. The bump policy lives in docs/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

The four entry points, identical across every repo in the family:


Sibling MCP servers by the same author — open-source, Apache-2.0 licensed, targeting banking and financial-services AI agents. noyalib-mcp complements them by giving agents lossless YAML editing for structured configuration files:

ServerPurpose
pain001-mcpGenerate & validate ISO 20022 pain.001 payment initiation files (Customer Credit Transfer)
bankstatementparser-mcpParse bank statements (BAI2, MT940/MT942, CAMT.053, OFX, CSV) into structured transactions
camt053-mcpParse & reconcile ISO 20022 camt.053 bank-to-customer statements — CBPR+/HVPS+ ready
acmt001-mcpGenerate & validate ISO 20022 acmt.001 account management messages

MCP Registry

mcp-name: io.github.sebastienrousseau/noyalib-mcp


Conformance

Every push runs the official yaml-test-suite through this server’s tools, from the same vendored suite and the same core commit as the noyalib core: 195 of 195 addressable cases (the other 211 have no top-level key for noyalib_get to read; noyalib_parse sees all of them). A two-document configuration that uses most of YAML at once (tests/fixtures/ultra-complex/) parses to exactly its expected JSON through noyalib_parse. Details and the family table: noyalib.com/conformance.

License

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