Go語(yǔ)言開發(fā)實(shí)現(xiàn)查詢IP信息的MCP服務(wù)器
前言
隨著 MCP 的快速普及和廣泛應(yīng)用,MCP 服務(wù)器也層出不窮。大多數(shù)開發(fā)者使用的 MCP 服務(wù)器開發(fā)庫(kù)是官方提供的 typescript-sdk,而作為 Go 開發(fā)者,我們也可以借助優(yōu)秀的第三方庫(kù)去開發(fā) MCP 服務(wù)器,例如 ThinkInAIXYZ/go-mcp。
本文將詳細(xì)介紹如何在 Go 語(yǔ)言中使用 go-mcp 庫(kù)來(lái)開發(fā)一個(gè)查詢 IP 信息的 MCP 服務(wù)器。
mcp-ip-geo 服務(wù)器
mcp-ip-geo 是一個(gè)用于查詢 IP 信息的 MCP 服務(wù)器,項(xiàng)目已開源,倉(cāng)庫(kù)地址:mcp-ip-geo。
目錄結(jié)構(gòu)說(shuō)明
├─cmd
│ └─mcp-ip-geo
└─internal
├─domain
├─server
├─service
└─tools
cmd/mcp-ip-geo:應(yīng)用的啟動(dòng)入口目錄,包含如main.go啟動(dòng)文件。internal/domain:定義項(xiàng)目中的核心數(shù)據(jù)結(jié)構(gòu),例如IP API的響應(yīng)體等。internal/server:MCP服務(wù)器的核心邏輯實(shí)現(xiàn)。internal/service:對(duì)接第三方服務(wù)的實(shí)現(xiàn),如調(diào)用IP解析API。internal/tools:MCP工具的具體實(shí)現(xiàn),支持靈活擴(kuò)展和注冊(cè)。
查詢 IP 信息功能實(shí)現(xiàn)
代碼位于 service 包中,通過(guò) ip-api.com 提供的接口獲取 IP 地理位置信息,具體實(shí)現(xiàn)如下:
package service
import (
"context"
"fmt"
"github.com/chenmingyong0423/mcp-ip-geo/internal/domain"
"net/http"
"time"
httpchain "github.com/chenmingyong0423/go-http-chain"
)
func NewIpApiService() *IpApiService {
return &IpApiService{
host: "http://ip-api.com",
client: httpchain.NewWithClient(&http.Client{
Timeout: time.Second * 10,
}),
}
}
type IIpApiService interface {
GetLocation(ctx context.Context, ip string) (*domain.IpApiResponse, error)
}
var _ IIpApiService = (*IpApiService)(nil)
type IpApiService struct {
host string
client *httpchain.Client
}
func (s *IpApiService) GetLocation(ctx context.Context, ip string) (*domain.IpApiResponse, error) {
var resp domain.IpApiResponse
err := s.client.Get(fmt.Sprintf("%s/json/%s", s.host, ip)).DoAndParse(ctx, &resp)
if err != nil {
return nil, err
}
return &resp, nil
}代碼解釋:
服務(wù)初始化(
NewIpApiService)- 創(chuàng)建一個(gè)新的
IpApiService實(shí)例。 - 設(shè)置了
API地址為http://ip-api.com。 - 使用
httpchain封裝的HTTP客戶端,設(shè)置請(qǐng)求超時(shí)時(shí)間為 10 秒。
- 創(chuàng)建一個(gè)新的
接口定義(
IIpApiService)- 定義了服務(wù)對(duì)外暴露的功能:
GetLocation方法,用于獲取IP地理位置信息。 - 使用接口有助于后續(xù)做依賴注入、
mock測(cè)試等。 var _ IIpApiService = (*IpApiService)(nil)這行代碼用于編譯時(shí)檢查,確保IpApiService實(shí)現(xiàn)了IIpApiService接口。
- 定義了服務(wù)對(duì)外暴露的功能:
結(jié)構(gòu)體定義(
IpApiService)- 包含兩個(gè)字段:
host:API的基礎(chǔ)地址。client:封裝的HTTP客戶端,類型為*httpchain.Client。
核心方法實(shí)現(xiàn)(
GetLocation)- 根據(jù)傳入的
IP構(gòu)造請(qǐng)求地址:http://ip-api.com/json/{ip}。 - 使用
httpchain庫(kù)發(fā)起GET請(qǐng)求,并將結(jié)果解析到domain.IpApiResponse結(jié)構(gòu)體中。
- 根據(jù)傳入的
工具實(shí)現(xiàn)
工具管理
代碼位于 tools 包中,用于管理工具,具體實(shí)現(xiàn)如下:
package tools
import (
"github.com/ThinkInAIXYZ/go-mcp/protocol"
"github.com/ThinkInAIXYZ/go-mcp/server"
)
type ToolFunc func() (tool *protocol.Tool, toolHandler server.ToolHandlerFunc)
func GetToolFuncList() []ToolFunc {
return []ToolFunc{
SingleIpParser,
}
}
代碼解釋:
ToolFunc類型定義定義了一個(gè)函數(shù)類型
ToolFunc,返回兩個(gè)值:*protocol.Tool:工具的元信息;server.ToolHandlerFunc:該工具的處理邏輯函數(shù)。
用這種方式可以將 工具的定義 與 工具的執(zhí)行邏輯 一并管理,后續(xù)在定義工具時(shí)都可以通過(guò)實(shí)現(xiàn)該函數(shù)簽名進(jìn)行表示。
GetToolFuncList函數(shù)- 返回一個(gè)
ToolFunc列表。 - 當(dāng)前只注冊(cè)了一個(gè)工具:
SingleIpParser,但這種結(jié)構(gòu)易于擴(kuò)展,后續(xù)只需往列表中添加新的工具函數(shù)即可。 - 通過(guò)集中注冊(cè),應(yīng)用在初始化時(shí)可以統(tǒng)一加載所有工具。
- 返回一個(gè)
查詢單個(gè) IP 信息工具的實(shí)現(xiàn)
代碼位于 tools 包中,用于查詢單個(gè) IP 信息,具體實(shí)現(xiàn)如下:
package tools
import (
"context"
"encoding/json"
"github.com/ThinkInAIXYZ/go-mcp/protocol"
"github.com/ThinkInAIXYZ/go-mcp/server"
"github.com/chenmingyong0423/mcp-ip-geo/internal/service"
)
var singleIpParserTool *protocol.Tool
type ipRequest struct {
Ip string `json:"ip"`
}
func init() {
var err error
singleIpParserTool, err = protocol.NewTool("ip-details", "a tool that provides IP geolocation information", ipRequest{})
if err != nil {
panic(err)
}
}
func SingleIpParser() (*protocol.Tool, server.ToolHandlerFunc) {
ipApiService := service.NewIpApiService()
return singleIpParserTool, func(toolRequest *protocol.CallToolRequest) (*protocol.CallToolResult, error) {
var req ipRequest
if err := protocol.VerifyAndUnmarshal(toolRequest.RawArguments, &req); err != nil {
return nil, err
}
resp, err := ipApiService.GetLocation(context.Background(), req.Ip)
if err != nil {
return nil, err
}
marshal, err := json.Marshal(resp)
if err != nil {
return nil, err
}
return &protocol.CallToolResult{
Content: []protocol.Content{
protocol.TextContent{
Type: "text",
Text: string(marshal),
},
},
}, nil
}
}代碼解釋:
全局變量聲明
singleIpParserTool:存儲(chǔ)工具元信息的協(xié)議工具對(duì)象ipRequest:定義工具輸入?yún)?shù)結(jié)構(gòu)體,包含ip字符串字段
初始化函數(shù)(
init)- 在包加載時(shí)通過(guò)
protocol.NewTool創(chuàng)建工具元信息 - 指定工具標(biāo)識(shí)符
ip-details,描述信息和輸入?yún)?shù)結(jié)構(gòu)體ipRequest{} - 錯(cuò)誤處理采用
panic,確保工具元信息必須正確初始化
- 在包加載時(shí)通過(guò)
工具注冊(cè)函數(shù)(
SingleIpParser)創(chuàng)建
IpApiService服務(wù)實(shí)例用于IP定位查詢返回兩個(gè)值:
- 預(yù)定義的
singleIpParserTool元信息對(duì)象 - 工具處理函數(shù)
- 預(yù)定義的
工具處理函數(shù)
參數(shù)驗(yàn)證與解析
- 調(diào)用
protocol.VerifyAndUnmarshal驗(yàn)證請(qǐng)求參數(shù)有效性 - 將原始參數(shù)反序列化到
ipRequest結(jié)構(gòu)體
- 調(diào)用
服務(wù)調(diào)用
- 使用
ipApiService.GetLocation獲取IP地理位置信息
- 使用
結(jié)果處理
- 將服務(wù)響應(yīng)結(jié)果序列化為
JSON字符串并包裝為protocol.CallToolResult結(jié)構(gòu)體返回
- 將服務(wù)響應(yīng)結(jié)果序列化為
服務(wù)器的創(chuàng)建與啟動(dòng)
代碼位于 server 包中,用于初始化服務(wù)并啟動(dòng)服務(wù)端,具體實(shí)現(xiàn)如下:
package server
import (
"github.com/ThinkInAIXYZ/go-mcp/server"
"github.com/ThinkInAIXYZ/go-mcp/transport"
"github.com/chenmingyong0423/mcp-ip-geo/internal/tools"
)
func Run(address string) error {
var err error
var ts transport.ServerTransport
if address == "" {
ts = transport.NewStdioServerTransport()
} else {
ts, err = transport.NewSSEServerTransport(address)
if err != nil {
return err
}
}
s, err := server.NewServer(ts)
if err != nil {
return err
}
toolFuncList := tools.GetToolFuncList()
for _, tool := range toolFuncList {
s.RegisterTool(tool())
}
return s.Run()
}代碼解釋:
傳輸層初始化
根據(jù)
address參數(shù)判斷運(yùn)行模式:- 空地址模式:使用
NewStdioServerTransport創(chuàng)建標(biāo)準(zhǔn)輸入輸出傳輸,適用于命令行工具等場(chǎng)景。 - 指定地址模式:使用
NewSSEServerTransport創(chuàng)建SSE(Server-Sent Events) 傳輸,適用于HTTP長(zhǎng)連接服務(wù)。
- 空地址模式:使用
服務(wù)實(shí)例化
- 使用
server.NewServer方法創(chuàng)建服務(wù)實(shí)例,注入配置好的傳輸層對(duì)象ts。
- 使用
工具注冊(cè)
調(diào)用
tools.GetToolFuncList獲取所有預(yù)定義的工具函數(shù)列表。遍歷工具列表,通過(guò)
s.RegisterTool(tool())注冊(cè)每個(gè)工具:tool()執(zhí)行后返回元信息*protocol.Tool和處理函數(shù)ToolHandlerFunc。
服務(wù)啟動(dòng)
- 調(diào)用
s.Run()啟動(dòng)服務(wù),開始監(jiān)聽請(qǐng)求。
- 調(diào)用
主程序入口實(shí)現(xiàn)
代碼位于 main 包中,作為程序啟動(dòng)入口,具體實(shí)現(xiàn)如下:
package main
import (
"flag"
"github.com/chenmingyong0423/mcp-ip-geo/internal/server"
)
func main() {
addr := flag.String("address", "", "The host and port to run the sse server")
flag.Parse()
if err := server.Run(*addr); err != nil {
panic(err)
}
}代碼解釋:
命令行參數(shù)解析
定義
address參數(shù):- 參數(shù)名稱:
-address - 默認(rèn)值:空字符串
- 描述:指定
SSE服務(wù)運(yùn)行的地址和端口
- 參數(shù)名稱:
調(diào)用
flag.Parse()解析命令行參數(shù)
服務(wù)啟動(dòng)
- 調(diào)用
server.Run(*addr)啟動(dòng)服務(wù) - 將解析后的
address參數(shù)值傳遞給服務(wù)啟動(dòng)函數(shù)
- 調(diào)用
從源碼構(gòu)建
本地構(gòu)建
使用 Go 命令
# 在類 Unix 系統(tǒng)(Linux/macOS)上 go build -o mcp-ip-geo ./cmd/mcp-ip-geo # 在 Windows 上 go build -o mcp-ip-geo.exe .\cmd\mcp-ip-geo
使用 Docker
構(gòu)建 Docker 鏡像:
docker build -t mcp-ip-geo-server .
運(yùn)行容器:
docker run -d --name mcp-ip-geo-server -p 8000:8000 mcp-ip-geo-server
安裝預(yù)編譯版本
使用 Go 安裝最新版本的服務(wù):
go install github.com/chenmingyong0423/mcp-ip-geo/cmd/mcp-ip-geo@latest
MCP 集成
你可以通過(guò)以下兩種方式集成 mcp-ip-geo 服務(wù):
可執(zhí)行文件集成(本地運(yùn)行)
{
"mcpServers": {
"mcp-ip-geo": {
"command": "/path/to/mcp-ip-geo"
}
}
}
HTTP 接口集成(連接到已運(yùn)行的服務(wù))
{
"mcpServers": {
"mcp-ip-geo": {
"url": "http://host:port/sse"
}
}
}
效果演示

小結(jié)
本文將詳細(xì)介紹 mcp-ip-geo —— 一個(gè)用于查詢 IP 信息的 MCP 服務(wù)器的實(shí)現(xiàn)細(xì)節(jié)。該服務(wù)器目前支持兩種數(shù)據(jù)傳輸方式:stdio 和 SSE(Server-Sent Events)。未來(lái)還計(jì)劃支持 Streamable HTTP 傳輸方式,并持續(xù)擴(kuò)展更多實(shí)用的工具(tools)模塊。
到此這篇關(guān)于Go語(yǔ)言開發(fā)實(shí)現(xiàn)查詢IP信息的MCP服務(wù)器的文章就介紹到這了,更多相關(guān)Go MCP服務(wù)器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
初學(xué)Go必備的vscode插件及最常用快捷鍵和代碼自動(dòng)補(bǔ)全
這篇文章主要給大家介紹了關(guān)于初學(xué)vscode寫Go必備的vscode插件及最常用快捷鍵和代碼自動(dòng)補(bǔ)全的相關(guān)資料,由于vscode是開源免費(fèi)的,而且開發(fā)支持vscode的插件相對(duì)比較容易,更新速度也很快,需要的朋友可以參考下2023-07-07
Go語(yǔ)言基于HTTP的內(nèi)存緩存服務(wù)的實(shí)現(xiàn)
這篇文章主要介紹了Go語(yǔ)言基于HTTP的內(nèi)存緩存服務(wù),本程序采用REST接口,支持設(shè)置(Set)、獲取(Get)和刪除(Del)這3個(gè)基本操作,同時(shí)還支持對(duì)緩存服務(wù)狀態(tài)進(jìn)行查詢,需要的朋友可以參考下2022-08-08
go實(shí)現(xiàn)整型的二進(jìn)制轉(zhuǎn)化的方法
這篇文章主要介紹了go實(shí)現(xiàn)整型的二進(jìn)制轉(zhuǎn)化的方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下2019-07-07
golang 切片的三種使用方式及區(qū)別的說(shuō)明
這篇文章主要介紹了golang 切片的三種使用方式及區(qū)別的說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-04-04
golang使用正則表達(dá)式解析網(wǎng)頁(yè)
這篇文章主要介紹了golang使用正則表達(dá)式解析網(wǎng)頁(yè),需要的朋友可以參考下2015-03-03
一文帶你了解Go語(yǔ)言中鎖特性和實(shí)現(xiàn)
Go語(yǔ)言中的sync包主要提供的對(duì)并發(fā)操作的支持,標(biāo)志性的工具有cond(條件變量)?once?(原子性)?還有?鎖,本文會(huì)主要向大家介紹Go語(yǔ)言中鎖的特性和實(shí)現(xiàn),感興趣的可以了解下2024-03-03

