88 "os"
99 "os/signal"
1010 "path/filepath"
11+ "strings"
1112 "syscall"
1213
1314 "github.com/mark3labs/mcp-go/client"
@@ -19,6 +20,7 @@ import (
1920// In a real implementation, this would enumerate workspace/project roots.
2021type MockRootsHandler struct {}
2122
23+ // ListRoots implements client.RootsHandler by returning example workspace roots.
2224func (h * MockRootsHandler ) ListRoots (ctx context.Context , request mcp.ListRootsRequest ) (* mcp.ListRootsResult , error ) {
2325 home , err := os .UserHomeDir ()
2426 if err != nil {
@@ -31,17 +33,26 @@ func (h *MockRootsHandler) ListRoots(ctx context.Context, request mcp.ListRootsR
3133 Roots : []mcp.Root {
3234 {
3335 Name : "app" ,
34- URI : ( & url. URL { Scheme : "file" , Path : app }). String ( ),
36+ URI : h . fileURI ( app ),
3537 },
3638 {
3739 Name : "test-project" ,
38- URI : ( & url. URL { Scheme : "file" , Path : proj }). String ( ),
40+ URI : h . fileURI ( proj ),
3941 },
4042 },
4143 }
4244 return result , nil
4345}
4446
47+ // fileURI returns a file:// URI for both Unix and Windows absolute paths.
48+ func (h * MockRootsHandler ) fileURI (p string ) string {
49+ p = filepath .ToSlash (p )
50+ if ! strings .HasPrefix (p , "/" ) { // e.g., "C:/Users/..." on Windows
51+ p = "/" + p
52+ }
53+ return (& url.URL {Scheme : "file" , Path : p }).String ()
54+ }
55+
4556// main starts a mock MCP roots client over HTTP.
4657// The server tool triggers a roots/list request on the client.
4758// The client shuts down gracefully on SIGINT or SIGTERM.
@@ -57,7 +68,6 @@ func main() {
5768 if err != nil {
5869 log .Fatalf ("Failed to create HTTP transport: %v" , err )
5970 }
60- defer httpTransport .Close ()
6171
6272 // Create client with roots support
6373 mcpClient := client .NewClient (
@@ -123,24 +133,19 @@ func main() {
123133 } else if len (result .Content ) > 0 {
124134 resultStr := ""
125135 for _ , content := range result .Content {
126- if textContent , ok := content .(mcp.TextContent ); ok {
127- resultStr += fmt .Sprintf ("%s\n " , textContent .Text )
136+ switch tc := content .(type ) {
137+ case mcp.TextContent :
138+ resultStr += fmt .Sprintf ("%s\n " , tc .Text )
139+ case * mcp.TextContent :
140+ resultStr += fmt .Sprintf ("%s\n " , tc .Text )
128141 }
129142 }
130143 fmt .Printf ("client call tool result: %s\n " , resultStr )
131144 }
132145
133146 // Keep the client running (in a real app, you'd have your main application logic here)
134- sigChan := make (chan os.Signal , 1 )
135- signal .Notify (sigChan , os .Interrupt , syscall .SIGTERM )
136-
137- shutdownCtx , cancel := context .WithCancel (ctx )
138- defer cancel ()
139-
140- go func () {
141- <- sigChan
142- log .Println ("Received shutdown signal" )
143- cancel ()
144- }()
145- <- shutdownCtx .Done ()
147+ waitCtx , stop := signal .NotifyContext (ctx , os .Interrupt , syscall .SIGTERM )
148+ defer stop ()
149+ <- waitCtx .Done ()
150+ log .Println ("Received shutdown signal" )
146151}
0 commit comments