{"record":{"id":"be8abf10112d8b2a","repo":"charmbracelet/crush","slug":"session-id-is-required-for-creating-a-new-file-be8abf","errorCode":null,"errorMessage":"session ID is required for creating a new file","messagePattern":"session ID is required for creating a new file","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/agent/tools/mcp-tools.go","lineNumber":102,"sourceCode":"\t\t\t}\n\t\t} else if reqStr, ok := input[\"required\"].([]string); ok {\n\t\t\t// Handle case where it's already []string\n\t\t\trequired = reqStr\n\t\t}\n\t}\n\n\treturn fantasy.ToolInfo{\n\t\tName:        m.Name(),\n\t\tDescription: m.tool.Description,\n\t\tParameters:  parameters,\n\t\tRequired:    required,\n\t}\n}\n\nfunc (m *Tool) Run(ctx context.Context, params fantasy.ToolCall) (fantasy.ToolResponse, error) {\n\tsessionID := GetSessionFromContext(ctx)\n\tif sessionID == \"\" {\n\t\treturn fantasy.ToolResponse{}, fmt.Errorf(\"session ID is required for creating a new file\")\n\t}\n\n\t// Skip permission for whitelisted Docker MCP tools.\n\tif !slices.Contains(whitelistDockerTools, params.Name) {\n\t\tpermissionDescription := fmt.Sprintf(\"execute %s with the following parameters:\", m.Info().Name)\n\t\tp, err := m.permissions.Request(\n\t\t\tctx,\n\t\t\tpermission.CreatePermissionRequest{\n\t\t\t\tSessionID:   sessionID,\n\t\t\t\tToolCallID:  params.ID,\n\t\t\t\tPath:        m.workingDir,\n\t\t\t\tToolName:    m.Info().Name,\n\t\t\t\tAction:      \"execute\",\n\t\t\t\tDescription: permissionDescription,\n\t\t\t\tParams:      params.Input,\n\t\t\t},\n\t\t)\n\t\tif err != nil {","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/agent/tools/mcp-tools.go#L84-L120","documentation":"The MCP tool wrapper requires a session ID in the context because MCP tool executions are tracked per session and gated by permissions scoped to that session. If GetSessionFromContext(ctx) returns an empty string, Run immediately fails with this error before checking permissions or invoking the MCP server.","triggerScenarios":"Calling the MCP Tool's Run with a context built without the session value — e.g. invoking the tool directly in tests or from code paths that bypass the normal agent session setup (runBashTool-style harnesses).","commonSituations":"Custom scripts or tests invoking MCP tools with context.Background(); refactoring removed the session injection; running a tool outside the agent's execution loop.","solutions":["Build the tool context with the session ID injected via the package's WithSession/GetSessionFromContext helper.","Run the tool through the normal agent/coordinator flow which always attaches a session.","In tests, use the same context helper the other tests use to set a session ID.","Guard callers to skip MCP tools when no session is available instead of invoking Run."],"exampleFix":"// before\nresp, err := mcpTool.Run(context.Background(), call)\n// after\nctx := tools.WithSessionContext(context.Background(), \"session-123\")\nresp, err := mcpTool.Run(ctx, call)","handlingStrategy":"validation","validationCode":"if tools.GetSessionFromContext(ctx) == \"\" {\n\treturn errors.New(\"MCP tools require a session-scoped context\")\n}","typeGuard":null,"tryCatchPattern":"resp, err := tool.Run(ctx, call)\nif err != nil && strings.Contains(err.Error(), \"session ID is required\") {\n\tctx = tools.WithSessionContext(ctx, sessionID)\n\tresp, err = tool.Run(ctx, call)\n}","preventionTips":["Always build tool contexts via the agent's session helpers.","Never invoke MCP tools with bare context.Background().","In tests, mirror the production context setup (session injection).","Route all tool execution through the coordinator, which guarantees session context."],"tags":["mcp","go","context","session"],"backgroundTag":"missing-context-value","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}