Visitar URL original
Comparing v1.8.4...v1.8.5 · modelcontextprotocol/registry · GitHub
Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: modelcontextprotocol/registry
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.8.4
Choose a base ref
...
head repository: modelcontextprotocol/registry
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v1.8.5
Choose a head ref
  • 17 commits
  • 39 files changed
  • 12 contributors

Commits on Oct 23, 2026

  1. chore(deploy): promote production to 1.8.4 (#1732)

    Promote production from `1.8.3` to
    [v1.8.4](https://github.com/modelcontextprotocol/registry/releases/tag/v1.8.4),
    deploying #1562. Package ownership validation now runs before opening
    the publish transaction, reducing database connection occupancy during
    external registry requests. Publish timing logs also include transaction
    begin and commit failures.
    
    The release points to `65ee4b2f8456eb753c6e38fa157cc5e6c3d95146`, the
    exact commit validated in staging. This PR changes only the production
    image tag; there are no new database migrations in this release.
    
    Validation:
    - Staging smoke test passed 28 assertions across `/v0` and `/v0.1`:
    successful publishing, latest-version selection, duplicate rejection,
    ownership-validation failure, and controlled advisory-lock contention.
    - PostgreSQL statement counters confirmed failed ownership validation
    opens no transaction; timing logs reported the expected API version and
    failure phase.
    - Eight focused service tests passed with the race detector; `git diff
    --check` passed for this promotion.
    
    **Before merging:** confirm the [v1.8.4 release
    workflow](https://github.com/modelcontextprotocol/registry/actions/runs/40020244577)
    completes successfully and publishes
    `ghcr.io/modelcontextprotocol/registry:1.8.4`. It was still running when
    this PR was opened. Merging triggers the production deployment.
    
    Rollback: restore the production image tag to `1.8.3`.
    rdimitrov authored Oct 23, 2026
    Configuration menu
    Copy the full SHA
    c434598 View commit details
    Browse the repository at this point in the history

Commits on Oct 24, 2026

  1. fix(publisher): pad ECDSA P-384 signature to fixed width (#1457)

    The in-process ECDSA P-384 signer built the signature with
    `append(r.Bytes(), s.Bytes()...)`. big.Int.Bytes() strips leading zero
    bytes, so whenever r or s had a high zero byte (roughly 1 in 128
    signatures) the concatenation came out shorter than 96 bytes and the
    registry rejected the publish with "invalid signature size for ECDSA
    P-384". Intermittent and confusing to debug. Fixed by left-padding each
    component to 48 bytes with FillBytes, same as the googlekms signer
    already does. Added a test pinning the fixed-width encoding plus a
    sign/verify round-trip.
    JosephDoUrden authored Oct 24, 2026
    Configuration menu
    Copy the full SHA
    097bdc4 View commit details
    Browse the repository at this point in the history
  2. fix(validators): reject incomplete repository metadata (#1555)

    Fixes #1546
    
    ## What changed
    
    - preserve the existing behavior for an omitted `repository` field
    - reject a present repository object when `url` or `source` is missing
    or empty
    - add focused validator and publish-handler regressions, including the
    HTTP 422 response
    
    ## Validation
    
    Published head: `be0c97339875ebf083a06bf1a5686f763024e84d`.
    
    On 2026-10-03, the unchanged patch merged cleanly into upstream `main`
    at `bf4e88cbe8d1a635c06144ccea1d24cb52fa6186` for a local integration
    check:
    
    - full `internal/validators` and `internal/api/handlers/v0` suites with
    `-race`: pass
    - repository regression cases, omitted/complete repository controls, and
    the full publish-endpoint table: pass
    - `go vet` for both affected packages: pass
    - `go build ./cmd/registry`: pass
    - changed-file formatting and diff checks: pass
    
    The published head's GitHub **Build, Lint, and Validate** and **Tests**
    checks also passed. Those results are from 2026-08-20, not a new
    current-main CI run. Full repository `make check` was not rerun locally.
    
    No public API shape is changed, and the patch remains limited to
    repository semantic validation. Broader schema enforcement and
    existing-data cleanup are outside this PR.
    
    Co-authored-by: samrusani <14844597+samrusani@users.noreply.github.com>
    samrusani and samrusani authored Oct 24, 2026
    Configuration menu
    Copy the full SHA
    efee8f0 View commit details
    Browse the repository at this point in the history
  3. fix(validators): allow GitLab repository URLs with nested subgroups (#…

    …1361)
    
    Fixes #1359
    
    ## Problem
    `gitlabURLRegex` in `internal/validators/utils.go` only accepts exactly
    two path segments (`owner/repo`), so valid GitLab repository URLs using
    nested groups/subgroups (e.g.
    `https://gitlab.com/myorg/team/subgroup/my-mcp-server`) are rejected
    with `invalid repository URL`. Subgroups are a standard GitLab feature,
    and this blocks publishing servers whose source lives in a GitLab group
    hierarchy.
    
    ## Fix
    Change the regex from `^https?://(www\.)?gitlab\.com/[\w.-]+/[\w.-]+/?$`
    to `^https?://(www\.)?gitlab\.com/[\w.-]+(/[\w.-]+)+/?$`.
    
    Note this is slightly stricter than the `[\w./-]+` variant suggested in
    the issue: it validates segment-by-segment, so URLs with empty path
    segments (`gitlab.com/group//repo`) stay rejected. The GitHub regex is
    unchanged (GitHub has no subgroups).
    
    ## Testing
    - Added `internal/validators/utils_test.go` with table-driven cases for
    `IsValidRepositoryURL`: nested/deeply-nested subgroup URLs now pass;
    flat `owner/repo`, trailing slash, and `www.` cases keep passing;
    malformed URLs (empty segments, spaces, spoofed hosts, query strings,
    fragments, missing repo) stay rejected; GitHub behavior unchanged.
    - Added an end-to-end `ValidateServerJSON` case with a GitLab subgroup
    repository URL.
    - `go test ./internal/validators/...` green; `gofmt`/`go vet` clean;
    `golangci-lint` introduces no new issues.
    anneheartrecord authored Oct 24, 2026
    Configuration menu
    Copy the full SHA
    8a2efd0 View commit details
    Browse the repository at this point in the history
  4. fix(validators): reject invalid argument types and empty positional a…

    …rguments (#1583)
    
    ## Summary
    
    Publish accepts arguments that violate the schema. `validateArgument`
    only checks the named branch, so a `type` that is empty or outside the
    enum passes through, and a positional argument with neither `value` nor
    `valueHint` also passes. The scan in #1546 counted 52 entries with bad
    argument types and 8 bare positional ones, my own paging of /v0/servers
    found even more of the first kind. One I checked by hand:
    `io.github.Jordan-Horner/symbols@1.0.1` (empty type under
    packageArguments), another is `com.keyboardcrumbs/mcp@1.0.1` (type
    "literal", still active). Every published schema version requires `type`
    to be "positional" or "named" and positional args to carry `value` or
    `valueHint`. Relates to #1546, the empty repository case is #1555's, and
    version "latest" is already handled since #413.
    
    ## Change
    
    `validateArgument` becomes a switch. Named branch unchanged. Positional
    now requires `value` or `valueHint`. Unknown or empty `type` is
    rejected. Two new errors in constants.go, references
    `invalid-argument-type` and
    `positional-argument-value-or-hint-required`.
    
    Why not full schema validation at publish: the enhanced validation
    design doc gates that behind the anyOf error consolidation (Phase 3),
    raw anyOf failures on arguments come out as a noisy multi-error cluster.
    These two checks give one clean message each and are one case arm each,
    easy to delete at Phase 5 when schema-first lands. Until then publish
    and edit just agree with what /v0/validate already reports.
    
    Heads up on two consequences: editing a stored server that still carries
    one of these legacy arguments will 422 until the argument is fixed, and
    the importer skips invalid servers with a warning, so a re-seed from a
    live dump drops those entries instead of failing. Also #1339 adds a
    check inside the named branch of the same function, whichever lands
    second has a small conflict to resolve there, happy to do it from my
    side.
    
    ## Test
    
    Tests first, they fail on main, the handler regression actually
    publishes an empty-type argument with 200 on main and gets 422 with the
    fix. On the branch: go test ./internal/... all green including the
    handler tests against postgres, golangci-lint v2.13.1 (what CI pins) 0
    issues, make validate passes. Two existing fixtures had positional args
    with neither value nor valueHint, they got a valueHint since no
    published schema version ever allowed that shape. New error paths and
    references are pinned in validation_detailed_test.go.
    
    ## AI Disclosure
    
    AI assistance (Claude) was used for issue research and during
    development. All changes were reviewed and tested by the author.
    
    ---------
    
    Co-authored-by: Radoslav Dimitrov <radoslav@stacklok.com>
    JosephDoUrden and rdimitrov authored Oct 24, 2026
    Configuration menu
    Copy the full SHA
    020fed3 View commit details
    Browse the repository at this point in the history
  5. fix(publisher): record repository.id at init so renames stay resolvab…

    …le (#1570)
    
    Towards #1484
    
    ## Background
    
    #1484 audited the `repository.url` of the 398 highest-graded remote
    servers and
    found 38 (9.5%) pointing at repositories that have since been renamed or
    transferred. No hard 404s — GitHub's REST API follows the redirect — but
    GraphQL
    consumers resolve them as nonexistent (`Could not resolve to a
    Repository`), so
    the source link is broken for a real class of tooling, and it stays
    broken once
    the redirect eventually lapses.
    
    ## The gap this closes
    
    `pkg/model/types.go` already defines the field that solves this:
    
    ```go
    ID string `json:"id,omitempty" doc:"Repository identifier from the hosting service (e.g., GitHub repo ID). Owned and determined by the source forge. Should remain stable across repository renames and may be used to detect repository resurrection attacks …"`
    ```
    
    Nothing populates it. `mcp-publisher init` builds the repository block
    from
    `detectRepoURL()` and writes `url` and `source` only, so in practice
    every entry's
    sole pointer at its source is a URL — and a URL is not a stable pointer.
    
    This PR resolves the ID at init time and writes it alongside the URL. A
    rename
    after that point no longer loses the entry: the ID still identifies the
    repository, and it also gives the "deleted and recreated" detection the
    schema
    doc already describes something to compare against.
    
    ## Scope and deliberate limits
    
    - **One request, at scaffolding time.** Not in the publish path, so it
    adds no
      latency or GitHub rate-limit exposure to publishing.
    - **Best effort.** `init` is otherwise fully offline. Being off the
    network,
    rate limited, or pointed at a private repo leaves the field empty rather
    than
    failing the command. `GITHUB_TOKEN` is used when set, mostly so a
    rate-limited
      developer still gets an ID.
    - **GitHub only.** `repository.source` also allows `gitlab`, and
    `detectRepoURL`
    can produce a plain `git` source. Those return empty; GitLab's
    equivalent
    lookup is easy to add if you want it, but I did not want to guess at the
      ID semantics for a forge the audit did not cover.
    - Host matching is exact (`github.com`, optionally `www.`) so a
    lookalike host
    cannot get us to fetch an ID that belongs to somebody else. Covered by a
    test.
    
    ## What this does **not** do
    
    Two parts of #1484 are maintainer calls, not code I should pick
    unilaterally, and
    I have written them up on the issue rather than guessing here:
    
    1. **Backfilling the 38 existing entries.** The registry's data is in
    the
    database, not this repo — `CLAUDE.md` is explicit that `data/seed.json`
    is
    local dev seed data and must not be used to publish. So a data fix
    cannot
    arrive as a PR to this repository at all; it needs an operator-run
    migration,
    and someone has to decide whether rewriting a publisher's
    `repository.url`
       without them re-publishing is acceptable.
    2. **Publish-time behaviour on a redirecting URL** — reject, warn, or
    accept and
    record. `ValidateServerJSON` is currently pure and offline; the only
    network
       validation lives in `ValidatePublishRequest` behind
    `cfg.EnableRegistryValidation`, and it returns a bare `error` with no
    channel
    for a warning even though `ValidationIssueSeverityWarning` exists
    elsewhere.
    Wiring a warning through is a real design decision about the publish
    contract.
    
    ## Test
    
    `cmd/publisher/commands/init_internal_test.go`:
    
    - `TestParseGitHubOwnerRepo` — the URL shapes `detectRepoURL` actually
    produces
    (plain, `www.`, trailing slash, `.git`), plus the ones that must **not**
    be
    treated as GitHub: gitlab, a `github.com.evil.example` lookalike, a deep
      `/tree/main/...` path, an owner with no repo.
    - `TestDetectRepoID` — against an `httptest` stub: records the numeric
    id and
    requests `/repos/{owner}/{repo}`; and stays empty on 404 / non-GitHub
    source /
      empty URL, so a failed lookup can never fail `init`.
    
    ```
    $ go test ./cmd/publisher/...
    ok      github.com/modelcontextprotocol/registry/cmd/publisher/auth      2.363s
    ok      github.com/modelcontextprotocol/registry/cmd/publisher/commands  4.838s
    
    $ go build ./...      # clean
    $ gofmt -l cmd/       # clean
    ```
    
    `golangci-lint` was not available in my environment, so that gate is
    unverified
    locally.
    
    ---------
    
    Signed-off-by: Kush Zingade <kush.zingade@gmail.com>
    UgaTheDev authored Oct 24, 2026
    Configuration menu
    Copy the full SHA
    63d22fa View commit details
    Browse the repository at this point in the history
  6. docs(security): pin and verify mcp-publisher installer (#1523)

    ## Motivation and Context
    
    Fixes #1505.
    
    The GitHub Actions publishing guide downloaded `mcp-publisher` through
    the mutable `releases/latest` URL and extracted it without checking the
    published Sigstore bundle. The three credential-bearing examples now pin
    the release to `v1.8.1`, download the archive and its bundle separately,
    verify the release workflow identity and GitHub Actions OIDC issuer with
    `cosign verify-blob`, and extract only after verification.
    
    ## How Has This Been Tested?
    
    - Parsed all three fenced workflow examples with PyYAML and checked the
    pinned version, cosign installer, and verification flags.
    - Verified the published `v1.8.1` Linux amd64 archive against its
    published Sigstore bundle with cosign v3.0.6 (the version installed by
    the pinned cosign-installer action); verification returned `Verified
    OK`.
    - Ran `git diff --check`.
    
    ## Breaking Changes
    
    None. This only hardens the documented installer workflow; existing
    registry APIs and authentication commands are unchanged.
    
    ## Types of changes
    
    - [x] Bug fix (non-breaking change which fixes an issue)
    - [ ] New feature (non-breaking change which adds functionality)
    - [ ] Breaking change (fix or feature that would cause existing users to
    update)
    - [x] Documentation update
    
    ## Checklist
    
    - [x] I have read the [MCP
    Documentation](https://modelcontextprotocol.io)
    - [x] My code follows the repository's style guidelines
    - [x] New and existing tests pass locally (documentation/workflow
    validation listed above)
    - [x] I have added appropriate error handling
    - [x] I have added or updated documentation as needed
    
    ## Additional context
    
    The release version is intentionally explicit so upgrades are
    reviewable. The Sigstore certificate identity is constrained to this
    repository's release workflow and the selected tag.
    
    ---------
    
    Co-authored-by: Radoslav Dimitrov <radoslav@stacklok.com>
    sys-ops-node and rdimitrov authored Oct 24, 2026
    Configuration menu
    Copy the full SHA
    cd511f4 View commit details
    Browse the repository at this point in the history
  7. docs(auth): document HTTP verification requirements and pin them with…

    … tests (#1640)
    
    ## Summary
    
    Answers the documentation ask in #1625: when HTTP verification fails
    there is no way to tell whether the fault is the key, the file, or the
    Registry's ability to reach the endpoint, and the Registry's egress
    addresses are not a fixed set that can be allowlisted.
    
    ### Documented fetch contract
    (`docs/modelcontextprotocol-io/authentication.mdx`)
    
    New "Troubleshooting failed HTTP verification" subsection describing
    what the Registry actually requests when `mcp-publisher login http`
    runs, why a successful local `curl` proves nothing, and how to reproduce
    the fetch from outside your own network:
    
    - `GET https://<domain>/.well-known/mcp-registry-auth` with `Accept:
    text/plain` and `User-Agent: mcp-registry/1.0`
    - `200 OK` only — redirects are not followed, so a `3xx` fails
    verification
    - proof record of at most 4096 bytes, with surrounding whitespace
    ignored
    - 10 second budget for the whole request
    - the request originates from Google Cloud, where the hosted Registry
    runs, so per-request IP allowlisting is not a workable fix
    
    It then lists the edge rules that break verification in practice
    (WAF/bot-management challenges, geo-blocking or allowlists that exclude
    cloud ranges, an unreachable `AAAA` record, redirects, an HTML error
    page served with `200 OK`), how to read the Registry's own fetch error
    out of the login failure, and where to fix it.
    
    ### The same contract is pinned by tests
    (`internal/api/handlers/v0/auth/http_internal_test.go`)
    
    These properties were previously untested: the existing fetcher tests
    inject a custom `http.Client`, so the production client's redirect
    policy was never exercised, and nothing asserted the request headers or
    whitespace trimming.
    
    - `TestHTTPKeyFetcherClient_DoesNotFollowRedirects` — a `301` must fail
    verification and the redirect target must never be requested.
    - `TestHTTPKeyFetcherClient_TimeoutAndRequestHeaders` — pins the 10
    second timeout, the two documented request headers, and `TrimSpace` on
    the proof record.
    - `TestHTTPKeyFetcher_RejectsResponseAboveDocumentedLimit` — a `200 OK`
    body above 4096 bytes fails.
    
    To make the production client testable, client construction moved into
    `newHTTPKeyFetcherClient(transport http.RoundTripper)`;
    `NewDefaultHTTPKeyFetcher` passes the same cloned transport with
    `safeDialContext`, so production behavior is unchanged. This PR changes
    no production behavior.
    
    ## Verification
    
    - `go build ./...` — clean.
    - `go vet ./...` — clean.
    - `gofmt -l internal/` — clean.
    - `go test ./internal/api/handlers/v0/auth/ -count=1` — `ok` (whole
    package passes).
    - The redirect test is load-bearing: deleting the `CheckRedirect` policy
    from `newHTTPKeyFetcherClient` makes it fail with `stopped after 10
    redirects`, which is exactly the regression it guards.
    - `go test ./internal/api/handlers/v0/ -count=1` fails on this machine
    only because that suite needs PostgreSQL from `docker-compose up -d
    postgres`; unrelated to this change. `golangci-lint` is not installed
    locally, so `make lint` was not run.
    
    Related to #1625.
    
    > AI assistance disclosure: AI was used to discover this opportunity and
    draft the change or text. The submission was checked against the
    prepared artifact and recorded verification evidence.
    
    Co-authored-by: ump45nose <ump45nose@users.noreply.github.com>
    ump45nose and ump45nose authored Oct 24, 2026
    Configuration menu
    Copy the full SHA
    c34626b View commit details
    Browse the repository at this point in the history
  8. docs(publishing): troubleshooting for DNS/HTTP auth (#845) (#1268)

    ## Summary
    
    Adds a **Troubleshooting DNS and HTTP authentication** section to the
    publishing authentication guide. Patterned after #1253 (my prior docs
    fix in the same file): docs-only, focused on the recurring failure modes
    that bottom out as a generic `signature verification failed` or `no MCP
    public key found` error.
    
    Motivated by #845 (improve CLI/TUI experience for DNS/HTTP auth) and the
    recurring confusion around DNS apex/selector placement called out in
    #1126. The full TUI work in #845 is a larger lift; this is the docs
    slice that lets people self-diagnose today using the tools they already
    have (`dig`, `curl`).
    
    The new section covers, in order:
    
    1. **Comparing the CLI's "Expected proof record" against what's actually
    published** — the most common cause of false-fail loops, especially
    after rotating keys.
    2. **DNS: verifying the TXT record with `dig` before logging in** —
    distinguishes missing / stale / misplaced records, and notes the
    existing misplaced-selector probe added for #1126 (so users know what
    error shape to expect).
    3. **HTTP: verifying `/.well-known/mcp-registry-auth` with `curl -i`** —
    plus the four constraints baked into the server-side fetcher in
    `internal/api/handlers/v0/auth/http.go`: HTTPS only, no redirects (the
    fetcher returns `http.ErrUseLastResponse` from `CheckRedirect`),
    `MaxKeyResponseSize = 4096` byte cap, and the `safeDialContext`
    blocklist of loopback / RFC1918 / link-local / CGNAT IPs.
    4. **Algorithm vs key mismatch** — `--algorithm` must match the
    published `k=` field.
    
    Nothing new in code; the existing apex/selector `<Warning>` (already in
    the file) and the OpenSSL 3.x `<Note>` from #1253 are untouched.
    
    ## Test plan
    
    - [x] `git diff --stat` confirms a single-file docs change
    (`docs/modelcontextprotocol-io/authentication.mdx`, +48/-0).
    - [x] Verified the documented HTTP constraints against
    `internal/api/handlers/v0/auth/http.go`: `MaxKeyResponseSize = 4096`,
    `CheckRedirect` returning `ErrUseLastResponse`, `safeDialContext` IP
    blocklist, `https://` URL construction, `strings.TrimSpace` of the body.
    - [x] Verified the documented DNS misplaced-selector behavior against
    `internal/api/handlers/v0/auth/dns.go` (`commonWrongSelectors =
    ["_mcp-auth", "_mcp-registry"]`, `findMisplacedSelector` probe).
    - [x] Verified the "Expected proof record" output line is what
    `cmd/publisher/auth/common.go` actually prints (`PrintEd25519KeyInfo` /
    `printEcdsaKeyInfo`).
    - [ ] Markdown rendering of `<CodeGroup>` / fenced blocks — relying on
    the existing patterns in this file for syntax validity, no new MDX
    components introduced.
    
    Continuing the publisher-devex thread from #1253. Happy to split or trim
    if maintainers prefer a smaller surface area.
    
    Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
    rhinocap and claude authored Oct 24, 2026
    Configuration menu
    Copy the full SHA
    edd9fa7 View commit details
    Browse the repository at this point in the history

Commits on Oct 25, 2026

  1. docs(api): clarify per-version listings and latest filtering (#1735)

    Callers can mistake the first search result for the current version
    because the list documentation does not explain that results contain one
    record per version. Document ascending name/version-string ordering,
    explain that it is neither semantic-version nor publication-date
    ordering, and show `version=latest` for current records only. The
    clarification appears in the API guide, reference OpenAPI document, and
    generated documentation for both API versions.
    
    Closes #1676.
    
    Validation:
    - CI build, lint, schema/example validation, govulncheck, and full
    unit/integration tests passed for `aff04c2`.
    - Local `make validate` and `go test ./internal/api -run
    '^TestOpenAPIEndpointCompliance$' -count=1` passed.
    - `gofmt` and `git diff --check` passed.
    - Live read-only verification reproduced superseded records without the
    filter and only `isLatest=true` with `version=latest`.
    
    This changes documentation only; query behavior and result ordering are
    unchanged.
    rdimitrov authored Oct 25, 2026
    Configuration menu
    Copy the full SHA
    13f90b2 View commit details
    Browse the repository at this point in the history
  2. docs: add ProtocolProbe to community projects (#1736)

    ## Motivation and Context
    Adds ProtocolProbe to the Other section, in alphabetical order (between
    polygraph and PulseFeed MCP Drift Watch).
    
    ProtocolProbe (https://protocolprobe.com) is a free, neutral site with
    dated, sourced facts about every server in the official registry: the
    listing, npm/PyPI and GitHub repository checks, version history, and a
    record of what changed each day (https://protocolprobe.com/mcp/changes).
    The same facts are an open CC BY 4.0 dataset with a Zenodo DOI (all
    versions: 10.5281/zenodo.23386799; also on Hugging Face and Kaggle) and
    a public read-only API (https://protocolprobe.com/docs/api). It also
    publishes a self-test command that operators run on their own machine
    against their own server. ProtocolProbe does not grade servers and never
    calls tools on servers that are not its own.
    
    I am the maintainer of ProtocolProbe. AI disclosure: this PR (the
    one-line change and this description) was prepared with an AI assistant
    (Claude) and submitted from my account after I approved it.
    
    ## How Has This Been Tested?
    Documentation only. Checked that the link loads, that the entry follows
    the list's one-line format and alphabetical order, and that the file's
    line endings are unchanged.
    
    ## Breaking Changes
    None.
    
    ## Types of changes
    - [ ] Bug fix (non-breaking change which fixes an issue)
    - [ ] New feature (non-breaking change which adds functionality)
    - [ ] Breaking change (fix or feature that would cause existing
    functionality to change)
    - [x] Documentation update
    
    ## Checklist
    - [x] I have read the [MCP
    Documentation](https://modelcontextprotocol.io)
    - [x] My code follows the repository's style guidelines
    - [ ] New and existing tests pass locally
    - [ ] I have added appropriate error handling
    - [x] I have added or updated documentation as needed
    
    ## Additional context
    Related to #1715, where I shared the same dated pulls as input for
    periodic re-validation.
    md sultan mahamud authored Oct 25, 2026
    Configuration menu
    Copy the full SHA
    df677de View commit details
    Browse the repository at this point in the history
  3. fix(deploy): reduce ingress restarts under load (#1737)

    Production ingress repeatedly exceeded its one-second health-check
    deadline under load. Both registry replicas were co-located with
    PostgreSQL despite soft spreading; 12 of 13 ingress restarts on that
    node followed near-saturated CPU. A second node also showed disk
    pressure, which needs a separate node rollout.
    
    Enforce per-revision spreading for registry and ingress in
    staging/production, using `pod-template-hash` so old replicas cannot
    mask placement of new ones. Reserve 300m CPU per ingress and 250m per
    registry replica, retaining unlimited CPU bursts. Set ingress
    readiness/liveness timeouts to 3s/5s and explicitly retain a one-pod
    surge with zero unavailable replicas. Local development keeps soft
    registry spreading and 100m CPU requests.
    
    Document staging-first verification and a separate subsequent upgrade
    from the 20 GB standard boot disks to 50 GB balanced disks. This PR
    changes no node pool or production promotion config and does not close
    #1252.
    
    Validation: `make -C deploy build`, `go vet ./...` in deploy, and `git
    diff --check` pass. Executed the actual deployment constructors with
    Pulumi mocks and rendered pinned ingress chart 4.13.0 for
    local/staging/prod; verified selectors, revision spreading, CPU
    requests, merged probe defaults, and rollout policies. Both staging and
    production API servers accepted the generated Deployments with `kubectl
    apply --dry-run=server`. A CPU scheduling model of the current
    production placement found no deadlocks across 70 reachable states,
    assuming ready replacements and unchanged background requests; final
    requests are approximately 1490m/1489m of 1930m per node.
    
    Production `pulumi preview --stack gcpProd --refresh --diff` completed
    successfully for commit 5bac183. It plans the two intended Deployment
    updates, two existing Grafana RBAC resources changing only `rules: null`
    to `rules: []` (no permission change), and recreation of the two
    existing ingress admission setup Jobs with `ttlSecondsAfterFinished: 0`.
    There are no node, database, or backup-resource changes and no deletions
    or replacements. The non-refresh preview showed the same four updates
    without the cleaned-up Jobs. No infrastructure update has been applied;
    verify staging before production rollout.
    rdimitrov authored Oct 25, 2026
    Configuration menu
    Copy the full SHA
    5b2a1a3 View commit details
    Browse the repository at this point in the history
  4. deploy: promote ingress stability fixes to production (#1738)

    Promote the infrastructure changes from #1737 through the existing
    production workflow while retaining registry application image `1.8.4`.
    The comment-only change to `deploy/Pulumi.gcpProd.yaml` deliberately
    triggers that workflow on merge; it does not change application
    configuration or encrypted secrets.
    
    Staging deployment of merge commit `5b2a1a3` succeeded:
    https://github.com/modelcontextprotocol/registry/actions/runs/40241181207.
    Verified both registry replicas are available on different nodes with
    250m CPU requests, ingress is available with a 300m request and 3s/5s
    readiness/liveness timeouts, and per-revision spreading is applied. All
    new containers had zero restarts. Health, list, and name-search requests
    returned HTTP 200 in approximately 0.6 seconds. Staging has one ingress
    replica, so production's two-replica placement still needs
    post-deployment verification; these smoke checks do not establish
    peak-load performance.
    
    Production preview at this promotion commit succeeded: two intended
    Deployment updates plus existing Grafana empty-rule normalization. The
    refreshed preview of the identical infrastructure code also showed
    recreation of the two automatically cleaned-up ingress admission setup
    Jobs. No node, database, or backup changes, deletions, or replacements
    are planned.
    
    After deployment, verify both production Deployments and node placement,
    then compare probe failures/restarts and ingress request latency at
    comparable traffic during a busy period. The disk upgrade remains a
    separate rollout. Related: #1252.
    rdimitrov authored Oct 25, 2026
    Configuration menu
    Copy the full SHA
    4e2df3f View commit details
    Browse the repository at this point in the history
  5. deploy: upgrade GKE boot disks to 50 GB balanced storage (#1739)

    Production ingress stalls correlated with high I/O latency and queues on
    the 20 GB `pd-standard` boot disks, which also serve the ingress cache
    and container logs. Increase both hosted environments to 50 GB
    `pd-balanced` boot disks and explicitly retain GKE's surge strategy
    (`maxSurge: 1`, `maxUnavailable: 0`). Node count and machine type stay
    the same; database and monitoring persistent volumes keep their existing
    sizes.
    
    **Merge and verify production promotion #1738 before merging this PR.**
    Merging this PR automatically rolls staging; production needs a
    subsequent promotion after staging verification. Production deployment
    uses all infrastructure code at the triggering commit, so reversing this
    merge order would combine the pod and disk changes. GKE updates the
    existing node pool by replacing its VMs incrementally. The single
    registry and Grafana PostgreSQL instances will be interrupted while
    their separate persistent disks move; surge capacity does not provide
    database HA. The README documents preparation and verification.
    
    Validation:
    - `make -C deploy build`, `go vet ./...` in `deploy`, and `git diff
    --check` passed.
    - Refreshed production Pulumi preview at `1048543` succeeded. The
    node-pool diff contains only `nodeConfig.diskSizeGb` and
    `nodeConfig.diskType`; no Pulumi resource deletions or replacements and
    no persistent-volume/database changes. The rest of the plan is the
    pending #1738 Deployment updates, two automatically cleaned-up ingress
    admission Jobs, and existing Grafana empty-rule normalization.
    Re-preview after #1738 deploys before production promotion.
    - Both projects have regional CPU, SSD-disk, and address quota headroom
    for a surge node; actual zonal capacity is only established during
    provisioning.
    - Both production PostgreSQL clusters are healthy with one instance and
    PDBs disabled. Their disks use the GCE persistent-disk CSI driver. The
    production registry backup last succeeded at 2026-10-25 04:47:13 UTC;
    check freshness again at rollout.
    
    No infrastructure has been applied from this branch. After rollout,
    verify disk configuration, workload readiness/placement and API smoke
    checks, then compare disk queues, ingress restarts and request latency
    during busy traffic. Related to #1252; this change does not establish
    that the latency target has been met.
    
    [GKE surge upgrade
    behavior](https://docs.cloud.google.com/kubernetes-engine/docs/concepts/node-pool-upgrade-strategies)
    rdimitrov authored Oct 25, 2026
    Configuration menu
    Copy the full SHA
    cfc66cb View commit details
    Browse the repository at this point in the history
  6. deploy: promote balanced node disks to production (#1740)

    Promote the 50 GB `pd-balanced` node boot disks from #1739 through the
    existing production workflow while retaining registry application image
    `1.8.4`. This comment-only change to `deploy/Pulumi.gcpProd.yaml`
    deliberately triggers that workflow on merge. The two-node pool retains
    `e2-standard-2` machines and uses surge upgrades with one extra node and
    zero unavailable nodes.
    
    Staging rollout succeeded:
    https://github.com/modelcontextprotocol/registry/actions/runs/40243009855.
    Verified both original nodes were replaced with Ready nodes whose actual
    boot disks are 50 GB `pd-balanced`. All four original persistent volumes
    retain their identities, volume handles and sizes, and both PostgreSQL
    clusters recovered. Every active workload is ready; the two registry
    replicas are on different nodes, and registry/ingress containers have
    zero restarts. Health, listing and name-search checks returned HTTP 200
    in about 0.6 seconds; a fresh unique search also returned HTTP 200.
    
    **Allow for a multi-minute database interruption when merging.** During
    staging replacement, registry PostgreSQL was unready from 23:16:45 to
    23:20:29 UTC on October 25 (3m44s), including its configured 180-second
    smart-shutdown timeout before disk reattachment/startup. This is an
    observed staging duration, not a production guarantee. Grafana
    PostgreSQL also moved. The single staging ingress replica caused three
    failed health samples during its move; production has two ingress
    replicas but still only one instance of each database. `/health` does
    not query PostgreSQL, so database readiness was checked separately.
    Surge capacity does not provide database HA.
    
    Refreshed production Pulumi preview at `c71e488`, after #1738 deployed,
    passed: node-pool boot-disk size/type update, registry deploy-commit
    annotation update, recreation of two automatically cleaned-up ingress
    admission Jobs, and existing Grafana empty-rule normalization. No Pulumi
    resource deletions/replacements or database/persistent-volume changes.
    GKE nevertheless replaces the node VMs incrementally. All PR CI checks
    passed.
    
    Check the latest successful registry backup when merging; it last
    succeeded at 2026-10-25 04:47:13 UTC during preparation. Both projects
    have surge quota headroom; actual zonal capacity is established during
    provisioning.
    
    After production rollout, verify both nodes have 50 GB balanced boot
    disks, all original persistent volumes are retained, both databases
    recover, and workloads/API smoke checks pass. Compare disk queues,
    ingress restarts and request latency during busy traffic before
    concluding that #1252 is resolved.
    rdimitrov authored Oct 25, 2026
    Configuration menu
    Copy the full SHA
    e47b29e View commit details
    Browse the repository at this point in the history

Commits on Oct 26, 2026

  1. feat(observability): expose request backlog and database waits (#1742)

    When handlers stall, the existing request counter falls because it
    counts completions, hiding incoming demand and backlog growth. Ingress
    logs also omit cache outcomes, making duplicate upstream work difficult
    to distinguish from database contention.
    
    This adds application arrival and in-flight metrics, pgx pool
    acquisition timing/pending counts and connection gauges, and query
    timing after acquisition through row consumption. Database labels use
    bounded operation/outcome values without SQL or parameters. Existing
    completion metrics retain their semantics. Pool callbacks are
    unregistered on close, and failed startup pools are cleaned up.
    
    Ingress access logs retain their existing combined-log prefix and append
    cache status, scheme/host, controller pod, upstream connection/header
    timing, and a millisecond completion timestamp. The runbook explains
    measurement limits, PromQL queries, and how to correlate cache and
    database evidence. Existing log parsers anchored to the end of the old
    format must accept the suffix; ingress logs remain in the existing GKE
    logging destination rather than being added to VictoriaLogs.
    
    Validation:
    - Full internal/cmd unit suite with race detection and coverage against
    temporary local PostgreSQL 17.
    - New tests for blocked-handler arrivals, cancellation/panic cleanup,
    canceled pool waits, query timing through row close, and bounded labels.
    - `make lint`, `make validate`, `make build`, and `make -C deploy build`
    passed.
    - Local application smoke checks verified exported metrics for all four
    list operation classes and in-flight drainage.
    - GitHub CI passed, including the Docker-based integration tests,
    build/lint/validation, govulncheck, and Go/Python/Actions analysis.
    
    Application metrics require an application release/promotion; cache log
    fields require infrastructure promotion. No changes to cache policy,
    concurrency limits, SQL/indexes, or production configuration were
    applied.
    rdimitrov authored Oct 26, 2026
    Configuration menu
    Copy the full SHA
    b64980a View commit details
    Browse the repository at this point in the history
  2. feat(observability): diagnose individual slow listing requests (#1743)

    Slow listing requests currently expose separate HTTP and database
    histograms, but there is no request-level timing record. Database timing
    also includes application JSON decoding, making a slow query
    indistinguishable from slow row processing.
    
    Add bounded structured diagnostics for GET `/v0/servers` and
    `/v0.1/servers`: progress after 2 seconds and every 10 seconds while
    outstanding, plus completion for slow or failed requests. Records
    correlate ingress request ID, pod, route, query-shape flags, page size,
    PostgreSQL backend PID and SQLSTATE, row/JSON-byte counts, and exclusive
    handler/acquisition/query/fetch/decode/response timings. Raw SQL,
    arguments, cursors, search strings and payloads are excluded. Logging is
    capped per pod at 2 events/second with burst 10 and suppression
    accounting; fast successful requests remain silent.
    
    Validation:
    - Full internal/cmd unit suite passed with race detection and coverage
    against PostgreSQL 17.
    - Controlled tests prove a blocked pool is visible before cancellation,
    delayed queries are distinct from row processing, timings account for
    the full request, and request IDs/context propagate through the real
    Huma adapter.
    - Tests cover SQLSTATE-only error detail, panic/cancellation completion,
    timer shutdown and bounded log volume.
    - `make lint`, `make build`, `make validate`, and `git diff --check`
    passed.
    
    Follow-up to #1742. No query, index, resource, or cache-policy changes.
    After staging deployment, verify a bounded slow request and log
    ingestion before cutting the production release. Internal PostgreSQL
    wait attribution still requires contemporaneous database samples;
    sampled logs are not exhaustive tracing.
    rdimitrov authored Oct 26, 2026
    Configuration menu
    Copy the full SHA
    ad119f3 View commit details
    Browse the repository at this point in the history
Loading