【技术文档摘要】
<h1 align="center"> <img alt="主logo" src="./docs/content/assets/logo.png" width="150"/> <br/> Foxy Contexts </h1> <!-- --8<-- [start:content] --> <h4 align="center">使用Golang声明式构建MCP服务器</h4> <p align="center"> <a href="https://pkg.go.dev/github.com/strowk/foxy-contexts"><img src="https://pkg.go.dev/badge/github.com/strowk/foxy-contexts.svg" alt="Go参考"></a> <a href="https://goreportcard.com/report/github.com/strowk/foxy-contexts"><img src="https://goreportcard.com/badge/github.com/strowk/foxy-contexts" alt="Go参考"></a> <a href="https://github.com/strowk/foxy-contexts/actions/workflows/test.yaml"><img src="https://github.com/strowk/foxy-contexts/actions/workflows/test.yaml/badge.svg"/></a> <a href="https://github.com/strowk/foxy-contexts/actions/workflows/golangci-lint.yaml"><img src="https://github.com/strowk/foxy-contexts/actions/workflows/golangci-lint.yaml/badge.svg"/></a> </p> <p align="center"> <a href="#features">特性</a> 🦊 <a href="#tool-example">工具示例</a> 🦊 <a href="https://foxy-contexts.str4.io">文档</a> 🦊 <a href="https://github.com/strowk/foxy-contexts">源代码</a> </p>Foxy contexts 是一个用于构建支持 Model Context Protocol 的上下文服务器的 Golang 库。
此库仅支持协议的服务端。使用它可以采用声明式方法构建上下文服务器,通过定义 工具、资源 和 提示,然后将它们注册到你的 app.Builder 中,该 app.Builder 使用的是 Uber 的 fx 应用程序,并且你可以将其注入到容器中。
通过这种方法,你可以轻松地将调用/读取/获取逻辑与工具/资源/提示的定义放在同一个地方,同时依赖注入允许你重用共享部分,如客户端、数据库连接等。
以下是已实现和计划实现的功能列表:
toolinput 帮助定义工具输入模式并验证到达的输入foxytestfoxytest 包进行功能测试例如尝试以下操作
git clone https://github.com/strowk/foxy-contexts
cd foxy-contexts/examples/list_current_dir_files_tool
npx @modelcontextprotocol/inspector go run main.go
,然后在浏览器中打开 http://localhost:6274 并尝试使用 list-current-dir-files。
这是来自 examples/list_current_dir_files_tool/main.go 示例的代码(在实际应用中,你可能希望将其拆分为多个文件):
package main
import (
"fmt"
"os"
"github.com/strowk/foxy-contexts/pkg/app"
"github.com/strowk/foxy-contexts/pkg/fxctx"
"github.com/strowk/foxy-contexts/pkg/mcp"
"github.com/strowk/foxy-contexts/pkg/stdio"
"go.uber.org/fx"
"go.uber.org/fx/fxevent"
"go.uber.org/zap"
)
// 此示例定义了一个用于 MCP 服务器的 `list-current-dir-files` 工具,该工具会打印当前目录中的文件
// ,运行它:
// npx @modelcontextprotocol/inspector go run main.go
// ,然后在浏览器中打开 http://localhost:6274
// ,然后点击连接
// ,然后点击列出工具
// ,然后点击 `list-current-dir-files`
// NewListCurrentDirFilesTool 定义了一个列出当前目录文件的工具
func NewListCurrentDirFilesTool() fxctx.Tool {
return fxctx.NewTool(
// 当工具被列出时,这些信息会被使用:
&mcp.Tool{
Name: "list-current-dir-files",
Description: Ptr("列出当前目录中的文件"),
InputSchema: mcp.ToolInputSchema{
Type: "object",
Properties: map[string]map[string]interface{}{},
Required: []string{},
},
},
// 这是当工具被调用时执行的回调函数:
func(_ context.Context, args map[string]interface{}) *mcp.CallToolResult {
files, err := os.ReadDir(".")
if err != nil {
return &mcp.CallToolResult{
IsError: Ptr(true),
Meta: map[string]interface{}{},
Content: []interface{}{
mcp.TextContent{
Type: "text",
Text: fmt.Sprintf("读取目录失败:%v", err),
},
},
}
}
var contents []interface{} = make([]interface{}, len(files))
for i, f := range files {
contents[i] = mcp.TextContent{
Type: "text",
Text: f.Name(),
}
}
return &mcp.CallToolResult{
Meta: map[string]interface{}{},
Content: contents,
IsError: Ptr(false),
}
},
)
}
func main() {
app.
NewBuilder().
// 将工具添加到应用程序中
WithTool(NewListCurrentDirFilesTool).
// 设置服务器
WithName("list-current-dir-files").
WithVersion("0.0.1").
WithTransport(stdio.NewTransport()).
// 配置 fx 日志记录以仅显示错误
WithFxOptions(fx.Provide(func() *zap.Logger {
cfg := zap.NewDevelopmentConfig()
cfg.Level.SetLevel(zap.ErrorLevel)
logger, _ := cfg.Build()
return logger
}),
fx.Option(fx.WithLogger(
func(logger *zap.Logger) fxevent.Logger {
return &fxevent.ZapLogger{Logger: logger}
},
)),
).
Run()
}
func Ptr[T any](v T) *T {
return &v
}