Go語言開發(fā)實現(xiàn)查詢IP信息的MCP服務(wù)器
前言
隨著 MCP
的快速普及和廣泛應(yīng)用,MCP
服務(wù)器也層出不窮。大多數(shù)開發(fā)者使用的 MCP
服務(wù)器開發(fā)庫是官方提供的 typescript-sdk
,而作為 Go
開發(fā)者,我們也可以借助優(yōu)秀的第三方庫去開發(fā) MCP
服務(wù)器,例如 ThinkInAIXYZ/go-mcp
。
本文將詳細(xì)介紹如何在 Go
語言中使用 go-mcp
庫來開發(fā)一個查詢 IP
信息的 MCP
服務(wù)器。
mcp-ip-geo 服務(wù)器
mcp-ip-geo
是一個用于查詢 IP
信息的 MCP
服務(wù)器,項目已開源,倉庫地址:mcp-ip-geo。
目錄結(jié)構(gòu)說明
├─cmd
│ └─mcp-ip-geo
└─internal
├─domain
├─server
├─service
└─tools
cmd/mcp-ip-geo
:應(yīng)用的啟動入口目錄,包含如main.go
啟動文件。internal/domain
:定義項目中的核心數(shù)據(jù)結(jié)構(gòu),例如IP API
的響應(yīng)體等。internal/server
:MCP
服務(wù)器的核心邏輯實現(xiàn)。internal/service
:對接第三方服務(wù)的實現(xiàn),如調(diào)用IP
解析API
。internal/tools
:MCP
工具的具體實現(xiàn),支持靈活擴展和注冊。
查詢 IP 信息功能實現(xiàn)
代碼位于 service
包中,通過 ip-api.com
提供的接口獲取 IP
地理位置信息,具體實現(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)建一個新的
IpApiService
實例。 - 設(shè)置了
API
地址為http://ip-api.com
。 - 使用
httpchain
封裝的HTTP
客戶端,設(shè)置請求超時時間為 10 秒。
- 創(chuàng)建一個新的
接口定義(
IIpApiService
)- 定義了服務(wù)對外暴露的功能:
GetLocation
方法,用于獲取IP
地理位置信息。 - 使用接口有助于后續(xù)做依賴注入、
mock
測試等。 var _ IIpApiService = (*IpApiService)(nil)
這行代碼用于編譯時檢查,確保IpApiService
實現(xiàn)了IIpApiService
接口。
- 定義了服務(wù)對外暴露的功能:
結(jié)構(gòu)體定義(
IpApiService
)- 包含兩個字段:
host
:API
的基礎(chǔ)地址。client
:封裝的HTTP
客戶端,類型為*httpchain.Client
。
核心方法實現(xiàn)(
GetLocation
)- 根據(jù)傳入的
IP
構(gòu)造請求地址:http://ip-api.com/json/{ip}
。 - 使用
httpchain
庫發(fā)起GET
請求,并將結(jié)果解析到domain.IpApiResponse
結(jié)構(gòu)體中。
- 根據(jù)傳入的
工具實現(xiàn)
工具管理
代碼位于 tools
包中,用于管理工具,具體實現(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
類型定義定義了一個函數(shù)類型
ToolFunc
,返回兩個值:*protocol.Tool
:工具的元信息;server.ToolHandlerFunc
:該工具的處理邏輯函數(shù)。
用這種方式可以將 工具的定義 與 工具的執(zhí)行邏輯 一并管理,后續(xù)在定義工具時都可以通過實現(xiàn)該函數(shù)簽名進(jìn)行表示。
GetToolFuncList
函數(shù)- 返回一個
ToolFunc
列表。 - 當(dāng)前只注冊了一個工具:
SingleIpParser
,但這種結(jié)構(gòu)易于擴展,后續(xù)只需往列表中添加新的工具函數(shù)即可。 - 通過集中注冊,應(yīng)用在初始化時可以統(tǒng)一加載所有工具。
- 返回一個
查詢單個 IP 信息工具的實現(xiàn)
代碼位于 tools
包中,用于查詢單個 IP
信息,具體實現(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
:存儲工具元信息的協(xié)議工具對象ipRequest
:定義工具輸入?yún)?shù)結(jié)構(gòu)體,包含ip
字符串字段
初始化函數(shù)(
init
)- 在包加載時通過
protocol.NewTool
創(chuàng)建工具元信息 - 指定工具標(biāo)識符
ip-details
,描述信息和輸入?yún)?shù)結(jié)構(gòu)體ipRequest{}
- 錯誤處理采用
panic
,確保工具元信息必須正確初始化
- 在包加載時通過
工具注冊函數(shù)(
SingleIpParser
)創(chuàng)建
IpApiService
服務(wù)實例用于IP
定位查詢返回兩個值:
- 預(yù)定義的
singleIpParserTool
元信息對象 - 工具處理函數(shù)
- 預(yù)定義的
工具處理函數(shù)
參數(shù)驗證與解析
- 調(diào)用
protocol.VerifyAndUnmarshal
驗證請求參數(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)建與啟動
代碼位于 server
包中,用于初始化服務(wù)并啟動服務(wù)端,具體實現(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ù)判斷運行模式:- 空地址模式:使用
NewStdioServerTransport
創(chuàng)建標(biāo)準(zhǔn)輸入輸出傳輸,適用于命令行工具等場景。 - 指定地址模式:使用
NewSSEServerTransport
創(chuàng)建SSE
(Server-Sent Events
) 傳輸,適用于HTTP
長連接服務(wù)。
- 空地址模式:使用
服務(wù)實例化
- 使用
server.NewServer
方法創(chuàng)建服務(wù)實例,注入配置好的傳輸層對象ts
。
- 使用
工具注冊
調(diào)用
tools.GetToolFuncList
獲取所有預(yù)定義的工具函數(shù)列表。遍歷工具列表,通過
s.RegisterTool(tool())
注冊每個工具:tool()
執(zhí)行后返回元信息*protocol.Tool
和處理函數(shù)ToolHandlerFunc
。
服務(wù)啟動
- 調(diào)用
s.Run()
啟動服務(wù),開始監(jiān)聽請求。
- 調(diào)用
主程序入口實現(xiàn)
代碼位于 main
包中,作為程序啟動入口,具體實現(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ù)運行的地址和端口
- 參數(shù)名稱:
調(diào)用
flag.Parse()
解析命令行參數(shù)
服務(wù)啟動
- 調(diào)用
server.Run(*addr)
啟動服務(wù) - 將解析后的
address
參數(shù)值傳遞給服務(wù)啟動函數(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 .
運行容器:
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 集成
你可以通過以下兩種方式集成 mcp-ip-geo
服務(wù):
可執(zhí)行文件集成(本地運行)
{ "mcpServers": { "mcp-ip-geo": { "command": "/path/to/mcp-ip-geo" } } }
HTTP 接口集成(連接到已運行的服務(wù))
{ "mcpServers": { "mcp-ip-geo": { "url": "http://host:port/sse" } } }
效果演示
小結(jié)
本文將詳細(xì)介紹 mcp-ip-geo
—— 一個用于查詢 IP
信息的 MCP
服務(wù)器的實現(xiàn)細(xì)節(jié)。該服務(wù)器目前支持兩種數(shù)據(jù)傳輸方式:stdio
和 SSE(Server-Sent Events)
。未來還計劃支持 Streamable HTTP
傳輸方式,并持續(xù)擴展更多實用的工具(tools
)模塊。
到此這篇關(guān)于Go語言開發(fā)實現(xiàn)查詢IP信息的MCP服務(wù)器的文章就介紹到這了,更多相關(guān)Go MCP服務(wù)器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
初學(xué)Go必備的vscode插件及最常用快捷鍵和代碼自動補全
這篇文章主要給大家介紹了關(guān)于初學(xué)vscode寫Go必備的vscode插件及最常用快捷鍵和代碼自動補全的相關(guān)資料,由于vscode是開源免費的,而且開發(fā)支持vscode的插件相對比較容易,更新速度也很快,需要的朋友可以參考下2023-07-07Go語言基于HTTP的內(nèi)存緩存服務(wù)的實現(xiàn)
這篇文章主要介紹了Go語言基于HTTP的內(nèi)存緩存服務(wù),本程序采用REST接口,支持設(shè)置(Set)、獲取(Get)和刪除(Del)這3個基本操作,同時還支持對緩存服務(wù)狀態(tài)進(jìn)行查詢,需要的朋友可以參考下2022-08-08go實現(xiàn)整型的二進(jìn)制轉(zhuǎn)化的方法
這篇文章主要介紹了go實現(xiàn)整型的二進(jìn)制轉(zhuǎn)化的方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值 ,需要的朋友可以參考下2019-07-07