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

@nordio/brreg-mcp-server

v0.1.3

Published

Norwegian business register (Brønnøysundregistrene) as an MCP server — companies, roles, subunits and annual accounts, with the register's silent traps encoded as guards.

Readme

brreg-mcp-server

The Norwegian business register for AI agents — companies, roles, subunits and annual accounts — with the register's silent traps encoded as guards.

License: MIT Node

Brønnøysundregistrene's API is free, public and keyless. Fetching from it is easy — a 40-line script does it, faster than any MCP will. The problem is that the register lies quietly, and every trap returns a plausible number instead of an error:

naeringskode=96.02   →  totalElements: 0        # "no hairdressers in Oslo"?
naeringskode=96.210  →  totalElements: 1283     # the code was renumbered. No error. No warning.

That is the whole reason this exists.

✨ Features

  • Annual accounts (regnskapsregisteret) — no other public brreg MCP covers them.
  • Retired-NACE guard — a zero result arrives with a hint naming the current code and its live match count. The query is never silently rewritten.
  • filed_no_revenue_line — holding companies file driftsinntekter: {} (the key is absent, not zero, and not ""). A revenue >= X filter silently deletes every one of them; this status is how you notice.
  • employees_min/employees_max — brreg hides every headcount below 5 from the payload, so filtering on the antallAnsatte field silently drops the small companies. The range filter sees them (219 Oslo hairdressers have 1–4 staff). antallAnsatte: null means withheld, not unknown.
  • INNH resolution — sole proprietorships have no board and no daglig leder. Looking only for DAGL/LEDE makes ~78% of Norwegian small business look contactless.
  • VAT-sector warning — registrertIMvaregisteret costs ~a third of results in 96.x/93.x and deletes ~98% of genuine clinics under NACE 86.* (health is VAT-exempt by law).
  • valuta never assumed — Equinor files in USD.
  • Privacy by default — no personal names unless you ask; birth dates never, even if you do.
  • Contact data — epostadresse, mobil, telefon, hjemmeside: sparse (~1 in 3 units) but real. For a sole proprietorship they are a private individual's personal details, and the tool says so.
  • Bulk by array — one call for many orgnrs, per-item partial success.
  • No cache, no state, no telemetry — one outbound host, data.brreg.no.

📋 Available Tools

| Tool | Does | Key params | |---|---|---| | get_units | Look up companies/branches by orgnr; resolves main-vs-branch for you and returns unit_type, contact fields, and is_natural_person | orgnrs | | search_units | Search by industry, municipality, name, org form, VAT or employee range; carries the guards | nace, kommune, navn, org_form, registrertIMvaregisteret, employees_min, employees_max, strict_location, cap | | get_roles | Board, management and sole-proprietor owner. Structure only by default | orgnrs, include_persons | | get_financials | Annual accounts, as a discriminated union you must read before the numbers | orgnrs, statement_type |

🚀 Quick Start

npm install && npm run build
npm run dev:mock          # real offline mode — no network, every guard live

--mock is not a stub: it swaps the socket, not the code path, and its dataset is the register's traps (a USD filer, a holding company with no revenue line, an ENK, a dissolved unit, a 410, a retired NACE code). Everything on this page reproduces offline.

⌨️ CLI

The same handlers the MCP registers, over argv — src/cli.ts dispatches the identical buildTools() array, so a finding from one surface holds for the other.

brreg get_units --orgnrs 923609016
brreg search_units --nace 96.02 --kommune 0301     # watch it catch the retired code
brreg get_financials --orgnrs 918035443
brreg reference                                     # field glossary + statutory sources
brreg self-test --mock                              # proves the install works offline

stdout is one JSON object (with elapsed_sec); diagnostics on stderr; usage errors exit 2, upstream failures exit 1. --orgnrs a --orgnrs b and --orgnrs a,b both work — bulk is the intended shape.

📚 Skill

skills/brreg/SKILL.md carries the domain knowledge an agent can't infer from a successful response — which silences are meaningful and which plausible number is wrong. The tools' guards always fire; the skill is what lets an agent go past the four tools when the question needs it.

🖥️ Claude Desktop

Download the .mcpb from Releases and double-click it. No terminal, no Node install, no API key — brreg needs no credentials.

dist/ is not committed, so build it once:

git clone https://github.com/nordio-ai/brreg-mcp-server
cd brreg-mcp-server && npm ci && npm run build

.mcp.json is committed and works when the client's working directory is the repo:

{ "mcpServers": { "brreg": { "command": "node", "args": ["./dist/stdio.js"] } } }

From anywhere else, give an absolute path to dist/stdio.js — the relative form above resolves against the client's cwd, not this file.

💬 Try it

"Look up 923609016 and tell me what the accounts say."

"Find hairdressers in Oslo, NACE 96.02." — watch it catch the retired code

"Which of these 50 companies has a real operator and filed accounts?"

🔍 Read this before trusting a number

| You see | It means | |---|---| | total: 0 | Maybe not "none exist." Check hints — the NACE code may be retired. | | driftsinntekter: null + filed_no_revenue_line | Accounts filed, no operating revenue line. A holding company. Not zero revenue. | | status: not_applicable | An ENK. Sole proprietorships never file. Not a red flag. | | antallAnsatte: null | Withheld, not unknown — brreg never shows a value below 5. Use employees_min/employees_max to filter; antallAnsatte_reported says whether a hidden count exists. | | valuta: "USD" | It happens. Never compare revenue across companies without reading it. | | deleted vs gone vs not_found | Dissolved · removed on legal grounds · never existed. Three different facts. |

Read brreg://reference for the field glossary (with statutory sources), the retired-NACE table, and role codes.

📂 Paths & state

None. No config, no cache, no logs on disk, no state directory. Every read is live.

That is deliberate. brreg's documentation treats HTTP 410 as "en forespørsel om at eventuelle kopier/cacher også fjerner den aktuelle enheten" — an instruction to purge, not a status code. A cache is exactly what turns that into an obligation you can silently fail: the request that would reveal the erasure is the one a cache promises not to make. For an interactive connector caching buys almost nothing, so there isn't any — and a test fails if someone adds one.

🔄 Updating

Re-download the .mcpb from Releases. Version lives in package.json; see CHANGELOG.md.

Scope

Interactive discovery and targeted enrichment — tens to a couple of hundred results. Register-scale extraction (thousands of rows) is a non-goal: an MCP returns data through the model's context window, so a script will always win at that size. Use the API directly.

Also out of scope: kunngjøringer (no open REST API exists), fødselsnummer (needs Maskinporten), writes (brreg is read-only), and anything feeding a creditworthiness decision (that engages EU AI Act Annex III 5(b)).

Licence

MIT. Not affiliated with Brønnøysundregistrene.

Data © Brønnøysundregistrene, NLOD 2.0. NLOD is a copyright licence and explicitly excludes personal data — it is not a legal basis for processing the names in this register. If you bulk-harvest role data, you are the controller: you need your own basis (GDPR Art 6(1)(f)), an Art 14 notice at first contact, and an Art 21(2) suppression list. And note that ENK names are people — foretaksnavneloven §2-2 requires a sole proprietorship's registered name to contain the owner's surname, and ~74% of the register are ENKs.