fix(codersdk/toolsdk): fix tool schemata (#17365)

Fixes two issues with the MCP server:
- Ensures we have a non-null schema, as the following schema was making
claude-code unhappy:

 
```
        "inputSchema": { "type": "object", "properties": null },
```


- Skip adding the coder_report_task tool if an agent client is not
available. Otherwise the agent may try to report tasks and get confused.
This commit is contained in:
Cian Johnston
2025-04-11 18:58:17 +01:00
committed by GitHub
parent 6330b0d545
commit 7b0422b49b
2 changed files with 20 additions and 0 deletions
+12
View File
@@ -402,7 +402,9 @@ func mcpServerHandler(inv *serpent.Invocation, client *codersdk.Client, instruct
// Create a new context for the tools with all relevant information.
clientCtx := toolsdk.WithClient(ctx, client)
// Get the workspace agent token from the environment.
var hasAgentClient bool
if agentToken, err := getAgentToken(fs); err == nil && agentToken != "" {
hasAgentClient = true
agentClient := agentsdk.New(client.URL)
agentClient.SetSessionToken(agentToken)
clientCtx = toolsdk.WithAgentClient(clientCtx, agentClient)
@@ -417,6 +419,11 @@ func mcpServerHandler(inv *serpent.Invocation, client *codersdk.Client, instruct
// Register tools based on the allowlist (if specified)
for _, tool := range toolsdk.All {
// Skip adding the coder_report_task tool if there is no agent client
if !hasAgentClient && tool.Tool.Name == "coder_report_task" {
cliui.Warnf(inv.Stderr, "Task reporting not available")
continue
}
if len(allowedTools) == 0 || slices.ContainsFunc(allowedTools, func(t string) bool {
return t == tool.Tool.Name
}) {
@@ -689,6 +696,11 @@ func getAgentToken(fs afero.Fs) (string, error) {
// mcpFromSDK adapts a toolsdk.Tool to go-mcp's server.ServerTool.
// It assumes that the tool responds with a valid JSON object.
func mcpFromSDK(sdkTool toolsdk.Tool[any]) server.ServerTool {
// NOTE: some clients will silently refuse to use tools if there is an issue
// with the tool's schema or configuration.
if sdkTool.Schema.Properties == nil {
panic("developer error: schema properties cannot be nil")
}
return server.ServerTool{
Tool: mcp.Tool{
Name: sdkTool.Tool.Name,
+8
View File
@@ -259,6 +259,10 @@ is provisioned correctly and the agent can connect to the control plane.
Tool: aisdk.Tool{
Name: "coder_list_templates",
Description: "Lists templates for the authenticated user.",
Schema: aisdk.Schema{
Properties: map[string]any{},
Required: []string{},
},
},
Handler: func(ctx context.Context, _ map[string]any) ([]MinimalTemplate, error) {
client, err := clientFromContext(ctx)
@@ -318,6 +322,10 @@ is provisioned correctly and the agent can connect to the control plane.
Tool: aisdk.Tool{
Name: "coder_get_authenticated_user",
Description: "Get the currently authenticated user, similar to the `whoami` command.",
Schema: aisdk.Schema{
Properties: map[string]any{},
Required: []string{},
},
},
Handler: func(ctx context.Context, _ map[string]any) (codersdk.User, error) {
client, err := clientFromContext(ctx)