使用 Go 构建 MCP Server
一个互联网技术玩家,一个爱聊技术的家伙。在工作和学习中不断思考,把这些思考总结出来,并分享,和大家一起交流进步。
一、MCP 介绍
1. 基本介绍
MCP(Model Context Protocol,模型上下文协议)是由 Anthropic 公司(Claude 大模型的创造者)于 2024 年 11 月推出的一种开放标准协议,旨在统一大型语言模型(LLM)与外部数据源和工具之间的通信方式。MCP 的核心目标是解决当前 AI 应用开发中的数据孤岛和碎片化集成问题。
2. 协议特点
MCP 可以被理解为 AI 大模型的"万能接口",类似于 USB-C 接口在硬件领域的作用,它提供了一种标准化的方法,使 AI 模型能够与不同的数据源和工具进行无缝交互。通过 MCP,开发者可以更轻松地构建复杂的 AI 应用,而无需为每个工具或数据源编写专门的集成代码。
MCP 是一个标准协议,如同电子设备的 Type C 协议(可以充电也可以传输数据),使 AI 模型能够与不同的 API 和数据源无缝交互。
MCP 旨在替换碎片化的 Agent 代码集成,从而使 AI 系统更可靠,更有效。通过建立通用标准,服务商可以基于协议来推出它们自己服务的 AI 能力,从而支持开发者更快的构建更强大的 AI 应用。开发者也不需要重复造轮子,通过开源项目可以建立强大的 AI Agent 生态。
MCP 可以在不同的应用/服务之间保持上下文,从而增强整体自主执行任务的能力。
可以理解为 MCP 是将不同任务进行分层处理,每一层都提供特定的能力、描述和限制。而 MCP Client 端根据不同的任务判断,选择是否需要调用某个能力,然后通过每层的输入和输出,构建一个可以处理复杂、多步对话和统一上下文的 Agent。
3. AI Agent 和 MCP 间的关系
AI Agent 是一个智能系统,它可以自主运行以实现特定目标。传统的 AI 聊天仅提供建议或者需要手动执行任务,AI Agent 则可以分析具体情况,做出决策,并自行采取行动。
AI Agent 可以利用 MCP 提供的功能描述来理解更多的上下文,并在各种平台/服务自动执行任务。
4. MCP 如何工作
MCP 采用客户端-服务器架构,MCP 架构主要包含以下核心组件:

MCP 的基本工作流程如下:
用户向 AI 模型(MCP 客户端)发送请求
AI 模型分析请求,确定需要调用的外部工具或数据
AI 模型通过 MCP 协议向相应的 MCP 服务器发送请求
MCP 服务器处理请求并返回结果
AI 模型整合结果,生成最终回复给用户
二、cline 配置本地模型
我做测试使用的客户端是 vscode+cline,cline 在 vscode 的插件市场中直接安装即可。cline 对 MCP 的支持也是非常好的。因为要使用到大模型,所以这里还要给 cline 配置一个大模型。
外网开放的免费模型一般都不太好用,所以我一般都是配置本地模型来测试,这里也介绍一下 cline 如何配置本地模型。
我这里配置了 ollama 启动的 qwen2.5:14b 模型。如下图配置即可,这个配置过程比较简单。
三、MCP 服务开发
1. 典型应用场景
实时数据分析:LLM 通过 MCP 直接查询数据库生成动态报告(如销售数据可视化)。
跨平台自动化:结合本地文件读写和 API 调用,实现“读取文档 → 生成会议摘要 → 发送邮件”全流程自动化。
隐私敏感任务:医疗数据存储在本地 Server,模型处理时不外传,符合 GDPR 合规要求。
工具增强生成:例如代码编辑器中集成 MCP Server,根据用户需求调用图像生成工具自动插入图片。
2. 案例开发
这部分代码参考了这篇文章:https://mp.weixin.qq.com/s/JmPxMBRZa8UhsIOQVgupLw ,这篇文章主要是一个按照时区获取时间的工具,我在测试 ok 之后扩展了一个天气获取的工具。
天气接口使用的是腾讯云的接口,大家可以直接使用免费额度,代码也是直接从腾讯云 api 的介绍中拷贝过来的,这里做了简单的封装调用。
下面的代码直接拷贝过去就可以使用,不过天气 api 的 key要替换成你自己的。
package main
import ( "context" "crypto/hmac" "crypto/sha1" "encoding/base64" "fmt" "io" "io/ioutil" "net/http" gourl "net/url" "strings" "time""github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server")
func main() { // GetWeaher("北京") // Create MCP server s := server.NewMCPServer("MCPDemo", "1.0.0") // Add Get time tool timetool := mcp.NewTool("current_time", mcp.WithDescription("Get current time with timezone, Asia/Shanghai is default"), mcp.WithString("timezone", mcp.Required(), mcp.Description("current time timezone"))) // Add tool handler s.AddTool(timetool, currentTimeHandler)// add weather tool weathertool := mcp.NewTool("current_weather", mcp.WithDescription("Get current weather with city name, 北京 is default, 需要输入中文"), mcp.WithString("city", mcp.Required(), mcp.Description("city name"))) // Add tool handler s.AddTool(weathertool, weatherHandler) // Start the stdio server if err := server.ServeStdio(s); err != nil { fmt.Printf("Server error: %v\n", err) }}
func currentTimeHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { timezone, ok := request.Params.Arguments["timezone"].(string) if !ok { return mcp.NewToolResultError("timezone must be a string"), nil } loc, err := time.LoadLocation(timezone) if err != nil { return mcp.NewToolResultError(fmt.Sprintf("parse timezone with error: %v", err)), nil } return mcp.NewToolResultText(fmt.Sprintf(`current time is %s`, time.Now().In(loc))), nil}
func weatherHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { city, ok := request.Params.Arguments["city"].(string) if !ok { return mcp.NewToolResultError("city must be a string"), nil } body, err := GetWeaher(city) if err != nil { return mcp.NewToolResultError(fmt.Sprintf("read response body with error: %v", err)), nil } return mcp.NewToolResultText(string(body)), nil}
func calcAuthorization(source string, secretId string, secretKey string) (auth string, datetime string, err error) { timeLocation, _ := time.LoadLocation("Etc/GMT") datetime = time.Now().In(timeLocation).Format("Mon, 02 Jan 2006 15:04:05 GMT") signStr := fmt.Sprintf("x-date: %s\nx-source: %s", datetime, source)// hmac-sha1 mac := hmac.New(sha1.New, []byte(secretKey)) mac.Write([]byte(signStr)) sign := base64.StdEncoding.EncodeToString(mac.Sum(nil))auth = fmt.Sprintf("hmac id=\"%s\", algorithm=\"hmac-sha1\", headers=\"x-date x-source\", signature=\"%s\"", secretId, sign)return auth, datetime, nil}
func urlencode(params map[string]string) string { var p = gourl.Values{} for k, v := range params { p.Add(k, v) } return p.Encode()}
func GetWeaher(city string) (ret string, err error) { // 云市场分配的密钥Id secretId := "xxx" // 云市场分配的密钥Key secretKey := "xxx" source := "usagePlan-xxx"// 签名 auth, datetime, _ := calcAuthorization(source, secretId, secretKey)// 请求方法 method := "GET" // 请求头 headers := map[string]string{"X-Source": source, "X-Date": datetime, "Authorization": auth}// 查询参数 queryParams := make(map[string]string) queryParams["areaCn"] = city queryParams["areaCode"] = "" queryParams["ip"] = "" queryParams["lat"] = "" queryParams["lng"] = "" queryParams["need1hour"] = "" queryParams["need3hour"] = "" queryParams["needIndex"] = "" queryParams["needObserve"] = "" queryParams["needalarm"] = "" // body参数 bodyParams := make(map[string]string)// url参数拼接 url := "https://service-6drgk6su-1258850945.gz.apigw.tencentcs.com/release/lundear/weather1d" if len(queryParams) > 0 { url = fmt.Sprintf("%s?%s", url, urlencode(queryParams)) }bodyMethods := map[string]bool{"POST": true, "PUT": true, "PATCH": true} var body io.Reader = nil if bodyMethods[method] { body = strings.NewReader(urlencode(bodyParams)) headers["Content-Type"] = "application/x-www-form-urlencoded" }client := &http.Client{ Timeout: 5 * time.Second, } request, err := http.NewRequest(method, url, body) if err != nil { panic(err) } for k, v := range headers { request.Header.Set(k, v) } response, err := client.Do(request) if err != nil { panic(err) } defer response.Body.Close()bodyBytes, err := ioutil.ReadAll(response.Body) if err != nil { panic(err) } fmt.Println(string(bodyBytes)) return string(bodyBytes), nil} 四、Cline 上配置自己开发的 MCP 服务
在 Cline 上添加 MCP 服务点击右上角“+”号旁边的 4 个小方块按钮即可进入。
里面有默认的服务市场和已经安装,我们在已经安装这个 tab 中选择 “Configure MCP Servers”,打开配置文件编辑,填写以下内容:
{ "mcpServers": { "helight-mcpServers": { "command": "/Users/helightxu/aillm/mcpgolangtest/mcp-server", "args": [], "env": {}, "disabled": false, "autoApprove": [ "current_weather", "current_time" ] } }} 主要就是MCP 服务的名称,里面服务二进制地址等配置。这里还有一个“autoApprove”配置项,这个是在执行命令的时候是否需要人工二次确认还是自动确认。配置之后就可以看到下图的内容了。

这里还可以点击下面的“Restart Server”,对服务进行重启,重启之后也会获取最新的服务工具信息。在你重新编译 MCP 服务之后,这里一般需要点击重启一下。
五、案例测试
1. 时间获取案例
这里输入“当前东京的时间是多少”,执行过程如下,就会在大模型解析之后去调用我们的工具进行执行获取结果,并且会对工具返回的结果使用大模型进行再次组织。

2. 天气获取案例
天气这里也是,提问:“深圳的天气怎么样”,在大模型分析之后就会调用我们的天气获取工具进行天气信息获取,获取之后再使用大模型进行信息组织和展示。

这里是对信息的再次组织
五、MCP 的优势和典型应用场景
1. MCP 的核心优势
从系统集成和开放集成的角度来看,我认为 MCP会带来以下的突破。
打破数据孤岛:通过统一协议连接异构系统(如本地文档、云服务),减少大量的适配代码开发量。
双向动态交互:支持实时请求-响应和主动通知(如 WebSocket),相比传统 API 的静态交互更灵活。
隐私与安全:
数据隔离:敏感操作(如医疗数据处理)在本地 Server 完成,无需向 LLM 提供商暴露密钥。
权限控制:Server 可自主定义访问范围,防止越权操作。
开发效率提升: 开发者只需关注业务逻辑,无需重复实现通信层,例如通过 Python SDK 快速构建天气查询服务。
2. MCP 目前比较典型的应用场景
我认为目前 MCP 的一些典型应用场景会在以下几个方面,不过这个应该发展会很快,未来也许会有更为复杂的应用场景出现。
智能助手增强
MCP 可以显著增强智能助手的能力,使其能够:
访问实时信息(如天气、新闻、股票价格等)
执行复杂计算
查询和操作数据库
控制外部设备和系统
2. 企业知识管理
在企业环境中,MCP 可以帮助:
构建智能知识库
实现跨部门数据共享
自动化文档处理和分析
提供个性化的员工支持
六、总结
我认为这种模式应该是 AI 应用的趋势,不做大模型,而是做大模型、内容信息和工具之间的一种胶水层,是一种思考模式的实现。感觉未来大厂的这些工具都会向这个方向发展。在特定的领域之内,结合大模型、具体场景信息和相关工具,思考组织执行方式和流程,最终完成一个自动化大规模计算的复杂任务。比如复杂的 k8s 集群运维,复杂大规模的数据分析。
多智能体协作系统应该是未来的大趋势。而 MCP 在多智能体系统中的应用是其最强大的特性之一。通过 MCP,多个 AI 智能体可以协同工作,各自负责不同的任务,并通过标准化的接口进行通信。
多智能体可能的一个架构:
多智能体系统 多智能体系统├── 协调者智能体(Coordinator Agent)├── 专家智能体 1(Expert Agent 1)├── 专家智能体 2(Expert Agent 2)├── ...└── 专家智能体 N(Expert Agent N) 六、参考
- https://mp.weixin.qq.com/s/JmPxMBRZa8UhsIOQVgupLw
https://guangzhengli.com/blog/zh/model-context-protocol/
相关文章:
使用 Go 构建 MCP Server
一个互联网技术玩家,一个爱聊技术的家伙。在工作和学习中不断思考,把这些思考总结出来,并分享,和大家一起交流进步。 一、MCP 介绍 1. 基本介绍 MCP(Model Context Protocol,模型上下文协议)是…...
C语言贪吃蛇实现
When the night gets dark,remember that the Sun is also a star. 当夜幕降临时,请记住太阳也是一颗星星。 ————《去月球海滩篇》 目录 文章目录 一、《贪吃蛇》游戏介绍 二、WIN32部分接口简单介绍 2.1 控制台窗口大小设置 2.2 命令行窗口的名称的变更 2…...
pytorch小记(十五):pytorch中 交叉熵损失详解:为什么logits比targets多一个维度?
pytorch小记(十五):pytorch中 交叉熵损失详解:为什么logits比targets多一个维度? PyTorch交叉熵损失详解:为什么logits比targets多一个维度?一、前言:新手常见困惑二、核心概念&…...
利用zabbix自带key获取数据
获取数据的三种方法 1、链接模版 服务器系统自身的监控 CPU CPU使用率、CPU负载 内存 内存剩余量 硬盘 关键性硬盘的剩余量、IO 网卡 流量/IO(流入流量、流出流量、总流量、错误数据包流量) 进程数 用户数 2、利用zabbix自带的键值key 1)监…...
无人机数据处理系统设计要点与难点!
一、系统设计要点 无人机数据处理系统需要高效、可靠、低延迟地处理多源异构数据(如影像、传感器数据、位置信息等),同时支持实时分析和长期存储。以下是核心设计要点: 1.数据采集与预处理 多传感器融合:集成摄像头…...
最大异或对 The XOR Largest Pair
题目来自洛谷网站: 思路: 两个循环时间复杂度太高了,会超时。 我们可以先将读入的数字,插入到字典树中,从高位到低位。对每个数查询的时候,题目要求是最大的异或对,所以我们选择相反的路径&am…...
基于SpringBoot + Vue 的汽车租赁管理系统
技术介绍: ①:架构: B/S、MVC ②:系统环境:Windows/Mac ③:开发环境:IDEA、JDK1.8、Maven、Mysql ④:技术栈:Java、Mysql、SpringBoot、Mybatis、Vue 项目功能: 角色&am…...
基于DrissionPage的TB商品信息采集与可视化分析
一、项目背景 随着电子商务的快速发展,淘宝作为中国最大的电商平台之一,拥有海量的商品信息。这些数据对于市场分析、用户行为研究以及竞争情报收集具有重要意义。然而,由于淘宝的反爬虫机制和复杂的页面结构,直接获取商品信息并不容易。尤其是在电商行业高速发展的今天,商…...
电气、电子信息与通信工程的探索与应用
从传统定义来看,电气工程是现代科技领域的核心学科和关键学科。它涵盖了创造产生电气与电子系统的有关学科的总和。然而,随着科学技术的飞速发展,电气工程的概念已经远超出这一范畴。 电子信息工程则是将电子技术、通信技术、计算机技术等应…...
Python备赛笔记2
1.区间求和 题目描述 给定a1……an一共N个整数,有M次查询,每次需要查询区间【L,R】的和。 输入描述: 第一行包含两个数:N,M 第二行输入N个整数 接下来的M行,每行有两个整数,L R,中间用空格隔开&…...
HTML5 拖放(Drag and Drop)学习笔记
一、HTML5 拖放简介 HTML5 拖放(Drag and Drop)是HTML5标准的一部分,允许用户抓取一个对象并将其拖动到另一个位置。拖放功能在现代网页中非常常见,例如文件上传、任务管理、布局调整等场景。 HTML5 拖放功能支持以下浏览器&…...
Sass (Scss) 与 Less 的区别与选择
Sass 与 Less 的区别与选择 1. 语法差异2. 特性与支持3. 兼容性4. 选择建议 在前端开发中,CSS预处理器如Sass(Syntactically Awesome Stylesheets)和Less被广泛使用,它们通过引入变量、嵌套规则、混合、函数等特性,使C…...
Unity2022发布Webgl2微信小游戏部分真机黑屏
复现规律: Unity PlayerSetting中取消勾选ShowSplashScreen 分析: 在Unity中,Splash Screen(启动画面) 不仅是视觉上的加载动画,还承担了关键的引擎初始化、资源预加载和渲染环境准备等底层逻辑。禁用后导…...
记一次线上SQL死锁事故
一、 引言 SQL死锁是一个常见且复杂的并发控制问题。当多个事务在数据库中互相等待对方释放锁时,就会形成死锁,从而导致事务无法继续执行,影响系统的性能和可用性。死锁不仅会导致数据库操作的阻塞,增加延迟,还可能对…...
Java并发编程 什么是分布式锁 跟其他的锁有什么区别 底层原理 实战讲解
目录 一、分布式锁的定义与核心作用 二、分布式锁与普通锁的核心区别 三、分布式锁的底层原理与实现方式 1. 核心实现原理 2. 主流实现方案对比 3. 关键技术细节 四、典型问题与解决方案 五、总结 六、具体代码实现 一、分布式锁的定义与核心作用 分布式锁是一种在分布…...
【react】在react中async/await一般用来实现什么功能
目录 基本概念 工作原理 优点 注意事项 底层原理 实际应用场景 1. 数据获取 (API 请求) 2. 表单提交 3. 异步状态管理 4. 异步路由切换 5. 异步数据预加载 6. 第三方 API 调用 7. 文件上传/下载 8. 路由导航拦截 关键注意事项 基本概念 async 函数:用…...
Axure项目实战:智慧城市APP(六)市民互动(动态面板、显示与隐藏)
亲爱的小伙伴,在您浏览之前,烦请关注一下,在此深表感谢! 课程主题:市民互动 主要内容:动态面板、显示与隐藏交互应用 应用场景:AI产品交互、互动类应用 案例展示: 案例视频&am…...
为何服务器监听异常?
报错: 执行./RCF后出现监听异常--在切换网络后,由于前面没有退出./RCF执行状态;重新连接后,会出现服务器监听异常 原因如下: 由于刚开始登录内网,切换之后再重新登录内网,并且切换网络的过程中…...
1.认识Excel
一 Excel 可以用来做什么 二 提升技巧 1.数据太多 2.计算太累 3.提升数据的价值和意义 4.团队协作 三 学习目标 学习目标不是为了掌握所有的技能,追逐新功能。而是学知识来解决需求,如果之前的技能和新出的技能都可以解决问题,那不学新技能也…...
目标跟踪——deepsort算法详细阐述
deepsort 算法详解 Unmatched Tracks(未匹配的轨迹) 本质角色: 是已存在的轨迹在当前帧中“失联”的状态,即预测位置与检测结果不匹配。 生命周期阶段: 已初始化: 轨迹已存在多帧,可能携带历史信息(如外观特征、运动模型)。 未被观测到: 当前帧中未找到对应的检测框…...
AI Agent 是什么?从 Chatbot 到自动化 Agent(LangChain、AutoGPT、BabyAGI)
1. 引言:AI Agent 的演进 AI Agent(人工智能智能体)是 AI 发展的重要方向之一。早期的 AI 主要以 Chatbot 形式存在,如客服机器人、智能助手等,主要基于 NLP 技术进行任务处理。而随着大模型(LLM)能力的提升,AI Agent 逐步演进为能够自主执行任务的智能体,如 AutoGPT…...
ngx_http_core_root
定义在 src\http\ngx_http_core_module.c static char * ngx_http_core_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {ngx_http_core_loc_conf_t *clcf conf;ngx_str_t *value;ngx_int_t alias;ngx_uint_t …...
python康复日记-request库的使用,爬虫自动化测试
一,request的简单应用 #1请求地址 URLhttps://example.com/login #2参数表单 form_data {username: admin,password: secret } #3返回的响应对象response response requests.post(URL,dataform_data,timeout5 ) #4处理返回结果,这里直接打印返回网页的…...
光谱范围与颜色感知的关系
光谱范围与颜色感知是光学、生理学及技术应用交叉的核心课题,两者通过波长分布、人眼响应及技术处理共同决定人类对色彩的认知。以下是其关系的系统解析: 1.基础原理:光谱范围与可见光 光谱范围定义: 电磁波谱中能被特定…...
OpenCV vs MediaPipe:哪种方案更适合实时手势识别?
引言 手势识别是计算机视觉的重要应用,在人机交互(HCI)、增强现实(AR)、虚拟现实(VR)、智能家居控制、游戏等领域有广泛的应用。实现实时手势识别的技术方案主要有基于传统计算机视觉的方法&am…...
el-select下拉框,搜索时,若是匹配后的数据有且只有一条,则当失去焦点时,默认选中该条数据
1、使用指令 当所需功能只能通过直接的 DOM 操作来实现时,才应该使用自定义指令。可使用方法2封装成共用函数,但用指令他人复用时比较便捷。 <el-tablev-loading"tableLoading"border:data"tableList"default-expand-allrow-key…...
网络地址转换技术(2)
NAT的配置方法: (一)静态NAT的配置方法 进入接口视图配置NAT转换规则 Nat static global 公网地址 inside 私网地址 内网终端PC2(192.168.20.2/24)与公网路由器AR1的G0/0/1(11.22.33.1/24)做…...
Python正则表达式(一)
目录 一、正则表达式的基本概念 1、基本概念 2、正则表达式的特殊字符 二、范围符号和量词 1、范围符号 2、匹配汉字 3、量词 三、正则表达式函数 1、使用正则表达式: 2、re.match()函数 3、re.search()函数 4、findall()函数 5、re.finditer()函数 6…...
【TI MSPM0】PWM学习
一、样例展示 #include "ti_msp_dl_config.h"int main(void) {SYSCFG_DL_init();DL_TimerG_startCounter(PWM_0_INST);while (1) {__WFI();} } TimerG0输出一对边缘对齐的PWM信号 TimerG0会输出一对62.5Hz的边缘对齐的PWM信号在PA12和PA13引脚上,PA12被…...
MySQL: 创建两个关联的表,用联表sql创建一个新表
MySQL: 创建两个关联的表 建表思路 USERS 表:包含用户的基本信息,像 ID、NAME、EMAIL 等。v_card 表:存有虚拟卡的相关信息,如 type 和 amount。关联字段:USERS 表的 V_CARD 字段和 v_card 表的 v_card 字段用于建立…...
