返回市场
狐狸上下文

狐狸上下文

作者:strowk109 星标更新:2025-11-19

项目介绍

【技术文档摘要】

<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 应用程序,并且你可以将其注入到容器中。

通过这种方法,你可以轻松地将调用/读取/获取逻辑与工具/资源/提示的定义放在同一个地方,同时依赖注入允许你重用共享部分,如客户端、数据库连接等。

特性

以下是已实现和计划实现的功能列表:

  • 基础(生命周期/心跳)
    • 进度(计划中)
  • 传输
    • 标准 I/O 传输
    • SSE 传输
    • 可流式传输的 HTTP 传输(测试版)
  • 工具
    • toolinput 帮助定义工具输入模式并验证到达的输入
  • 资源
    • 静态资源
    • 动态资源通过资源提供者
    • 动态资源通过资源模板(计划中)
    • 资源模板完成(计划中)
    • 资源订阅
  • 提示
  • 提示完成
  • 功能测试包 foxytest
  • 使用依赖注入的强大功能简单构建你的 MCP 服务器
  • 通过 MCP 日志(计划中)
  • 抽样(计划中)
  • 根节点(计划中)
  • 分页(计划中)
  • 通知列表更改(计划中)
  • 测试 - 使用 foxytest 包进行功能测试

查看 文档示例 获取更多信息。

工具示例

例如尝试以下操作

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
}