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

ai-catalog

v0.1.2

Published

Build, validate, discover, and resolve ai-catalog.json files for the Agentic Resource Discovery (ARD) spec. TypeScript, zero runtime deps.

Readme

ai-catalog

The only TypeScript toolkit for Agentic Resource Discovery (ARD). The spec's reference tooling is a Python conformance CLI; if you're shipping a site or MCP server from Node, this is the side you were missing. Zero runtime dependencies, ESM + CJS, Node 18+.

npx ai-catalog validate ./.well-known/ai-catalog.json
error /entries/0/type  required `type` is missing — `mediaType` was renamed to `type` (ADR-0014)

That rename (ADR-0014) is one the spec's own shipped example still gets wrong. The validator tracks the normative spec text, so it catches the things a hand-edited catalog drifts on.

ARD lets a website advertise its AI agents, MCP servers, skills, and datasets at /.well-known/ai-catalog.json so agents can find them before invocation. This package is the TypeScript side: typed builders, a spec-aware validator with precise error paths, the full agent-driven discovery walk, and nested-catalog resolution.

npm install ai-catalog

Validate a catalog (CLI)

npx ai-catalog validate ./.well-known/ai-catalog.json
error /entries/0/type  required `type` is missing — `mediaType` was renamed to `type` (ADR-0014)
warn  /entries/1/identifier  should use urn:air:{publisher}:{namespace}:{name} for open/federated use

The validator splits the spec's normative MUST rules (missing required members, the exactly-one-of url/data rule, identifier/version uniqueness, trust-identity domain alignment) from SHOULD/RECOMMENDED rules (urn:air identifiers, known media types, RFC 3339 timestamps), so you see error vs warn instead of one undifferentiated wall. Pass --strict to fail on warnings too.

Point it at a live one — Hugging Face (an ARD co-author) publishes a catalog you can validate today:

npx ai-catalog discover https://huggingface.co
npx ai-catalog validate <(curl -s https://huggingface.co/.well-known/ai-catalog.json)

It passes, with one warn: their registry entry uses application/ai-registry+json, which isn't in the spec's recommended type set. That's the point of the split — a real-world file that's correct on every MUST but carries a media type the spec doesn't enumerate shows up as a note, not an error.

Discover what a site publishes

discover runs the spec's agent-driven procedure in order — HTTP Link header, then HTML <link rel="ai-catalog">, then the /.well-known/ fallback — and tells you which one hit:

npx ai-catalog discover https://example.com
import { discover } from "ai-catalog";

const { url, via, catalog } = await discover("https://example.com");
// via: "link-header" | "html-link" | "well-known"
console.log(`${catalog.entries.length} entries, found via ${via}`);

Build one, type-safe

import { CatalogBuilder, KnownType, buildAirUrn } from "ai-catalog";

const catalog = new CatalogBuilder({
  displayName: "Acme Services",
  identifier: "did:web:acme.com",
})
  .addEntry({
    identifier: buildAirUrn("acme.com", "mcp", "weather"),
    type: KnownType.McpServerCard,
    description: "Weather lookup MCP server.",
    tags: ["weather", "mcp"],
    url: "https://acme.com/.well-known/mcp/weather.json",
  })
  .addNestedCatalog("urn:air:acme.com:catalog:ml", "https://acme.com/ml/ai-catalog.json")
  .validateOrThrow(); // throws with every problem listed, or returns the catalog

import { writeFileSync } from "node:fs";
writeFileSync(".well-known/ai-catalog.json", JSON.stringify(catalog, null, 2));

Resolve nested catalogs

A catalog can point at child catalogs (type: application/ai-catalog+json). resolveCatalog walks the tree, flattens every leaf entry, tags each with the depth and source URL it came from, follows the spec's depth limit of 4, and won't loop on a cycle:

import { resolveCatalog, selectLatest, resolveDisplayName } from "ai-catalog";

const entries = await resolveCatalog("https://acme.com/.well-known/ai-catalog.json");

for (const e of entries) {
  console.log(e.depth, resolveDisplayName(e), e.type);
}

// Multi-version entries: pick the newest by SemVer, then updatedAt.
const latest = selectLatest(entries, "urn:air:acme.com:agent:finance");

CLI equivalent:

npx ai-catalog resolve https://acme.com --names

API

| Export | What it does | | --- | --- | | validateCatalog(doc, { strict? }) | Structural validation → { valid, errors, warnings } with JSON-pointer paths | | assertValidCatalog(doc) | Throwing validator; narrows the type to AiCatalog | | CatalogBuilder / defineCatalog(host?) | Chainable typed builder | | discover(siteUrl, opts?) | Agent-driven discovery (Link header → HTML link → well-known) | | fetchCatalog(url, fetch?, timeoutMs?) | Fetch + validate a catalog from a URL | | resolveCatalog(rootOrUrl, opts?) | Walk nested catalogs, flatten to leaf entries | | resolveDisplayName(entry, referencedName?) | Spec display-name resolution order | | selectLatest(entries, identifier) | Newest entry among shared-identifier versions | | parseAirUrn / buildAirUrn / isAirUrn / identifierTail | urn:air helpers | | parseLinkHeader / parseHtmlLink | Standalone discovery parsers | | KnownType, WELL_KNOWN_PATH, CATALOG_MEDIA_TYPE, SPEC_VERSION | Spec constants |

All functions that fetch accept an opts.fetch so you can inject a mock, a proxy, or an authenticated client; on Node 18+ the global fetch is the default.

Spec tracking

Tracks ARD v1.0 as published in Agent-Card/ai-catalog, including ADR-0014 (mediaTypetype) and the depth-4 nesting recommendation. ARD is a v0.9-era draft and still moving; if a field name shifts under you, open an issue.

License

Apache-2.0