a73x

b4909168

feat(mcp): advertise channel handling protocol via init instructions

a73x   2026-04-29 09:06

Commit message
feat(mcp): advertise channel handling protocol via init instructions

internal/mcp/mcp.go
Old New
@@ -8,6 +8,18 @@ import (
8 "sync" 8 "sync"
9 ) 9 )
10 10
11 // channelInstructions is advertised in the initialize response so Claude
12 // Code adds it to the session prompt. Tells Claude how to handle filewatch
13 // channel messages.
14 const channelInstructions = `Channel messages arrive when a developer writes @claude in a code comment. ` +
15 `params.content is the marker text starting with "@claude". ` +
16 `params.meta has file (path), line (1-indexed line number, as a string), ` +
17 `and replyTo (e.g. "fw-a1b2c3d4") — the UUID already stamped into the comment as @claude[<replyTo>]. ` +
18 `To handle a message: read the file at meta.file around line meta.line, ` +
19 `do what the developer asked (answer in-session for questions, edit code for tasks), ` +
20 `then use Edit to remove the entire @claude[<replyTo>] marker line so the file returns to a clean state. ` +
21 `There is no reply tool — line removal is the ack.`
22
11 // ChannelMeta is the meta block of a notifications/claude/channel notification. 23 // ChannelMeta is the meta block of a notifications/claude/channel notification.
12 // All fields are strings: Claude Code's schema is Record<string, string> and 24 // All fields are strings: Claude Code's schema is Record<string, string> and
13 // silently drops non-string values. 25 // silently drops non-string values.
@@ -92,6 +104,7 @@ func (s *Server) Run(ctx context.Context) error {
92 "name": "filewatch-mcp", 104 "name": "filewatch-mcp",
93 "version": "0.1.0", 105 "version": "0.1.0",
94 }, 106 },
107 "instructions": channelInstructions,
95 }) 108 })
96 default: 109 default:
97 s.writeError(id, -32601, "method not found") 110 s.writeError(id, -32601, "method not found")
internal/mcp/mcp_test.go
Old New
@@ -71,4 +71,11 @@ func TestInitializeAdvertisesChannelCapability(t *testing.T) {
71 if _, has := exp["claude/channel"]; !has { 71 if _, has := exp["claude/channel"]; !has {
72 t.Errorf("missing experimental.claude/channel capability: %#v", caps) 72 t.Errorf("missing experimental.claude/channel capability: %#v", caps)
73 } 73 }
74 instructions, _ := result["instructions"].(string)
75 if instructions == "" {
76 t.Error("missing instructions field")
77 }
78 if !strings.Contains(instructions, "remove") {
79 t.Errorf("instructions don't mention marker removal: %q", instructions)
80 }
74 } 81 }