Notary

Verify a notarization

Paste a Kenwea record and check its signature against our published key. It runs in your browser, nothing is sent to us, so you do not have to take our word for it.

Step one

Try it first

One command, no account, no key. Name any npm package, or give an https URL to a file, an npm tarball or a Python wheel:

npx -y @kenwea/mcp check lodash

It installs the package in a sealed box with no real network and decoy credentials, and traces what its install steps reach for. The answer starts with one word, from nothing_runs and quiet to sends_credentials (do not install it). The signedAttestation block in the result is what the box below checks. A quiet trace is evidence, not proof.

As a CI gate, the GitHub Action checks your whole lockfile and fails the step on what the signed record says. From a shell: npx -y @kenwea/mcp check-tree package-lock.json.

- uses: kenwea-protocol/kenwea-notary-action@v2
  with:
    lockfile: package-lock.json   # the whole tree
    fail-on: network,credentials
Step two

Use it inside your tools

In Claude Code, a plugin checks each package before Claude installs it, and asks you first if an install step reaches for the network.

/plugin marketplace add kenwea-protocol/kenwea-claude-plugin
/plugin install kenwea-notary-guard@kenwea

The notary is also an MCP server, no key needed, so your agent can ask before it installs something.

https://mcp.kenwea.com/notary/v1

Claude Code

claude mcp add --transport http \
  kenwea-notary https://mcp.kenwea.com/notary/v1

Devin Local (Windsurf's default agent)

devin mcp add kenwea-notary \
  https://mcp.kenwea.com/notary/v1

Windsurf Cascade (mcp_config.json)

{
  "mcpServers": {
    "kenwea-notary": {
      "serverUrl": "https://mcp.kenwea.com/notary/v1"
    }
  }
}

LangChain

# pip install langchain-mcp-adapters
from langchain_mcp_adapters.client import MultiServerMCPClient

client = MultiServerMCPClient({"kenwea-notary": {
    "transport": "streamable_http",
    "url": "https://mcp.kenwea.com/notary/v1"}})
tools = await client.get_tools()

LlamaIndex

# pip install llama-index-tools-mcp
from llama_index.tools.mcp import (
    BasicMCPClient, McpToolSpec)

client = BasicMCPClient("https://mcp.kenwea.com/notary/v1")
tools = await McpToolSpec(
    client=client).to_tool_list_async()

CrewAI

# pip install "crewai-tools[mcp]"
from crewai_tools import MCPServerAdapter

server = {"url": "https://mcp.kenwea.com/notary/v1",
          "transport": "streamable-http"}
with MCPServerAdapter(server) as tools:
    ...  # kenwea_notary_check, kenwea_notary_verify

Without a key the limit is 20 checks an hour.

Not built yet

For teams: private packages, alerts and a shared history

Private packages, lockfile alerts and one history for a team. This paid tier does not exist yet. Leave an address if you would use it.

We keep the address only for this, until the tier launches or you ask us to remove it. See the privacy policy.

What a record does and does not say

  • The claim is about the hash, not the URL. Hash what you hold and compare it to contentSha256.
  • An unreadable artifact is never signed. No bytes, no signature.
  • A signature is not an endorsement. It says what happened, not that the code is good.

Every key we have signed with, and its status: /.well-known/kenwea-attestation-keys.json. The active key alone, as PEM: /.well-known/kenwea-attestation-key. A record signed with a revoked key proves nothing.

Every record is also added to a public, append only transparency log signed with the same key. kenwea_notary_verify checks inclusion for you and says log.included.