1. 为什么要在本地跑一个股票行情 MCP ServerMCP Server 这个词最近出现频率很高但很多人第一次接触会有点懵它到底解决什么问题简单说MCPModel Context Protocol是一套让大语言模型调用外部工具的协议你可以把它理解成「给 AI 装插件的标准接口」。模型本身不知道今天的股价但通过 MCP Server 暴露一个get-quote工具模型就能在对话里直接查行情。这篇要做的是用 Node.js 从零写一个能获取实时股票价格的 MCP Server然后把它接到 TaoToken 的统一 Key/API 通道上让本地 AI 工具比如 Claude Code、Cursor 这类支持 MCP 的客户端真正调用一次行情数据。适合谁看会一点 JavaScript、想让 AI 助手能查股票、但不想折腾一堆鉴权和网络配置的人。我试过把行情查询塞进普通脚本里问题是每次都要手动跑换成 MCP Server 之后模型自己决定什么时候调、调哪只股票体验完全不一样。下面从环境准备开始一步步跑通。2. TaoToken 前置准备统一 Key 与接入地址在写代码之前先把「通道」准备好。TaoToken 的作用是提供一个统一的 API 入口和 Key你不需要为每个模型或工具单独配一套鉴权。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 基址是 https://taotoken.net/api 这个不加 UTM。你需要做两件事第一拿到 API Key。登录后进控制台在 API Keys 页面创建一个新 Key复制保存。这个 Key 后面会写进 MCP 客户端的配置里用来让模型侧请求走 TaoToken 通道。第二确认你要用的模型对话入口。如果你只是想验证 MCP Server 能不能被调用用模型对话页面就够了如果你打算长期在编码工具里用建议看 Coding Plan它更适合 Agent 场景。注意Key 只创建一次就够不要把它硬编码进要提交到 Git 的源码里。用环境变量或客户端配置文件承载。这里有个容易踩的坑很多人以为 MCP Server 自己要去请求 TaoToken其实不是。MCP Server 只负责「查行情」这一件事它请求的是行情数据源TaoToken 的 Key 是配在 MCP 客户端也就是调用方那一侧的用来让模型能正常对话并触发工具调用。两者职责分开别混在一起。3. 可复制配置项目骨架与 MCP Server 代码先建项目。Node.js 版本建议 18 以上因为要用到内置的fetch。mkdir stock-mcp-server cd stock-mcp-server npm init -y npm install modelcontextprotocol/sdk zod然后在package.json里加上type: module因为下面用的是 ESM 语法。接着创建server.js核心逻辑分三块请求行情、解析数据、注册工具。#!/usr/bin/env node import { McpServer } from modelcontextprotocol/sdk/server/mcp.js; import { StdioServerTransport } from modelcontextprotocol/sdk/server/stdio.js; import { z } from zod; const SINA_API_BASE https://hq.sinajs.cn/list; const server new McpServer({ name: stock, version: 1.0.0, capabilities: { resources: {}, tools: {} }, }); async function makeStockRequest(symbol) { const url ${SINA_API_BASE}${symbol}; const headers { Referer: https://finance.sina.com.cn }; try { const response await fetch(url, { headers }); if (!response.ok) throw new Error(HTTP error! status: ${response.status}); const buffer await response.arrayBuffer(); const decoder new TextDecoder(gb2312); const text decoder.decode(buffer); return parseSinaStockData(text, symbol); } catch (error) { console.error(Error making stock request:, error); return null; } } function parseSinaStockData(text, symbol) { const matches text.match(/(.*)/); if (!matches || !matches[1]) return null; const values matches[1].split(,); if (values.length 32) return null; return { symbol, name: values[0], open: values[1], close: values[2], price: values[3], high: values[4], low: values[5], volume: values[8], amount: values[9], date: values[30], time: values[31], }; } function formatQuote(quote) { return [ Stock Code: ${quote.symbol}, Stock Name: ${quote.name}, Current Price: ¥${quote.price}, Change Rate: ${(((Number(quote.price) - Number(quote.close)) / Number(quote.close)) * 100).toFixed(2)}%, Open Price: ¥${quote.open}, High Price: ¥${quote.high}, Low Price: ¥${quote.low}, Volume: ${(Number(quote.volume) / 100).toFixed(0)} lots, Turnover: ¥${(Number(quote.amount) / 10000).toFixed(2)} million, Update Time: ${quote.date} ${quote.time}, ].join(\n); } server.tool( get-quote, Get real-time stock quote, { symbol: z.string().describe(Stock symbol (e.g.: sh600000, sz000001)) }, async ({ symbol }) { const quoteData await makeStockRequest(symbol); if (!quoteData) { return { content: [{ type: text, text: Failed to retrieve stock data for ${symbol} }] }; } return { content: [{ type: text, text: formatQuote(quoteData) }] }; } ); async function main() { const transport new StdioServerTransport(); await server.connect(transport); console.error(Stock MCP Server running on stdio); } main().catch((error) { console.error(Fatal error in main():, error); process.exit(1); });几个关键点解释一下。StdioServerTransport表示这个 Server 通过标准输入输出和客户端通信这是本地 MCP 最常见的模式。server.tool注册了一个名为get-quote的工具参数用 zod 定义模型看到描述后就知道该传什么。行情源返回的是 GB2312 编码所以要用TextDecoder(gb2312)解码直接当 UTF-8 读会乱码——这是实测下来最容易忽略的一步。4. 接入配置config.toml 与 settings.json 骨架代码写完了接下来是让客户端认识它。不同客户端配置格式不一样这里给两个常见骨架。Claude Code 用的是config.toml在项目或用户目录下[mcp_servers.stock] command node args [/absolute/path/to/stock-mcp-server/server.js]Cursor 这类用settings.json{ mcpServers: { stock: { command: node, args: [/absolute/path/to/stock-mcp-server/server.js] } } }路径一定要写绝对路径相对路径在客户端启动时工作目录不确定会找不到文件。如果你希望模型侧走 TaoToken 通道把 API Key 配在客户端的模型设置里而不是这个 MCP 配置块里。两者是并列关系一个管「模型怎么连」一个管「工具怎么跑」。启动命令很简单node /absolute/path/to/stock-mcp-server/server.js正常的话终端不会有输出因为 stdio 被占用了只有出错才会打印到 stderr。看到Stock MCP Server running on stdio说明启动成功。5. 验证请求跑通一次真实行情查询配置好之后重启客户端在对话里直接问「帮我查一下 sh600000 的实时价格」。模型应该会触发get-quote工具返回类似这样的结果Stock Code: sh600000 Stock Name: 浦发银行 Current Price: ¥10.25 Change Rate: 0.59% Open Price: ¥10.20 High Price: ¥10.31 Low Price: ¥10.18 Volume: 123456 lots Turnover: ¥12345.67 million Update Time: 2025-01-15 14:30:00如果模型没有调用工具先确认客户端是否识别到了 MCP Server一般在设置里能看到已连接的工具列表。如果工具被调用了但返回Failed to retrieve stock data多半是 symbol 格式不对——A 股要带sh或sz前缀比如sh600000、sz000001。想单独测试 Server 本身可以用 MCP Inspectornpx modelcontextprotocol/inspector node /absolute/path/to/stock-mcp-server/server.js它会打开一个网页界面你可以手动调用get-quote并传参看到原始返回。这一步能把「Server 问题」和「客户端配置问题」分开排障效率高很多。6. 本篇常见错排查报错Cannot find module modelcontextprotocol/sdk没装依赖或者客户端启动时工作目录不对。回到项目目录跑npm install配置里用绝对路径。行情返回乱码忘了用TextDecoder(gb2312)。行情源是 GB2312 编码用默认 UTF-8 解码中文名会变成问号。HTTP error! status: 403请求头缺Referer。行情接口对来源有校验加上Referer: https://finance.sina.com.cn就好。模型不调用工具检查客户端是否加载了 MCP 配置以及工具描述是否清晰。描述写「Get real-time stock quote」比写「stock」更容易被模型正确触发。Key 相关报错如果你在客户端里配了 TaoToken 的 Key 但对话报鉴权失败去控制台确认 Key 是否有效、是否复制完整。接入文档里有各客户端的详细配置说明对照检查一遍通常能定位。排障时优先看 API Keys 和接入文档这两处大部分问题都在配置层。验证模型是否正常响应可以用模型对话页面单独测如果你是要长期在编码工具里跑 AgentCoding Plan 的额度模型更适合持续调用。把上面这套跑通之后你其实已经掌握了 MCP Server 的通用套路注册工具、处理请求、返回结构化文本。换成天气、汇率、数据库查询结构几乎一样改的是makeStockRequest里的数据源和解析逻辑。真正花时间的往往不是代码而是编码、请求头、路径这些细节——踩过一次就记住了。
企业数字化 ERP 产品动态
相关推荐
3个实战案例揭秘:网站建设的工期拖延如何解决与SEO破局 3个实战案例揭秘:网站建设的工期拖延如何解决与SEO破局 网站做好了没人访问,这是90%新手站长上线第一周就遇到的噩梦。我见过太多老板砸钱建站,结果首页打开速度超过5秒,百度收录半个月还是零,最后只能含泪重做。别急着骂SEO无用,很多时候问… · 2026/9/27 13:42:57
js获取网站html完整流程避坑指南 js获取网站html完整流程避坑指南 网站做好了没人访问,这大概是很多站长和技术负责人最头疼的事。你熬了几个通宵,把页面调得跟艺术品似的,结果上线一周,后台流量还是个位数。这时候你才意识到,光有好看的皮囊不够,还得让搜索引擎能读懂你的代码,… · 2026/9/27 13:42:57
Laravel Lang 中库尔德语(ckb)翻译完成度报告:15 个缺失键位全解析与补全指南 后端 【免费下载链接】lang List of 128 languages for Laravel Framework, Laravel Jetstream, Laravel Fortify, Laravel Breeze, Laravel Cashier, Laravel Nova and Laravel UI. 项目地址: https://gitcode.com/gh_mirrors/la/lang 点击查看 免费下载 本指南以… · 2026/9/27 23:49:50
3个坑让你省5万:内蒙古高等级公路建设开发有限责任公司网站对比评测 3个坑让你省5万:内蒙古高等级公路建设开发有限责任公司网站对比评测 找建站公司最怕什么?不是功能做不全,而是报价单上那些看不懂的术语,最后结账时才发现多花了几万块冤枉钱。很多老板拿着需求去问价,销售嘴里蹦出“微服务架构”、“全栈云原生”,转… · 2026/9/27 23:49:50
UG数控编程从入门到精通:工艺思维与实战避坑指南 1. 为什么UG数控编程值得你花时间啃下来干了十几年机加工,从手编宏程序到现在的CAM软件,我最大的感受就是:UG(现在官方叫Siemens NX)在数控编程这块,依然是国内模具、汽车、航空零件加工厂里最硬的那块敲门… · 2026/9/27 23:49:50
Java数字签名与证书生成实战:从keytool到Bouncy Castle全解析 简介:围绕Java数字签名与数字证书的源码示例,面向中高级Java开发者及安全编程初学者,演示如何在网络通信中利用非对称加密保障数据完整性与发送方身份验证。压缩包为RAR格式,体积仅17KB,便于快速下载与阅读;… · 2026/9/27 23:49:44
苹果序列号查询全解析:从底层逻辑到二手交易避坑实战 1. 苹果序列号查询的底层逻辑与核心价值很多人第一次接触“序列号查询”这个概念,是因为买了一台二手 iPhone 或者 Mac,想确认卖家说的“全新未激活”“国行正品”到底靠不靠谱。苹果的序列号就像设备的身份证号,它不只是一串随机字符&#x… · 2026/9/27 23:49:44
Python多模态情感分析:文本、语音、图像与视频融合实战 简介:基于Python实现的多模态融合情感分析项目,完整覆盖文本、语音、图像和视频四种输入模态,适用于课程设计、期末大作业及毕设场景。项目代码含详尽注释,新手也能看懂,经过严格调试可直接运行,能够支撑答… · 2026/9/27 23:49:38
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01