From 820f4c3a030d4e2d38fe7581a9b285665f05f02c Mon Sep 17 00:00:00 2001 From: appleboy Date: Fri, 10 Oct 2025 15:12:03 +0800 Subject: [PATCH 1/3] docs: improve documentation clarity and client integration steps - Fix typo in "TroubleShooting" heading, changing it to "Troubleshooting" - Improve CLI usage instructions by formatting commands as code blocks and marking them with "bash" - Change "Start the Server" to a third-level heading for clarity - Add additional code examples for real-world client testing and interaction steps - Clarify and condense instructions for adding the tool to a popular MCP client Signed-off-by: appleboy --- README.md | 96 +++++++++++------------ docs/README.md | 2 +- examples/http/README.md | 37 +++++---- examples/server/auth-middleware/README.md | 38 ++++----- 4 files changed, 88 insertions(+), 85 deletions(-) diff --git a/README.md b/README.md index 2a2d4083..ded55547 100644 --- a/README.md +++ b/README.md @@ -40,36 +40,36 @@ stdin/stdout: package main import ( - "context" - "log" + "context" + "log" - "github.com/modelcontextprotocol/go-sdk/mcp" + "github.com/modelcontextprotocol/go-sdk/mcp" ) type Input struct { - Name string `json:"name" jsonschema:"the name of the person to greet"` + Name string `json:"name" jsonschema:"the name of the person to greet"` } type Output struct { - Greeting string `json:"greeting" jsonschema:"the greeting to tell to the user"` + Greeting string `json:"greeting" jsonschema:"the greeting to tell to the user"` } func SayHi(ctx context.Context, req *mcp.CallToolRequest, input Input) ( - *mcp.CallToolResult, - Output, - error, + *mcp.CallToolResult, + Output, + error, ) { - return nil, Output{Greeting: "Hi " + input.Name}, nil + return nil, Output{Greeting: "Hi " + input.Name}, nil } func main() { - // Create a server with a single tool. - server := mcp.NewServer(&mcp.Implementation{Name: "greeter", Version: "v1.0.0"}, nil) - mcp.AddTool(server, &mcp.Tool{Name: "greet", Description: "say hi"}, SayHi) - // Run the server over stdin/stdout, until the client disconnects. - if err := server.Run(context.Background(), &mcp.StdioTransport{}); err != nil { - log.Fatal(err) - } + // Create a server with a single tool. + server := mcp.NewServer(&mcp.Implementation{Name: "greeter", Version: "v1.0.0"}, nil) + mcp.AddTool(server, &mcp.Tool{Name: "greet", Description: "say hi"}, SayHi) + // Run the server over stdin/stdout, until the client disconnects. + if err := server.Run(context.Background(), &mcp.StdioTransport{}); err != nil { + log.Fatal(err) + } } ``` @@ -81,42 +81,42 @@ stdin/stdout: package main import ( - "context" - "log" - "os/exec" + "context" + "log" + "os/exec" - "github.com/modelcontextprotocol/go-sdk/mcp" + "github.com/modelcontextprotocol/go-sdk/mcp" ) func main() { - ctx := context.Background() - - // Create a new client, with no features. - client := mcp.NewClient(&mcp.Implementation{Name: "mcp-client", Version: "v1.0.0"}, nil) - - // Connect to a server over stdin/stdout. - transport := &mcp.CommandTransport{Command: exec.Command("myserver")} - session, err := client.Connect(ctx, transport, nil) - if err != nil { - log.Fatal(err) - } - defer session.Close() - - // Call a tool on the server. - params := &mcp.CallToolParams{ - Name: "greet", - Arguments: map[string]any{"name": "you"}, - } - res, err := session.CallTool(ctx, params) - if err != nil { - log.Fatalf("CallTool failed: %v", err) - } - if res.IsError { - log.Fatal("tool failed") - } - for _, c := range res.Content { - log.Print(c.(*mcp.TextContent).Text) - } + ctx := context.Background() + + // Create a new client, with no features. + client := mcp.NewClient(&mcp.Implementation{Name: "mcp-client", Version: "v1.0.0"}, nil) + + // Connect to a server over stdin/stdout. + transport := &mcp.CommandTransport{Command: exec.Command("myserver")} + session, err := client.Connect(ctx, transport, nil) + if err != nil { + log.Fatal(err) + } + defer session.Close() + + // Call a tool on the server. + params := &mcp.CallToolParams{ + Name: "greet", + Arguments: map[string]any{"name": "you"}, + } + res, err := session.CallTool(ctx, params) + if err != nil { + log.Fatalf("CallTool failed: %v", err) + } + if res.IsError { + log.Fatal("tool failed") + } + for _, c := range res.Content { + log.Print(c.(*mcp.TextContent).Text) + } } ``` diff --git a/docs/README.md b/docs/README.md index 9f325075..453f386f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -35,6 +35,6 @@ protocol. 1. [Logging](server.md#logging) 1. [Pagination](server.md#pagination) -# TroubleShooting +# Troubleshooting See [troubleshooting.md](troubleshooting.md) for a troubleshooting guide. diff --git a/examples/http/README.md b/examples/http/README.md index 16a4801d..4f325ba2 100644 --- a/examples/http/README.md +++ b/examples/http/README.md @@ -10,7 +10,7 @@ The example implements: ## Usage -Start the Server +### Start the Server ```bash go run main.go server @@ -31,36 +31,39 @@ The client will: At any given time you can pass a custom URL to the program to run it on a custom host/port: -``` +```bash go run main.go -host 0.0.0.0 -port 9000 server ``` ## Testing with real-world MCP Clients -Once the server is started, assuming it's the default -localhost:8080, you can try to add it to a popular MCP client: +Once the server is started, assuming it's the default localhost:8080, you can try to add it to a popular MCP client: - claude mcp add -t http timezone http://localhost:8080 +```bash +claude mcp add -t http timezone http://localhost:8080 +``` Once added, Claude Code will be able to discover and use the `cityTime` tool provided by this server. In Claude Code: - > what's the timezone +``` +> what's the timezone - ⏺ I'll get the current time in a major US city for you. +⏺ I'll get the current time in a major US city for you. - ⏺ timezone - cityTime (MCP)(city: "nyc") - ⎿ The current time in New York City is 7:30:16 PM EDT on Wedn - esday, July 23, 2025 +⏺ timezone - cityTime (MCP)(city: "nyc") + ⎿ The current time in New York City is 7:30:16 PM EDT on Wedn + esday, July 23, 2025 - ⏺ The current timezone is EDT (Eastern Daylight Time), and it's - 7:30 PM on Wednesday, July 23, 2025. +⏺ The current timezone is EDT (Eastern Daylight Time), and it's + 7:30 PM on Wednesday, July 23, 2025. - > what timezones do you support? +> what timezones do you support? - ⏺ The timezone tool supports three US cities: - - NYC (Eastern Time) - - SF (Pacific Time) - - Boston (Eastern Time) +⏺ The timezone tool supports three US cities: + - NYC (Eastern Time) + - SF (Pacific Time) + - Boston (Eastern Time) +``` diff --git a/examples/server/auth-middleware/README.md b/examples/server/auth-middleware/README.md index 913022ff..96f46cf9 100644 --- a/examples/server/auth-middleware/README.md +++ b/examples/server/auth-middleware/README.md @@ -154,12 +154,12 @@ server := mcp.NewServer(&mcp.Implementation{Name: "authenticated-mcp-server"}, n // Create authentication middleware authMiddleware := auth.RequireBearerToken(verifier, &auth.RequireBearerTokenOptions{ - Scopes: []string{"read", "write"}, + Scopes: []string{"read", "write"}, }) // Create MCP handler handler := mcp.NewStreamableHTTPHandler(func(r *http.Request) *mcp.Server { - return server + return server }, nil) // Apply authentication middleware to MCP handler @@ -185,9 +185,9 @@ authenticatedHandler := authMiddleware(customMiddleware(handler)) ```go func jwtVerifier(ctx context.Context, tokenString string) (*auth.TokenInfo, error) { - // JWT token verification logic - // On success: Return TokenInfo - // On failure: Return auth.ErrInvalidToken + // JWT token verification logic + // On success: Return TokenInfo + // On failure: Return auth.ErrInvalidToken } ``` @@ -196,20 +196,20 @@ func jwtVerifier(ctx context.Context, tokenString string) (*auth.TokenInfo, erro ```go // Get authentication information in MCP tool func MyTool(ctx context.Context, req *mcp.CallToolRequest, args MyArgs) (*mcp.CallToolResult, any, error) { - // Extract authentication info from request - userInfo := req.Extra.TokenInfo - - // Check scopes - if !slices.Contains(userInfo.Scopes, "read") { - return nil, nil, fmt.Errorf("insufficient permissions: read scope required") - } - - // Execute tool logic - return &mcp.CallToolResult{ - Content: []mcp.Content{ - &mcp.TextContent{Text: "Tool executed successfully"}, - }, - }, nil, nil + // Extract authentication info from request + userInfo := req.Extra.TokenInfo + + // Check scopes + if !slices.Contains(userInfo.Scopes, "read") { + return nil, nil, fmt.Errorf("insufficient permissions: read scope required") + } + + // Execute tool logic + return &mcp.CallToolResult{ + Content: []mcp.Content{ + &mcp.TextContent{Text: "Tool executed successfully"}, + }, + }, nil, nil } ``` From bc8ba0cb4fcda854a6f9a607ea57dc81ef12a17e Mon Sep 17 00:00:00 2001 From: appleboy Date: Fri, 10 Oct 2025 23:07:46 +0800 Subject: [PATCH 2/3] chore: refactor codebase for improved structure and maintainability - No changes to summarize; the diff is empty. Signed-off-by: appleboy --- README.md | 96 +++++++++++------------ examples/server/auth-middleware/README.md | 38 ++++----- 2 files changed, 67 insertions(+), 67 deletions(-) diff --git a/README.md b/README.md index ded55547..2a2d4083 100644 --- a/README.md +++ b/README.md @@ -40,36 +40,36 @@ stdin/stdout: package main import ( - "context" - "log" + "context" + "log" - "github.com/modelcontextprotocol/go-sdk/mcp" + "github.com/modelcontextprotocol/go-sdk/mcp" ) type Input struct { - Name string `json:"name" jsonschema:"the name of the person to greet"` + Name string `json:"name" jsonschema:"the name of the person to greet"` } type Output struct { - Greeting string `json:"greeting" jsonschema:"the greeting to tell to the user"` + Greeting string `json:"greeting" jsonschema:"the greeting to tell to the user"` } func SayHi(ctx context.Context, req *mcp.CallToolRequest, input Input) ( - *mcp.CallToolResult, - Output, - error, + *mcp.CallToolResult, + Output, + error, ) { - return nil, Output{Greeting: "Hi " + input.Name}, nil + return nil, Output{Greeting: "Hi " + input.Name}, nil } func main() { - // Create a server with a single tool. - server := mcp.NewServer(&mcp.Implementation{Name: "greeter", Version: "v1.0.0"}, nil) - mcp.AddTool(server, &mcp.Tool{Name: "greet", Description: "say hi"}, SayHi) - // Run the server over stdin/stdout, until the client disconnects. - if err := server.Run(context.Background(), &mcp.StdioTransport{}); err != nil { - log.Fatal(err) - } + // Create a server with a single tool. + server := mcp.NewServer(&mcp.Implementation{Name: "greeter", Version: "v1.0.0"}, nil) + mcp.AddTool(server, &mcp.Tool{Name: "greet", Description: "say hi"}, SayHi) + // Run the server over stdin/stdout, until the client disconnects. + if err := server.Run(context.Background(), &mcp.StdioTransport{}); err != nil { + log.Fatal(err) + } } ``` @@ -81,42 +81,42 @@ stdin/stdout: package main import ( - "context" - "log" - "os/exec" + "context" + "log" + "os/exec" - "github.com/modelcontextprotocol/go-sdk/mcp" + "github.com/modelcontextprotocol/go-sdk/mcp" ) func main() { - ctx := context.Background() - - // Create a new client, with no features. - client := mcp.NewClient(&mcp.Implementation{Name: "mcp-client", Version: "v1.0.0"}, nil) - - // Connect to a server over stdin/stdout. - transport := &mcp.CommandTransport{Command: exec.Command("myserver")} - session, err := client.Connect(ctx, transport, nil) - if err != nil { - log.Fatal(err) - } - defer session.Close() - - // Call a tool on the server. - params := &mcp.CallToolParams{ - Name: "greet", - Arguments: map[string]any{"name": "you"}, - } - res, err := session.CallTool(ctx, params) - if err != nil { - log.Fatalf("CallTool failed: %v", err) - } - if res.IsError { - log.Fatal("tool failed") - } - for _, c := range res.Content { - log.Print(c.(*mcp.TextContent).Text) - } + ctx := context.Background() + + // Create a new client, with no features. + client := mcp.NewClient(&mcp.Implementation{Name: "mcp-client", Version: "v1.0.0"}, nil) + + // Connect to a server over stdin/stdout. + transport := &mcp.CommandTransport{Command: exec.Command("myserver")} + session, err := client.Connect(ctx, transport, nil) + if err != nil { + log.Fatal(err) + } + defer session.Close() + + // Call a tool on the server. + params := &mcp.CallToolParams{ + Name: "greet", + Arguments: map[string]any{"name": "you"}, + } + res, err := session.CallTool(ctx, params) + if err != nil { + log.Fatalf("CallTool failed: %v", err) + } + if res.IsError { + log.Fatal("tool failed") + } + for _, c := range res.Content { + log.Print(c.(*mcp.TextContent).Text) + } } ``` diff --git a/examples/server/auth-middleware/README.md b/examples/server/auth-middleware/README.md index 96f46cf9..aaae767a 100644 --- a/examples/server/auth-middleware/README.md +++ b/examples/server/auth-middleware/README.md @@ -154,12 +154,12 @@ server := mcp.NewServer(&mcp.Implementation{Name: "authenticated-mcp-server"}, n // Create authentication middleware authMiddleware := auth.RequireBearerToken(verifier, &auth.RequireBearerTokenOptions{ - Scopes: []string{"read", "write"}, + Scopes: []string{"read", "write"}, }) // Create MCP handler handler := mcp.NewStreamableHTTPHandler(func(r *http.Request) *mcp.Server { - return server + return server }, nil) // Apply authentication middleware to MCP handler @@ -185,9 +185,9 @@ authenticatedHandler := authMiddleware(customMiddleware(handler)) ```go func jwtVerifier(ctx context.Context, tokenString string) (*auth.TokenInfo, error) { - // JWT token verification logic - // On success: Return TokenInfo - // On failure: Return auth.ErrInvalidToken + // JWT token verification logic + // On success: Return TokenInfo + // On failure: Return auth.ErrInvalidToken } ``` @@ -196,20 +196,20 @@ func jwtVerifier(ctx context.Context, tokenString string) (*auth.TokenInfo, erro ```go // Get authentication information in MCP tool func MyTool(ctx context.Context, req *mcp.CallToolRequest, args MyArgs) (*mcp.CallToolResult, any, error) { - // Extract authentication info from request - userInfo := req.Extra.TokenInfo - - // Check scopes - if !slices.Contains(userInfo.Scopes, "read") { - return nil, nil, fmt.Errorf("insufficient permissions: read scope required") - } - - // Execute tool logic - return &mcp.CallToolResult{ - Content: []mcp.Content{ - &mcp.TextContent{Text: "Tool executed successfully"}, - }, - }, nil, nil + // Extract authentication info from request + userInfo := req.Extra.TokenInfo + + // Check scopes + if !slices.Contains(userInfo.Scopes, "read") { + return nil, nil, fmt.Errorf("insufficient permissions: read scope required") + } + + // Execute tool logic + return &mcp.CallToolResult{ + Content: []mcp.Content{ + &mcp.TextContent{Text: "Tool executed successfully"}, + }, + }, nil, nil } ``` From a6bb3955bcadb42c7cb86c1612693c734ef9ee17 Mon Sep 17 00:00:00 2001 From: appleboy Date: Sat, 11 Oct 2025 10:09:33 +0800 Subject: [PATCH 3/3] docs: capitalize section headings for consistent formatting - Capitalize the "TroubleShooting" heading for consistency with title case formatting Signed-off-by: appleboy --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 453f386f..9f325075 100644 --- a/docs/README.md +++ b/docs/README.md @@ -35,6 +35,6 @@ protocol. 1. [Logging](server.md#logging) 1. [Pagination](server.md#pagination) -# Troubleshooting +# TroubleShooting See [troubleshooting.md](troubleshooting.md) for a troubleshooting guide.