返回市场
皮层

皮层

作者:FreePeak21 星标更新:2025-05-18

项目介绍

<h1 align="center"> <img alt="主标志" src="logo.svg" width="150"/> <br/> Cortex </h1> <h4 align="center">使用Golang声明式地构建MCP服务器</h4> <p align="center"> <a href="https://pkg.go.dev/github.com/FreePeak/cortex"><img src="https://pkg.go.dev/badge/github.com/FreePeak/cortex.svg" alt="Go参考"></a> <a href="https://goreportcard.com/report/github.com/FreePeak/cortex"><img src="https://goreportcard.com/badge/github.com/FreePeak/cortex" alt="Go报告卡"></a> <a href="https://github.com/FreePeak/cortex/actions/workflows/go.yml"><img src="https://github.com/FreePeak/cortex/actions/workflows/go.yml/badge.svg" alt="Go工作流"></a> <a href="https://opensource.org/licenses/Apache-2.0"><img src="https://img.shields.io/badge/License-Apache%202.0-blue.svg" alt="许可证:Apache 2.0"></a> <a href="https://github.com/FreePeak/cortex/graphs/contributors"><img src="https://img.shields.io/github/contributors/FreePeak/cortex" alt="贡献者"></a> </p>

目录

概述

模型上下文协议允许应用程序以标准化的方式为LLMs提供上下文,将提供上下文的关注点与实际的LLM交互分离。Cortex实现了完整的MCP规范,使其易于:

  • 构建暴露资源和工具的MCP服务器
  • 使用标准传输方式如STDIO和服务器发送事件(SSE)
  • 处理所有MCP协议消息和生命周期事件
  • 遵循Go的最佳实践和干净架构原则
  • 将Cortex嵌入到现有的服务器和应用程序中

注意: 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?

模型上下文协议(MCP)是一个标准化协议,它允许应用程序以安全且高效的方式为LLMs提供上下文。它将提供上下文和工具的关注点与实际的LLM交互分离。MCP服务器可以:

  • 通过资源(只读数据端点)暴露数据
  • 通过工具(可执行函数)提供功能
  • 通过提示(可重用模板)定义交互模式
  • 支持各种传输方法(STDIO、HTTP/SSE)

核心概念

服务器

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

对于命令行工具和直接集成:

// 启动一个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")

HTTP与SSE

对于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

Cortex可以嵌入到现有应用程序中,以添加MCP功能而不必运行单独的服务器。这对于与现有的Web框架或应用程序(如PocketBase)集成非常有用。

HTTP服务器集成

您可以轻松地将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)
}

PocketBase集成

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目录中:

  • STDIO服务器:一个简单的MCP服务器,通过STDIO通信(examples/stdio-server
  • SSE服务器:一个使用HTTP和服务器发送事件进行通信的服务器(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。

  1. 分叉仓库
  2. 创建您的功能分支(git checkout -b feature/amazing-feature
  3. 提交更改(git commit -m '添加一些惊人的功能'
  4. 推送到分支(git push origin feature/amazing-feature
  5. 打开一个Pull Request

许可