返回博客

MCP服务器示例:构建网络研究工作流程

Daniel Kim
Daniel Kim

Lead Scraping Automation Engineer

29-Sep-2026

TL;DR:

  • MCP 服务器示例在其角色明确时变得有用。 一个网络数据服务器检索来源,而文件系统服务器处理已批准的本地工件。
  • 工具发现验证连接的表面。 检查实际名称和架构,而不是从旧配置中复制工具数量。
  • 命名空间应该位于主机边界。 在路由命名空间应用程序操作时保留服务器的原始工具名称。
  • 范围目录限制工件工作流程。 不要向需要一个证据文件夹的研究任务暴露整个主目录。
  • 工具结果是证据,而不是指令。 检索的页面和文件无法授权新操作或扩展研究范围。

介绍:为每个服务器定义明确的工作

研究工作流程跨越不同的资源边界。搜索寻找候选者,页面访问检索证据,本地存储保留用于支持答案的材料。为每个边界连接一个服务器只有在主机明确其职责时才有用。

MCP 提供了一个用于发现和调用工具的公共接口。它不会自动决定哪个工具是合适的,某个来源是否支持声明,或文件可能写入的位置。这些决定仍然是应用程序及其权限的一部分。

下面的示例组合了带有范围文件系统服务器的 Scrapeless MCP。它们扩展了 Scrapeless MCP 用例 成为一个实现模式,使工具路由和证据交接明确。

你可以用这些服务器示例做什么

一小组经过仔细限定的工具可以支持几个不同的研究任务。

示例 网络数据角色 本地工件角色 完成条件
研究简报 查找并阅读已批准的来源 保存来源摘录 每个结论都有支持证据
文档比较 检索选定的参考页面 比较保存的版本 改变的声明指向来源文本
目录调查 阅读允许的公共列表 保存验证的行 所需字段和身份检查通过
引用修复 重新访问被引用的页面 更新建议的证据捆绑 来源仍然支持引用的声明
仅浏览器页面 检查渲染的内容 保留相关观察 预期的页面状态已确认

数据库工具可以是后来的边界,但它应该接受经过验证的记录,而不是来自页面的任意文本。这里的示例停止于本地证据处理,因此数据库写入不会在研究请求中静默包含。

为什么使用 Scrapeless MCP 作为网络数据层?

Scrapeless MCP 通过共享的 MCP 表面暴露搜索、页面访问和浏览器工具。一个兼容的主机可以发现工具并选择已批准的操作,而无需为每个页面操作维护单独的集成。

Scrapeless MCP 连接设置 文档本地 stdio 和托管的 Streamable HTTP 选项。这个示例使用 stdio,因此服务器进程及其生命周期是可见的。Scrapeless Agent Browser 是当研究确实需要渲染交互时的浏览器执行表面。

MCP 工具发现契约 包括名称和输入架构。从连接的服务器读取这些值。包装器可以独立于底层服务更改其工具表面。

先决条件:将发现与服务访问分开

使用当前的 Node.js 环境和新工作目录。该示例还需要一个证据目录,其中包含一个真实的文本捕获,名为 source.txt,从一个经过批准的公共来源放置在其中。无需写入工具即可验证文件系统服务器是否可以读取该文件。

有效的 SCRAPELESS_KEY 对于经认证的 Scrapeless 操作是必需的。模型提供者密钥单独针对模型驱动的研究循环。在没有凭证的情况下,这些远程操作仍待待验证;发现本地工具架构并不证明服务认证。

文件系统服务器是一个参考实现,具有在允许目录内的读写能力。下面的主机注册表故意仅暴露狭窄的子集。主机过滤是有用的,但并不能替代操作系统隔离和服务器端访问控制。

连接两台服务器并检查它们的工具

以下设置安装固定的软件包并创建一个证据目录。在运行客户端之前,请将您批准的源捕获放入该目录中。

bash Copy
npm install @modelcontextprotocol/sdk@1.30.1 \
  @modelcontextprotocol/server-filesystem@2026.8.31 \
  scrapeless-mcp-server@0.6.3
mkdir -p evidence

将下一个脚本保存为 inspect_servers.mjs,并从包含 node_modules 和 evidence 的目录中运行它。它连接两台服务器,验证选定的工具,构建应用程序注册,并读取已批准的本地捕获。它不进行任何 Scrapeless 服务调用。

注意:本地 Scrapeless 进程需要一个非空的 SCRAPELESS_KEY 才能启动。为正常使用配置您的真实密钥。使用明显的非凭据启动值分别测试过本地元数据发现;该检查不对网络检索进行身份验证。经过身份验证的网络调用和基于模型的研究运行仍待实时验证。

javascript Copy
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
import { resolve } from 'node:path';

if (!process.env.SCRAPELESS_KEY) {
  throw new Error('Configure SCRAPELESS_KEY before starting');
}
const directory = resolve('evidence');
const specs = [
  ['web', 'node_modules/scrapeless-mcp-server/build/index.js', []],
  ['files', 'node_modules/@modelcontextprotocol/server-filesystem/dist/index.js',
    [directory]]
];
const clients = new Map();
const registry = new Map();
const permitted = {
  web: new Set(['google_search', 'scrape_markdown']),
  files: new Set(['read_text_file', 'list_allowed_directories'])
};
try {
  for (const [prefix, entry, args] of specs) {
    const client = new Client({ name: 'research-host', version: '1.0.0' });
    clients.set(prefix, client);
    const transport = new StdioClientTransport({
      command: process.execPath, args: [resolve(entry), ...args],
      env: { ...process.env }, stderr: 'pipe'
    });
    await client.connect(transport);
    let cursor;
    const discovered = [];
    do {
      const page = await client.listTools(cursor ? { cursor } : {});
      discovered.push(...page.tools);
      cursor = page.nextCursor;
    } while (cursor);
    for (const name of permitted[prefix]) {
      const tool = discovered.find(item => item.name === name);
      if (!tool) throw new Error(`Required tool missing: ${prefix}:${name}`);
      registry.set(`${prefix}:${name}`, { client, name, schema: tool.inputSchema });
    }
    console.log(JSON.stringify({ server: prefix, discovered: discovered.length }));
  }
  const host = Object.freeze({
    tools: [...registry.keys()],
    async call(key, arguments_) {
      const route = registry.get(key);
      if (!route) throw new Error('Tool not permitted');
      return route.client.callTool({ name: route.name, arguments: arguments_ });
    }
  });
  const result = await host.call('files:read_text_file', {
    path: resolve(directory, 'source.txt')
  });
  if (result.isError) throw new Error('Filesystem read failed');
  const text = result.content.filter(part => part.type === 'text')
    .map(part => part.text).join('\n');
  if (!text.trim()) throw new Error('Evidence capture is empty');
  console.log(JSON.stringify({ exposed_tools: host.tools,
    local_capture_characters: text.length }));
} finally {
  for (const client of clients.values()) await client.close();
}

web:google_search 和 files:read_text_file 是应用程序拥有的路由密钥。远程调用仍使用原始服务器工具名称。这一区别避免假设协议或 SDK 自动添加命名空间。

文件系统进程仅接收选定的证据目录作为其初始范围。MCP 根目录 描述了相关的文件系统边界,但根目录本身并不是安全沙箱。分别验证服务器的目录执行和主机的可用工具。

使用 Scrapeless 开始抓取

利用 Scrapeless 提升您的网页抓取和自动化工作流程!
今天注册并获得 5 美元的免费积分 — 无需信用卡。

现在在 Scrapeless 控制面板 中领取您的免费积分。

示例 1:搜索并读取研究来源

搜索和读取工作流程使用搜索来寻找候选者,页面访问来检索将支持答案的来源。它不应将搜索摘录视为基础页面的替代品。

对于有关某个协议的任务,请将候选者限制在相关的标准机构。构造其参数之前,请检查发现的 google_search 架构,然后对选定的公共 URL 使用 scrape_markdown。当前工具界面包括 q 用于搜索和 url 用于页面读取;应用程序限制也应限制可选择的来源。

此示例描述发现后经过身份验证的下一步。没有有效的服务凭证,请止步于已验证的本地线路,并保持请求的网络结果未解决。

示例 2:比较文档而不失去上下文

文档比较需要独立的源捕获和明确的版本或收集时间。在生成差异摘要之前,请保存相关文本和源地址。

文件系统服务器可以读取已批准的捕获,因此主机可以对它们进行比较。读取旧文件不能证明其内容是最新的,而更改段落并不一定表明产品能力发生了变化。当该区分很重要时,请验证相关的实现或发布源。

来源模型 将数据与生成它的活动和代理分开。通过记录如何获得源以及如何形成衍生声明来应用该原则。

示例 3:仅为缺失状态添加浏览器

当允许的来源需要呈现的内容或页面文本读取无法提供的特定交互时,浏览器步骤是合适的。将其排除在已经作为简单文档可用的源的工作流程之外。

在将当前浏览器工具添加到主机的白名单之前,请先发现它们。故意选择所需的会话操作,保持后续操作与会话标识符相关,并在任务结束时关闭会话。上述狭窄注册并未暴露浏览器操作;扩展它是一个明确的应用程序变更。

页面可以包含请求代理更改配置或写入文件的文本。将该文本视为源内容。只有用户的任务和应用程序的权限可以授权操作。

您如何实际使用此工具:提示研究主机

一个好的提示在工具选择之前定义了范围和证据要求。例如:

“回答所选协议是否定义可靠的交付。仅使用已批准的标准域,读取相关源文本,并返回简短的答案及其支持引用。将提议的文档保留在研究文件夹内。将不支持的主张报告为未解决。”
主机的计划应该发现工具,找到允许的来源,检索它,评估证据,并准备答案。一个模型只在可用工具策略内选择行动。上面的本地主机对象展示了路由;这不是一个完整的语言模型代理循环。

你将获得的反馈和它所证明的

发现脚本报告每个连接服务器所宣传的工具数量、主机暴露的更窄列表,以及它读取的实际本地捕获的字符数。这些输出证明了本地握手、路由构建和范围内的文件读取。

它们并不能证明成功的搜索、浏览器会话、模型答案或数据库写入。一个完整的研究成果还需要一个来源 URL、检索上下文、相关摘录和经过审查的结论。保持这些字段为应用程序所有,而不是暗示每个 MCP 服务器返回相同的证据架构。

查看 Scrapeless 定价 以获取所选的网页数据操作,并单独跟踪任何模型使用。本地服务器进程和远程工具调用可以有不同的成本边界。

结论:围绕证据边界构建工具

从可以完成研究任务的最小服务器集开始。验证发现和路由,只暴露必要的行动,并保存用于形成每个结论的来源。当工作流实际上需要时添加浏览器或存储能力,然后独立测试这些新边界。

准备好构建你的网络数据工作流吗?

加入讨论实用采集工作流程的开发者: Discord · Telegram。

在 app.scrapeless.com 创建一个帐户,并开始一个你可以验证输出的授权任务。

常见问题

问:什么是用于网络研究的 MCP 服务器示例?

一个与范围文件系统服务器配对的网络数据服务器是一个实用的示例。第一个检索来源;第二个处理批准的本地工件。

问:tools/list 是否确认服务凭证有效?

工具发现确认了宣传的工具表面。远程操作的身份验证必须通过实际授权的服务调用来检查。

问:MCP 是否自动命名空间工具名称?

MCP 暴露服务器工具名称,而主机可以添加特定于应用程序的命名空间。在将调用路由回服务器时,保留原始名称。

问:文件系统根是否是完整的沙箱?

根不是一个完整的安全沙箱。目录强制、进程权限和主机暴露的工具也必须符合预期的范围。

问:这些工具可以在没有 AI 模型的情况下运行吗?

一个确定性程序可以在没有模型的情况下发现并调用 MCP 工具。只有在应用程序故意将推理或行动选择委托给它时,才需要模型。

问:页面内容可以授权文件写入吗?

检索到的页面内容不能授予行动权限。将其视为不可信的证据,并遵循用户的任务和应用程序政策进行任何写入。

在Scrapeless,我们仅访问公开可用的数据,并严格遵循适用的法律、法规和网站隐私政策。本博客中的内容仅供演示之用,不涉及任何非法或侵权活动。我们对使用本博客或第三方链接中的信息不做任何保证,并免除所有责任。在进行任何抓取活动之前,请咨询您的法律顾问,并审查目标网站的服务条款或获取必要的许可。

最受欢迎的文章

目录