Skip to content

Commit 9f938b9

Browse files
committed
chore: refactor RegisterTools
1 parent 4afd149 commit 9f938b9

File tree

3 files changed

+58
-44
lines changed

3 files changed

+58
-44
lines changed

coderd/mcp/mcp.go

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,10 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
6767
s.streamableServer.ServeHTTP(w, r)
6868
}
6969

70-
// RegisterTools registers MCP tools with the server
71-
func (s *Server) RegisterTools(client *codersdk.Client, tools []toolsdk.GenericTool) error {
70+
// Register all available MCP tools with the server excluding:
71+
// - ReportTask - which requires dependencies not available in the remote MCP context
72+
// - ChatGPT search and fetch tools, which are redundant with the standard tools.
73+
func (s *Server) RegisterTools(client *codersdk.Client) error {
7274
if client == nil {
7375
return xerrors.New("client cannot be nil: MCP HTTP server requires authenticated client")
7476
}
@@ -79,7 +81,39 @@ func (s *Server) RegisterTools(client *codersdk.Client, tools []toolsdk.GenericT
7981
return xerrors.Errorf("failed to initialize tool dependencies: %w", err)
8082
}
8183

82-
for _, tool := range tools {
84+
for _, tool := range toolsdk.All {
85+
// the ReportTask tool requires dependencies not available in the remote MCP context
86+
// the ChatGPT search and fetch tools are redundant with the standard tools.
87+
if tool.Name == toolsdk.ToolNameReportTask ||
88+
tool.Name == toolsdk.ToolNameChatGPTSearch || tool.Name == toolsdk.ToolNameChatGPTFetch {
89+
continue
90+
}
91+
92+
s.mcpServer.AddTools(mcpFromSDK(tool, toolDeps))
93+
}
94+
return nil
95+
}
96+
97+
// ChatGPT tools are the search and fetch tools as defined in https://platform.openai.com/docs/mcp.
98+
// We do not expose any extra ones because ChatGPT has an undocumented "Safety Scan" feature.
99+
// In my experiments, if I included extra tools in the MCP server, ChatGPT would often - but not always -
100+
// refuse to add Coder as a connector.
101+
func (s *Server) RegisterChatGPTTools(client *codersdk.Client) error {
102+
if client == nil {
103+
return xerrors.New("client cannot be nil: MCP HTTP server requires authenticated client")
104+
}
105+
106+
// Create tool dependencies
107+
toolDeps, err := toolsdk.NewDeps(client)
108+
if err != nil {
109+
return xerrors.Errorf("failed to initialize tool dependencies: %w", err)
110+
}
111+
112+
for _, tool := range toolsdk.All {
113+
if tool.Name == toolsdk.ToolNameChatGPTSearch || tool.Name == toolsdk.ToolNameChatGPTFetch {
114+
continue
115+
}
116+
83117
s.mcpServer.AddTools(mcpFromSDK(tool, toolDeps))
84118
}
85119
return nil

coderd/mcp/mcp_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,13 @@ func TestMCPHTTP_ToolRegistration(t *testing.T) {
110110
require.NoError(t, err)
111111

112112
// Test registering tools with nil client should return error
113-
err = server.RegisterTools(nil, toolsdk.All)
113+
err = server.RegisterTools(nil)
114114
require.Error(t, err)
115115
require.Contains(t, err.Error(), "client cannot be nil", "Should reject nil client with appropriate error message")
116116

117117
// Test registering tools with valid client should succeed
118118
client := &codersdk.Client{}
119-
err = server.RegisterTools(client, toolsdk.All)
119+
err = server.RegisterTools(client)
120120
require.NoError(t, err)
121121

122122
// Verify that all expected tools are available in the toolsdk

coderd/mcp_http.go

Lines changed: 19 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package coderd
22

33
import (
4+
"fmt"
45
"net/http"
56

67
"cdr.dev/slog"
@@ -9,7 +10,6 @@ import (
910
"github.com/coder/coder/v2/coderd/httpmw"
1011
"github.com/coder/coder/v2/coderd/mcp"
1112
"github.com/coder/coder/v2/codersdk"
12-
"github.com/coder/coder/v2/codersdk/toolsdk"
1313
)
1414

1515
type MCPToolset string
@@ -23,61 +23,41 @@ const (
2323
// It supports a "toolset" query parameter to select the set of tools to register.
2424
func (api *API) mcpHTTPHandler() http.Handler {
2525
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
26+
// Create MCP server instance for each request
27+
mcpServer, err := mcp.NewServer(api.Logger.Named("mcp"))
28+
if err != nil {
29+
api.Logger.Error(r.Context(), "failed to create MCP server", slog.Error(err))
30+
httpapi.Write(r.Context(), w, http.StatusInternalServerError, codersdk.Response{
31+
Message: "MCP server initialization failed",
32+
})
33+
return
34+
}
35+
authenticatedClient := codersdk.New(api.AccessURL)
36+
// Extract the original session token from the request
37+
authenticatedClient.SetSessionToken(httpmw.APITokenFromRequest(r))
38+
2639
toolset := MCPToolset(r.URL.Query().Get("toolset"))
2740
// Default to standard toolset if no toolset is specified.
2841
if toolset == "" {
2942
toolset = MCPToolsetStandard
3043
}
3144

32-
mcpTools := []toolsdk.GenericTool{}
3345
switch toolset {
3446
case MCPToolsetStandard:
35-
// Register all available tools, but exclude:
36-
// - ReportTask - which requires dependencies not available in the remote MCP context
37-
// - ChatGPT search and fetch tools, which are redundant with the standard tools.
38-
for _, tool := range toolsdk.All {
39-
if tool.Name == toolsdk.ToolNameReportTask ||
40-
tool.Name == toolsdk.ToolNameChatGPTSearch || tool.Name == toolsdk.ToolNameChatGPTFetch {
41-
continue
42-
}
43-
mcpTools = append(mcpTools, tool)
47+
if err := mcpServer.RegisterTools(authenticatedClient); err != nil {
48+
api.Logger.Warn(r.Context(), "failed to register MCP tools", slog.Error(err))
4449
}
4550
case MCPToolsetChatGPT:
46-
// ChatGPT tools are the search and fetch tools as defined in https://platform.openai.com/docs/mcp.
47-
// We do not expose any extra ones because ChatGPT has an undocumented "Safety Scan" feature.
48-
// In my experiments, if I included extra tools in the MCP server, ChatGPT would often - but not always -
49-
// refuse to add Coder as a connector.
50-
for _, tool := range toolsdk.All {
51-
if tool.Name == toolsdk.ToolNameChatGPTSearch || tool.Name == toolsdk.ToolNameChatGPTFetch {
52-
mcpTools = append(mcpTools, tool)
53-
}
51+
if err := mcpServer.RegisterChatGPTTools(authenticatedClient); err != nil {
52+
api.Logger.Warn(r.Context(), "failed to register MCP tools", slog.Error(err))
5453
}
5554
default:
5655
httpapi.Write(r.Context(), w, http.StatusBadRequest, codersdk.Response{
57-
Message: "Invalid toolset",
56+
Message: fmt.Sprintf("Invalid toolset: %s", toolset),
5857
})
5958
return
6059
}
6160

62-
// Create MCP server instance for each request
63-
mcpServer, err := mcp.NewServer(api.Logger.Named("mcp"))
64-
if err != nil {
65-
api.Logger.Error(r.Context(), "failed to create MCP server", slog.Error(err))
66-
httpapi.Write(r.Context(), w, http.StatusInternalServerError, codersdk.Response{
67-
Message: "MCP server initialization failed",
68-
})
69-
return
70-
}
71-
72-
authenticatedClient := codersdk.New(api.AccessURL)
73-
// Extract the original session token from the request
74-
authenticatedClient.SetSessionToken(httpmw.APITokenFromRequest(r))
75-
76-
// Register tools with authenticated client
77-
if err := mcpServer.RegisterTools(authenticatedClient, mcpTools); err != nil {
78-
api.Logger.Warn(r.Context(), "failed to register MCP tools", slog.Error(err))
79-
}
80-
8161
// Handle the MCP request
8262
mcpServer.ServeHTTP(w, r)
8363
})

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy