Java 让 AI 自己爬网页存数据,MCP 这个新玩意儿真好用:TaoToken 统一 Key 接入实战
发布时间:2026/10/1 6:51:46 作者:尧图编辑部 阅读量:1,286

1. 从“我写爬虫喂 AI”到“AI 自己爬自己存”的转变先说清楚这篇要解决什么问题在 Java Spring Boot 环境里用 MCPModel Context Protocol把“抓网页”和“写数据库”包装成 AI 能直接调用的工具让模型自己决定什么时候爬、爬哪个页面、把哪些字段落库。适合谁适合已经有一个 Spring Boot 后端、手头有 MyBatis-Plus 或 JPA、想让 AI 接管一部分数据采集流程的 Java 开发者。核心检索词就是 Java MCP 爬虫落库读完你能拿到一套可复制的配置和一次完整的验证动作。我之前的做法很笨写个定时任务Jsoup 抓页面正则清洗拼成一段 Prompt 丢给大模型做分析。整个链路里 AI 只负责最后“动嘴”前面 80% 的脏活全是我在干。问题不在于爬虫难写而在于每次换一个数据源我都要改代码、加解析规则、重新部署。AI 明明有能力判断“这个页面里哪个是价格、哪个是标题”却因为拿不到工具而只能干看着。MCP 改变的就是这一层。它定义了一套 Client 和 Server 之间的通信标准把“工具”抽象成带参数 Schema 的可调用单元。你的 Java 应用作为 MCP Client把工具列表发给大模型模型根据用户指令返回“我要调 web_fetch参数是 urlxxx”Client 执行完把结果回传模型再决定下一步是继续爬还是调 save_product 落库。整个过程模型是决策者你的 Java 代码只是执行者。这里有个容易被忽略的点多工具共用一套 Key 的配置管理。当你同时接 MCP Server、Cline、Codex 这类工具时如果每个都单独配一套 Base URL 和 API Key改一次密钥要改五个地方迟早出错。所以这篇会把 TaoToken 统一 Key 通道的配置方式一起给出来让 MCP 服务、编码工具、对话工具共用同一个入口接入成本压到最低。下面按“环境准备 → 写工具 → 注册 MCP Server → 配置统一 Key → 验证抓取落库 → 排错”的顺序走代码都能直接抄。2. TaoToken 统一 Key 与 MCP 接入前置准备在写业务代码之前先把“模型从哪来”这件事定下来。MCP 本身只负责工具调用协议真正做决策的大模型需要一个兼容 OpenAI 或 Anthropic 接口的通道。TaoToken 在这里扮演的角色就是统一入口一个 Base URL、一个 API Key同时给 MCP Client、Cline、Codex、Claude Code 这些工具用。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 通道地址是 https://taotoken.net/api 注意 API 地址后面不加任何查询参数。你需要在控制台里创建一个 Key控制台入口在 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite Key 列表页在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。创建完先复制出来后面配置里要用。模型 ID 这块做 MCP 工具决策建议用带 Function Calling 能力的模型比如 claude-sonnet 系列或 gpt-4o 系列。具体可用列表以控制台为准不要凭记忆写。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 遇到参数不确定就去翻。Java 侧依赖先补齐。MCP Server 用官方 SDK爬虫用 Jsoup数据库用 MyBatis-Plus再加一个 HTTP 客户端用于调模型接口dependency groupIdio.modelcontextprotocol/groupId artifactIdmcp-server/artifactId version0.4.0/version /dependency dependency groupIdorg.jsoup/groupId artifactIdjsoup/artifactId version1.18.1/version /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.7/version /dependency dependency groupIdcom.squareup.okhttp3/groupId artifactIdokhttp/artifactId version4.12.0/version /dependency数据库表结构很简单一张 product_data 表字段包括 id、product_name、price、source_url、create_time。建表语句CREATE TABLE product_data ( id BIGINT AUTO_INCREMENT PRIMARY KEY, product_name VARCHAR(255) NOT NULL, price VARCHAR(64), source_url VARCHAR(512), create_time DATETIME DEFAULT CURRENT_TIMESTAMP );对应的实体类和 Mapper 用 MyBatis-Plus 生成即可这里不展开。重点在于工具方法里注入 MapperMCP Server 启动时把这些方法注册成工具。前置准备做到这一步就够了接下来进入可复制配置环节。3. 可复制配置MCP Server 注册工具与统一 Key 写入这一节是全文最核心的部分所有配置片段都能直接复制。先写工具类把爬取、落库、查询三个能力封装好import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.springframework.stereotype.Component; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import javax.annotation.Resource; import java.time.LocalDateTime; import java.util.List; import java.util.stream.Collectors; Component public class WebTools { Resource private ProductDataMapper productDataMapper; public String fetchWebPage(String url) { try { Document doc Jsoup.connect(url) .userAgent(Mozilla/5.0 (compatible; DataCollector/1.0)) .timeout(10000) .get(); return doc.body().text(); } catch (Exception e) { return 爬取失败: e.getMessage(); } } public String saveProductData(String productName, String price, String sourceUrl) { ProductData data new ProductData(); data.setProductName(productName); data.setPrice(price); data.setSourceUrl(sourceUrl); data.setCreateTime(LocalDateTime.now()); productDataMapper.insert(data); return 已保存 productName 价格 price; } public String queryProducts(String keyword) { ListProductData list productDataMapper.selectList( new QueryWrapperProductData().like(product_name, keyword)); if (list.isEmpty()) return 没找到相关产品; return list.stream() .map(p - p.getProductName() : p.getPrice()) .collect(Collectors.joining(\n)); } }然后是 MCP Server 启动类把三个方法注册成工具每个工具都要定义 inputSchema模型才知道参数怎么填import io.modelcontextprotocol.server.*; import io.modelcontextprotocol.server.transport.StdioServerTransport; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; Component public class McpServerStarter { Autowired private WebTools webTools; PostConstruct public void start() { McpServer server McpServer.create(); server.addTool(McpTool.newBuilder() .name(web_fetch) .description(爬取指定URL的网页文本内容返回纯文本) .inputSchema(JsonSchema.builder() .addProperty(url, JsonType.STRING, 要爬取的网页地址) .required(url).build()) .handler(params - { String url params.get(url).getAsString(); return ToolCallResult.success(new TextContent(webTools.fetchWebPage(url))); }).build()); server.addTool(McpTool.newBuilder() .name(save_product) .description(将产品信息保存到数据库) .inputSchema(JsonSchema.builder() .addProperty(productName, JsonType.STRING, 产品名称) .addProperty(price, JsonType.STRING, 价格) .addProperty(sourceUrl, JsonType.STRING, 来源URL) .required(productName, price, sourceUrl).build()) .handler(params - { String r webTools.saveProductData( params.get(productName).getAsString(), params.get(price).getAsString(), params.get(sourceUrl).getAsString()); return ToolCallResult.success(new TextContent(r)); }).build()); server.addTool(McpTool.newBuilder() .name(query_products) .description(按关键字查询已保存的产品数据) .inputSchema(JsonSchema.builder() .addProperty(keyword, JsonType.STRING, 产品名称关键字) .required(keyword).build()) .handler(params - { String r webTools.queryProducts(params.get(keyword).getAsString()); return ToolCallResult.success(new TextContent(r)); }).build()); server.start(new StdioServerTransport()); } }接下来是统一 Key 的配置。MCP Client 调模型时需要一个 OpenAI 兼容的配置写成 JSON 放在项目 resources 目录下命名 model-config.json{ baseUrl: https://taotoken.net/api, apiKey: sk-你的TaoToken密钥, model: claude-sonnet-4-20250514, timeout: 60000 }如果你同时用 Cline 或 Codex它们的配置也指向同一个 Base URL 和 Key。Codex 的 auth.json 放在 ~/.codex/auth.json{ OPENAI_API_KEY: sk-你的TaoToken密钥, OPENAI_BASE_URL: https://taotoken.net/api }Cline 的 MCP 配置在 settings.json 里关键是三件套齐全Base URL、Key、Model ID。缺任何一个都会在调用时报 401 或 model not found。Claude Code 的接入同理Base URL 填 https://taotoken.net/api Key 用同一个模型 ID 按控制台列表填。这样 MCP Server、编码工具、对话工具共用一套凭证改 Key 只改一处。4. 验证请求一次抓取任务从触发到入库配置写完跑一次完整链路验证。启动 Spring Boot 应用MCP Server 会通过 STDIO 挂起等待 Client 连接。Java 侧写一个简单的 Client 测试类import io.modelcontextprotocol.client.McpClient; import io.modelcontextprotocol.client.transport.StdioClientTransport; import java.util.Map; public class AiClient { public static void main(String[] args) { McpClient client McpClient.withTransport( new StdioClientTransport(java -jar your-mcp-server.jar) ).build(); client.listTools().forEach(t - System.out.println(t.getName() : t.getDescription())); String pageContent client.callTool(web_fetch, Map.of(url, https://example.com/product/123)); System.out.println(抓取结果前200字: pageContent.substring(0, 200)); String saveResult client.callTool(save_product, Map.of( productName, 示例产品A, price, 199.00, sourceUrl, https://example.com/product/123 )); System.out.println(saveResult); String queryResult client.callTool(query_products, Map.of(keyword, 示例产品)); System.out.println(查询结果: queryResult); } }运行后你应该看到三段输出工具列表包含 web_fetch、save_product、query_products抓取结果返回页面正文文本保存返回“已保存示例产品A 价格199.00”查询返回“示例产品A : 199.00”。去数据库 select 一下create_time 字段有值说明落库成功。真正让 AI 自主决策的版本是把工具列表转成 Function Calling 定义发给模型。用户说“去 example.com/product/123 把价格爬下来存库”模型返回 tool_calls 数组里面是 web_fetch 和 save_product 的调用参数。你的 Client 依次执行把结果回传模型最后回复“已完成价格 199.00 已入库”。这一步的 HTTP 请求用 OkHttp 发到 https://taotoken.net/api/v1/chat/completions Header 里带 Authorization: Bearer sk-xxxbody 里 tools 字段填 MCP 工具转出来的 JSON Schema。验证成功的标志有三个数据库多了一行记录日志里能看到模型返回的 tool_calls再次 query_products 能查到刚存的数据。如果只做到前两步但数据库没数据大概率是 save_product 的 handler 里事务没提交或者 Mapper 注入失败。5. 本篇常见错误排查401、local proxy failed 与 reading choices排错这块我踩过的坑比较集中按报错信息对照着查最快。401 Unauthorized九成是 Key 没配对。检查 model-config.json 里的 apiKey 是否以 sk- 开头Base URL 是否是 https://taotoken.net/api 且没有多余斜杠。如果你在 Codex 的 auth.json 里写了 OPENAI_BASE_URL 但 Key 还是旧的也会 401。统一 Key 的意义就在这里改一处所有工具生效。另外注意 Key 有没有过期或被删除去控制台确认。local proxy failed / connection refused这个报错通常出现在 MCP Client 用 STDIO 启动 Server 时。原因是启动命令路径不对或者 jar 包没打全。检查 StdioClientTransport 里的命令是不是java -jar加绝对路径。如果 Server 启动时抛了异常直接退出Client 就会报连接失败。先把 Server 单独跑一遍确认能正常挂起再让 Client 连。reading choices 报错 / choices 字段为空这是模型返回体解析失败。常见原因是模型 ID 写错了或者请求体里 tools 字段格式不符合 OpenAI 规范。检查 model 字段是否和控制台列表一致tools 里每个 function 的 parameters 必须是合法的 JSON Schema。如果返回体里没有 choices先打印原始响应看看是不是返回了 error 对象。OAuth 相关报错如果你用的是 Claude Code 或某些需要 OAuth 的工具报 OAuth token invalid 时说明它没走 API Key 而是走了 OAuth 流程。这时候要在工具配置里显式指定用 API Key 模式Base URL 填 https://taotoken.net/api 不要让它去读本地的 OAuth 缓存。工具被调用但参数为空模型没按 Schema 填参数。在 Prompt 里加一句“调用工具时必须填写所有 required 字段”或者在工具 description 里把参数说明写得更明确。实测下来description 写得越具体模型填参准确率越高。数据库写入成功但查询不到检查 MyBatis-Plus 的驼峰映射是否开启product_name 字段和实体类属性名是否对应。如果用了 TableField 注解但值写错插入会静默失败。6. 语义一致 CTA把统一 Key 用在你的 MCP 工作流里走到这里你已经有一套能跑的 Java MCP 爬虫落库链路了。接下来最省事的做法是把统一 Key 铺到所有工具上避免每个工具单独配一套凭证。需要创建或管理 Key 就去 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 接入参数不确定就翻 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。如果你主要用 MCP 做工具调用和模型对话验证模型对话入口在 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 可以先把工具 Schema 贴进去试一轮确认模型能正确选工具再写进 Java 代码。如果你打算长期跑编码 Agent 或让 MCP 接管更多自动化任务Coding Plan 在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 按用量规划比临时充更稳。Claude Code 接入的完整配置在 https://taotoken.net/claude-code?utm_sourcetaotoken_aicg_blog_endutm_contentclaude-codeutm_campaignrewrite Anthropic 兼容通道说明在 https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaude-code-anthropicutm_campaignrewrite 。控制台总入口 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 可以看用量和余额。最后给一个实用技巧把 MCP Server 的启动命令写成一个 shell 脚本里面 export 好 TAOTOKEN_API_KEY 环境变量Java 代码里用 System.getenv 读取这样 Key 不会硬编码进 jar 包。脚本内容大概是这样#!/bin/bash export TAOTOKEN_API_KEYsk-你的密钥 export TAOTOKEN_BASE_URLhttps://taotoken.net/api java -jar your-mcp-server.jarClient 的 StdioClientTransport 里改成调用这个脚本Key 就统一从环境变量走。换 Key 只改脚本一处MCP Server、Cline、Codex 全部生效。这套跑通之后你只需要对 AI 说“去把某页面价格爬下来存库”剩下的它自己完成。