mcpField
T
The Roofing List

The Roofing List

远程服务
theroofinglist.com商业与营销01 周前更新

关于 The Roofing List

The Roofing List 是公开、只读的 MCP 服务,可按地点查找美国经过核验的屋顶、外墙和排水槽承包商。它提供搜索和承包商查询工具,并排除已停业或未列出的企业,不设付费排名。

主要功能

  1. 01按行业和地点搜索
  2. 02获取承包商资料
  3. 03排除停业或未列出企业
  4. 04不设付费排名

适用场景

  1. 01查找美国城市的屋顶承包商
  2. 02按州寻找外墙承包商
  3. 03通过 ID 查询承包商

MCP 相关

通过 Streamable HTTP 向 MCP 客户端提供 `search_contractors` 和 `get_contractor` 工具。无需登录或 API 密钥。

配置

远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。

服务地址https://mcp.theroofinglist.com/mcp
一键复制安装命令
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。

工具

详细介绍

The Roofing List:MCP 服务

The Roofing List 的公开只读 MCP 服务。AI 助手可通过它按城市查找经过核验的美国屋顶维修、外墙板和排水沟承包商。

使用方法

Claude Code:

claude mcp add --transport http the-roofing-list https://mcp.theroofinglist.com/mcp

Claude Desktop:将以下内容添加到 claude_desktop_config.json。由于该配置文件只能启动本地服务,因此这里使用 mcp-remote。也可以在 Settings > Connectors 中将此 URL 添加为自定义连接器。

{
  "mcpServers": {
    "the-roofing-list": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://mcp.theroofinglist.com/mcp"]
    }
  }
}

其他 MCP 客户端:通过 Streamable HTTP 连接到 https://mcp.theroofinglist.com/mcp。

从任意 Agent 连接:本仓库根目录下的 .mcp.json 包含服务条目。打开本仓库时,Claude Code 会读取该文件。使用其他客户端时,请将该条目复制到相应客户端的 MCP 配置中。

数据规则
  • 只有列出且仍在营业的公司会从此服务返回。即使数据源发送了已停业或未列出的记录,也会将其剔除。
  • 不提供付费置顶。此服务没有排序代码,会保留目录返回的顺序,并将结果截取至 limit 指定的数量。
  • 评分仅来自发布在 The Roofing List 上的评价。不含 Google 评分或评价数据:数据契约中没有这些字段,且字段白名单会剔除任何额外字段。
  • 免费档案不会包含网站。

这些规则位于 src/present.ts。test/tools.test.ts 中的测试会使用一个特意设计为泄漏数据的桩来验证这些规则。

工作原理

  • Worker 名称:theroofinglist-mcp
  • 端点:POST /mcp(Streamable HTTP)。无需登录。GET / 会发送 301 重定向到 https://theroofinglist.com/mcp/。
  • 无状态:agents/mcp/server 中的 createMcpHandler 会为每个请求创建一个新的 McpServer。不使用 Durable Objects。Cloudflare 将 McpAgent 标记为新无状态服务的旧路径。
  • 协议:MCP SDK v2 提供 2026-07-28 规范服务。它也会通过无状态回退机制响应 2025 年的客户端。

REST API

同一个 Worker 还提供一个小型 REST API,供 RapidAPI 和不使用 MCP 的用户使用。该 API 只读、免费且无需密钥。它调用与 MCP 工具相同的查询(src/lookup.ts),因此两者返回的记录相同。

路由返回内容
GET /v1/contractors?trade=&city=&state=&limit={ "contractors": Contractor[] }。输入和限制与 search_contractors 相同。
GET /v1/contractors/{id}Contractor;若 ID 对应的公司已停业、未列出或未知,则返回 404
GET /openapi.jsonOpenAPI 3.1 文档(本文件夹中的 openapi.json)
curl 'https://mcp.theroofinglist.com/v1/contractors?trade=roofing&city=Austin&state=TX&limit=5'
curl 'https://mcp.theroofinglist.com/v1/contractors/101'
  • 错误格式为 { "error": "..." }:400 表示输入无效(错误消息与工具相同),404,非 GET 方法返回 405,超出速率限制时返回 429(附带 Retry-After: 60),Web Worker 出错时返回 503。
  • 每个响应都带有 access-control-allow-origin: *。OPTIONS 会响应 CORS 预检请求。
  • 缓存:200、400、404 和 405 响应使用 public, max-age=300。429 和 503 使用 no-store,避免缓存短暂的错误。/openapi.json 的缓存时间为 1 小时。
  • openapi.json 是该文档的唯一来源。src/openapi.ts 会导入它。提高 SERVER_VERSION 时,也要提高 info.version;有测试会检查两者是否一致。
RapidAPI 与速率限制

所有 RapidAPI 调用都来自 RapidAPI 的服务器。按 IP 限制会把所有 RapidAPI 用户都算作同一个调用方。因此:

  • 将 RapidAPI 提供方控制面板中的代理密钥设为 Worker 密钥:pnpm exec wrangler secret put RAPIDAPI_PROXY_SECRET。这是可选的。本地开发时,在 .dev.vars 中留空即可。
  • 请求携带该密钥(位于 x-rapidapi-proxy-secret)时,密钥为 rapidapi:<x-rapidapi-user>。如果没有用户标头,密钥则回退为 IP。
  • 缺少密钥或密钥错误时,密钥为 IP。调用方不能通过发送伪造的 x-rapidapi-user 来自选密钥。比较采用恒定时间。
  • REST 和 MCP 在同一绑定上使用独立的额度:密钥分别以 rest: 或 mcp: 开头。每种额度均为每分钟 60 次调用。/openapi.json 和 OPTIONS 不计入。

工具

工具输入返回值
search_contractorstrade(roofing、siding、gutters)、city、state(代码或名称)、limit(1–25,默认 10){ contractors: Contractor[] }
get_contractorid(搜索结果中的整数)Contractor;如果对应 ID 已关闭、未列出或未知,则返回错误

Contractor:id、name、trades、city、state、phone、profileUrl、claimed、website(仅限已认领)、rating({ value, count },仅包含我们网站上发布的评价;没有评价时不返回)。

关于哪些数据可以离开此 Worker,请参阅上文“数据规则”。

在本地运行

你需要 Node 22+(Wrangler 4)和 pnpm。无需登录 Cloudflare。

pnpm install
pnpm dev          # MCP Worker on :8787 plus the stub web Worker
pnpm smoke        # in a second shell: official MCP client lists and calls both tools
pnpm smoke --burst  # also checks the rate limit (uses up this minute's budget)
pnpm test
pnpm typecheck

首次运行 pnpm dev 时,会将 .dev.vars.example 复制为 .dev.vars。两者都包含一个虚假的本地令牌。

对接真实 Web 应用

真实数据路由位于私有 Web 应用(theroofinglist-web)中。src/contract.ts 对其进行了描述,stub/ 则使用虚假数据行复制了其结构。如果你有该 Web 应用,请在端口 8790 上运行它,并通过 WEB 服务绑定将此 Worker 指向它:

pnpm exec wrangler dev -c wrangler.jsonc --local --port 8792
MCP_URL=http://localhost:8792/mcp pnpm smoke

两个 Worker 的 .dev.vars 中必须设置相同的 INTERNAL_API_TOKEN。

pnpm smoke 会通过搜索德克萨斯州奥斯汀的屋顶承包商来获取 ID,因此可用于桩服务和真实数据。SMOKE_CITY 和 SMOKE_STATE 可以更改搜索条件。SMOKE_CLOSED_ID 指定一个不应返回的 ID:运行 SMOKE_CLOSED_ID=103 pnpm smoke 可检查桩服务中的已关闭数据行。

Inspector:运行 npx @modelcontextprotocol/inspector,并使用 Streamable HTTP 连接到 http://localhost:8787/mcp。

数据读取方式

MCP Worker 通过服务绑定(WEB)调用 theroofinglist-web。Web Worker 通过 Payload 读取数据,与公共页面使用相同的方式。在本地开发中,stub/ 以 theroofinglist-web 的名称运行,并提供虚假数据行。桩服务有意采用宽松设置:它会发送已关闭的数据行、免费的网站字段和 Google 字段,以证明此 Worker 会过滤这些内容。

内部路由

私有 Web 应用提供此路由。src/contract.ts 对其进行了定义。该路径位于 /api 之外,因此不会被 Payload 的 /api/[...slug] 捕获。

GET /internal/mcp/contractors?trade=<slug>&state=<USPS>&city=<city-slug>&limit=<1..25>
  200 { "contractors": Contractor[] }

GET /internal/mcp/contractors/<id>
  200 { "contractor": Contractor }
  404 { "error": "not_found" }      // also for closed or unlisted

Header on every request: x-internal-token: <INTERNAL_API_TOKEN>
  401 { "error": "unauthorized" }   // missing or wrong token

Contractor = {
  id: number,                      // Businesses.id
  name: string,
  trades: string[],                // Trades slugs, TRADE_PATHS order
  city: string,                    // city name, e.g. "Austin"
  state: string,                   // USPS code, e.g. "TX"
  phone: string | null,            // E.164
  tier: "free" | "claimed",
  website: string | null,          // as stored; the MCP Worker drops it for free
  status: "active" | "closed",
  listed: boolean,
  path: string,                    // profilePath(), e.g. "/roofers/texas/austin/lone-star-roofing"
  rating: { value: number, count: number } | null   // getRatings(): published reviews only
}

速率限制

RATE_LIMITER 是 Workers 速率限制绑定:按 cf-connecting-ip 作为键,每个 IP 每 60 秒最多 60 个请求。超过限制时,/mcp 返回 429,并附带 Retry-After: 60 和 JSON-RPC 错误。对于 RapidAPI 流量,使用 RapidAPI 用户作为键;请参阅上文“RapidAPI 与速率限制”。该绑定按 Cloudflare 位置计数,并采用最终一致性,因此用于阻止滥用,而非精确限制超额使用。

生产环境

自 2026 年 10 月 4 日起,已在 https://mcp.theroofinglist.com/mcp(自定义域名)上线。使用 pnpm exec wrangler deploy 部署。

  • INTERNAL_API_TOKEN 是两个 Worker 上的机密,值相同。轮换时,请在两者上设置新值。
  • wrangler.jsonc 中的 ALLOWED_HOSTNAMES 列出了自定义域名、workers.dev 名称和本地名称。
  • 合约变更时,先部署 theroofinglist-web。切勿部署 stub/。
  • 冒烟测试:MCP_URL=https://mcp.theroofinglist.com/mcp pnpm smoke。
  • Web 应用通过 /internal/mcp/contractors/(末尾带斜杠)提供此路由。不带斜杠的调用会收到 308,服务绑定会跟随重定向。多一次跳转,但可以正常工作。

官方 MCP 注册表

自 2026 年 10 月 5 日起,以 io.github.redpath1/the-roofing-list 名称收录。此文件夹中的 server.json 是注册条目。检查方式:

curl -s 'https://registry.modelcontextprotocol.io/v0.1/servers?search=redpath1'

名称使用 GitHub 命名空间。域名命名空间(com.theroofinglist/...)需要在顶级域名上添加 TXT 记录,或在 theroofinglist.com 上添加 /.well-known/mcp-registry-auth 文件。Wrangler 登录无法编辑 DNS,而添加文件意味着需要部署 Web,因此我们选择了 GitHub。自 0.1.1 版本起,server.json 会在其 repository 字段中注明此仓库。只有在发布 0.1.1 后,注册表才会显示该字段(见下文)。仓库公开后再发布。

发布新版本

注册表会永久保留所有版本。版本字符串不能更改或重复使用。

  1. 安装 CLI:brew install mcp-publisher(1.8.1 或更高版本)。
  2. 在 server.json 中提高 version(semver,例如 0.1.1)。保持其与 src/server.ts 中的 SERVER_VERSION 一致。
  3. 检查:mcp-publisher validate server.json。
  4. 以命名空间所有者 redpath1 的身份登录。运行 mcp-publisher login github 并输入设备代码。也可以复用 gh 登录,且不显示令牌:gh auth token | xargs -I{} mcp-publisher login github --token={}。
  5. 发布:mcp-publisher publish server.json。
  6. 运行上面的 curl。新版本会显示 "isLatest": true。

theroofinglist.com 上的目录页面已将此服务标记为已在官方注册表中收录。发布新版本不会改变这一点。

公开仓库

https://github.com/redpath1/the-roofing-list-mcp 是 The Roofing List 私有单体仓库中 mcp/ 文件夹的已发布副本。在单体仓库中开发。公开仓库有独立且精简的历史记录,因此不要使用 git subtree push:这会将单体仓库的提交历史(包括作者邮箱)推送到公开仓库。mcp/ 的变更合并到 main 后,请改为复制文件:

git clone https://github.com/redpath1/the-roofing-list-mcp /tmp/trl-mcp
rsync -a --delete --exclude .git --exclude node_modules --exclude .wrangler --exclude .dev.vars mcp/ /tmp/trl-mcp/
cd /tmp/trl-mcp && git add -A && git commit -m "<what changed>" && git push

提交身份使用 Keith Evans <[email protected]>。公开历史中不会出现个人邮箱。

贡献

欢迎提交 Issue。有时间时我们会审查拉取请求。我们不承诺路线图。

许可证

MIT。请参阅 LICENSE。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。