如何实现一个MCP server呢?

以github.com/mark3labs/mcp-go为例

开始以一个简单的查看文件列表工具作为范例,来展示该如何开发mcp server

func main() {
	// 创建 MCP 服务器
	mcpServer := server.NewMCPServer(
		"file-server",
		"1.0.0",
		server.WithResourceCapabilities(true, true),
		server.WithPromptCapabilities(true),
		server.WithToolCapabilities(true),
	)

	// 添加查看文件列表的工具
	mcpServer.AddTool(mcp.NewTool(
		ToolListFiles,
		mcp.WithDescription("List files in ~/Documents"),
	), handleListFiles)

	// 创建 SSE 服务器
	sseServer := server.NewSSEServer(mcpServer,
		server.WithBaseURL("http://localhost:8080"),
		server.WithSSEEndpoint("/sse"),
		server.WithMessageEndpoint("/message"),
	)

	// 启动服务器
	go func() {
		if err := sseServer.Start(":8080"); err != nil && err != http.ErrServerClosed {
			fmt.Printf("Failed to start server: %v\n", err)
		}
	}()

	fmt.Println("Server started on :8080")
	// 保持程序运行
	select {}
}

// 处理查看文件列表的工具请求
func handleListFiles(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
	documentsPath, err := os.UserHomeDir()
	if err != nil {
		return nil, err
	}
	documentsPath = filepath.Join(documentsPath, "Documents")

	files, err := ioutil.ReadDir(documentsPath)
	if err != nil {
		return nil, err
	}

	var fileNames []string
	for _, file := range files {
		fileNames = append(fileNames, file.Name())
	}

	return &mcp.CallToolResult{
		Content: []mcp.Content{
			mcp.TextContent{
				Type: "text",
				Text: fmt.Sprintf("%v", fileNames),
			},
		},
	}, nil
}

server启动

服务器初始化

接收服务器的名称、版本和一系列可选参数,用于配置服务器的功能和能力。通过传入不同的 ServerOption,可以启用或禁用特定的功能,如资源管理、工具调用、提示处理等

// NewMCPServer creates a new MCP server instance with the given name, version and options
func NewMCPServer(
	name, version string,
	opts ...ServerOption,
) *MCPServer {
	s := &MCPServer{
		resources:            make(map[string]resourceEntry),
		resourceTemplates:    make(map[string]resourceTemplateEntry),
		prompts:              make(map[string]mcp.Prompt),
		promptHandlers:       make(map[string]PromptHandlerFunc),
		tools:                make(map[string]ServerTool),
		name:                 name,
		version:              version,
		notificationHandlers: make(map[string]NotificationHandlerFunc),
		capabilities: serverCapabilities{
			tools:     nil,
			resources: nil,
			prompts:   nil,
			logging:   false,
		},
	}

	for _, opt := range opts {
		opt(s)
	}

	return s
}

资源、功能注册

MCP 服务器可以暴露各种资源和功能,包括资源(Resources)、工具(Tools)和提示(Prompts)。这些资源和功能需要在服务器启动前进行注册。

资源是MCP中的上下文对象,用于跨步骤携带信息、文件、图片、结构化数据等

{
  "resources": [
    {
      "id": "logs-result-123",
      "type": "text",
      "name": "分析结果",
      "data": "这里是日志分析结果..."
    }
  ]
}

将资源和对应的处理函数关联起来,当客户端请求读取该资源时,服务器会调用相应的处理函数来返回资源内容。

// AddResource registers a new resource and its handler
func (s *MCPServer) AddResource(
    resource mcp.Resource,
    handler ResourceHandlerFunc,
) {
    s.capabilitiesMu.Lock()
    if s.capabilities.resources == nil {
       s.capabilities.resources = &resourceCapabilities{}
    }
    s.capabilitiesMu.Unlock()

    s.resourcesMu.Lock()
    defer s.resourcesMu.Unlock()
    s.resources[resource.URI] = resourceEntry{
       resource: resource,
       handler:  handler,
    }
}

工具注册

工具是 MCP 中的一种功能,允许client调用mcp server上的特定操作。

// AddTool registers a new tool and its handler
func (s *MCPServer) AddTool(tool mcp.Tool, handler ToolHandlerFunc) {
    s.AddTools(ServerTool{Tool: tool, Handler: handler})
}

// AddTools registers multiple tools at once
func (s *MCPServer) AddTools(tools ...ServerTool) {
    s.capabilitiesMu.Lock()
    if s.capabilities.tools == nil {
       s.capabilities.tools = &toolCapabilities{}
    }
    s.capabilitiesMu.Unlock()

    s.toolsMu.Lock()
    for _, entry := range tools {
       s.tools[entry.Tool.Name] = entry
    }
    s.toolsMu.Unlock()

    // Send notification to all initialized sessions
    s.sendNotificationToAllClients("notifications/tools/list_changed", nil)
}

server消息处理

HandleMessage 方法是 MCP 服务器处理传入 JSON - RPC 消息的核心方法,它会根据消息的类型和方法进行不同的处理,并返回相应的响应。比如初始化请求、心跳请求、列出资源请求、列出工具请求、调用工具等

// HandleMessage processes an incoming JSON-RPC message and returns an appropriate response
func (s *MCPServer) HandleMessage(
	ctx context.Context,
	message json.RawMessage,
) mcp.JSONRPCMessage {
	// Add server to context
	ctx = context.WithValue(ctx, serverKey{}, s)
	var err *requestError

	var baseMessage struct {
		JSONRPC string        `json:"jsonrpc"`
		Method  mcp.MCPMethod `json:"method"`
		ID      any           `json:"id,omitempty"`
	}

	if err := json.Unmarshal(message, &baseMessage); err != nil {
		return createErrorResponse(
			nil,
			mcp.PARSE_ERROR,
			"Failed to parse message",
		)
	}

	// Check for valid JSONRPC version
	if baseMessage.JSONRPC != mcp.JSONRPC_VERSION {
		return createErrorResponse(
			baseMessage.ID,
			mcp.INVALID_REQUEST,
			"Invalid JSON-RPC version",
		)
	}

    // 如果消息 ID 为空,说明这是一个通知消息
    if baseMessage.ID == nil {
        var notification mcp.JSONRPCNotification
        // 尝试将消息解析为通知消息结构体
        if err := json.Unmarshal(message, &notification); err != nil {
            // 如果解析通知消息失败,返回一个解析错误响应
            return createErrorResponse(
                nil,
                mcp.PARSE_ERROR,
                "Failed to parse notification",
            )
        }
        // 处理通知消息
        s.handleNotification(ctx, notification)
        // 通知消息不需要响应,返回 nil
        return nil 
    }

	switch baseMessage.Method {   // 根据不同的方法名进行不同的处理
    switch baseMessage.Method {
    case mcp.MethodInitialize:
        // 初始化请求
        var request mcp.InitializeRequest
        var result *mcp.InitializeResult
        // 尝试将消息解析为初始化请求结构体
        if unmarshalErr := json.Unmarshal(message, &request); unmarshalErr != nil {
            // 如果解析失败,记录错误信息
            err = &requestError{
                id:   baseMessage.ID,
                code: mcp.INVALID_REQUEST,
                err:  &UnparseableMessageError{message: message, err: unmarshalErr, method: baseMessage.Method},
            }
        } else {
            // 调用钩子函数,在处理初始化请求前执行一些操作
            s.hooks.beforeInitialize(ctx, baseMessage.ID, &request)
            // 处理初始化请求
            result, err = s.handleInitialize(ctx, baseMessage.ID, request)
        }
        if err != nil {
            // 如果处理过程中出现错误,调用钩子函数记录错误信息,并返回错误响应
            s.hooks.onError(ctx, baseMessage.ID, baseMessage.Method, &request, err)
            return err.ToJSONRPCError()
        }
        // 调用钩子函数,在处理初始化请求后执行一些操作
        s.hooks.afterInitialize(ctx, baseMessage.ID, &request, result)
        // 返回初始化请求的响应
        return createResponse(baseMessage.ID, *result)
      
    case mcp.MethodPing:
        // 心跳请求
        var request mcp.PingRequest
        var result *mcp.EmptyResult
        // 尝试将消息解析为心跳请求结构体
        if unmarshalErr := json.Unmarshal(message, &request); unmarshalErr != nil {
            // 如果解析失败,记录错误信息
            err = &requestError{
                id:   baseMessage.ID,
                code: mcp.INVALID_REQUEST,
                err:  &UnparseableMessageError{message: message, err: unmarshalErr, method: baseMessage.Method},
            }
        } else {
            // 调用钩子函数,在处理心跳请求前执行一些操作
            s.hooks.beforePing(ctx, baseMessage.ID, &request)
            // 处理心跳请求
            result, err = s.handlePing(ctx, baseMessage.ID, request)
        }
        if err != nil {
            // 如果处理过程中出现错误,调用钩子函数记录错误信息,并返回错误响应
            s.hooks.onError(ctx, baseMessage.ID, baseMessage.Method, &request, err)
            return err.ToJSONRPCError()
        }
        // 调用钩子函数,在处理心跳请求后执行一些操作
        s.hooks.afterPing(ctx, baseMessage.ID, &request, result)
        // 返回心跳请求的响应
        return createResponse(baseMessage.ID, *result)
      
    case mcp.MethodResourcesList:
        // 列出资源请求
        var request mcp.ListResourcesRequest
        var result *mcp.ListResourcesResult
        // 检查服务器是否支持资源功能
        if s.capabilities.resources == nil {
            // 如果不支持,记录方法未找到错误信息
            err = &requestError{
                id:   baseMessage.ID,
                code: mcp.METHOD_NOT_FOUND,
                err:  fmt.Errorf("resources %w", ErrUnsupported),
            }
        } else if unmarshalErr := json.Unmarshal(message, &request); unmarshalErr != nil {
            // 如果解析失败,记录错误信息
            err = &requestError{
                id:   baseMessage.ID,
                code: mcp.INVALID_REQUEST,
                err:  &UnparseableMessageError{message: message, err: unmarshalErr, method: baseMessage.Method},
            }
        } else {
            // 调用钩子函数,在处理列出资源请求前执行一些操作
            s.hooks.beforeListResources(ctx, baseMessage.ID, &request)
            // 处理列出资源请求
            result, err = s.handleListResources(ctx, baseMessage.ID, request)
        }
        if err != nil {
            // 如果处理过程中出现错误,调用钩子函数记录错误信息,并返回错误响应
            s.hooks.onError(ctx, baseMessage.ID, baseMessage.Method, &request, err)
            return err.ToJSONRPCError()
        }
        // 调用钩子函数,在处理列出资源请求后执行一些操作
        s.hooks.afterListResources(ctx, baseMessage.ID, &request, result)
        // 返回列出资源请求的响应
        return createResponse(baseMessage.ID, *result)
      
    case mcp.MethodResourcesTemplatesList:
        // 列出资源模板请求
        var request mcp.ListResourceTemplatesRequest
        var result *mcp.ListResourceTemplatesResult
        // 检查服务器是否支持资源功能
        if s.capabilities.resources == nil {
            // 如果不支持,记录方法未找到错误信息
            err = &requestError{
                id:   baseMessage.ID,
                code: mcp.METHOD_NOT_FOUND,
                err:  fmt.Errorf("resources %w", ErrUnsupported),
            }
        } else if unmarshalErr := json.Unmarshal(message, &request); unmarshalErr != nil {
            // 如果解析失败,记录错误信息
            err = &requestError{
                id:   baseMessage.ID,
                code: mcp.INVALID_REQUEST,
                err:  &UnparseableMessageError{message: message, err: unmarshalErr, method: baseMessage.Method},
            }
        } else {
            // 调用钩子函数,在处理列出资源模板请求前执行一些操作
            s.hooks.beforeListResourceTemplates(ctx, baseMessage.ID, &request)
            // 处理列出资源模板请求
            result, err = s.handleListResourceTemplates(ctx, baseMessage.ID, request)
        }
        if err != nil {
            // 如果处理过程中出现错误,调用钩子函数记录错误信息,并返回错误响应
            s.hooks.onError(ctx, baseMessage.ID, baseMessage.Method, &request, err)
            return err.ToJSONRPCError()
        }
        // 调用钩子函数,在处理列出资源模板请求后执行一些操作
        s.hooks.afterListResourceTemplates(ctx, baseMessage.ID, &request, result)
        // 返回列出资源模板请求的响应
        return createResponse(baseMessage.ID, *result)
      
    case mcp.MethodResourcesRead:
        // 读取资源请求
        var request mcp.ReadResourceRequest
        var result *mcp.ReadResourceResult
        // 检查服务器是否支持资源功能
        if s.capabilities.resources == nil {
            // 如果不支持,记录方法未找到错误信息
            err = &requestError{
                id:   baseMessage.ID,
                code: mcp.METHOD_NOT_FOUND,
                err:  fmt.Errorf("resources %w", ErrUnsupported),
            }
        } else if unmarshalErr := json.Unmarshal(message, &request); unmarshalErr != nil {
            // 如果解析失败,记录错误信息
            err = &requestError{
                id:   baseMessage.ID,
                code: mcp.INVALID_REQUEST,
                err:  &UnparseableMessageError{message: message, err: unmarshalErr, method: baseMessage.Method},
            }
        } else {
            // 调用钩子函数,在处理读取资源请求前执行一些操作
            s.hooks.beforeReadResource(ctx, baseMessage.ID, &request)
            // 处理读取资源请求
            result, err = s.handleReadResource(ctx, baseMessage.ID, request)
        }
        if err != nil {
            // 如果处理过程中出现错误,调用钩子函数记录错误信息,并返回错误响应
            s.hooks.onError(ctx, baseMessage.ID, baseMessage.Method, &request, err)
            return err.ToJSONRPCError()
        }
        // 调用钩子函数,在处理读取资源请求后执行一些操作
        s.hooks.afterReadResource(ctx, baseMessage.ID, &request, result)
        // 返回读取资源请求的响应
        return createResponse(baseMessage.ID, *result)
      
    case mcp.MethodPromptsList:
        // 列出提示请求
        var request mcp.ListPromptsRequest
        var result *mcp.ListPromptsResult
        // 检查服务器是否支持提示功能
        if s.capabilities.prompts == nil {
            // 如果不支持,记录方法未找到错误信息
            err = &requestError{
                id:   baseMessage.ID,
                code: mcp.METHOD_NOT_FOUND,
                err:  fmt.Errorf("prompts %w", ErrUnsupported),
            }
        } else if unmarshalErr := json.Unmarshal(message, &request); unmarshalErr != nil {
            // 如果解析失败,记录错误信息
            err = &requestError{
                id:   baseMessage.ID,
                code: mcp.INVALID_REQUEST,
                err:  &UnparseableMessageError{message: message, err: unmarshalErr, method: baseMessage.Method},
            }
        } else {
            // 调用钩子函数,在处理列出提示请求前执行一些操作
            s.hooks.beforeListPrompts(ctx, baseMessage.ID, &request)
            // 处理列出提示请求
            result, err = s.handleListPrompts(ctx, baseMessage.ID, request)
        }
        if err != nil {
            // 如果处理过程中出现错误,调用钩子函数记录错误信息,并返回错误响应
            s.hooks.onError(ctx, baseMessage.ID, baseMessage.Method, &request, err)
            return err.ToJSONRPCError()
        }
        // 调用钩子函数,在处理列出提示请求后执行一些操作
        s.hooks.afterListPrompts(ctx, baseMessage.ID, &request, result)
        // 返回列出提示请求的响应
        return createResponse(baseMessage.ID, *result)
      
    case mcp.MethodPromptsGet:
        // 获取提示请求
        var request mcp.GetPromptRequest
        var result *mcp.GetPromptResult
        // 检查服务器是否支持提示功能
        if s.capabilities.prompts == nil {
            // 如果不支持,记录方法未找到错误信息
            err = &requestError{
                id:   baseMessage.ID,
                code: mcp.METHOD_NOT_FOUND,
                err:  fmt.Errorf("prompts %w", ErrUnsupported),
            }
        } else if unmarshalErr := json.Unmarshal(message, &request); unmarshalErr != nil {
            // 如果解析失败,记录错误信息
            err = &requestError{
                id:   baseMessage.ID,
                code: mcp.INVALID_REQUEST,
                err:  &UnparseableMessageError{message: message, err: unmarshalErr, method: baseMessage.Method},
            }
        } else {
            // 调用钩子函数,在处理获取提示请求前执行一些操作
            s.hooks.beforeGetPrompt(ctx, baseMessage.ID, &request)
            // 处理获取提示请求
            result, err = s.handleGetPrompt(ctx, baseMessage.ID, request)
        }
        if err != nil {
            // 如果处理过程中出现错误,调用钩子函数记录错误信息,并返回错误响应
            s.hooks.onError(ctx, baseMessage.ID, baseMessage.Method, &request, err)
            return err.ToJSONRPCError()
        }
        // 调用钩子函数,在处理获取提示请求后执行一些操作
        s.hooks.afterGetPrompt(ctx, baseMessage.ID, &request, result)
        // 返回获取提示请求的响应
        return createResponse(baseMessage.ID, *result)
      
    case mcp.MethodToolsList:
        // 列出工具请求
        var request mcp.ListToolsRequest
        var result *mcp.ListToolsResult
        // 检查服务器是否支持工具功能
        if s.capabilities.tools == nil {
            // 如果不支持,记录方法未找到错误信息
            err = &requestError{
                id:   baseMessage.ID,
                code: mcp.METHOD_NOT_FOUND,
                err:  fmt.Errorf("tools %w", ErrUnsupported),
            }
        } else if unmarshalErr := json.Unmarshal(message, &request); unmarshalErr != nil {
            // 如果解析失败,记录错误信息
            err = &requestError{
                id:   baseMessage.ID,
                code: mcp.INVALID_REQUEST,
                err:  &UnparseableMessageError{message: message, err: unmarshalErr, method: baseMessage.Method},
            }
        } else {
            // 调用钩子函数,在处理列出工具请求前执行一些操作
            s.hooks.beforeListTools(ctx, baseMessage.ID, &request)
            // 处理列出工具请求
            result, err = s.handleListTools(ctx, baseMessage.ID, request)
        }
        if err != nil {
            // 如果处理过程中出现错误,调用钩子函数记录错误信息,并返回错误响应
            s.hooks.onError(ctx, baseMessage.ID, baseMessage.Method, &request, err)
            return err.ToJSONRPCError()
        }
        // 调用钩子函数,在处理列出工具请求后执行一些操作
        s.hooks.afterListTools(ctx, baseMessage.ID, &request, result)
        // 返回列出工具请求的响应
        return createResponse(baseMessage.ID, *result)
      
    case mcp.MethodToolsCall:
        // 调用工具请求
        var request mcp.CallToolRequest
        var result *mcp.CallToolResult
        // 检查服务器是否支持工具功能
        if s.capabilities.tools == nil {
            // 如果不支持,记录方法未找到错误信息
            err = &requestError{
                id:   baseMessage.ID,
                code: mcp.METHOD_NOT_FOUND,
                err:  fmt.Errorf("tools %w", ErrUnsupported),
            }
        } else if unmarshalErr := json.Unmarshal(message, &request); unmarshalErr != nil {
            // 如果解析失败,记录错误信息
            err = &requestError{
                id:   baseMessage.ID,
                code: mcp.INVALID_REQUEST,
                err:  &UnparseableMessageError{message: message, err: unmarshalErr, method: baseMessage.Method},
            }
        } else {
            // 调用钩子函数,在处理调用工具请求前执行一些操作
            s.hooks.beforeCallTool(ctx, baseMessage.ID, &request)
            // 处理调用工具请求
            result, err = s.handleToolCall(ctx, baseMessage.ID, request)
        }
        if err != nil {
            // 如果处理过程中出现错误,调用钩子函数记录错误信息,并返回错误响应
            s.hooks.onError(ctx, baseMessage.ID, baseMessage.Method, &request, err)
            return err.ToJSONRPCError()
        }
        // 调用钩子函数,在处理调用工具请求后执行一些操作
        s.hooks.afterCallTool(ctx, baseMessage.ID, &request, result)
        // 返回调用工具请求的响应
        return createResponse(baseMessage.ID, *result)
      
    default:
        // 如果方法名不匹配任何已知方法,返回方法未找到错误响应
        return createErrorResponse(
            baseMessage.ID,
            mcp.METHOD_NOT_FOUND,
            fmt.Sprintf("Method %s not found", baseMessage.Method),
        )
    }
}

初始化请求处理

handleInitialize 方法用于处理初始化请求,根据服务器配置设置相应的功能能力(资源、提示、工具、日志),构建并返回初始化结果,同时若上下文中存在客户端会话则对其进行初始化。

func (s *MCPServer) handleInitialize(
	ctx context.Context,
	id interface{},
	request mcp.InitializeRequest,
) (*mcp.InitializeResult, *requestError) {
	capabilities := mcp.ServerCapabilities{}

	// Only add resource capabilities if they're configured
	if s.capabilities.resources != nil {
		capabilities.Resources = &struct {
			Subscribe   bool `json:"subscribe,omitempty"`
			ListChanged bool `json:"listChanged,omitempty"`
		}{
			Subscribe:   s.capabilities.resources.subscribe,
			ListChanged: s.capabilities.resources.listChanged,
		}
	}

	// Only add prompt capabilities if they're configured
	if s.capabilities.prompts != nil {
		capabilities.Prompts = &struct {
			ListChanged bool `json:"listChanged,omitempty"`
		}{
			ListChanged: s.capabilities.prompts.listChanged,
		}
	}

	// Only add tool capabilities if they're configured
	if s.capabilities.tools != nil {
		capabilities.Tools = &struct {
			ListChanged bool `json:"listChanged,omitempty"`
		}{
			ListChanged: s.capabilities.tools.listChanged,
		}
	}

	if s.capabilities.logging {
		capabilities.Logging = &struct{}{}
	}

	result := mcp.InitializeResult{
		ProtocolVersion: mcp.LATEST_PROTOCOL_VERSION,
		ServerInfo: mcp.Implementation{
			Name:    s.name,
			Version: s.version,
		},
		Capabilities: capabilities,
		Instructions: s.instructions,
	}

	if session := ClientSessionFromContext(ctx); session != nil {
		session.Initialize()
	}
	return &result, nil
}

资源列表请求处理

handleListResources 处理列出资源的请求。它从服务器中检索所有资源,对资源进行排序,并根据请求中的分页参数返回相应的资源列表

func (s *MCPServer) handleListResources(
	ctx context.Context,
	id interface{},
	request mcp.ListResourcesRequest,
) (*mcp.ListResourcesResult, *requestError) {
	// 对资源进行读锁定,防止在读取资源时其他 goroutine 修改资源
	s.resourcesMu.RLock()
	// 初始化一个切片,用于存储所有资源,切片的初始容量为服务器中资源的数量
	resources := make([]mcp.Resource, 0, len(s.resources))
	// 遍历服务器中存储的所有资源条目
	for _, entry := range s.resources {
		// 将每个资源条目中的资源添加到 resources 切片中
		resources = append(resources, entry.resource)
	}
	// 释放资源的读锁定
	s.resourcesMu.RUnlock()

	// 对资源切片进行排序,按照资源的名称进行升序排序
	sort.Slice(resources, func(i, j int) bool {
		return resources[i].Name < resources[j].Name
	})
	// 根据请求中的游标参数进行分页,返回当前页的资源列表、下一页的游标和可能的错误
	resourcesToReturn, nextCursor, err := listByPagination[mcp.Resource](ctx, s, request.Params.Cursor, resources)
	if err != nil {
		// 如果分页过程中出现错误,返回一个包含错误信息的请求错误对象
		return nil, &requestError{
			id:   id,
			code: mcp.INVALID_PARAMS,
			err:  err,
		}
	}
	// 创建一个 ListResourcesResult 对象,包含当前页的资源列表和下一页的游标
	result := mcp.ListResourcesResult{
		Resources: resourcesToReturn,
		PaginatedResult: mcp.PaginatedResult{
			NextCursor: nextCursor,
		},
	}
	// 返回包含资源列表和分页信息的结果对象,以及 nil 错误
	return &result, nil
}

工具调用请求处理

handleToolCall 处理调用工具的请求。它接收一个上下文、请求 ID 和调用工具的请求作为参数,然后查找对应的工具处理程序,应用中间件,并执行处理程序以获取工具调用的结果。

func (s *MCPServer) handleToolCall(
	ctx context.Context,
	id interface{},
	request mcp.CallToolRequest,
) (*mcp.CallToolResult, *requestError) {
	// 对工具进行读锁定,防止在查找工具时其他 goroutine 修改工具列表
	s.toolsMu.RLock()
	// 从服务器存储的工具中查找请求的工具
	tool, ok := s.tools[request.Params.Name]
	// 释放工具的读锁定
	s.toolsMu.RUnlock()

	// 如果未找到请求的工具,返回一个包含错误信息的请求错误对象
	if !ok {
		return nil, &requestError{
			id:   id,
			code: mcp.INVALID_PARAMS,
			err:  fmt.Errorf("tool '%s' not found: %w", request.Params.Name, ErrToolNotFound),
		}
	}

	// 获取找到的工具的处理程序
	finalHandler := tool.Handler

	// 对中间件进行读锁定,防止在获取中间件时其他 goroutine 修改中间件列表
	s.middlewareMu.RLock()
	// 获取服务器存储的所有工具处理程序中间件
	mw := s.toolHandlerMiddlewares
	// 释放中间件的读锁定
	s.middlewareMu.RUnlock()

	// 反向遍历中间件列表,将中间件依次应用到最终处理程序上
	// 这样可以确保中间件按照添加的顺序依次执行
	for i := len(mw) - 1; i >= 0; i-- {
		finalHandler = mw[i](finalHandler)
	}

	// 使用最终处理程序处理工具调用请求,获取工具调用的结果和可能的错误
	result, err := finalHandler(ctx, request)
	// 如果处理过程中出现错误,返回一个包含错误信息的请求错误对象
	if err != nil {
		return nil, &requestError{
			id:   id,
			code: mcp.INTERNAL_ERROR,
			err:  err,
		}
	}

	// 返回工具调用的结果和 nil 错误
	return result, nil
}

你可能感兴趣的:(lang,ai,ai,go)