@@ -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.
183182func (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 {
226224func 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 {
505503func 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