Back to Discover

register-mcp

connector

malkreide

Zefix commercial register with a company-UID join to amtsblattportal.ch (SHAB + cantonal gazettes)

View on GitHub
0 starsSynced Aug 16, 2026

Install to Claude Code

/plugin marketplace add malkreide/register-mcp

README

πŸ‡¨πŸ‡­ Part of the Swiss Public Data MCP Portfolio

register-mcp

Version License: MIT Python 3.11+ MCP No Auth Required CI

MCP Server for the Swiss Federal Commercial Register (Zefix/Handelsregister), with a company-UID join to the official gazettes (SHAB + cantonal AmtsblΓ€tter)

πŸ‡©πŸ‡ͺ Deutsche Version


Overview

register-mcp provides AI-native access to two Swiss federal data sources, joined on the UID, all without authentication:

SourceDataAPI
Zefix (Handelsregister)Swiss companies, legal forms, registered-office dataZefixREST v1
AmtsblattportalEverything published about a specific company (by its UID): HR mutations, calls to creditors, bankruptcyamtsblattportal.ch v1

The two sources share one key β€” the UID. The value is in the join: Zefix tells you whether a company exists; the gazette tells you what has been published about it.

The gazette access here is deliberately company-scoped only β€” keyed on a company UID or a specific publication id. There is no free-text / person-name gazette search in this server; that would be a profiling tool over the gazette's person-data rubrics (bankruptcy, debt-collection, inheritance). Broad Amtsblatt platform search (procurement, cantonal notices, full-text) is proposed as a separate amtsblatt-mcp β€” see docs/amtsblatt-mcp-proposal.md and the Data Protection & Scope section below.

Designed for Swiss public administration use cases: vendor verification, contract partner due diligence, and supplier onboarding β€” all via natural language queries.

Anchor demo query: "Before we sign a framework agreement with Lehrmittelverlag ZΓΌrich AG: is the company active in the commercial register, what is its UID and stated purpose β€” and, via that UID, what has the official gazette published about it (HR mutations, calls to creditors, any bankruptcy)?"

That single question walks the whole tool chain across both sources:

zefix_search_company  β†’  zefix_verify_company  β†’  gazette_company_publications(uid=…)  β†’  gazette_get_publication(id=…)

Features

  • πŸ›οΈ 9 tools across two sources β€” company search & verification (Zefix) + the company-scoped gazette join (SHAB/cantonal)
  • πŸ”— gazette_company_publications β€” the UID join: everything published about a company
  • πŸ›‘οΈ Data-protection-safe by construction β€” the only gazette entry points are UID- or id-scoped; no person-name search entry exists (see Data Protection & Scope)
  • πŸ” zefix_verify_company β€” quick active/dissolved status check
  • 🌐 Bilingual output (Markdown / JSON) with per-source attribution + provenance
  • πŸ”“ No API key required β€” open data from zefix.admin.ch and amtsblattportal.ch
  • ☁️ Dual transport β€” stdio (Claude Desktop) + SSE (cloud)

Prerequisites

  • Python 3.11+
  • uv (recommended) or pip

Installation

# Clone the repository
git clone https://github.com/malkreide/register-mcp.git
cd register-mcp

# Install
pip install -e .
# or with uv:
uv pip install -e .

Or with uvx (no permanent installation):

uvx register-mcp

Quickstart

# stdio (for Claude Desktop)
python -m register_mcp.server

# SSE (cloud deployment) β€” MCP_API_KEY is REQUIRED
MCP_API_KEY=$(openssl rand -hex 32) MCP_TRANSPORT=sse PORT=8000 \
  python -m register_mcp.server

SSE / Cloud Deployment

When running with MCP_TRANSPORT=sse, the server enforces:

  • Bearer-token auth β€” set MCP_API_KEY to a secret string. Clients must send Authorization: Bearer <key> on every request. Missing or wrong β†’ HTTP 401. The server refuses to start without MCP_API_KEY set.

  • Rate limiting β€” sliding window per bearer-token hash. Defaults: 60 req / 60 s. Tunable via MCP_RATE_LIMIT and MCP_RATE_WINDOW. Exceeding the limit returns HTTP 429 with Retry-After.

  • Structured JSON logging β€” every tool call emits one line to stderr with tool, status, latency_ms. Auth failures and rate-limit events are logged at WARNING level. Configure verbosity with LOG_LEVEL (default INFO).

  • Reference-data cache β€” Zefix legal-forms are cached for 24h (LEGAL_FORMS_TTL seconds) to avoid an extra upstream call per tool invocation.

  • Egress allow-list β€” outbound HTTP is restricted to www.zefix.admin.ch and amtsblattportal.ch via an httpx request hook that also fires on redirects. A Location header pointing elsewhere raises EgressDenied and is never followed. Override with MCP_ALLOWED_HOSTS=host1,host2 (comma-separated, lower-case).

    ⚠️ Upgrade note (0.2.x β†’ 0.3.0): amtsblattportal.ch was added to the default allow-list when the gazette tools shipped. If your deployment pins MCP_ALLOWED_HOSTS, that value overrides the default entirely β€” add amtsblattportal.ch to it, or every gazette_* call will raise EgressDenied.

  • Optional OpenTelemetry tracing β€” install with pip install register-mcp[otel] and set OTEL_EXPORTER_OTLP_ENDPOINT (e.g. http://otel-collector:4318/v1/traces). Without the extra or without the env var the server stays silent β€” no hard dependency on the OTel SDK.

For multi-instance deployments, place a real gateway (Cloudflare, Railway internal networking, an API-Gateway with Redis-backed rate limiting) in front of the in-memory limiter, which is per-process by design.

Container deployment

A minimal multi-stage Dockerfile ships with the repo. The image runs as a non-root mcp user; dependencies are resolved from uv.lock (uv sync --frozen), so the build is reproducible.

docker build -t register-mcp:local .

docker run --rm -p 8000:8000 \
  -e MCP_TRANSPORT=sse \
  -e MCP_API_KEY="$(openssl rand -hex 32)" \
  register-mcp:local

For local iteration there is a compose.yaml with read_only, cap_drop: ALL and no-new-privileges:

MCP_API_KEY=$(openssl rand -hex 32) docker compose up --build

See SECURITY.md for hardening notes (egress restriction, key rotation, SIEM forwarding).

Try it immediately in Claude Desktop:

"Is Lehrmittelverlag ZΓΌrich AG active in the commercial register?" "Look up the company with UID CHE-108.954.978" "List all Swiss legal forms"


Configuration

Claude Desktop

Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "register": {
      "command": "python",
      "args": ["-m", "register_mcp.server"]
    }
  }
}

Or with uvx:

{
  "mcpServers": {
    "register": {
      "command": "uvx",
      "args": ["register-mcp"]
    }
  }
}

Config file locations:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Cloud Deployment (SSE for browser access)

For use via claude.ai in the browser (e.g. on managed workstations without local software):

Render.com (recommended):

  1. Push/fork the repository to GitHub
  2. On render.com: New Web Service β†’ connect GitHub repo
  3. Set start command: python -m register_mcp.server --http --port 8000
  4. In claude.ai under Settings β†’ MCP Servers, add: https://your-app.onrender.com/sse

πŸ’‘ "stdio for the developer laptop, SSE for the browser."


Available Tools

Zefix β€” commercial register (6):

ToolDescription
zefix_search_companiesSearch companies by name, canton, legal form
zefix_get_companyFull company profile by internal EHRAID
zefix_get_company_by_uidCompany lookup by UID (CHE-xxx.xxx.xxx)
zefix_verify_companyQuick active/dissolved status check
zefix_list_legal_formsAll Swiss legal forms with IDs
zefix_list_municipalitiesSwiss municipalities with BFS IDs

Amtsblattportal β€” the company-scoped gazette join (3):

ToolDescription
gazette_company_publicationsThe UID join. All gazette publications for a company UID, newest first, optional (validated) rubric/time filters
gazette_get_publicationSingle publication incl. XML full text, defensively parsed (by publication id)
gazette_source_statusReachability of both sources + cache ages (rubrics, legal forms)

The prefix is gazette_, not shab_, because the source covers SHAB and the cantonal gazettes. Every entry point is UID- or id-scoped β€” see Data Protection & Scope. Broad, non-company gazette search (procurement, cantonal full-text) is scoped to the separate amtsblatt-mcp.

Example Use Cases

QueryTool
"Is Lehrmittelverlag ZΓΌrich AG active?"zefix_verify_company
"Look up CHE-108.954.978"zefix_get_company_by_uid
"Find companies named Migros in canton ZH"zefix_search_companies
"What has been published about CHE-116.115.052?"gazette_company_publications
"Show the full official text of that HR deletion notice"gazette_get_publication
"Are both data sources reachable right now?"gazette_source_status

Architecture

                                                          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                                    β”Œβ”€β”€β”€β”€β–Άβ”‚  Zefix (Handelsregister)     β”‚
                                                    β”‚     β”‚  www.zefix.admin.ch          β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”   β”‚  ZefixREST/api/v1            β”‚
β”‚   Claude / AI   │────▢│       register-mcp           β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚   (MCP Host)    │◀────│       (MCP Server)           β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚  9 Tools (zefix_ + gazette_) β”œβ”€β”€β–Άβ”‚  Amtsblattportal             β”‚
                        β”‚  Stdio | SSE                 β”‚   β”‚  amtsblattportal.ch/api/v1   β”‚
                        β”‚  Egress allow-list           β”‚   β”‚  SHAB + cantonal gazettes    β”‚
                        β”‚  No authentication required  β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              join key: UID (CHE-XXX.XXX.XXX)

Data Source Characteristics

SourceProtocolCoverageAuth
ZefixREST/JSONSwiss companies, legal forms, registered officesNone
AmtsblattportalREST/JSON (list) + XML (full text)SHAB + cantonal gazettes, 2.79M publicationsNone
ZefixPublicREST (planned)REST/JSONSignatories, capital, full historyBasic Auth (free)
UID Register (planned)SOAPMwSt, NOGA codes, cross-validationPublic (20 req/min)

The UID join β€” Zefix ↔ Amtsblatt

The two sources share exactly one key: the UID (CHE-XXX.XXX.XXX). That is what turns them from two data sets into one workflow.

zefix_get_company_by_uid(uid)        # Zefix: does the company exist? status, purpose, legal form
        β”‚  UID
        β–Ό
gazette_company_publications(uid)    # Gazette: everything published about it (HR, KK, SB, LS, …)
        β”‚  publication id
        β–Ό
gazette_get_publication(id)          # Full official text from the per-rubric XML

Two properties of the source shape this path (both verified in docs/probe-shab.md):

  • The bulk list carries no company UID (meta.uid is null). The company UID lives only in the single-publication fetch β€” meta.uid in the single JSON, or <uid> in the XML (which also carries the full text). So the join runs list β†’ per-hit single fetch β†’ match against the Zefix UID.
  • gazette_company_publications filters the corpus by uids=<UID> directly, so in practice you get the company's publications in one call without walking every record.

Procurement lives in the separate amtsblatt-mcp

Public procurement (Submissionen) is not a federal SHAB rubric and is not covered by this server. It exists only as a cantonal OB-<canton> rubric, only a few cantons publish it in this portal, and most β€” including ZΓΌrich β€” route tenders through simap.ch, a separate platform. Procurement, cantonal notices, and broad full-text search are scoped to the proposed amtsblatt-mcp server, which applies a fail-closed green-rubric allow-list. See that proposal for the full OB-* coverage map and the rubric traffic-light table.

SB β‰  Submissionen. SB is Schuldbetreibungen (debt collection), a person-data-heavy rubric this server never exposes as a search entry.


Data Protection & Scope

This section is not a footnote β€” it is the reason the server is shaped the way it is.

The Amtsblattportal systematically publishes rubrics containing personal data of natural persons: bankruptcies (KK), debt-collection (SB), calls to creditors (LS/SR), inheritance/estate calls (ES, TE-*), and building applications with owner names. Those publications are public β€” but making them systematically queryable by name through an AI agent is a repurposing the publication never intended, and under the revised Swiss Federal Act on Data Protection (revDSG) a "show me every debt-collection entry for person X" tool is a profiling instrument. Deliberate design choices follow:

  • No person-based search entry. No tool takes a natural person's name, birth date or address. The only gazette entry points are keyed on a company UID (gazette_company_publications) or an opaque publication id (gazette_get_publication). A firm's own bankruptcy is returned via its UID β€” that is corporate data about a legal person, not name-based profiling.
  • No free-text gazette search here. keyword and cantons are not even on the internal query-parameter allow-list, so no future code change can smuggle a corpus-wide keyword search in. Broad search lives in amtsblatt-mcp behind a fail-closed green allow-list (procurement, HR, official notices only).
  • No persistence of publication content. The server is a pass-through; only the rubric taxonomy and Zefix legal-forms list are cached in memory (24 h). Official publications carry statutory deletion periods β€” a store that outlived them would actively undermine those periods.
  • Fail closed. Rubric codes are validated against the live taxonomy before any call; an unknown code is refused, not silently widened.

The broad-platform counterpart, its green/yellow/red rubric classification and its fail-closed design are specified in docs/amtsblatt-mcp-proposal.md.


Architecture decision

ARCH A β€” live-API-only, consistent with the existing Zefix integration (decided 2026-07-18).

The Amtsblattportal is queried live on every call. All endpoints respond in 0.2–2.0 s, and the use case β€” targeted company and topic research β€” does not need a local bulk copy. A bulk dump would mean mirroring 2.79M records, with an ongoing sync burden and staleness risk, for no benefit to the join-on-UID workflow. The taxonomy (/rubrics) and the Zefix legal-forms list are the only data cached, each for 24h in memory, because they change at most a few times a year and every filtered call needs them.


Phased Implementation

PhaseAPIAuthStatus
Phase 1ZefixREST/api/v1NoneCurrent
Phase 2ZefixPublicREST/api/v1Basic Auth (free, email zefix@bj.admin.ch)Planned
Phase 3UID-Register SOAPPublic (20 req/min)Planned

Phase 2 will add: signatory details, share capital, full historical entries. Phase 3 will add: MwSt status, NOGA industry codes, cross-register validation.


Project Structure

register-mcp/
β”œβ”€β”€ src/register_mcp/
β”‚   β”œβ”€β”€ __init__.py              # Package
β”‚   └── server.py                # 9 tools (Zefix + company-scoped gazette join)
β”œβ”€β”€ tests/
β”‚   β”œβ”€β”€ test_server.py           # Zefix unit + integration tests (mocked HTTP)
β”‚   β”œβ”€β”€ test_gazette.py          # Gazette tools + the three quirks (mocked HTTP)
β”‚   └── test_egress.py           # Egress allow-list
β”œβ”€β”€ docs/
β”‚   β”œβ”€β”€ probe-shab.md            # Phase-1 live probe of amtsblattportal.ch
β”‚   β”œβ”€β”€ amtsblatt-mcp-proposal.md# Spec for the separate broad-platform server
β”‚   └── demo/                    # vhs demo script + standalone CLI demo
β”œβ”€β”€ .github/workflows/ci.yml     # GitHub Actions (Python 3.11/3.12/3.13)
β”œβ”€β”€ pyproject.toml
β”œβ”€β”€ CHANGELOG.md
β”œβ”€β”€ CONTRIBUTING.md
β”œβ”€β”€ LICENSE
β”œβ”€β”€ README.md                    # This file (English)
└── README.de.md                 # German version

Known Limitations

  • Search by canton without a name filter may return API errors (Zefix API limitation)
  • Phase 1 Zefix API may be rate-limited under heavy load; retry after a short delay
  • ZefixPublicREST (new API) requires registration: email zefix@bj.admin.ch

Amtsblattportal β€” verified behaviour (live-checked 2026-07-18)

CallHTTPStatusRecordsNote
/publications?publicationStates=PUBLISHED200OK2,790,323baseline (full corpus) β€” never queried unfiltered
?uids=CHE-116.115.052200OK4the join β€” core (and only) gazette entry
?uids=…&rubrics=HR200OK–optional, validated rubric narrowing on the join
/publications/{id}/xml200OK–full text, rubric-specific schema
/rubrics200OK–taxonomy (for code validation)
?rubrics=ZZZZ (invalid)200Silent Empty0, total: nullQuirk 2
?uid=… (wrong param name)200Silent Ignore2,790,323Quirk 1

Free-text (keyword) and broad cantons search are not performed by this server β€” those probe results live in docs/probe-shab.md and inform the separate amtsblatt-mcp.

Zefix β€” verified behaviour (live-checked 2026-08-15)

Found by the weekly live suite, not by the unit tests β€” which stayed green throughout.

Call to firm/search.jsonHTTPResult
{"name": "Migros", …}20035 hits
a name with no hits404NORESULT envelope β€” not an empty 200
{"uid": "109741634", …}400Bad Request β€” there is no uid field
{"name": "CHE-999.999.999", "searchType": "CONTAINS"}200Β«CHEMAM - 999Β», UID CHE-113.593.998
a dissolved firm without activeOnly: false404NORESULT β€” as if it never existed

Three shapes, one shipped bug each:

  • No hits answer with HTTP 404, carrying the NORESULT envelope. Every call therefore goes through _zefix_post_search; a raw raise_for_status() makes the friendly branch unreachable. That is how zefix_verify_company shipped answering "Eintrag nicht gefunden. Bitte EHRAID oder UID prΓΌfen" to a name search, where neither an EHRAID nor a UID was in play. A fixture that puts the NORESULT body into a 200 makes exactly that dead branch look green.
  • A hit list is not an answer. UID lookup searches the name field with searchType: CONTAINS, so CHE-999.999.999 returns a real company under a UID that is not its own. Defence: exact digit match or nothing β€” no firms[0] fallback. The former fallback produced a complete, plausible, formatted record about somebody else, indistinguishable from a correct answer.
  • Without activeOnly: false, "dissolved" looks like "never existed". Zefix returns only active entries by default; zefix_verify_company sets the flag deliberately. A firm with no UID comes back as a string of blanks (uid: " ", uidFormatted: null), not as null.

Three quirks are defended in code (details in the CHANGELOG under Known findings):

  • Quirk 1 β€” Silent Ignore (critical). Unknown query parameters are dropped silently and return the full 2.79M corpus with HTTP 200. Defence: query strings are built exclusively from an ALLOWED_GAZETTE_PARAMS allow-list, and every filtered response is plausibility-checked β€” a total above 2,000,000 is rejected as "filter ignored by upstream β€” result not trustworthy".
  • Quirk 2 β€” Silent Empty. An invalid rubric code returns HTTP 200 with an empty result. Defence: the /rubrics taxonomy is cached 24h and every code is validated before any call, failing with the five closest valid codes.
  • Quirk 3 β€” Two-step fetch. The JSON list carries only meta; the content lives only in the per-rubric namespaced XML. Defence: namespace-agnostic defensive parsing (meta + publicationText mandatory, HR company when present, everything else in additional_fields).

Safety & Limits

Rate Limits

APILimitNotes
ZefixREST (Phase 1)Not officially documentedThrottling possible under heavy load β€” retry after 1–2 s
ZefixPublicREST (Phase 2)Not officially documentedRequires prior registration (free)
UID-Register SOAP (Phase 3)20 req/minHard limit, publicly documented

Data Privacy

  • Read-only access β€” all tools carry readOnlyHint: True; the server performs no write, delete, or mutation operations against any API
  • No person-based search entry β€” no tool accepts a natural person's name, birth date or address; gazette access is UID- or publication-id-scoped only (see Data Protection & Scope). This is a deliberate revDSG-driven design choice, not an accident of the API
  • No persistence of publication content β€” the server is a stateless pass-through; only the rubric taxonomy and Zefix legal-forms list are cached in memory (24 h), never publication bodies, so statutory deletion periods are respected
  • Public register data only β€” the Zefix Handelsregister is a public federal register (HRegV); gazette data returned is likewise legally public, retrieved per company UID
  • No personal tracking β€” the server does not transmit user identity, query history, or session data to the upstream sources

Terms of Service & Data Sources

  • Zefix API ToS: Usage of the Zefix REST API is governed by the zefix.admin.ch terms of use. The data is published under the Open Government Data (OGD) Switzerland principles.
  • SHAB: Swiss Official Gazette of Commerce β€” published by the Federal Chancellery (BK). Public by law.
  • Institutional use: This server is designed for read-only queries in public administration workflows. Not suitable for mass harvesting or automated surveillance use cases.

Security

  • No credentials are stored or transmitted (Phase 1)
  • Phase 2 credentials (ZEFIX_USER, ZEFIX_PASSWORD) are passed via environment variables only β€” never hardcoded
  • All HTTP calls use HTTPS exclusively
  • Tool inputs are validated via Pydantic v2 before any API call is made

Demo

register-mcp demo

πŸ“½οΈ Terminal GIF coming soon β€” see docs/demo/ to generate it locally with vhs

Example interaction:

User:  "Is Lehrmittelverlag ZΓΌrich AG active in the commercial register?"

β†’ Tool: zefix_verify_company(name="Lehrmittelverlag ZΓΌrich AG")

Claude: βœ… Lehrmittelverlag ZΓΌrich AG is ACTIVE in the Handelsregister.
        UID: CHE-404.020.972 | Canton: ZH | Legal form: AG
        Last SHAB mutation: 2023-07-27

β†’ More use cases by audience β†’

To generate the demo GIF locally:

# Install vhs (macOS/Linux)
brew install vhs        # macOS
# or: go install github.com/charmbracelet/vhs@latest

# Generate
vhs docs/demo/demo.tape
# β†’ outputs docs/demo/demo.gif

Testing

# Unit tests (no API key required)
PYTHONPATH=src pytest tests/ -m "not live"

# Integration tests (live API calls)
pytest tests/ -m "live"

# Re-record the fixtures from the live sources (writes tests/fixtures/PROVENANCE.md)
python scripts/record_fixtures.py

The unit-test payloads are recorded, not invented. Source, retrieval date, selection rule, redaction and SHA-256 per file are in tests/fixtures/PROVENANCE.md.

Two things are stated there rather than papered over. Personal data: the gazette carries debt-collection notices and Zefix carries the full SHAB text naming registered persons with their place of residence β€” the recorded payloads keep the shape and redact those values, with the complete list of redacted fields alongside. Zefix needs no credentials: until 2026-08-08 this repository recorded no Zefix fixtures because the recording script measured HTTP 401. The measurement was right about the wrong address β€” the script asked ZefixPublicREST, while the server speaks to ZefixREST, which answers with no authentication at all.

The live suite

ci.yml runs -m "not live": a foreign 503 must not redden a stranger's pull request, because a suite that does gets switched off, and a switched-off suite checks nothing. The exclusion has a safety net β€” .github/workflows/live-tests.yml runs weekly (cron: "31 5 * * 1") plus workflow_dispatch.

The verdict is read from the JUnit XML rather than the exit code, by scripts/classify_live_run.py, because a live run has three answers and not two:

StateMeaningIssue
clearthe suite ran and was greencloses an open one
findingthe suite ran and something fellopens or updates one
unknownthe suite did not run β€” failed install, timeout, renamed marker, everything skippedleft untouched

tests - skipped == 0 is unknown, not clear: pytest exits 0 when every test was skipped, and a job that books that as green closes an issue on a comparison that never happened.

One caveat when editing that workflow: the pull-request checks do not cover it β€” it has no push or pull_request trigger, so a green PR says nothing about it. Verify changes with a manual workflow_dispatch run on the branch before merging.


Changelog

See CHANGELOG.md


Contributing

See CONTRIBUTING.md


Security

See SECURITY.md (Deutsch) for the security posture and how to report a vulnerability.


License

MIT License β€” see LICENSE


Author

Hayal Oezkan Β· malkreide


Credits & Related Projects

Installation

Run via uv's uvx β€” no clone or manual install needed. Add to your MCP client config (mcpServers for Claude Desktop, Cursor and Windsurf; use a top-level servers key for VS Code in .vscode/mcp.json):

{
  "mcpServers": {
    "register-mcp": {
      "command": "uvx",
      "args": [
        "register-mcp"
      ]
    }
  }
}

Rendered live from malkreide/register-mcp's GitHub README β€” not stored, always reflects the source repo.

1 Install Method

NameDescriptionCategorySource
pypi packageInstall via pypi (stdio transport)mcp-serverregister-mcp

0 Comments

Login required
Log in to post a comment or update on this repo.

No comments yet β€” be the first to share an update.