关于 Cortex
Cortex 是一个用 Golang 声明式构建 MCP 服务的框架,支持以结构化方式暴露工具、资源和提示词。它面向 Go 开发者,并可嵌入已有的 HTTP 服务或应用。
主要功能
- 01声明式定义 MCP 服务
- 02支持工具、资源与提示词
- 03支持 stdio 与 HTTP/SSE 传输
- 04可嵌入已有 HTTP 服务或 PocketBase
- 05提供插件系统扩展服务能力
适用场景
- 01使用 Go 构建 MCP 服务
- 02将 MCP 能力嵌入现有 Go Web 应用
- 03通过 Provider 组织相关工具与资源
MCP 相关
Cortex 实现了 MCP 规范的完整协议,开发者可借助它构建 MCP 服务,向 MCP 客户端提供工具、资源与提示词。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
Cortex
使用 Golang 以声明式方式构建 MCP 服务
目录
概述
模型上下文协议允许应用以标准化的方式为大模型提供上下文,将提供上下文与实际的大模型交互分开处理。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() {
// Create a logger that writes to stderr instead of stdout
// This is critical for STDIO servers as stdout must only contain JSON-RPC messages
logger := log.New(os.Stderr, "[cortex] ", log.LstdFlags)
// Create the server
mcpServer := server.NewMCPServer("Echo Server Example", "1.0.0", logger)
// Create an echo tool
echoTool := tools.NewTool("echo",
tools.WithDescription("Echoes back the input message"),
tools.WithString("message",
tools.Description("The message to echo back"),
tools.Required(),
),
)
// Example of a tool with array parameter
arrayExampleTool := tools.NewTool("array_example",
tools.WithDescription("Example tool with array parameter"),
tools.WithArray("values",
tools.Description("Array of string values"),
tools.Required(),
tools.Items(map[string]interface{}{
"type": "string",
}),
),
)
// Add the tools to the server with handlers
ctx := context.Background()
err := mcpServer.AddTool(ctx, echoTool, handleEcho)
if err != nil {
logger.Fatalf("Error adding tool: %v", err)
}
err = mcpServer.AddTool(ctx, arrayExampleTool, handleArrayExample)
if err != nil {
logger.Fatalf("Error adding array example tool: %v", err)
}
// Write server status to stderr instead of stdout to maintain clean JSON protocol
fmt.Fprintf(os.Stderr, "Starting Echo Server...\n")
fmt.Fprintf(os.Stderr, "Send JSON-RPC messages via stdin to interact with the server.\n")
fmt.Fprintf(os.Stderr, `Try: {"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"echo","parameters":{"message":"Hello, World!"}}}\n`)
// Serve over stdio
if err := mcpServer.ServeStdio(); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
}
// Echo tool handler
func handleEcho(ctx context.Context, request server.ToolCallRequest) (interface{}, error) {
// Extract the message parameter
message, ok := request.Parameters["message"].(string)
if !ok {
return nil, fmt.Errorf("missing or invalid 'message' parameter")
}
// Return the echo response in the format expected by the MCP protocol
return map[string]interface{}{
"content": []map[string]interface{}{
{
"type": "text",
"text": message,
},
},
}, nil
}
// Array example tool handler
func handleArrayExample(ctx context.Context, request server.ToolCallRequest) (interface{}, error) {
// Extract the values parameter
values, ok := request.Parameters["values"].([]interface{})
if !ok {
return nil, fmt.Errorf("missing or invalid 'values' parameter")
}
// Convert values to string array
stringValues := make([]string, len(values))
for i, v := range values {
stringValues[i] = v.(string)
}
// Return the array response in the format expected by the MCP protocol
return map[string]interface{}{
"content": stringValues,
}, nil
}
什么是 MCP?
模型上下文协议(MCP) 是一种标准化协议,允许应用以安全高效的方式为大模型提供上下文。它将提供上下文和工具与实际的大模型交互分开处理。MCP 服务可以:
- 通过 资源(只读数据端点)公开数据
- 通过 工具(可执行函数)提供功能
- 通过 提示词(可复用模板)定义交互模式
- 支持多种传输方式(stdio、HTTP/SSE)
核心概念
服务端
MCP 服务端是你与 MCP 协议交互的核心接口。它负责连接管理、协议合规性和消息路由:
// Create a new MCP server with logger
mcpServer := server.NewMCPServer("My App", "1.0.0", logger)
工具
工具让大模型能够通过你的服务执行操作。与资源不同,工具通常会执行计算并产生副作用:
// Define a calculator tool
calculatorTool := tools.NewTool("calculator",
tools.WithDescription("Performs basic math operations"),
tools.WithString("operation",
tools.Description("The operation to perform (add, subtract, multiply, divide)"),
tools.Required(),
),
tools.WithNumber("a",
tools.Description("First operand"),
tools.Required(),
),
tools.WithNumber("b",
tools.Description("Second operand"),
tools.Required(),
),
)
// Add the tool to the server with a handler
mcpServer.AddTool(ctx, calculatorTool, handleCalculator)
提供程序
提供程序允许你将相关工具和资源组合成一个包,以便轻松注册到服务端:
// Create a weather provider
weatherProvider, err := weather.NewWeatherProvider(logger)
if err != nil {
logger.Fatalf("Failed to create weather provider: %v", err)
}
// Register the provider with the server
err = mcpServer.RegisterProvider(ctx, weatherProvider)
if err != nil {
logger.Fatalf("Failed to register weather provider: %v", err)
}
资源
资源用于向大模型公开数据。它们类似于 REST API 中的 GET 端点——提供数据,但不应执行大量计算或产生副作用:
// Create a resource (Currently using the internal API)
resource := &domain.Resource{
URI: "sample://hello-world",
Name: "Hello World Resource",
Description: "A sample resource for demonstration purposes",
MIMEType: "text/plain",
}
提示词
提示词是可重复使用的模板,可帮助大模型有效地与您的服务交互:
// Create a prompt (Currently using the internal API)
codeReviewPrompt := &domain.Prompt{
Name: "review-code",
Description: "A prompt for code review",
Template: "Please review this code:\n\n{{.code}}",
Parameters: []domain.PromptParameter{
{
Name: "code",
Description: "The code to review",
Type: "string",
Required: true,
},
},
}
// Note: Prompt support is being updated in the public API
运行您的服务
Go 中的 MCP 服务可根据您的使用场景连接到不同的传输方式:
STDIO
适用于命令行工具和直接集成:
// Start a stdio server
if err := mcpServer.ServeStdio(); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
重要提示:使用 STDIO 时,所有日志都必须输出到 stderr,以确保 stdout 上的 JSON-RPC 协议保持干净:
// Create a logger that writes to stderr
logger := log.New(os.Stderr, "[cortex] ", log.LstdFlags)
// All debug/status messages should use stderr
fmt.Fprintf(os.Stderr, "Server starting...\n")
HTTP 与 SSE
对于 Web 应用,您可以使用 Server-Sent Events(SSE)进行实时通信:
// Configure the HTTP address
mcpServer.SetAddress(":8080")
// Start an HTTP server with SSE support
if err := mcpServer.ServeHTTP(); err != nil {
log.Fatalf("HTTP server error: %v", err)
}
// For graceful shutdown
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := mcpServer.Shutdown(ctx); err != nil {
log.Fatalf("Server shutdown error: %v", err)
}
多协议
您还可以使用 goroutine 同时运行多个协议服务:
// Start an HTTP server
go func() {
if err := mcpServer.ServeHTTP(); err != nil {
log.Fatalf("HTTP server error: %v", err)
}
}()
// Start a STDIO server
go func() {
if err := mcpServer.ServeStdio(); err != nil {
log.Fatalf("STDIO server error: %v", err)
}
}()
// Wait for shutdown signal
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() {
// Create a logger
logger := log.New(os.Stderr, "[cortex] ", log.LstdFlags)
// Create an MCP server
mcpServer := server.NewMCPServer("Embedded MCP Server", "1.0.0", logger)
// Add some tools
echoTool := tools.NewTool("echo",
tools.WithDescription("Echoes back the input message"),
tools.WithString("message",
tools.Description("The message to echo back"),
tools.Required(),
),
)
// Add the tool to the server
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
})
// Create an HTTP adapter for the MCP server
adapter := server.NewHTTPAdapter(mcpServer, server.WithPath("/api/mcp"))
// Use the adapter in your HTTP server
http.Handle("/api/mcp/", adapter.Handler())
// Add your other routes
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello from the main server!"))
})
// Start the server
logger.Println("Starting server on :8080")
http.ListenAndServe(":8080", nil)
}
PocketBase 集成
Cortex 可与 PocketBase 集成。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() {
// Create a new PocketBase app
app := pocketbase.New()
// Initialize Cortex plugin
plugin := pocketbase.NewCortexPlugin(
pocketbase.WithName("PocketBase MCP Server"),
pocketbase.WithVersion("1.0.0"),
pocketbase.WithBasePath("/api/mcp"),
)
// Add tools to the plugin
echoTool := tools.NewTool("echo",
tools.WithDescription("Echoes back the input message"),
tools.WithString("message",
tools.Description("The message to echo back"),
tools.Required(),
),
)
// Add the tool with a handler
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
})
// Register the plugin with PocketBase
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
// Register the plugin
return plugin.RegisterWithPocketBase(app)
})
// Start the PocketBase app
if err := app.Start(); err != nil {
log.Fatal(err)
}
}
有关嵌入 Cortex 的详细文档,请参阅嵌入指南。
示例
基本示例
仓库的 examples 目录中包含多个基本示例:
- STDIO 服务:通过 STDIO 通信的简单 MCP 服务(
examples/stdio-server) - SSE 服务:使用 HTTP 和 Server-Sent Events 进行通信的服务(
examples/sse-server) - 多协议:可同时使用多种协议运行的服务(
examples/multi-protocol)
高级示例
examples 目录中还包含更高级的用例:
- Providers:展示如何创建和使用 provider 来组织相关工具的示例(
examples/providers)- 天气 Provider:演示如何创建用于天气相关工具的 provider
- 数据库 Provider:展示如何创建用于数据库操作的 provider
插件系统
Cortex 包含一个用于扩展服务功能的插件系统:
// Create a new provider based on the BaseProvider
type MyProvider struct {
*plugin.BaseProvider
}
// Create a new provider instance
func NewMyProvider(logger *log.Logger) (*MyProvider, error) {
info := plugin.ProviderInfo{
ID: "my-provider",
Name: "My Provider",
Version: "1.0.0",
Description: "A custom provider for my tools",
Author: "Your Name",
URL: "https://github.com/yourusername/myrepo",
}
baseProvider := plugin.NewBaseProvider(info, logger)
provider := &MyProvider{
BaseProvider: baseProvider,
}
// Register tools with the provider
// ...
return provider, nil
}
包结构
Cortex 代码库由多个包组成:
pkg/server:核心服务实现pkg/tools:工具的创建和管理pkg/plugin:用于扩展服务功能的插件系统pkg/types:通用类型和接口pkg/builder:用于创建复杂对象的构建器
贡献
欢迎贡献!请随时提交 Pull Request。
- Fork 此仓库
- 创建功能分支(
git checkout -b feature/amazing-feature) - 提交更改(
git commit -m 'Add some amazing feature') - 推送到分支(
git push origin feature/amazing-feature) - 创建 Pull Request
许可证
本项目采用 Apache License 2.0 许可,详情请参阅 LICENSE 文件。
支持与联系
- 如有问题或疑问,请发送邮件至 [email protected]
- 直接提交问题:问题跟踪器
- 如果 Cortex 对您的工作有所帮助,请考虑支持我们:
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。