tidybrregmcp

A Model Context Protocol server for Norway's business registry, derived entirely from the tidybrreg R package.

The server has no catalogue of its own. At start-up it reads the installed tidybrreg namespace and help pages and builds one tool per exported function:

From tidybrreg Becomes
exported function name tool name
\title of the help page tool title
description, details, sections, value tool description (Markdown)
formals + @param text input JSON schema (types, enums, defaults, required)
the tibble the function returns structuredContent.rows, with tidybrreg's column names and codes
attributes (total_matches, complete, http_status, cursor, ...) structuredContent.attributes
typed warnings and messages (tidybrreg_warning_*) structuredContent.conditions
typed errors (tidybrreg_error_*) isError = true with class and fields
every help topic, bundled dataset, NEWS and README resources under tidybrreg://
DESCRIPTION + ?tidybrreg_conditions server instructions

So when tidybrreg gains an export, changes an argument, or rewrites a help page, the MCP catalogue changes with it. A test asserts the tool list equals getNamespaceExports("tidybrreg") and that the two packages share a version, and the Docker image is built and smoke-tested from the same commit as tidybrreg in every CI run, then pushed and deployed on main.

The server adds exactly four optional arguments to every tool, all prefixed with a dot so they cannot collide with tidybrreg's: .limit (rows returned, default 200), .offset, .columns, and .format (records, csv, markdown). The structured result always carries n_total, so a slice is never mistaken for the population.

Install

install.packages(c("tidybrreg", "tidybrregmcp"),
  repos = c("https://sondreskarsten.r-universe.dev", "https://cloud.r-project.org"))

Run locally (stdio)

Claude Desktop / Claude Code / Cursor configuration:

{
  "mcpServers": {
    "tidybrreg": {
      "command": "Rscript",
      "args": ["-e", "tidybrregmcp::mcp_serve()"]
    }
  }
}

Or with Claude Code:

claude mcp add tidybrreg -- Rscript -e "tidybrregmcp::mcp_serve()"

Run as a service (streamable HTTP)

tidybrregmcp::mcp_serve("http", port = 8080)

POST /mcp carries JSON-RPC; GET /health reports versions. Set MCP_BEARER_TOKEN to require Authorization: Bearer. The image in Dockerfile runs the same server (MCP_TRANSPORT=http), and deploy/cloud-run.yaml is the Cloud Run service definition applied by the R-CMD-check workflow after every green build on main.

Remote client configuration:

{
  "mcpServers": {
    "tidybrreg": {
      "type": "http",
      "url": "https://<cloud-run-host>/mcp",
      "headers": {"Authorization": "Bearer <token>"}
    }
  }
}

Exclusions

TIDYBRREG_MCP_EXCLUDE="brreg_download" (comma-separated) removes tools from the catalogue without changing anything else, for deployments where a 150 MB bulk download is not appropriate.

Design notes