当前位置: 首页 > article >正文

MCP 工具开发入门:给 Claude 装上自定义技能

上周有个需求让 Claude 能直接查我们内部的工单系统。以前的做法是把工单内容复制粘贴给 Claude效率很低。研究了一下 MCP发现这个问题用 MCP 解决特别优雅写一个 server 就搞定了。这篇从头讲怎么写一个 MCP server然后接进 Claude Desktop。MCP 是什么MCPModel Context Protocol是 Anthropic 搞的一个开放协议让大模型能够调用外部工具和访问外部数据。简单说就是你写一个 MCP server声明好有哪些工具Claude 就能在对话中调用这些工具。跟 OpenAI 的 function calling 思路类似但 MCP 是协议层面的标准不绑定特定的模型而且 server 和 client 是独立进程通过标准 I/O 通信。开发环境pipinstallmcp anthropicMCP SDK 会帮你处理协议细节你只需要关心业务逻辑。写一个最简单的 MCP server从一个查天气的例子开始#!/usr/bin/env python3 简单的天气查询 MCP server importasyncioimportjsonfrommcp.serverimportServerfrommcp.server.modelsimportInitializationOptionsfrommcp.server.stdioimportstdio_serverfrommcpimporttypesimporthttpx# 创建 server 实例appServer(weather-server)app.list_tools()asyncdefhandle_list_tools()-list[types.Tool]: 声明这个 server 提供哪些工具 Claude 会读取这个列表知道有哪些工具可以调用 return[types.Tool(nameget_weather,description获取指定城市的天气信息,inputSchema{type:object,properties:{city:{type:string,description:城市名称例如北京、上海}},required:[city]})]app.call_tool()asyncdefhandle_call_tool(name:str,arguments:dict)-list[types.TextContent]: 工具调用的实际执行逻辑 ifnameget_weather:cityarguments.get(city,)# 这里调用真实的天气 API演示用随便写的# 实际替换成你用的天气服务asyncwithhttpx.AsyncClient()asclient:try:# 用 wttr.in 这个免费天气服务responseawaitclient.get(fhttps://wttr.in/{city}?formatj1,timeout10.0)dataresponse.json()currentdata[current_condition][0]temp_ccurrent[temp_C]weather_desccurrent[weatherDesc][0][value]humiditycurrent[humidity]resultf{city}天气{weather_desc}温度{temp_c}°C湿度{humidity}%exceptExceptionase:resultf获取天气失败{str(e)}return[types.TextContent(typetext,textresult)]raiseValueError(f未知工具{name})asyncdefmain():asyncwithstdio_server()as(read_stream,write_stream):awaitapp.run(read_stream,write_stream,InitializationOptions(server_nameweather-server,server_version1.0.0,capabilitiesapp.get_capabilities(notification_optionsNone,experimental_capabilities{})))if__name____main__:asyncio.run(main())更实用的例子查工单系统来个有实际价值的——查公司内部工单系统#!/usr/bin/env python3 工单系统 MCP server importasyncioimportjsonfromdatetimeimportdatetimefrommcp.serverimportServerfrommcp.server.modelsimportInitializationOptionsfrommcp.server.stdioimportstdio_serverfrommcpimporttypes appServer(ticket-server)# 模拟工单数据库实际替换成真实 API 调用MOCK_TICKETS{TICKET-001:{id:TICKET-001,title:登录页面 500 错误,status:处理中,priority:高,assignee:张三,created_at:2026-03-10 09:00,description:用户反馈登录时偶发 500 错误发生频率约 2%},TICKET-002:{id:TICKET-002,title:导出功能优化,status:待处理,priority:中,assignee:李四,created_at:2026-03-11 14:00,description:大数据量导出时速度很慢超过 10 万条会超时}}app.list_tools()asyncdefhandle_list_tools()-list[types.Tool]:return[types.Tool(nameget_ticket,description根据工单 ID 查询工单详情,inputSchema{type:object,properties:{ticket_id:{type:string,description:工单 ID格式如 TICKET-001}},required:[ticket_id]}),types.Tool(namelist_tickets,description列出工单支持按状态和优先级过滤,inputSchema{type:object,properties:{status:{type:string,description:工单状态待处理、处理中、已完成,enum:[待处理,处理中,已完成]},priority:{type:string,description:优先级高、中、低,enum:[高,中,低]}}}),types.Tool(nameupdate_ticket_status,description更新工单状态,inputSchema{type:object,properties:{ticket_id:{type:string,description:工单 ID},new_status:{type:string,description:新状态,enum:[待处理,处理中,已完成]}},required:[ticket_id,new_status]})]app.call_tool()asyncdefhandle_call_tool(name:str,arguments:dict)-list[types.TextContent]:ifnameget_ticket:ticket_idarguments[ticket_id]ticketMOCK_TICKETS.get(ticket_id)ifnotticket:return[types.TextContent(typetext,textf工单{ticket_id}不存在)]resultjson.dumps(ticket,ensure_asciiFalse,indent2)return[types.TextContent(typetext,textresult)]elifnamelist_tickets:status_filterarguments.get(status)priority_filterarguments.get(priority)ticketslist(MOCK_TICKETS.values())ifstatus_filter:tickets[tfortinticketsift[status]status_filter]ifpriority_filter:tickets[tfortinticketsift[priority]priority_filter]ifnottickets:return[types.TextContent(typetext,text没有找到符合条件的工单)]summary[]fortintickets:summary.append(f[{t[id]}]{t[title]}-{t[status]}({t[priority]}优先级) - 负责人{t[assignee]})return[types.TextContent(typetext,text\n.join(summary))]elifnameupdate_ticket_status:ticket_idarguments[ticket_id]new_statusarguments[new_status]ifticket_idnotinMOCK_TICKETS:return[types.TextContent(typetext,textf工单{ticket_id}不存在)]old_statusMOCK_TICKETS[ticket_id][status]MOCK_TICKETS[ticket_id][status]new_statusreturn[types.TextContent(typetext,textf工单{ticket_id}状态已更新{old_status}→{new_status})]raiseValueError(f未知工具{name})asyncdefmain():asyncwithstdio_server()as(read_stream,write_stream):awaitapp.run(read_stream,write_stream,InitializationOptions(server_nameticket-server,server_version1.0.0,capabilitiesapp.get_capabilities(notification_optionsNone,experimental_capabilities{})))if__name____main__:asyncio.run(main())接入 Claude Desktop把 server 写好之后需要在 Claude Desktop 的配置文件里注册。macOS 的配置文件位置~/Library/Application Support/Claude/claude_desktop_config.json{mcpServers:{ticket-server:{command:python,args:[/path/to/your/ticket_server.py],env:{TICKET_API_KEY:your_api_key_here}}}}重启 Claude Desktop在对话界面右下角会出现工具图标点开可以看到已注册的工具列表。然后直接跟 Claude 说「帮我查一下 TICKET-001 的状态」它就会自动调用对应工具。接入 CursorCursor 也支持 MCP配置方式类似。在.cursor/mcp.json里{mcpServers:{ticket-server:{command:python,args:[/path/to/ticket_server.py]}}}在 server 里调用大模型 API如果你的 MCP 工具本身也需要调用大模型比如做一些 AI 处理直接用 OpenAI 兼容的 SDK 就行fromopenaiimportAsyncOpenAI ai_clientAsyncOpenAI(api_keyos.environ.get(API_KEY),base_urlhttps://api.ofox.ai/v1)# 在工具实现里调用asyncdefsummarize_ticket(ticket_content:str)-str:responseawaitai_client.chat.completions.create(modelgpt-4o-mini,messages[{role:user,content:f用一句话总结这个工单的核心问题\n{ticket_content}}])returnresponse.choices[0].message.content坑点记录坑一server 启动失败不报错。Claude Desktop 加载 server 失败时不会弹提示你就是看不到工具列表。排查方法手动在命令行运行 python server.py看有没有报错通常是依赖没装或者路径写错了。坑二工具描述要写清楚。Claude 是靠读 description 来判断什么时候调用哪个工具的。如果描述写得含糊它可能压根不会想到调用或者调错工具。描述越精确调用越准确。坑三参数类型要匹配。inputSchema 里定义的类型和 Claude 实际传进来的类型可能不一致做好 type conversion。坑四异步 vs 同步。MCP SDK 是异步的如果你的工具里有同步 I/O 操作比如读文件包一层asyncio.to_thread避免阻塞。MCP 的生态现在还在快速发展社区里已经有很多现成的 server 可以直接用比如文件系统、GitHub、数据库等。自己写 server 主要是对接自家内部系统的时候用得上。

相关文章:

MCP 工具开发入门:给 Claude 装上自定义技能

上周有个需求:让 Claude 能直接查我们内部的工单系统。以前的做法是把工单内容复制粘贴给 Claude,效率很低。研究了一下 MCP,发现这个问题用 MCP 解决特别优雅,写一个 server 就搞定了。 这篇从头讲怎么写一个 MCP server&#xf…...

python中类与对象的小理解

定义 class Car:(这其中Car就是类哦) pass(暂时跨过)c1Car()(其中Car()是创建对象,这是对象就已经存在了,那我们可能会有疑问,为什么要专门有一个变量去存已经存在的对象呢?原来创建对象后我们还要一个贴在对象上的标签,一个写着对象地址的标签<有点像指针>)c1.color&q…...

真正的管理者,从不陷于具体事务

真正的管理者&#xff0c;从不陷于具体事务在管理实践中&#xff0c;存在一种普遍的误解&#xff1a;优秀的管理者必须巨细靡遗、亲力亲为&#xff0c;深入到每一项具体事务中&#xff0c;才能体现其负责与能干。然而&#xff0c;真正的管理智慧&#xff0c;绝非埋首于琐碎&…...

非常详细:AI大模型课程|非计算机专业转行人工智能,好就业吗?

很多就业者在看到人工智能领域发展的很好&#xff0c;意识觉醒的人想进入这个行业里面得到一些新兴行业的红利&#xff0c;想转行却担心自己的经历或者是专业被卡&#xff0c;犹豫不决&#xff0c;今天就来和大家聊一聊这个话题&#xff0c;看看能不能解除你的疑惑。 01写在前…...

C#上位机+YOLO+PLC对接:Modbus TCP实现产线全自动视觉检测,无人值守

摘要: 在工业4.0浪潮下,孤立的AI算法无法产生价值。真正的“无人值守”产线,需要视觉大脑(YOLO)、**控制中枢(C#上位机)与执行手脚(PLC)**的无缝协同。 很多开发者卡在最后一步:模型训练好了,C#界面写好了,但怎么让PLC知道结果?怎么保证信号不丢失?怎么处理通信超…...

全球 AI 大模型本质唯一与形式本质统一标准|Global Standard on Essence Uniqueness Form‑Essence Unity in Large AI Models

鸽姆智库发布全球首个AI大模型“本质唯一与形式本质统一”强制标准&#xff0c;终结表象欺诈摘要&#xff1a; 鸽姆智库于2026年3月发布全球首个关于AI大模型本质唯一性与形式本质统一的强制性标准。该标准旨在根治AI模型“形式高度发达、本质极其低劣”的表象欺诈&#xff0c;…...

衡山派开发板镜像烧录实战:使用AiBurn工具从编译到上电的完整指南

衡山派开发板镜像烧录实战&#xff1a;使用AiBurn工具从编译到上电的完整指南 最近有不少刚拿到衡山派&#xff08;HSPI&#xff09;开发板的朋友问我&#xff0c;编译好的系统镜像该怎么烧录到板子里&#xff1f;是像STM32那样用J-Link吗&#xff1f;其实衡山派有自己的一套方…...

全球 AI 大模型架构主权与因果涌现标准 |Global Standard for Architecture Causal Emergence in Large AI Models

鸽姆智库全球 AI 大模型架构主权与因果涌现标准&#xff08;正式法律文本格式&#xff09;GG3M Think Tank Global Standard on Architectural Sovereignty and Causal Emergence for Large AI Models (Formal Legal Text)表格基础信息项内容详情标准编号 / Standard No.GG3M-A…...

2025年中国脑机接口技术商业化路径与市场机遇

1. 从科幻到现实&#xff1a;脑机接口的商业化拐点已至 还记得那些科幻电影里&#xff0c;人们用意念操控机械臂、在虚拟世界里自由驰骋的场景吗&#xff1f;十年前&#xff0c;这还只是天马行空的想象。但今天&#xff0c;我可以很肯定地告诉你&#xff0c;这项名为“脑机接口…...

深入解析nslookup命令:从基础查询到高级DNS记录类型

1. 从零认识nslookup&#xff1a;你的网络“电话本”查询员 如果你刚接触网络管理或者运维&#xff0c;可能会觉得nslookup这个命令有点神秘。其实&#xff0c;把它想象成一个超级高效的“电话本查询员”就很好理解了。我们每天上网&#xff0c;输入像 www.baidu.com 这样的网…...

Linux OOM Killer实战解析:从日志分析到问题定位

1. 当你的Linux服务器突然“发疯”&#xff1a;OOM Killer登场 不知道你有没有遇到过这种情况&#xff1a;服务器上跑得好好的一个服务&#xff0c;突然就没了&#xff0c;查日志发现进程被系统“杀”了&#xff0c;留下一脸懵的你。或者&#xff0c;你的嵌入式设备在长时间运行…...

Hyper-V虚拟化环境下的多网口软路由单臂路由实战:VLAN配置与剩余端口上网全解析

1. 为什么要在Hyper-V里折腾多网口软路由单臂路由&#xff1f; 大家好&#xff0c;我是老张&#xff0c;一个在虚拟化和网络这块摸爬滚打了十来年的老玩家。今天想和大家聊聊一个挺有意思&#xff0c;也很有实用价值的场景&#xff1a;在Hyper-V里&#xff0c;用一台多网口的软…...

利用Windows特性(::$DATA)绕过文件上传检测的实战解析

1. 文件上传检测&#xff1a;一场猫鼠游戏 做安全测试的朋友们&#xff0c;尤其是搞Web渗透的&#xff0c;肯定对文件上传这个点又爱又恨。爱的是&#xff0c;一旦找到一个上传漏洞&#xff0c;往往就是拿到服务器权限的“高速公路”&#xff1b;恨的是&#xff0c;现在的防护…...

SeaweedFS与MinIO深度对比:架构差异与场景化选型指南

1. 从“存文件”到“管数据”&#xff1a;为什么选型这么难&#xff1f; 做技术选型&#xff0c;特别是存储这块&#xff0c;经常让人头疼。我见过不少团队&#xff0c;一开始图省事&#xff0c;随便选了一个“名气大”的方案&#xff0c;结果项目上线没多久&#xff0c;就遇到…...

临床队列分析总出错?(R tidyverse医学清洗模板大揭秘)——附FDA合规性验证脚本

第一章&#xff1a;临床队列分析出错的根源诊断与FDA合规性认知鸿沟临床队列分析在真实世界证据&#xff08;RWE&#xff09;生成中承担关键角色&#xff0c;但其结果偏差常源于底层数据治理缺陷与监管逻辑断层。当统计模型输出显著p值却无法通过FDA审评时&#xff0c;问题往往…...

从越狱到免越狱:利用TrollStore实现iPA包的提取与安装

1. 从“折腾”到“优雅”&#xff1a;iOS应用自由之路的变迁 几年前&#xff0c;如果你想在iPhone上安装一个没有上架App Store的应用&#xff0c;或者想把自己手机上已经安装的某个应用完整地“抠”出来备份&#xff0c;那几乎只有一条路可走&#xff1a;越狱。我记得那时候&a…...

基于IPv6与DDNS的远程办公解决方案:从路由器配置到Windows桌面控制

1. 为什么你需要IPv6DDNS&#xff1a;告别内网穿透的折腾 如果你和我一样&#xff0c;是个需要随时随地能连回家中电脑的上班族、开发者&#xff0c;或者只是想在外轻松管理家里网络设备的人&#xff0c;那你肯定没少为“远程访问”这件事头疼过。早几年&#xff0c;我们可能得…...

SecGPT-14B多场景落地:安全意识培训中生成钓鱼邮件识别互动测验题

SecGPT-14B多场景落地&#xff1a;安全意识培训中生成钓鱼邮件识别互动测验题 1. 引言&#xff1a;当安全意识培训遇上AI助手 想象一下这个场景&#xff1a;作为企业的安全负责人&#xff0c;你正在筹备新一轮的员工安全意识培训。传统的培训方式&#xff0c;比如播放PPT、发…...

影墨·今颜小红书模型生成作品集展示:覆盖美妆、旅行、美食多垂类

影墨今颜小红书模型生成作品集展示&#xff1a;覆盖美妆、旅行、美食多垂类 最近在内容创作圈子里&#xff0c;影墨今颜这个专门针对小红书平台的AI文案模型&#xff0c;讨论热度一直挺高。很多人好奇&#xff0c;一个专门训练的模型&#xff0c;生成的内容到底和通用模型有多…...

探索DeepSeek在双色球历史数据分析中的娱乐性应用

1. 先泼一盆冷水&#xff1a;AI预测彩票&#xff1f;这事儿不靠谱 我知道&#xff0c;点开这篇文章的你&#xff0c;心里可能揣着一个“一夜暴富”的小火苗。毕竟&#xff0c;谁没幻想过用高科技手段破解财富密码呢&#xff1f;我干了这么多年AI&#xff0c;也见过不少朋友拿着…...

Flutter环境搭建避坑指南:从Android Studio到VS Code的完整配置流程

Flutter 环境配置实战&#xff1a;跨越 Android Studio 与 VS Code 的深度配置与效能调优 对于许多希望踏入跨平台开发领域的开发者而言&#xff0c;Flutter 以其高效的渲染引擎和一致的开发体验&#xff0c;成为了一个极具吸引力的选择。然而&#xff0c;从零开始搭建一个顺畅…...

从零开始:西门子200SMART安全编程全攻略(含手动/自动切换逻辑详解)

从零开始&#xff1a;西门子200SMART安全编程全攻略&#xff08;含手动/自动切换逻辑详解&#xff09; 在工业自动化项目的现场&#xff0c;最让工程师心跳加速的瞬间&#xff0c;往往不是设备成功启动&#xff0c;而是调试时一个不经意的误操作&#xff0c;导致气缸撞上限位、…...

n8n子流程调用避坑指南:从数据库写入到模块化开发实战

n8n子流程调用避坑指南&#xff1a;从数据库写入到模块化开发实战 当你开始用n8n构建稍微复杂一点的自动化系统时&#xff0c;很快就会发现把所有逻辑都塞进一个长长的工作流里&#xff0c;不仅维护起来头疼&#xff0c;调试更是噩梦。这时候&#xff0c;子流程调用就成了你工具…...

华为路由器实战:路由递归与ECMP负载均衡配置详解(附避坑指南)

华为路由器实战&#xff1a;路由递归与ECMP负载均衡配置详解&#xff08;附避坑指南&#xff09; 在构建和维护企业级或运营商网络时&#xff0c;仅仅让路由“通”起来往往只是第一步。当网络拓扑变得复杂&#xff0c;冗余链路成为常态&#xff0c;如何让数据流更智能、更高效地…...

手把手教你用本地代理屏蔽Jetbrains验证域名(含详细hosts配置)

从网络策略到本地配置&#xff1a;构建稳定的开发环境访问体验 最近在开发者社区里&#xff0c;一个话题的讨论热度始终不减&#xff1a;如何确保我们每天赖以生存的开发工具能够稳定、顺畅地运行&#xff0c;而不被一些非核心的网络验证流程所干扰。对于深度依赖JetBrains系列…...

Qwen3-TTS-12Hz-1.7B-Base多场景:跨境电商独立站+邮件营销+WhatsApp消息语音化

Qwen3-TTS-12Hz-1.7B-Base多场景&#xff1a;跨境电商独立站邮件营销WhatsApp消息语音化 语音技术正在改变跨境电商的沟通方式——想象一下&#xff0c;你的商品描述能自动变成多国语言的语音介绍&#xff0c;营销邮件能发出真人般的声音&#xff0c;WhatsApp消息不再只是冰冷的…...

ChatGLM3-6B本地化部署一文详解:私有化、断网可用、数据零泄露保障

ChatGLM3-6B本地化部署一文详解&#xff1a;私有化、断网可用、数据零泄露保障 1. 引言&#xff1a;为什么你需要一个本地专属的AI助手&#xff1f; 想象一下&#xff0c;你正在处理一份包含敏感客户信息的商业计划书&#xff0c;或者一段尚未公开的核心算法代码。你想让AI帮…...

【独家首发】MCP本地数据库连接器安全基线检查清单(含12项强制项+4项高危项,GitHub Star 3.2k项目已采纳)

第一章&#xff1a;MCP本地数据库连接器安全基线检查清单概览MCP&#xff08;Model Control Protocol&#xff09;本地数据库连接器是模型服务与底层持久化层交互的关键组件&#xff0c;其安全性直接影响整个AI系统数据完整性、机密性与可用性。本节提供一套轻量、可落地的安全…...

Phi-3-Mini-128K企业应用:电力调度中心本地化电网规程智能问答系统

Phi-3-Mini-128K企业应用&#xff1a;电力调度中心本地化电网规程智能问答系统 1. 引言&#xff1a;当电网规程遇上AI助手 想象一下&#xff0c;深夜的电力调度中心&#xff0c;一个紧急故障发生了。调度员需要快速翻阅上千页的纸质规程手册&#xff0c;查找对应的处理步骤。…...

Stable Yogi Leather-Dress-Collection实战案例:基于LoRA权重切换的系列化设计

Stable Yogi Leather-Dress-Collection实战案例&#xff1a;基于LoRA权重切换的系列化设计 1. 引言&#xff1a;当动漫角色穿上定制皮衣 想象一下&#xff0c;你是一位动漫角色设计师&#xff0c;需要为你的角色设计一系列不同款式的皮衣穿搭。传统流程下&#xff0c;你需要为…...