Skip to content

Commit 6729310

Browse files
committed
Record session id on init
1 parent f7bd675 commit 6729310

File tree

2 files changed

+47
-15
lines changed

2 files changed

+47
-15
lines changed

contrib/mark3labs/mcp-go/hooks.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,18 @@ func (h *Hooks) AddHooks(hooks *server.Hooks) {
6666
// onBeforeInitialize is called before initialization is executed.
6767
func (h *Hooks) onBeforeInitialize(ctx context.Context, id any, request *mcp.InitializeRequest) {
6868
taskSpan, _ := llmobs.StartTaskSpan(ctx, "mcp.initialize")
69+
tagWithSessionID(ctx, taskSpan)
6970
h.spanCache.Set(id, taskSpan, ttlcache.DefaultTTL)
7071
}
7172

73+
func tagWithSessionID(ctx context.Context, span llmobs.Span) {
74+
session := server.ClientSessionFromContext(ctx)
75+
if session != nil {
76+
sessionID := session.SessionID()
77+
span.Annotate(llmobs.WithAnnotatedTags(map[string]string{"mcp_session_id": sessionID}))
78+
}
79+
}
80+
7281
// finishSpanWithIO retrieves a span from cache, annotates it with input/output, and finishes it.
7382
func finishSpanWithIO[Req any, Res any](h *Hooks, id any, request Req, result Res) {
7483
if item := h.spanCache.Get(id); item != nil {
@@ -93,12 +102,8 @@ func (h *Hooks) onAfterInitialize(ctx context.Context, id any, request *mcp.Init
93102
// onBeforeCallTool is called before a tool is executed.
94103
func (h *Hooks) onBeforeCallTool(ctx context.Context, id any, request *mcp.CallToolRequest) {
95104
toolSpan, _ := llmobs.StartToolSpan(ctx, request.Params.Name)
96-
session := server.ClientSessionFromContext(ctx)
97-
if session != nil {
98-
sessionID := session.SessionID()
99-
// toolSpan.Annotate(llmobs.WithAnnotatedSessionID(sessionID))
100-
toolSpan.Annotate(llmobs.WithAnnotatedTags(map[string]string{"mcp_session_id": sessionID}))
101-
}
105+
106+
tagWithSessionID(ctx, toolSpan)
102107

103108
h.spanCache.Set(id, toolSpan, ttlcache.DefaultTTL)
104109
}

contrib/mark3labs/mcp-go/hooks_test.go

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,13 @@ func TestIntegrationSessionInitialize(t *testing.T) {
6868
srv := server.NewMCPServer("test-server", "1.0.0",
6969
server.WithHooks(hooks))
7070

71-
// Create initialize request
71+
// Create initialize request with session
7272
ctx := context.Background()
73+
sessionID := "test-session-init"
74+
session := &mockSession{id: sessionID}
75+
session.Initialize()
76+
ctx = srv.WithContext(ctx, session)
77+
7378
initRequest := `{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test-client","version":"1.0.0"}}}`
7479

7580
// Send initialize request
@@ -96,6 +101,9 @@ func TestIntegrationSessionInitialize(t *testing.T) {
96101
assert.Equal(t, "mcp.initialize", taskSpan.Name)
97102
assert.Equal(t, "task", taskSpan.Meta["span.kind"])
98103

104+
// Verify session ID tag is set
105+
assert.Contains(t, taskSpan.Tags, "mcp_session_id:test-session-init")
106+
99107
// Verify input/output annotations exist
100108
assert.Contains(t, taskSpan.Meta, "input")
101109
assert.Contains(t, taskSpan.Meta, "output")
@@ -166,11 +174,16 @@ func TestIntegrationToolCallSuccess(t *testing.T) {
166174
session.Initialize()
167175
ctx = srv.WithContext(ctx, session)
168176

177+
// Send initialize request first
178+
initRequest := `{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test-client","version":"1.0.0"}}}`
179+
response := srv.HandleMessage(ctx, []byte(initRequest))
180+
assert.NotNil(t, response)
181+
169182
// Create the actual MCP tools/call request as JSON
170183
toolCallRequest := `{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"calculator","arguments":{"operation":"add","x":5,"y":3}}}`
171184

172185
// Call the actual MCP server's HandleMessage method
173-
response := srv.HandleMessage(ctx, []byte(toolCallRequest))
186+
response = srv.HandleMessage(ctx, []byte(toolCallRequest))
174187
assert.NotNil(t, response)
175188

176189
// Marshal response to check it
@@ -184,17 +197,31 @@ func TestIntegrationToolCallSuccess(t *testing.T) {
184197
assert.Equal(t, "2.0", resp["jsonrpc"])
185198
assert.NotNil(t, resp["result"])
186199

187-
// Verify LLMObs tool span was created
188-
spans := tt.WaitForLLMObsSpans(t, 1)
189-
require.Len(t, spans, 1)
200+
// Verify LLMObs spans were created for both initialize and tool call
201+
spans := tt.WaitForLLMObsSpans(t, 2)
202+
require.Len(t, spans, 2)
203+
204+
// Find initialize and tool spans
205+
var initSpan, toolSpan *testtracer.LLMObsSpan
206+
for i := range spans {
207+
if spans[i].Name == "mcp.initialize" {
208+
initSpan = &spans[i]
209+
} else if spans[i].Name == "calculator" {
210+
toolSpan = &spans[i]
211+
}
212+
}
213+
214+
require.NotNil(t, initSpan, "initialize span not found")
215+
require.NotNil(t, toolSpan, "tool span not found")
216+
217+
// Verify both spans have the same session ID tag
218+
expectedTag := "mcp_session_id:test-session-123"
219+
assert.Contains(t, initSpan.Tags, expectedTag)
220+
assert.Contains(t, toolSpan.Tags, expectedTag)
190221

191-
toolSpan := spans[0]
192222
assert.Equal(t, "calculator", toolSpan.Name)
193223
assert.Equal(t, "tool", toolSpan.Meta["span.kind"])
194224

195-
// Verify session ID tag is set
196-
assert.Contains(t, toolSpan.Tags, "mcp_session_id:test-session-123")
197-
198225
// Verify input/output annotations exist
199226
assert.Contains(t, toolSpan.Meta, "input")
200227
assert.Contains(t, toolSpan.Meta, "output")

0 commit comments

Comments
 (0)