Skip to content

MCP catalog audit: publish hosted endpoints hidden behind unusable first entries, fix Deel/AppDeploy URLs, report withheld endpoints (stacked on #97) - #98

Open
vaibhavamalgm wants to merge 2 commits into
UsefulSoftwareCo:mainfrom
vaibhavamalgm:fix/mcp-catalog-audit
Open

vaibhavamalgm wants to merge 2 commits into
UsefulSoftwareCo:mainfrom
vaibhavamalgm:fix/mcp-catalog-audit

Conversation

@vaibhavamalgm

Copy link
Copy Markdown

Stacked on #97. This branch contains #97's commit (63f7cba1, Resend + endpoint-less curated MCP entries). The new work here is commit 07aa32a3. Please review #97 first; once it merges, this diff shrinks to that one commit.

Audit

I compared every hosted MCP endpoint in domains/ with what output/search-index.json actually publishes. That file is what the worker's catalog feed serves.

Count
Discovered domains 3,334
Domains with a discovered MCP URL 1,319
…whose every MCP URL is unpublishable (dead, template or loopback, per output/mcp-endpoints.json) 121 (correct behaviour, not counted as issues)
…published correctly 1,127 → 1,142 after this PR
…with no MCP surface published 60 → 47
…published with a different URL than discovery 11 → 9
Curated MCP entries audited 18 hosted + 1 local (Resend, fixed in #97)
MCP surfaces in the search index with no URL 1 (Resend) → 0

I also checked the curated entries: all 18 curated hosted endpoints match discovery and the probe cache, and every curated auth: "none" is backed by a live (HTTP 200) probe. No stale curated endpoints and no contradicted auth claims.

All endpoint checks below were read-only: one plain GET (status and WWW-Authenticate only) and a fetch of the RFC 9728 protected-resource metadata. There were no MCP initialize calls, no sessions and no credentials.

Fix 1: discovered MCP selection (pipeline, scripts/normalize.ts)

Bug: buildDiscoveredEntries keeps the first MCP surface per domain. When that surface has no URL (a docs server listed without one) or an unusable {template} URL, the record is later dropped by isPublic / applyEndpointVerdicts, and the domain's real hosted server, listed second, is lost with it.

Fix: within a domain, a hosted endpoint now beats an earlier unusable one. "Hosted" means isHttpUrl plus the existing isPublishableMcpUrl, so the same template, loopback and dead-verdict rules apply. First-listed-wins is unchanged whenever the first entry is usable. Other kinds are unchanged.

Guard against new duplicates: a promoted surface is dropped if another row already publishes the same endpoint. For example, domotz.app's second entry is domotz.com's endpoint, so domotz.app does not get a duplicate card. The 22 cross-domain duplicate MCP URLs already on main are untouched (see draft #51).

Endpoints this publishes, each verified:

Domain Endpoint now published What was listed first Evidence
algolia.com https://mcp.algolia.com/mcp https://{APP_ID}.algolia.net/… template Protected-resource metadata (PRM) resource = endpoint, auth server dashboard.algolia.com; probe auth
commercelayer.io https://core-mcp.commercelayer.io/mcp docs MCP, no URL PRM resource = endpoint, auth server auth.commercelayer.io; 401 Bearer
langchain.com https://api.smith.langchain.com/mcp docs MCP, no URL PRM resource = endpoint; 401 with resource_metadata
snowplow.io https://console.snowplowanalytics.com/api/agent/mcp no URL PRM resource = endpoint, auth server id.snowplowanalytics.com
vectorize.io https://api.hindsight.vectorize.io/mcp no URL PRM resource = endpoint
mcp.usehalyard.ai https://mcp.usehalyard.ai no URL PRM resource = endpoint, auth server api.usehalyard.ai
promptlayer.com https://mcp.promptlayer.com/mcp docs MCP, no URL docs.promptlayer.com/agents/mcp: hosted URL, Authorization: Bearer pl_…
loqate.com https://reach.prod.fabric.gbgplatforms.com/mcp docs MCP, no URL docs.loqate.com/ai-agents/mcp/overview documents this hosted endpoint (API key)
cosmicjs.com https://mcp.cosmicjs.com/v1/agent …/v1/buckets/{your-bucket-slug} template cosmicjs.com/docs/mcp-server: documented agent-signup scope. The bucket scope is per-customer, so it stays unpublishable
coveragecat.com https://coveragecat.com/api/consumer/mcp server-card / manifest JSON URLs (probe: not MCP) coveragecat.com/developers/mcp: public consumer MCP, no auth
webiny.com https://mcp.docs.webiny.com/mcp no URL webiny.com/docs … build-with-llms-ai: remote docs MCP
weaviate.io https://weaviate-docs.mcp.kapa.ai no URL docs.weaviate.io/weaviate/mcp/docs-mcp-server: official docs MCP, hosted by Kapa
evlog.dev https://evlog.dev/mcp server-card JSON URL Probe cache: HTTP 200, initialize ok. No separate docs page found, so this rests on the repo's own probe

Fix 2: report hosted endpoints that are still withheld (pipeline)

A domain covered by another source with no MCP surface still has its discovered record skipped wholesale by the domain-wide knownRawDomains check. Examples of such sources: an apis.guru spec, a GraphQL or CLI feed row, or a curated file without an MCP interface. #26's commit message describes the intended rule as kind-aware, but for exact-domain matches it is still domain-wide.

I did not auto-publish these. Several crawled endpoints in this group are wrong:

  • apigee.net → api.marketcheck.com/mcp: a different vendor.
  • xero.com → https://api.xero.com: the API base, not MCP.
  • zuora.com → a sandbox host.
  • 1password.dev: no longer resolves.

The repo has no per-surface rejection, and catalog-denylist.json is whole-domain only. So the build now reports them instead of dropping them silently:

discovered-mcp-withheld: 35 hosted MCP endpoints found by discovery are not published (domain covered by another source with no MCP surface)
discovered-mcp-withheld: hubapi.com https://mcp.hubspot.com
…

withheldDiscoveredMcp() skips endpoints already published under another domain. Ten of the 60 gaps are that case (correct behaviour): bufferapp.com → buffer.com, fly.io → sprites.dev, polygon.io → massive.com, swaggerhub.com → smartbear.com, brex.io → brexapis.com, ote-godaddy.com → godaddy.com, planetscale.com → pscale.dev, opentargets.io → targetvalidation.org, mandrillapp.com → list-manage.com, domotz.app → domotz.com.

Fix 3: source data, overrides/mcp/

Both records come from the OpenAI directory feed (sources/openai.json):

Record Was Now Evidence
mcp/deel https://api-staging.letsdeel.com/mcp (staging) https://api.letsdeel.com/mcp developer.deel.com/mcp/connecting-clients: server URL https://api.letsdeel.com/mcp, OAuth2 or bearer token, no staging host documented. Both hosts serve PRM
mcp/appdeploy https://api.appdeploy.ai/mcp https://api-v2.appdeploy.ai/mcp Vendor's appdeploy.ai/openapi.json: production server https://api-v2.appdeploy.ai, /mcp, OAuth 2.0 + PKCE or bearer

Auth stays oauth, which matches both vendors' docs. Each override sets only mcp.remoteUrl and still goes through the existing endpoint verdicts.

Tests (scripts/normalize.test.ts, local fixtures only)

  • A hosted endpoint listed after an endpoint-less entry, or after a {APP_ID} template, is published, and the domain's other records and slugs are unchanged.
  • The first listed hosted endpoint still wins, and a domain whose MCP entries are all unusable still publishes none.
  • A promoted endpoint never duplicates another row's endpoint, and pre-existing duplicates are left alone.
  • A withheld endpoint is reported and not published. An endpoint already published under another domain is not reported, and nothing is reported once the domain has its own MCP surface.
  • The Deel and AppDeploy overrides point at the documented production URLs.
  • Publish Resend's hosted MCP endpoint; stop endpoint-less curated MCP entries hiding hosted ones #97's tests cover Resend, endpoint-less curated entries, curated selection, and preserving valid curated entries.

With fix 1 disabled, its test fails; with the duplicate guard disabled, its test fails. Both pass with the code as committed.

Verification (actual results)

Command Result
bun test scripts/ 49 pass, 0 fail
bun scripts/normalize.ts, all outputs diffed against unmodified main openapi.json, graphql.json, cli.json unchanged. mcp.json 1327 → 1340 (the 13 above). Changed records: curated/resend-com-mcp (#97), mcp/deel, mcp/appdeploy. Search index 3369 → 3370 rows (evlog.dev is new). Cross-domain duplicate MCP URLs: 22 → 22
bun run build Passes
tsc --noEmit -p . 12 errors, the same 12 as unmodified main
bun run validate:batch Exits 1 with 847 offenders, identical on unmodified main (pre-existing domains/ alias duplicates)

Needs maintainer review / live validation (not changed here)

  • The 35 withheld endpoints. Many have strong evidence and look like real, missing integrations. Examples include HubSpot (mcp.hubspot.com), Vimeo, TomTom, Netlify, Avaza, PocketSmith, Synq, Shotstack, elmah.io, Icons8, X (api.x.com/mcp), and Cisco ThousandEyes; most return 401 with PRM naming the endpoint. Others are wrong (see above). Making the known-domain rule kind-aware for MCP is a one-line change once there is a way to reject a single bad surface. Alternatively they could go in as curated records.
  • vio.com: the OpenAI feed's URL embeds api_key=… in the query string. Discovery lists https://mcp.vio.com/mcp with auth: none. I can't confirm which is right without opening a session.
  • Google endpoints: people.googleapis.com, searchconsole.googleapis.com and developerknowledge.googleapis.com are withheld or aliased. Left for issue file.googleapis.com MCP is misidentified as Google Drive and auth-free #69.
  • The 22 pre-existing cross-domain duplicate MCP URLs (draft Collapse duplicate MCP surfaces across host variants #51).
  • curated/GENERATION.md references scripts/validate-curated.ts, which doesn't exist.

🤖 Generated with Claude Code

Vaibhavlajurkar and others added 2 commits October 20, 2026 00:40
…entries hiding hosted ones

curated/resend.json described only the local stdio server (npx -y resend-mcp)
with no endpoint. Curated records claim their (domain, kind) slot before any
other source, so the hosted https://mcp.resend.com/mcp already present in
domains/resend.com was discarded and the catalog's Resend MCP surface had no
connect URL.

- curated/resend.json: add the hosted MCP interface (Streamable HTTP, OAuth
  in supporting clients, API-key bearer header otherwise; auth "mixed" like
  Stripe and GitHub) and keep the local stdio server as a second interface.
- normalize: when a curated file lists several MCP interfaces, a hosted,
  publishable endpoint beats an endpoint-less one listed before it.
- normalize: an endpoint-less curated MCP record no longer holds its slot.
  A feed or discovered hosted endpoint that passes the usual isPublic and
  endpoint-verdict rules replaces it, and the build prints a
  curated-mcp-no-endpoint warning so the curated file gets fixed.
- The curated/feed/discovered merge moves out of main() into
  assembleRecords() so tests exercise the real wiring with local fixtures.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…entries; report withheld ones

Audit of every discovered hosted MCP endpoint against the published search
index (1,319 domains) found three causes of a missing or wrong MCP surface:

- buildDiscoveredEntries kept the first MCP surface per domain even when it
  had no URL or an unusable {template} URL. That record was then dropped by
  the endpoint rules and the domain's real hosted server went with it. A
  hosted, publishable endpoint now beats an earlier unusable one (Algolia,
  Commerce Layer, LangChain/LangSmith, Snowplow, Vectorize, Halyard,
  PromptLayer, Loqate, Cosmic, Coverage Cat, Webiny, Weaviate, evlog). A
  promoted surface never becomes a second card for an endpoint another row
  already publishes; pre-existing duplicates are untouched.
- A domain covered by another source with no MCP surface (an apis.guru spec,
  a GraphQL/CLI feed row, a curated file without an MCP interface) still has
  its discovered record skipped wholesale. Those hosted endpoints are now
  reported by the build (discovered-mcp-withheld) instead of disappearing
  silently; they are not auto-published, since there is no per-surface
  rejection if a crawled one is wrong.
- The OpenAI directory feed lists Deel's staging host and AppDeploy's
  previous host. overrides/mcp/ points them at the production endpoints the
  vendors document.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants