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

@sbissoli/mcp-provenance

v0.2.0

Published

Contrato de proveniência para servidores MCP: todo retorno de tool carrega fonte, endpoint, período, data de extração e licença, em dois modos (concise/detailed), com serialização determinística

Readme

@sbissoli/mcp-provenance

Contrato de proveniência para servidores MCP: todo retorno de tool carrega fonte, endpoint, período, data de extração e licença, com serialização determinística, em dois modos — concise (padrão, piso legal) e detailed (bloco canônico completo).

Mantido para o meu portfólio de servidores MCP. Uso por terceiros é bem-vindo, mas o roadmap segue as necessidades dos meus servidores.

Especificação completa: docs/contrato-proveniencia-v1.md.

Uso

import { createProvenanceContext } from "@sbissoli/mcp-provenance";

// 1. Uma vez, na inicialização do servidor:
const prov = createProvenanceContext({
  metaNamespace: "com.sidneybissoli.senado",   // chaves de _meta (reverse-DNS, estável)
  locale: "pt-BR",                             // idioma do rodapé ("pt-BR" | "en" | LocaleSpec)
  timezone: { offset: "-03:00", label: "horário de Brasília" }, // default: "utc"
  defaultMode: "concise",                      // default: "concise"
});

// 2. Presets por fonte upstream (opcional):
const SENADO_LEGIS = {
  source: "Senado Federal — Dados Abertos (Legislativo)",
  citation: "Fonte: Senado Federal, Portal de Dados Abertos (Legislativo) — legis.senado.leg.br/dadosabertos.",
  license: "Dados Abertos do Senado Federal — uso livre com atribuição da fonte.",
};

// 3. Em cada tool:
const p = prov.from(SENADO_LEGIS, {
  source_url: `${baseUrl}/processo.json`,
  retrieved_at: fetchedAt,        // instante REAL da extração (preservado pelo cache)
  data_vintage: "2025",
});
return prov.result(shapedData, p);                      // modo concise (default)
return prov.result(shapedData, p, { mode: "detailed" }); // bloco canônico completo

result() emite os três canais: structuredContent (bloco + attribution RFC #711, visível ao modelo), _meta namespaced (auditoria/UI, zero tokens) e rodapé de texto compacto para clientes text-only.

Diagnóstico de origem (retrieval, contrato v1.1)

Como o dado foi obtido, para que o agente explique um dado instável em vez de inventar certeza. É a 7ª chave do modo concise (depois de retrieved_at) e entra no bloco canônico depois de served_from_cache. Só o que foi medido: servidor que não instrumenta suas idas à origem omite o campo e ele sai null — nunca {attempts: 1} inventado.

const p = prov.from(SENADO_LEGIS, {
  source_url,
  retrieved_at: fetchedAt,
  retrieval: {
    requests: 3,                                   // idas distintas à origem nesta chamada (fatias, páginas)
    attempts: 5,                                   // tentativas somadas (>= requests)
    anomalies: [{ kind: "timeout", count: 2 }],    // opcional; classes: timeout | network | http_4xx |
  },                                               //   http_5xx | rate_limited | malformed_body
});
// → provenance.retrieval = { requests: 3, attempts: 5, anomalies: [{kind:"timeout",count:2}], unstable: true }

unstable é derivado pela lib (attempts > requests ou alguma anomalia); anomalies é somado por classe e ordenado no vocabulário, então a ordem de coleta não muda os bytes. No rodapé, uma linha ao leitor aparece só quando instável: "Obtenção instável: 5 tentativas para 3 consultas à origem (2 tempos de resposta esgotados)." Semântica completa em docs/contrato-proveniencia-v1.md §3; regra de compatibilidade da linha 1.x em §8.

O outputSchema da tool: importe, não transcreva

O SDK do MCP valida structuredContent contra o outputSchema em runtime. Um servidor que fecha o bloco de proveniência com as chaves transcritas à mão (additionalProperties: false) e sobe o pacote sem reescrever a transcrição falha em toda chamada — foi o que a medição de 26/09/2026 mostrou em quatro servidores. Desde a 0.2.0 o pacote publica a projeção que ele mesmo emite:

import { CONCISE_BLOCK_JSON_SCHEMA, ConciseBlockSchema } from "@sbissoli/mcp-provenance";

// outputSchema em JSON Schema verbatim (bcb, sih, medical):
const outputSchema = {
  type: "object",
  properties: { total: { type: "integer" }, provenance: CONCISE_BLOCK_JSON_SCHEMA, attribution: ATTRIBUTION },
  required: ["total", "provenance", "attribution"],
};

// outputSchema em zod (ibge):
const outputSchema = z.object({ total: z.number().int(), provenance: ConciseBlockSchema, attribution: z.array(z.string()) });

DETAILED_BLOCK_JSON_SCHEMA/DetailedBlockSchema e provenanceBlockJsonSchema(mode) cobrem o modo detailed. Os testes do pacote prendem que schema e render* não divergem.

Fonte estruturada (ex.: ILOSTAT/SDMX)

const p = prov.build({
  source: { name: "ILOSTAT", agency: "ILO", database: "ILOSTAT", endpoint: "https://sdmx.ilo.org/rest" },
  dataset: { id: "DF_UNE_DEAP_SEX_AGE_RT", version: "1.0", name: "Unemployment rate by sex and age" },
  dimension_key: { REF_AREA: "BRA", SEX: "SEX_F", TIME_PERIOD: "2024" },
  data_vintage: "2026-06-15",
  retrieved_at: fetchedAt,
  source_url: canonicalRestUrl,
  license: { id: "CC-BY-4.0", url: "https://creativecommons.org/licenses/by/4.0/", verified_at: "2026-08-04" },
  citation: "International Labour Organization, ILOSTAT, https://ilostat.ilo.org/data/, accessed 2026-08-04.",
});

Multi-fonte (segregação de licenças)

// Um bloco POR FONTE; dados de cada fonte em estruturas separadas apontando para o seu bloco.
return prov.result({ ilostat: dadosIlo, uis: dadosUis }, [pIlo, pUis]);

Recortes múltiplos de uma mesma fonte

const p = prov.build({ ...base, field_sources: [
  { fields: ["relatoria"], source_url: urlRelatoria, retrieved_at: fetchedAtRelatoria },
]});

Regras que a lib impõe (server-side, antes de responder)

  • license com ao menos id ou name (piso legal);
  • derived: true exige derivation_note;
  • chaves em ordem fixa e ausência como null explícito (determinismo byte-a-byte por modo);
  • timestamps ISO-8601 sem milissegundos, normalizados ao fuso configurado (datas puras passam intactas — nunca inventa horário num vintage).

API

createProvenanceContext(options) → { build, from, render, footer, result, metaKeys }. Peças soltas também exportadas: CanonicalProvenanceSchema, renderConcise, renderDetailed, attributionList, provenanceFooter, toCanonicalIso, locales ptBR/en.