Skip to content

Commit db5da0a

Browse files
committed
refactor: migrate sequential thinking to new MCP SDK API
- Use mcp.AddTool instead of AddTools with manual schemas - Simplify server creation with Implementation struct
1 parent e788759 commit db5da0a

File tree

1 file changed

+28
-153
lines changed

1 file changed

+28
-153
lines changed

examples/sequentialthinking/main.go

Lines changed: 28 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"sync"
2121
"time"
2222

23-
"github.com/modelcontextprotocol/go-sdk/jsonschema"
2423
"github.com/modelcontextprotocol/go-sdk/mcp"
2524
)
2625

@@ -78,7 +77,7 @@ func (s *ThinkingSession) clone() *ThinkingSession {
7877
// The SessionStore uses a RWMutex to protect the sessions map from concurrent access.
7978
// All ThinkingSession modifications happen on deep copies, never on shared instances.
8079
// This means:
81-
// - Read locks protect map access (reading from a Go map during writes causes panics)
80+
// - Read locks protect map access.
8281
// - Write locks protect map modifications (adding/removing/replacing sessions)
8382
// - Session field modifications always happen on local copies via CompareAndSwap
8483
// - No shared ThinkingSession state is ever modified directly
@@ -171,15 +170,15 @@ func (s *SessionStore) SessionsSnapshot() []*ThinkingSession {
171170
s.mu.RLock()
172171
defer s.mu.RUnlock()
173172

174-
sessions := make([]*ThinkingSession, 0, len(s.sessions))
173+
var sessions []*ThinkingSession
175174
for _, session := range s.sessions {
176-
// Create a deep copy of each session
177175
sessions = append(sessions, session.clone())
178176
}
179177
return sessions
180178
}
181179

182180
// SessionSnapshot returns a deep copy of a session for safe concurrent access.
181+
// The second return value reports whether a session with the given id exists.
183182
func (s *SessionStore) SessionSnapshot(id string) (*ThinkingSession, bool) {
184183
s.mu.RLock()
185184
defer s.mu.RUnlock()
@@ -189,7 +188,6 @@ func (s *SessionStore) SessionSnapshot(id string) (*ThinkingSession, bool) {
189188
return nil, false
190189
}
191190

192-
// Create a deep copy
193191
return session.clone(), true
194192
}
195193

@@ -226,8 +224,8 @@ type ThinkingHistoryArgs struct {
226224
func deepCopyThoughts(thoughts []*Thought) []*Thought {
227225
thoughtsCopy := make([]*Thought, len(thoughts))
228226
for i, t := range thoughts {
229-
thoughtCopy := *t
230-
thoughtsCopy[i] = &thoughtCopy
227+
t2 := *t
228+
thoughtsCopy[i] = &t2
231229
}
232230
return thoughtsCopy
233231
}
@@ -505,152 +503,29 @@ func randText() string {
505503
func main() {
506504
flag.Parse()
507505

508-
server := mcp.NewServer("sequential-thinking", "v0.0.1", nil)
509-
510-
// Add thinking tools without output schemas
511-
startThinkingSchema, err := jsonschema.For[StartThinkingArgs]()
512-
if err != nil {
513-
log.Fatalf("Failed to create start_thinking schema: %v", err)
514-
}
515-
continueThinkingSchema, err := jsonschema.For[ContinueThinkingArgs]()
516-
if err != nil {
517-
log.Fatalf("Failed to create continue_thinking schema: %v", err)
518-
}
519-
reviewThinkingSchema, err := jsonschema.For[ReviewThinkingArgs]()
520-
if err != nil {
521-
log.Fatalf("Failed to create review_thinking schema: %v", err)
522-
}
523-
524-
server.AddTools(
525-
&mcp.ServerTool{
526-
Tool: &mcp.Tool{
527-
Name: "start_thinking",
528-
Description: "Begin a new sequential thinking session for a complex problem",
529-
InputSchema: startThinkingSchema,
530-
// No OutputSchema to avoid structured output requirement
531-
},
532-
Handler: func(ctx context.Context, ss *mcp.ServerSession, params *mcp.CallToolParamsFor[map[string]any]) (*mcp.CallToolResult, error) {
533-
// Convert map[string]any to StartThinkingArgs
534-
args := StartThinkingArgs{}
535-
if v, ok := params.Arguments["problem"].(string); ok {
536-
args.Problem = v
537-
}
538-
if v, ok := params.Arguments["sessionId"].(string); ok {
539-
args.SessionID = v
540-
}
541-
if v, ok := params.Arguments["estimatedSteps"].(float64); ok {
542-
args.EstimatedSteps = int(v)
543-
}
544-
545-
result, err := StartThinking(ctx, ss, &mcp.CallToolParamsFor[StartThinkingArgs]{
546-
Meta: params.Meta,
547-
Name: params.Name,
548-
Arguments: args,
549-
})
550-
if err != nil {
551-
return &mcp.CallToolResult{
552-
Content: []mcp.Content{&mcp.TextContent{Text: err.Error()}},
553-
IsError: true,
554-
}, nil
555-
}
556-
return &mcp.CallToolResult{
557-
Content: result.Content,
558-
IsError: result.IsError,
559-
}, nil
560-
},
561-
},
562-
&mcp.ServerTool{
563-
Tool: &mcp.Tool{
564-
Name: "continue_thinking",
565-
Description: "Add the next thought step, revise a previous step, or create a branch",
566-
InputSchema: continueThinkingSchema,
567-
// No OutputSchema to avoid structured output requirement
568-
},
569-
Handler: func(ctx context.Context, ss *mcp.ServerSession, params *mcp.CallToolParamsFor[map[string]any]) (*mcp.CallToolResult, error) {
570-
// Convert map[string]any to ContinueThinkingArgs
571-
args := ContinueThinkingArgs{}
572-
if v, ok := params.Arguments["sessionId"].(string); ok {
573-
args.SessionID = v
574-
}
575-
if v, ok := params.Arguments["thought"].(string); ok {
576-
args.Thought = v
577-
}
578-
if v, ok := params.Arguments["nextNeeded"].(bool); ok {
579-
args.NextNeeded = &v
580-
}
581-
if v, ok := params.Arguments["reviseStep"].(float64); ok {
582-
step := int(v)
583-
args.ReviseStep = &step
584-
}
585-
if v, ok := params.Arguments["createBranch"].(bool); ok {
586-
args.CreateBranch = v
587-
}
588-
if v, ok := params.Arguments["estimatedTotal"].(float64); ok {
589-
args.EstimatedTotal = int(v)
590-
}
591-
592-
result, err := ContinueThinking(ctx, ss, &mcp.CallToolParamsFor[ContinueThinkingArgs]{
593-
Meta: params.Meta,
594-
Name: params.Name,
595-
Arguments: args,
596-
})
597-
if err != nil {
598-
return &mcp.CallToolResult{
599-
Content: []mcp.Content{&mcp.TextContent{Text: err.Error()}},
600-
IsError: true,
601-
}, nil
602-
}
603-
return &mcp.CallToolResult{
604-
Content: result.Content,
605-
IsError: result.IsError,
606-
}, nil
607-
},
608-
},
609-
&mcp.ServerTool{
610-
Tool: &mcp.Tool{
611-
Name: "review_thinking",
612-
Description: "Review the complete thinking process for a session",
613-
InputSchema: reviewThinkingSchema,
614-
// No OutputSchema to avoid structured output requirement
615-
},
616-
Handler: func(ctx context.Context, ss *mcp.ServerSession, params *mcp.CallToolParamsFor[map[string]any]) (*mcp.CallToolResult, error) {
617-
// Convert map[string]any to ReviewThinkingArgs
618-
args := ReviewThinkingArgs{}
619-
if v, ok := params.Arguments["sessionId"].(string); ok {
620-
args.SessionID = v
621-
}
622-
623-
result, err := ReviewThinking(ctx, ss, &mcp.CallToolParamsFor[ReviewThinkingArgs]{
624-
Meta: params.Meta,
625-
Name: params.Name,
626-
Arguments: args,
627-
})
628-
if err != nil {
629-
return &mcp.CallToolResult{
630-
Content: []mcp.Content{&mcp.TextContent{Text: err.Error()}},
631-
IsError: true,
632-
}, nil
633-
}
634-
return &mcp.CallToolResult{
635-
Content: result.Content,
636-
IsError: result.IsError,
637-
}, nil
638-
},
639-
},
640-
)
641-
642-
// Add resources for accessing thinking history
643-
server.AddResources(
644-
&mcp.ServerResource{
645-
Resource: &mcp.Resource{
646-
Name: "thinking_sessions",
647-
Description: "Access thinking session data and history",
648-
URI: "thinking://sessions",
649-
MIMEType: "application/json",
650-
},
651-
Handler: ThinkingHistory,
652-
},
653-
)
506+
server := mcp.NewServer(&mcp.Implementation{Name: "sequential-thinking"}, nil)
507+
508+
mcp.AddTool(server, &mcp.Tool{
509+
Name: "start_thinking",
510+
Description: "Begin a new sequential thinking session for a complex problem",
511+
}, StartThinking)
512+
513+
mcp.AddTool(server, &mcp.Tool{
514+
Name: "continue_thinking",
515+
Description: "Add the next thought step, revise a previous step, or create a branch",
516+
}, ContinueThinking)
517+
518+
mcp.AddTool(server, &mcp.Tool{
519+
Name: "review_thinking",
520+
Description: "Review the complete thinking process for a session",
521+
}, ReviewThinking)
522+
523+
server.AddResource(&mcp.Resource{
524+
Name: "thinking_sessions",
525+
Description: "Access thinking session data and history",
526+
URI: "thinking://sessions",
527+
MIMEType: "application/json",
528+
}, ThinkingHistory)
654529

655530
if *httpAddr != "" {
656531
handler := mcp.NewStreamableHTTPHandler(func(*http.Request) *mcp.Server {

0 commit comments

Comments
 (0)