Skip to content

Commit 435b952

Browse files
author
Marek Safarik
committed
copilot review
Signed-off-by: Marek Safarik <[email protected]>
1 parent 5185ed6 commit 435b952

File tree

1 file changed

+49
-24
lines changed

1 file changed

+49
-24
lines changed

mcp-client/main.go

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,23 @@ import (
1515
)
1616

1717
const (
18-
serverPath = "../backend/server"
19-
mcpClientName = "mcp-client"
20-
mcpClientVersion = "v1.0.0"
18+
defaultServerPath = "../backend/server"
19+
mcpClientName = "mcp-client"
20+
mcpClientVersion = "v1.0.0"
2121

2222
claudeModel = anthropic.ModelClaude3_5HaikuLatest
2323
maxTokens = 2048
2424
maxAgentTurns = 5
2525

26-
systemPrompt = `You are an autonomous agent with access to Keylime system management tools. Your goal is to help users manage and monitor their Keylime infrastructure.
26+
systemPrompt = `You are an AI assistant with access to Keylime system management tools. Your goal is to help users manage and monitor their Keylime infrastructure.
2727
28-
When given a task:
28+
You have a maximum of 5 conversation turns to complete the task. When given a task:
2929
1. Break it down into steps if needed
3030
2. Use available tools to gather information and take actions
3131
3. Chain multiple tool calls together to accomplish complex tasks
3232
4. Provide clear explanations of what you're doing and what you found
33-
5. If you encounter failures, investigate and suggest solutions`
33+
5. If you encounter failures, investigate and suggest solutions
34+
6. Work efficiently to complete tasks within the turn limit`
3435
)
3536

3637
func main() {
@@ -49,6 +50,10 @@ func main() {
4950
log.Fatal("Usage: go run main.go <content>")
5051
}
5152
userQuery := strings.Join(os.Args[1:], " ")
53+
userQuery = strings.TrimSpace(userQuery)
54+
if userQuery == "" {
55+
log.Fatal("Error: user query cannot be empty")
56+
}
5257

5358
session, err := connectToMCPServer(ctx)
5459
if err != nil {
@@ -70,6 +75,11 @@ func main() {
7075

7176
// connectToMCPServer establishes connection to the MCP server
7277
func connectToMCPServer(ctx context.Context) (*mcp.ClientSession, error) {
78+
serverPath := os.Getenv("MCP_SERVER_PATH")
79+
if serverPath == "" {
80+
serverPath = defaultServerPath
81+
}
82+
7383
if _, err := os.Stat(serverPath); os.IsNotExist(err) {
7484
return nil, fmt.Errorf("server not found: %s", serverPath)
7585
}
@@ -89,9 +99,12 @@ func connectToMCPServer(ctx context.Context) (*mcp.ClientSession, error) {
8999
// Monitor server process for unexpected exits
90100
if cmd.Process != nil {
91101
go func() {
92-
state, err := cmd.Process.Wait()
93-
if err != nil {
94-
log.Printf("[Warning] MCP server process monitoring failed: %v", err)
102+
state, waitErr := cmd.Process.Wait()
103+
if ctx.Err() != nil {
104+
return
105+
}
106+
if waitErr != nil {
107+
log.Printf("[Warning] MCP server process monitoring failed: %v", waitErr)
95108
} else if !state.Success() {
96109
log.Printf("[Error] MCP server process exited unexpectedly with status: %v", state)
97110
} else {
@@ -127,10 +140,20 @@ func convertMCPToolToClaudeTool(tool *mcp.Tool) anthropic.ToolUnionParam {
127140
inputSchemaMap = map[string]any{}
128141
}
129142

130-
properties := inputSchemaMap["properties"]
143+
var properties any
144+
if p, ok := inputSchemaMap["properties"].(map[string]any); ok && p != nil {
145+
properties = p
146+
} else {
147+
properties = map[string]any{}
148+
}
149+
131150
var required []string
132-
if r, ok := inputSchemaMap["required"].([]string); ok {
133-
required = r
151+
if r, ok := inputSchemaMap["required"].([]interface{}); ok {
152+
for _, v := range r {
153+
if s, ok := v.(string); ok {
154+
required = append(required, s)
155+
}
156+
}
134157
}
135158

136159
toolParam := anthropic.ToolUnionParamOfTool(
@@ -174,6 +197,8 @@ func runAgentLoop(ctx context.Context, client anthropic.Client, session *mcp.Cli
174197
messages = append(messages, anthropic.NewAssistantMessage(assistantContent...))
175198
messages = append(messages, anthropic.NewUserMessage(toolResults...))
176199
}
200+
201+
log.Printf("\n=== Maximum turns reached, requesting summary ===")
177202
finalMessage(ctx, client, messages)
178203

179204
return nil
@@ -270,27 +295,27 @@ func extractTextContent(content []mcp.Content) string {
270295

271296
// finalMessage asks LLM to summarize what happened during session if max turns are reached
272297
func finalMessage(ctx context.Context, client anthropic.Client, messages []anthropic.MessageParam) {
273-
274-
summaryPrompt := `I've reached the maximum number of allowed turns. Please provide a summary of:\n
275-
1. What you accomplished so far
276-
2. What still needs to be done
277-
3. Any issues or blockers encountered`
298+
summaryPrompt := `I've reached the maximum number of allowed turns. Please provide a summary of:
299+
1. What you accomplished so far
300+
2. What still needs to be done
301+
3. Any issues or blockers encountered`
278302

279303
messages = append(messages, anthropic.NewUserMessage(anthropic.NewTextBlock(summaryPrompt)))
280304

281-
finalMessage, err := client.Messages.New(ctx, anthropic.MessageNewParams{
305+
finalMsg, err := client.Messages.New(ctx, anthropic.MessageNewParams{
282306
Model: claudeModel,
283307
MaxTokens: maxTokens,
284308
System: []anthropic.TextBlockParam{{Type: "text", Text: systemPrompt}},
285309
Messages: messages,
286310
})
287311
if err != nil {
288-
log.Printf("Failed to get final summary: %v", err)
289-
} else {
290-
for _, block := range finalMessage.Content {
291-
if textBlock, ok := block.AsAny().(anthropic.TextBlock); ok {
292-
fmt.Println(textBlock.Text)
293-
}
312+
log.Printf("failed to get final summary: %v", err)
313+
return
314+
}
315+
316+
for _, block := range finalMsg.Content {
317+
if textBlock, ok := block.AsAny().(anthropic.TextBlock); ok {
318+
fmt.Println(textBlock.Text)
294319
}
295320
}
296321
}

0 commit comments

Comments
 (0)