模型上下文协议允许应用程序以标准化的方式为LLMs提供上下文,将提供上下文的关注点与实际的LLM交互分离。Cortex实现了完整的MCP规范,使其易于:
注意: Cortex始终更新以符合来自spec.modelcontextprotocol.io/latest的最新MCP规范。
go get github.com/FreePeak/cortex
让我们创建一个简单的MCP服务器,该服务器暴露一个回声工具:
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/FreePeak/cortex/pkg/server"
"github.com/FreePeak/cortex/pkg/tools"
)
func main() {
// 创建一个将日志写入stderr而不是stdout的日志器
// 这对于STDIO服务器至关重要,因为stdout只能包含JSON-RPC消息
logger := log.New(os.Stderr, "[cortex] ", log.LstdFlags)
// 创建服务器
mcpServer := server.NewMCPServer("Echo Server Example", "1.0.0", logger)
// 创建一个回声工具
echoTool := tools.NewTool("echo",
tools.WithDescription("回声返回输入的消息"),
tools.WithString("message",
tools.Description("要回声返回的消息"),
tools.Required(),
),
)
// 带有数组参数的工具示例
arrayExampleTool := tools.NewTool("array_example",
tools.WithDescription("带有数组参数的工具示例"),
tools.WithArray("values",
tools.Description("字符串值数组"),
tools.Required(),
tools.Items(map[string]interface{}{
"type": "string",
}),
),
)
// 添加带处理器的工具到服务器
ctx := context.Background()
err := mcpServer.AddTool(ctx, echoTool, handleEcho)
if err != nil {
logger.Fatalf("添加工具时出错:%v", err)
}
err = mcpServer.AddTool(ctx, arrayExampleTool, handleArrayExample)
if err != nil {
logger.Fatalf("添加数组示例工具时出错:%v", err)
}
// 将服务器状态写入stderr而不是stdout,以保持干净的JSON协议
fmt.Fprintf(os.Stderr, "启动Echo服务器...\n")
fmt.Fprintf(os.Stderr, "通过stdin发送JSON-RPC消息以与服务器交互。\n")
fmt.Fprintf(os.Stderr, `尝试:{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"echo","parameters":{"message":"Hello, World!"}}}\n`)
// 通过STDIO服务
if err := mcpServer.ServeStdio(); err != nil {
fmt.Fprintf(os.Stderr, "错误:%v\n", err)
os.Exit(1)
}
}
// 回声工具处理器
func handleEcho(ctx context.Context, request server.ToolCallRequest) (interface{}, error) {
// 提取message参数
message, ok := request.Parameters["message"].(string)
if !ok {
return nil, fmt.Errorf("缺少或无效的'message'参数")
}
// 返回MCP协议期望的回声响应格式
return map[string]interface{}{
"content": []map[string]interface{}{
{
"type": "text",
"text": message,
},
},
}, nil
}
// 数组示例工具处理器
func handleArrayExample(ctx context.Context, request server.ToolCallRequest) (interface{}, error) {
// 提取values参数
values, ok := request.Parameters["values"].([]interface{})
if !ok {
return nil, fmt.Errorf("缺少或无效的'values'参数")
}
// 将values转换为字符串数组
stringValues := make([]string, len(values))
for i, v := range values {
stringValues[i] = v.(string)
}
// 返回MCP协议期望的数组响应格式
return map[string]interface{}{
"content": stringValues,
}, nil
}
模型上下文协议(MCP)是一个标准化协议,它允许应用程序以安全且高效的方式为LLMs提供上下文。它将提供上下文和工具的关注点与实际的LLM交互分离。MCP服务器可以:
MCP服务器是您与MCP协议的核心接口。它处理连接管理、协议合规性和消息路由:
// 创建一个新的MCP服务器并带有日志器
mcpServer := server.NewMCPServer("我的应用", "1.0.0", logger)
工具让LLMs通过您的服务器采取行动。与资源不同,工具预期执行计算并具有副作用:
// 定义一个计算器工具
calculatorTool := tools.NewTool("calculator",
tools.WithDescription("执行基本数学运算"),
tools.WithString("operation",
tools.Description("要执行的操作(加、减、乘、除)"),
tools.Required(),
),
tools.WithNumber("a",
tools.Description("第一个操作数"),
tools.Required(),
),
tools.WithNumber("b",
tools.Description("第二个操作数"),
tools.Required(),
),
)
// 将工具添加到服务器并带有处理器
mcpServer.AddTool(ctx, calculatorTool, handleCalculator)
提供者允许您将相关的工具和资源分组到一个可以轻松注册到服务器的单个包中:
// 创建一个天气提供者
weatherProvider, err := weather.NewWeatherProvider(logger)
if err != nil {
logger.Fatalf("创建天气提供者失败:%v", err)
}
// 注册提供者到服务器
err = mcpServer.RegisterProvider(ctx, weatherProvider)
if err != nil {
logger.Fatalf("注册天气提供者失败:%v", err)
}
资源是您向LLMs暴露数据的方式。它们类似于REST API中的GET端点——它们提供数据但不应执行显著的计算或具有副作用:
// 创建一个资源(当前使用内部API)
resource := &domain.Resource{
URI: "sample://hello-world",
Name: "Hello World资源",
Description: "用于演示目的的样本资源",
MIMEType: "text/plain",
}
提示是可重用的模板,有助于LLMs有效地与您的服务器交互:
// 创建一个提示(当前使用内部API)
codeReviewPrompt := &domain.Prompt{
Name: "review-code",
Description: "代码审查提示",
Template: "请审查此代码:\n\n{{.code}}",
Parameters: []domain.PromptParameter{
{
Name: "code",
Description: "要审查的代码",
Type: "string",
Required: true,
},
},
}
// 注意:提示支持正在公共API中进行更新
根据您的使用情况,Go中的MCP服务器可以连接到不同的传输方式:
对于命令行工具和直接集成:
// 启动一个STDIO服务器
if err := mcpServer.ServeStdio(); err != nil {
fmt.Fprintf(os.Stderr, "错误:%v\n", err)
os.Exit(1)
}
重要提示:当使用STDIO时,所有日志必须定向到stderr以保持stdout上的干净JSON-RPC协议:
// 创建一个将日志写入stderr的日志器
logger := log.New(os.Stderr, "[cortex] ", log.LstdFlags)
// 所有调试/状态消息应使用stderr
fmt.Fprintf(os.Stderr, "服务器启动中...\n")
对于Web应用程序,您可以使用服务器发送事件(SSE)进行实时通信:
// 配置HTTP地址
mcpServer.SetAddress(":8080")
// 启动带有SSE支持的HTTP服务器
if err := mcpServer.ServeHTTP(); err != nil {
log.Fatalf("HTTP服务器错误:%v", err)
}
// 优雅关闭
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := mcpServer.Shutdown(ctx); err != nil {
log.Fatalf("服务器关闭错误:%v", err)
}
您还可以同时运行多个协议服务器,通过使用goroutines:
// 启动HTTP服务器
go func() {
if err := mcpServer.ServeHTTP(); err != nil {
log.Fatalf("HTTP服务器错误:%v", err)
}
}()
// 启动STDIO服务器
go func() {
if err := mcpServer.ServeStdio(); err != nil {
log.Fatalf("STDIO服务器错误:%v", err)
}
}()
// 等待关闭信号
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
<-stop
有关测试和调试Cortex服务器的更多详细信息,请参阅测试指南。
Cortex可以嵌入到现有应用程序中,以添加MCP功能而不必运行单独的服务器。这对于与现有的Web框架或应用程序(如PocketBase)集成非常有用。
您可以轻松地将Cortex与任何Go HTTP服务器集成:
package main
import (
"log"
"net/http"
"os"
"github.com/FreePeak/cortex/pkg/server"
"github.com/FreePeak/cortex/pkg/tools"
)
func main() {
// 创建一个日志器
logger := log.New(os.Stderr, "[cortex] ", log.LstdFlags)
// 创建一个MCP服务器
mcpServer := server.NewMCPServer("嵌入式MCP服务器", "1.0.0", logger)
// 添加一些工具
echoTool := tools.NewTool("echo",
tools.WithDescription("回声返回输入的消息"),
tools.WithString("message",
tools.Description("要回声返回的消息"),
tools.Required(),
),
)
// 将工具添加到服务器
mcpServer.AddTool(context.Background(), echoTool, func(ctx context.Context, request server.ToolCallRequest) (interface{}, error) {
message := request.Parameters["message"].(string)
return map[string]interface{}{
"content": []map[string]interface{}{
{
"type": "text",
"text": message,
},
},
}, nil
})
// 为MCP服务器创建一个HTTP适配器
adapter := server.NewHTTPAdapter(mcpServer, server.WithPath("/api/mcp"))
// 在您的HTTP服务器中使用适配器
http.Handle("/api/mcp/", adapter.Handler())
// 添加您的其他路由
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("来自主服务器的问候!"))
})
// 启动服务器
logger.Println("在:8080上启动服务器")
http.ListenAndServe(":8080", nil)
}
Cortex可以与PocketBase集成,这是一个开源后端,具有数据库、认证和管理UI:
package main
import (
"log"
"github.com/pocketbase/pocketbase"
"github.com/pocketbase/pocketbase/core"
"github.com/FreePeak/cortex/pkg/integration/pocketbase"
"github.com/FreePeak/cortex/pkg/tools"
)
func main() {
// 创建一个新的PocketBase应用
app := pocketbase.New()
// 初始化Cortex插件
plugin := pocketbase.NewCortexPlugin(
pocketbase.WithName("PocketBase MCP服务器"),
pocketbase.WithVersion("1.0.0"),
pocketbase.WithBasePath("/api/mcp"),
)
// 向插件添加工具
echoTool := tools.NewTool("echo",
tools.WithDescription("回声返回输入的消息"),
tools.WithString("message",
tools.Description("要回声返回的消息"),
tools.Required(),
),
)
// 添加带有处理器的工具
plugin.AddTool(echoTool, func(ctx context.Context, request pocketbase.ToolCallRequest) (interface{}, error) {
message := request.Parameters["message"].(string)
return map[string]interface{}{
"content": []map[string]interface{}{
{
"type": "text",
"text": message,
},
},
}, nil
})
// 将插件注册到PocketBase
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
// 注册插件
return plugin.RegisterWithPocketBase(app)
})
// 启动PocketBase应用
if err := app.Start(); err != nil {
log.Fatal(err)
}
}
有关嵌入Cortex的更详细文档,请参阅嵌入指南。
仓库包括几个基本示例在examples目录中:
examples/stdio-server)examples/sse-server)examples/multi-protocol)examples目录还包括更高级的用例:
examples/providers)
Cortex包含一个扩展服务器能力的插件系统:
// 基于BaseProvider创建一个新的提供者
type MyProvider struct {
*plugin.BaseProvider
}
// 创建一个新的提供者实例
func NewMyProvider(logger *log.Logger) (*MyProvider, error) {
info := plugin.ProviderInfo{
ID: "my-provider",
Name: "我的提供者",
Version: "1.0.0",
Description: "我工具的自定义提供者",
Author: "您的名字",
URL: "https://github.com/yourusername/myrepo",
}
baseProvider := plugin.NewBaseProvider(info, logger)
provider := &MyProvider{
BaseProvider: baseProvider,
}
// 向提供者注册工具
// ...
return provider, nil
}
Cortex代码库被组织成几个包:
pkg/server:核心服务器实现pkg/tools:工具的创建和管理pkg/plugin:扩展服务器能力的插件系统pkg/types:通用类型和接口pkg/builder:用于创建复杂对象的构建器欢迎贡献!请随时提交Pull Request。
git checkout -b feature/amazing-feature)git commit -m '添加一些惊人的功能')git push origin feature/amazing-feature)