npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@nerdo/json-emitter-mcp

v0.4.0

Published

MCP server that converts YAML to validated JSON — a safer emission surface for LLMs generating structured JSON payloads.

Downloads

29

Readme

json-emitter

An MCP server with one tool: emit_json(yaml, jsonSchema?, options?). It converts a YAML 1.2 payload to JSON, optionally validating against a JSON Schema. The response body is the JSON. Failures raise an MCP error with a message naming the phase and location. A returned response is always a valid JSON payload.

Why

LLMs emitting JSON directly frequently drop escape-within-prose-strings at length — a stray " inside a long "text" value silently breaks the whole document (e.g. SyntaxError at position 12021). YAML block scalars (|, >) eliminate the context switch: inside |, quotes/colons/pipes/asterisks are just prose.

The tool returns the JSON as the response body rather than wrapping it in an envelope, and raises errors rather than returning them as data. Callers work with the JSON directly; whatever processing they do with it afterwards is their call.

Install & run

Local checkout (no publish):

bun install
bun run src/main.ts

Or build and run the bundle:

bun run build
bun dist/main.js

By default it listens on stdio. To listen on Streamable HTTP:

JSON_EMITTER_TRANSPORT=http JSON_EMITTER_HTTP_PORT=3000 bun src/main.ts
# or
bun src/main.ts --transport=http --port=3000
# then POST JSON-RPC to http://127.0.0.1:3000/mcp

Using it from a Claude Code MCP config

From npm (once published):

{
  "mcpServers": {
    "json-emitter": {
      "command": "npx",
      "args": ["-y", "@nerdo/json-emitter-mcp"]
    }
  }
}

From a local checkout:

{
  "mcpServers": {
    "json-emitter": {
      "command": "bun",
      "args": ["run", "/absolute/path/to/json-emitter-mcp/src/main.ts"]
    }
  }
}

The tool

emit_json({
  yaml: string,
  jsonSchema?: object,
  options?: { pretty?: boolean }
})

Success

The tool returns with content[0].text set to the JSON — literally, with no envelope:

{"text":"TI-13196 has been \"explore\" status...","count":3}

Default output is compact. Pass options: {pretty: true} for 2-space indentation.

Failure

The tool raises an MCP error. MCP clients surface it as an exception from callTool(...); LLMs see an error in the tool result. The error message names the phase and location.

Parse failure (malformed YAML):

YAML parse error at line 1, column 19 (offset 18):
Missing closing "quote at line 1, column 19:

   1 | foo: "unterminated
   1 |                   ^

Schema-compile failure (the user-supplied jsonSchema itself is invalid):

JSON Schema is invalid and could not be compiled: schema is invalid: data/type must be equal to one of the allowed values

Validation failure (YAML parses, but the data doesn't match the schema):

JSON Schema validation failed with 1 issue(s):
  /text: must NOT have more than 3000 characters  (keyword: maxLength, params: {"limit":3000})

For common parse errors (duplicate keys, multi-document streams, tab indentation, inconsistent indentation), the message appends a one-line Hint: pointing at the fix:

YAML parse error at line 2, column 1 (offset 5):
Map keys must be unique at line 2, column 1:

   1 | a: 1
   2 | a: 2
   2 | ^

Hint: Remove the duplicate key — YAML 1.2 mappings must have unique keys. If you need multiple values, use a sequence.

Resources

The server also exposes one MCP resource for clients that list them:

| URI | MIME | Purpose | |-----|------|---------| | json-emitter://docs/yaml-authoring-guide | text/markdown | Quoting rules, block-scalar usage, what the tool rejects vs. silently converts, and why a jsonSchema catches indentation-driven structural bugs. |

Read it via resources/read in any MCP client, or via the Inspector.

Example

Input YAML:

text: |
  TI-13196 has been "explore" status for a full sprint — Monday worth a check-in.
  Commits like "fix: thing" and times like 10:30am pass through intact.
count: 3

Optional JSON Schema:

{
  "type": "object",
  "required": ["text", "count"],
  "properties": {
    "text": { "type": "string", "maxLength": 3000 },
    "count": { "type": "integer" }
  }
}

Tool response content (success):

{"text":"TI-13196 has been \"explore\" status for a full sprint — Monday worth a check-in.\nCommits like \"fix: thing\" and times like 10:30am pass through intact.\n","count":3}

That's the response body — already valid JSON, already compact, the contract's output.

Authoring YAML for this tool

  • Put long or multi-line text under a | block scalar. Inside |, quotes/colons/pipes/asterisks are just prose.
  • Quote strings that look like booleans, numbers, dates, or null (yes, on, 12, 2024-01-01). YAML 1.2 Core Schema is used — the Norway problem is off (no stays "no", not false), but ambiguous-looking plain scalars are still safer quoted.
  • Quote all-digit identifiers (git SHAs, phone numbers, IDs past 2⁵³) and scientific-notation-shaped strings ("1e2") to avoid precision loss and silent numeric coercion.
  • Pass the target jsonSchema whenever one exists. Without it, only parse errors can be caught — the schema is also the one mechanical defense against indentation-driven structural bugs.

For a longer reference — including what the tool rejects outright and the inherently non-catchable residual — see the json-emitter://docs/yaml-authoring-guide MCP resource.

Libraries

Dev loop

bun run validate   # test → typecheck → test → build
bun run test       # just tests
bun run typecheck  # just tsc --noEmit
bun run lint       # biome lint
bun run format     # biome format --write

Run the Inspector against a local copy:

bunx @modelcontextprotocol/inspector bun src/main.ts
# or CLI mode:
bunx @modelcontextprotocol/inspector --cli bun src/main.ts --method tools/list
bunx @modelcontextprotocol/inspector --cli bun src/main.ts --method tools/call --tool-name emit_json --tool-arg yaml='foo: bar'

License

MIT.