Skip to content

Comments

Faces MCP#62

Open
kflynn wants to merge 4 commits intomainfrom
faces-mcp
Open

Faces MCP#62
kflynn wants to merge 4 commits intomainfrom
faces-mcp

Conversation

@kflynn
Copy link
Collaborator

@kflynn kflynn commented Jan 17, 2026

Have an MCP server for Faces. At present, it supports tools to query and change the smiley and color in use, for the center, the edge, or all.

@kflynn kflynn requested review from Copilot and fragglehunter and removed request for Copilot January 30, 2026 16:30
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a Model Context Protocol (MCP) server to the Faces demo application, providing tools to programmatically query and modify smiley and color settings for the center, edge, or all faces. The MCP server supports both streaming HTTP (SSE) and stdio transports.

Changes:

  • Added MCP server implementation with five tools (query/update for smiley, color, and face services)
  • Integrated MCP server into build system and Helm charts
  • Configured Docker images and Kubernetes deployments with Rollout support

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 20 comments.

Show a summary per file
File Description
make-gorel.py Adds MCP build configuration to the build system
.goreleaser.yaml Adds MCP binary builds and Docker images for arm64/amd64
faces-chart/values.yaml Adds MCP service configuration and rollout strategy
faces-chart/templates/mcp.yaml Defines Kubernetes Service, Rollout, and Deployment resources for MCP
faces-chart/templates/_frontend.yaml Adds helper templates for MCP image, affinity, and resources
cmd/generic/mcp/main.go MCP server entry point with transport mode selection
cmd/generic/mcp/server.go Core MCP server implementation with JSON-RPC 2.0 support
cmd/generic/mcp/types.go Type definitions for MCP protocol
cmd/generic/mcp/tool_*.go Tool implementations for querying and updating services
cmd/generic/mcp/README.md Documentation for MCP server usage and configuration

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

log.Fatal(err)
}
} else {
// stdio mode (default) - standard MCP protocol
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Misleading comment. The code on line 39 sets the default to "sse", but this comment incorrectly states that stdio is the default. The comment should match the code, which defaults to SSE mode.

Suggested change
// stdio mode (default) - standard MCP protocol
// stdio mode - standard MCP protocol

Copilot uses AI. Check for mistakes.
return
}
fmt.Fprintf(w, "data: %s\n\n", string(msg))
w.(http.Flusher).Flush()
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsafe type assertion without a check. If the ResponseWriter doesn't implement http.Flusher, this will panic. Use the comma-ok idiom to safely check if the type assertion succeeds before calling Flush.

Copilot uses AI. Check for mistakes.
"endpoint": "/messages",
},
}
endpointBytes, _ := json.Marshal(endpoint)
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JSON marshaling error is silently ignored. If marshaling the endpoint discovery message fails, the error is discarded. Check the error and handle it appropriately, perhaps by logging it or aborting the SSE connection.

Suggested change
endpointBytes, _ := json.Marshal(endpoint)
endpointBytes, err := json.Marshal(endpoint)
if err != nil {
log.Printf("failed to marshal SSE endpoint discovery message for client %d: %v", clientID, err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}

Copilot uses AI. Check for mistakes.
}
endpointBytes, _ := json.Marshal(endpoint)
fmt.Fprintf(w, "data: %s\n\n", string(endpointBytes))
w.(http.Flusher).Flush()
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsafe type assertion without a check. If the ResponseWriter doesn't implement http.Flusher (though http.ResponseWriter typically does), this will panic. Use the comma-ok idiom to safely check if the type assertion succeeds before calling Flush.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,192 @@
---
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mcp.yaml template is missing a check for mcp.enabled. Based on the values.yaml configuration (line 24), mcp can be disabled, but this template will always deploy resources. The entire template should be wrapped with a check like {{- if .Values.mcp.enabled }} at the beginning and {{- end }} at the end, similar to how ingress.yaml checks .Values.ingress.enabled.

Copilot uses AI. Check for mistakes.
return CallToolResponse{}, err
}
defer resp.Body.Close()

Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The HTTP response status code is not checked. Non-200 responses should be treated as errors. Check resp.StatusCode and return an error if it's not http.StatusOK (200) to ensure failures in the face service are properly reported.

Suggested change
if resp.StatusCode != http.StatusOK {
errorBody, _ := io.ReadAll(resp.Body)
return CallToolResponse{}, fmt.Errorf("face service returned non-200 status %d (%s): %s", resp.StatusCode, resp.Status, string(errorBody))
}

Copilot uses AI. Check for mistakes.
Comment on lines +235 to +236
w.Header().Set("Access-Control-Allow-Origin", "*")

Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overly permissive CORS configuration. The Access-Control-Allow-Origin header is set to "*" which allows any origin to access the MCP server. This could expose the service to unauthorized access. Consider restricting this to specific allowed origins or making it configurable via environment variable.

Suggested change
w.Header().Set("Access-Control-Allow-Origin", "*")
// Configure CORS origin via environment variable to avoid overly-permissive default.
// If MCP_ALLOWED_ORIGIN is not set, no Access-Control-Allow-Origin header is sent.
if allowedOrigin := os.Getenv("MCP_ALLOWED_ORIGIN"); allowedOrigin != "" {
w.Header().Set("Access-Control-Allow-Origin", allowedOrigin)
}

Copilot uses AI. Check for mistakes.
{{- end }}
ports:
- name: http
containerPort: 8000
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent container port configuration in Rollout. The containerPort is set to 8000 here, but in the Deployment section (line 189) it's set to 3000. The application code defaults to port 3000 (main.go:43), so both sections should use containerPort 3000 for consistency.

Suggested change
containerPort: 8000
containerPort: 3000

Copilot uses AI. Check for mistakes.
}

func (t *UpdateColorTool) Handle(ctx context.Context, s *MCPServer, args map[string]interface{}) (CallToolResponse, error) {
newColor := args["color"].(string)
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsafe type assertion without a check. If the "color" argument is missing or not a string, this will panic. Add a type check with the comma-ok idiom and return an error if the required parameter is not provided or has the wrong type.

Suggested change
newColor := args["color"].(string)
colorValue, ok := args["color"]
if !ok {
return CallToolResponse{}, fmt.Errorf("missing required parameter 'color'")
}
newColor, ok := colorValue.(string)
if !ok {
return CallToolResponse{}, fmt.Errorf("parameter 'color' must be a string")
}

Copilot uses AI. Check for mistakes.
Comment on lines +14 to +16
- **update_smiley_emojis**: Update success and failure emojis for the
smiley service via HTTP PUT
- **update_color_colors**: Update success and failure colors for the
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tool names in README don't match actual implementation. The README lists "update_smiley_emojis" and "update_color_colors", but the actual tool names are "update_smiley" and "update_color" (as seen in tool_update_smiley.go:34 and tool_update_color.go:34).

Suggested change
- **update_smiley_emojis**: Update success and failure emojis for the
smiley service via HTTP PUT
- **update_color_colors**: Update success and failure colors for the
- **update_smiley**: Update success and failure emojis for the
smiley service via HTTP PUT
- **update_color**: Update success and failure colors for the

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants