{"record":{"id":"4e7d651d6f1139aa","repo":"siyuan-note/siyuan","slug":"tool-handler-is-not-configured","errorCode":null,"errorMessage":"tool handler is not configured","messagePattern":"tool handler is not configured","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/mcp/server.go","lineNumber":301,"sourceCode":"\t\t\t\tif errors.Is(err, model.ErrEncryptedBoxNotUnlocked) {\n\t\t\t\t\treturn toolErrorResult(\"encrypted notebook is locked, please unlock it first\"), nil\n\t\t\t\t}\n\t\t\t\tlogging.LogWarnf(\"mcp: acquire encrypted notebook operations for tool [%s] failed: %v\", name, err)\n\t\t\t\treturn toolErrorResult(err.Error()), nil\n\t\t\t}\n\t\t}\n\t\tdefer releaseBoxLeases()\n\n\t\tvar (\n\t\t\tresult tools.CallToolResult\n\t\t\terr    error\n\t\t)\n\t\tif tool.ContextHandler != nil {\n\t\t\tresult, err = tool.ContextHandler(ctx, arguments)\n\t\t} else if tool.Handler != nil {\n\t\t\tresult, err = tool.Handler(arguments)\n\t\t} else {\n\t\t\terr = fmt.Errorf(\"tool handler is not configured\")\n\t\t}\n\t\tif err != nil {\n\t\t\treturn toolErrorResult(err.Error()), nil\n\t\t}\n\t\tif err = validator.ValidateOutputContext(ctx, result); err != nil {\n\t\t\treturn toolErrorResult(fmt.Sprintf(\n\t\t\t\t\"invalid tool output after execution; execution result may have side effects and must not be retried automatically: %v\",\n\t\t\t\terr)), nil\n\t\t}\n\n\t\tcontent := make([]mcpsdk.Content, 0, len(result.Content))\n\t\tfor _, item := range result.Content {\n\t\t\tconverted, convertErr := convertContentItem(item)\n\t\t\tif convertErr != nil {\n\t\t\t\treturn toolErrorResult(fmt.Sprintf(\n\t\t\t\t\t\"invalid tool content after execution; execution result may have side effects and must not be retried automatically: %v\",\n\t\t\t\t\tconvertErr)), nil\n\t\t\t}","sourceCodeStart":283,"sourceCodeEnd":319,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/mcp/server.go#L283-L319","documentation":"The tool being invoked has neither a `ContextHandler` nor a `Handler` function set on its definition, so the dispatch at `server.go:296-301` falls through to the `else` branch. This is an internal registration defect: a tool was registered with `server.AddTool` but its `Tool` struct was not populated with a callable handler.","triggerScenarios":"Calling any MCP tool whose `Tool` definition omitted both `Handler` and `ContextHandler`. Always reproducible for that tool name — it is a code/registration bug, not a runtime/transient condition.","commonSituations":"A tool was added to the registry with only metadata (name, schema) but its handler wiring was forgotten during refactoring. A conditional registration path that skips handler assignment under a feature flag.","solutions":["Locate the tool registration in `kernel/mcp/tools/*.go` and confirm the `Handler` (or `ContextHandler`) field is assigned.","Rebuild/restart the kernel after fixing the registration so the corrected tool table is loaded.","Add a unit test that asserts every registered tool has at least one handler set."],"exampleFix":"// before\ntools.Tool{Name: \"foo\", InputSchema: sch}\n// after\ntools.Tool{Name: \"foo\", InputSchema: sch, Handler: fooHandler}","handlingStrategy":"validation","validationCode":"// Registry self-check: every registered tool must define a handler.\nfor _, t := range registeredTools {\n    if t.Handler == nil && t.ContextHandler == nil {\n        panic(fmt.Sprintf(\"tool %q has no handler configured\", t.Name))\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Assert at registration time that every Tool has Handler or ContextHandler set.","Add a unit test enumerating the tool registry and checking handler presence.","Run the test suite after refactoring tool definitions."],"tags":["mcp","configuration","internal-bug","tool-registration"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}