{"record":{"id":"c57626de26f90109","repo":"micro/go-micro","slug":"topic-is-required","errorCode":null,"errorMessage":"topic is required","messagePattern":"topic is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gateway/mcp/mcp.go","lineNumber":545,"sourceCode":"\t\t\treturn map[string]interface{}{\"status\": \"ok\", \"key\": key}, nil\n\t\t},\n\t})\n\n\taddFramework(&Tool{\n\t\tName:        \"micro_broker_publish\",\n\t\tDescription: \"Publish a message to a broker topic\",\n\t\tInputSchema: map[string]interface{}{\n\t\t\t\"type\": \"object\",\n\t\t\t\"properties\": map[string]interface{}{\n\t\t\t\t\"topic\":   map[string]interface{}{\"type\": \"string\", \"description\": \"Topic name\"},\n\t\t\t\t\"message\": map[string]interface{}{\"type\": \"string\", \"description\": \"Message body\"},\n\t\t\t},\n\t\t},\n\t\tHandler: func(input map[string]interface{}) (interface{}, error) {\n\t\t\ttopic, _ := input[\"topic\"].(string)\n\t\t\tmessage, _ := input[\"message\"].(string)\n\t\t\tif topic == \"\" {\n\t\t\t\treturn nil, fmt.Errorf(\"topic is required\")\n\t\t\t}\n\t\t\tb := broker.DefaultBroker\n\t\t\tif err := b.Connect(); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif err := b.Publish(topic, &broker.Message{Body: []byte(message)}); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn map[string]interface{}{\"status\": \"ok\", \"topic\": topic}, nil\n\t\t},\n\t})\n}\n\n// watchServices watches for service registry changes via the shared schema\n// resolver and rebuilds the tool catalog on each change.\nfunc (s *Server) watchServices() {\n\tif s.watching {\n\t\treturn","sourceCodeStart":527,"sourceCodeEnd":563,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/gateway/mcp/mcp.go#L527-L563","documentation":"The built-in broker \"publish\" MCP tool requires a non-empty \"topic\" parameter specifying where the message is published. An empty or missing topic fails the guard before broker.Connect/Publish is called; the \"message\" body may be empty.","triggerScenarios":"An MCP client calls the publish tool with input {} or {\"topic\": \"\"}; the handler returns \"topic is required\" without touching the broker.","commonSituations":"LLM omits the topic argument; topic string built from an empty config/env variable; caller mixed up topic and message parameter names.","solutions":["Pass a non-empty \"topic\" string: {\"topic\": \"events.user.created\", \"message\": \"...\"}.","Validate the topic is non-empty in the client (and that it matches broker topic naming rules).","Check that the value feeding the topic variable (config, env) is actually populated."],"exampleFix":"// before\n{\"arguments\": {\"message\": \"hello\"}}\n// after\n{\"arguments\": {\"topic\": \"events.created\", \"message\": \"hello\"}}","handlingStrategy":"validation","validationCode":"topic, _ := input[\"topic\"].(string)\nif topic == \"\" {\n    return errors.New(\"publish requires a non-empty 'topic' argument\")\n}","typeGuard":"func validPublishInput(input map[string]interface{}) (topic, message string, ok bool) {\n    t, tOK := input[\"topic\"].(string)\n    m, _ := input[\"message\"].(string)\n    return t, m, tOK && t != \"\"\n}","tryCatchPattern":"_, err := callTool(\"publish\", map[string]interface{}{\"topic\": topic, \"message\": msg})\nif err != nil {\n    if strings.Contains(err.Error(), \"topic is required\") {\n        // supply topic and retry\n    }\n}","preventionTips":["Resolve topics from validated config so empty env values are caught early.","Validate topic naming (non-empty, allowed characters) before publishing.","Don't swap the topic and message parameter names."],"tags":["mcp","validation","broker"],"backgroundTag":"missing-required-argument","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}