最近在逛github的时候发现了一个有趣的mcp host cli 工具,还是由mcp-go框架的大佬写的,整体代码量也不多,但是功能还是很完善的,支持大多数模型的接入,可以自己按照需求配置mcp-server,就是当前还缺少流式输出,导致在问一些需要返回大量token的场景,不知道是超时了,还是正在响应中。
话不多说,先看下使用效果: 可以看到整体的 TUI 实现效果还是很不错的。
基本配置参数
代码拉取下来后在root文件中将config、model、url和apikey按照自己的使用初始化配置一下,后续通过 go install 命令后就可以在命令行使用中不再输入这些参数了。
下面是我自己使用 deepseek v3 api的示例:
go
func init() {
rootCmd.PersistentFlags().
StringVar(&configFile, "config", "C:\\Users\\Administrator\\.mcp.json", "")
rootCmd.PersistentFlags().
StringVarP(&modelFlag, "model", "m", "openai:deepseek-chat",
"model to use (format: provider:model, e.g. anthropic:claude-3-5-sonnet-latest or ollama:qwen2.5:3b)")
flags := rootCmd.PersistentFlags()
flags.StringVar(&openaiBaseURL, "openai-url", "https://api.deepseek.com/v1", "base URL for OpenAI API (defaults to api.openai.com)")
flags.StringVar(&anthropicBaseURL, "anthropic-url", "", "base URL for Anthropic API (defaults to api.anthropic.com)")
flags.StringVar(&openaiAPIKey, "openai-api-key", "***", "OpenAI API key")
flags.StringVar(&anthropicAPIKey, "anthropic-api-key", "", "Anthropic API key")
}
核心函数
runPrompt 方法是实现与大模型交互,集成mcp client和server来增强模型的核心实现。
- 接收用户输入并将其记录到消息历史中。
- 调用语言模型生成响应,支持重试机制以应对过载错误。
- 处理语言模型返回的工具调用请求,并将工具结果反馈给模型。
- 将最终的响应和工具结果更新到消息历史中。
其简化版代码如下:
go
func runPrompt(
provider llm.Provider,
mcpClients map[string]*mcpclient.StdioMCPClient,
tools []llm.Tool,
prompt string,
messages *[]history.HistoryMessage,
) error {
// 接收用户输入并将其记录到消息历史中。
if prompt != "" {
*messages = append(
*messages,
history.HistoryMessage{
},
)
}
llmMessages := make([]llm.Message, len(*messages))
for i := range *messages {
llmMessages[i] = &(*messages)[i]
}
for {
//调用大模型
action := func() {
message, err = provider.CreateMessage(
context.Background(),
prompt,
llmMessages,
tools,
)
}
_ = spinner.New().Title("Thinking...").Action(action).Run()
if err != nil {
// 重试
return err
}
// If we got here, the request succeeded
break
}
var messageContent []history.ContentBlock
// Handle the message response
if str, err := renderer.Render("\nAssistant: "); err == nil {
fmt.Print(str)
}
toolResults := []history.ContentBlock{}
messageContent = []history.ContentBlock{}
// 渲染大模型输出内容
if message.GetContent() != "" {
if err := updateRenderer(); err != nil {
return fmt.Errorf("error updating renderer: %v", err)
}
str, err := renderer.Render(message.GetContent() + "\n")
}
//处理调用工具的结果
for _, toolCall := range message.GetToolCalls() {
log.Info("🔧 Using tool", "name", toolCall.GetName())
input, _ := json.Marshal(toolCall.GetArguments())
messageContent = append(messageContent, history.ContentBlock{
Type: "tool_use",
ID: toolCall.GetID(),
Name: toolCall.GetName(),
Input: input,
})
// 省略...
resultBlock.Text = strings.TrimSpace(resultText)
log.Debug("created tool result block",
"block", resultBlock,
"tool_id", toolCall.GetID())
toolResults = append(toolResults, resultBlock)
}
}
*messages = append(*messages, history.HistoryMessage{
Role: message.GetRole(),
Content: messageContent,
})
if len(toolResults) > 0 {
*messages = append(*messages, history.HistoryMessage{
Role: "user",
Content: toolResults,
})
// Make another call to get Claude's response to the tool results
return runPrompt(provider, mcpClients, tools, "", messages)
}
fmt.Println() // Add spacing
return nil
}
项目地址
MCPhost的github仓库在mark3labs/mcphost。