#
tokens: 8437/50000 13/13 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .editorconfig
├── .github
│   └── workflows
│       └── ci.yml
├── .gitignore
├── .golangci.yml
├── build
│   ├── charcount
│   ├── mozisu-mcp-server
│   └── webserver
├── cmd
│   ├── charcount
│   │   ├── charcount
│   │   ├── main.go
│   │   └── output.txt
│   ├── direct_test
│   │   └── main.go
│   ├── mcpserver
│   │   └── main.go
│   ├── test
│   │   ├── mcp_client.go
│   │   └── test_client.go
│   └── webserver
│       ├── main.go
│       └── webserver
├── configs
│   └── config.json
├── go.mod
├── go.sum
├── image-1.png
├── image.png
├── internal
│   └── server
│       └── server.go
├── LICENSE
├── main_test.go
├── main.go
├── pkg
│   └── charcount
│       ├── charcount_test.go
│       └── charcount.go
├── README.md
├── scripts
│   └── build.sh
├── Taskfile.yml
└── test
    └── integration_test.go
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
 1 | # Binaries for programs and plugins
 2 | *.exe
 3 | *.exe~
 4 | *.dll
 5 | *.so
 6 | *.dylib
 7 | bin/
 8 | 
 9 | # Test binary, built with `go test -c`
10 | *.test
11 | 
12 | # Output of the go coverage tool
13 | *.out
14 | 
15 | # Dependency directories
16 | vendor/
17 | 
18 | # Go workspace file
19 | go.work
20 | 
21 | # IDE specific files
22 | .idea/
23 | .vscode/
24 | *.swp
25 | *.swo
26 | 
27 | # OS specific files
28 | .DS_Store
29 | Thumbs.db
30 | 
31 | # Build output
32 | /charcount
33 | /webserver
34 | /mozisu-mcp-server
35 | 
36 | # Debug files
37 | __debug_bin
38 | 
```

--------------------------------------------------------------------------------
/cmd/charcount/output.txt:
--------------------------------------------------------------------------------

```
1 | DEBUG: Starting character count
2 | 
3 | Text: hello
4 | Total characters: 5
5 | Non-whitespace characters: 5
6 | ----------------------------
7 | DEBUG: Completed character count for 'hello'
8 | 
```

--------------------------------------------------------------------------------
/configs/config.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "server": {
 3 |     "mcp": {
 4 |       "name": "Mozisu MCP Server",
 5 |       "version": "1.0.0"
 6 |     },
 7 |     "web": {
 8 |       "port": 8080,
 9 |       "timeouts": {
10 |         "read": 10,
11 |         "write": 10,
12 |         "idle": 120
13 |       }
14 |     }
15 |   },
16 |   "features": {
17 |     "debug": false,
18 |     "logging": true
19 |   }
20 | }
21 | 
```

--------------------------------------------------------------------------------
/pkg/charcount/charcount.go:
--------------------------------------------------------------------------------

```go
 1 | // Package charcount provides functionality for counting characters in text
 2 | package charcount
 3 | 
 4 | import (
 5 | 	"unicode"
 6 | )
 7 | 
 8 | // Result represents the result of a character count operation
 9 | type Result struct {
10 | 	Text               string
11 | 	TotalCount         int
12 | 	NonWhitespaceCount int
13 | }
14 | 
15 | // Count counts the total and non-whitespace characters in the given text
16 | // It properly handles multi-byte characters like Japanese text and emojis
17 | func Count(text string) Result {
18 | 	// Count total characters (including spaces)
19 | 	totalCount := len([]rune(text))
20 | 
21 | 	// Count non-whitespace characters
22 | 	nonWhitespaceCount := 0
23 | 	for _, r := range text {
24 | 		if !unicode.IsSpace(r) {
25 | 			nonWhitespaceCount++
26 | 		}
27 | 	}
28 | 
29 | 	return Result{
30 | 		Text:               text,
31 | 		TotalCount:         totalCount,
32 | 		NonWhitespaceCount: nonWhitespaceCount,
33 | 	}
34 | }
35 | 
```

--------------------------------------------------------------------------------
/cmd/direct_test/main.go:
--------------------------------------------------------------------------------

```go
 1 | package main
 2 | 
 3 | import (
 4 | 	"fmt"
 5 | 	"unicode"
 6 | )
 7 | 
 8 | func main() {
 9 | 	// Test cases
10 | 	testCases := []string{
11 | 		"Hello, World!",
12 | 		"こんにちは世界!",
13 | 		"Hello 世界 😊🚀",
14 | 		"スペースを 含む 日本語 テキスト with English and 絵文字😊",
15 | 		"1234567890",
16 | 		"    Spaces at the beginning and end    ",
17 | 		"", // Empty string
18 | 	}
19 | 
20 | 	fmt.Println("Character Count Test Results:")
21 | 	fmt.Println("============================")
22 | 
23 | 	for _, text := range testCases {
24 | 		// Count total characters (including spaces)
25 | 		totalCount := len([]rune(text))
26 | 
27 | 		// Count non-whitespace characters
28 | 		nonWhitespaceCount := 0
29 | 		for _, r := range text {
30 | 			if !unicode.IsSpace(r) {
31 | 				nonWhitespaceCount++
32 | 			}
33 | 		}
34 | 
35 | 		fmt.Printf("\nText: %s\n", text)
36 | 		fmt.Printf("Total characters: %d\n", totalCount)
37 | 		fmt.Printf("Non-whitespace characters: %d\n", nonWhitespaceCount)
38 | 		fmt.Println("----------------------------")
39 | 	}
40 | 
41 | 	fmt.Println("\nTest completed successfully!")
42 | }
43 | 
```

--------------------------------------------------------------------------------
/test/integration_test.go:
--------------------------------------------------------------------------------

```go
 1 | package test
 2 | 
 3 | import (
 4 | 	"testing"
 5 | 
 6 | 	"github.com/Atotti/mozisu-mcp-server/pkg/charcount"
 7 | )
 8 | 
 9 | // TestIntegration tests the integration between different components
10 | func TestIntegration(t *testing.T) {
11 | 	// テストケース
12 | 	testCases := []struct {
13 | 		name                  string
14 | 		input                 string
15 | 		expectedTotal         int
16 | 		expectedNonWhitespace int
17 | 	}{
18 | 		{
19 | 			name:                  "Integration test - ASCII",
20 | 			input:                 "Hello, World!",
21 | 			expectedTotal:         13,
22 | 			expectedNonWhitespace: 12,
23 | 		},
24 | 		{
25 | 			name:                  "Integration test - Japanese",
26 | 			input:                 "こんにちは世界!",
27 | 			expectedTotal:         8,
28 | 			expectedNonWhitespace: 8,
29 | 		},
30 | 	}
31 | 
32 | 	for _, tc := range testCases {
33 | 		t.Run(tc.name, func(t *testing.T) {
34 | 			// 共通パッケージを使用して文字数をカウント
35 | 			result := charcount.Count(tc.input)
36 | 
37 | 			// 結果を検証
38 | 			if result.TotalCount != tc.expectedTotal {
39 | 				t.Errorf("Expected total count %d, got %d", tc.expectedTotal, result.TotalCount)
40 | 			}
41 | 			if result.NonWhitespaceCount != tc.expectedNonWhitespace {
42 | 				t.Errorf("Expected non-whitespace count %d, got %d", tc.expectedNonWhitespace, result.NonWhitespaceCount)
43 | 			}
44 | 		})
45 | 	}
46 | }
47 | 
```

--------------------------------------------------------------------------------
/pkg/charcount/charcount_test.go:
--------------------------------------------------------------------------------

```go
 1 | package charcount
 2 | 
 3 | import (
 4 | 	"testing"
 5 | )
 6 | 
 7 | func TestCount(t *testing.T) {
 8 | 	// テストケース
 9 | 	testCases := []struct {
10 | 		name                  string
11 | 		input                 string
12 | 		expectedTotal         int
13 | 		expectedNonWhitespace int
14 | 	}{
15 | 		{
16 | 			name:                  "ASCII only",
17 | 			input:                 "Hello, World!",
18 | 			expectedTotal:         13,
19 | 			expectedNonWhitespace: 12,
20 | 		},
21 | 		{
22 | 			name:                  "Japanese characters",
23 | 			input:                 "こんにちは世界!",
24 | 			expectedTotal:         8,
25 | 			expectedNonWhitespace: 8,
26 | 		},
27 | 		{
28 | 			name:                  "Mixed with emojis",
29 | 			input:                 "Hello 世界 😊🚀",
30 | 			expectedTotal:         11,
31 | 			expectedNonWhitespace: 9,
32 | 		},
33 | 		{
34 | 			name:                  "Empty string",
35 | 			input:                 "",
36 | 			expectedTotal:         0,
37 | 			expectedNonWhitespace: 0,
38 | 		},
39 | 		{
40 | 			name:                  "Whitespace only",
41 | 			input:                 "   \t\n",
42 | 			expectedTotal:         5,
43 | 			expectedNonWhitespace: 0,
44 | 		},
45 | 	}
46 | 
47 | 	// 各テストケースを実行
48 | 	for _, tc := range testCases {
49 | 		t.Run(tc.name, func(t *testing.T) {
50 | 			// 文字数をカウント
51 | 			result := Count(tc.input)
52 | 
53 | 			// 結果を検証
54 | 			if result.TotalCount != tc.expectedTotal {
55 | 				t.Errorf("Expected total count %d, got %d", tc.expectedTotal, result.TotalCount)
56 | 			}
57 | 			if result.NonWhitespaceCount != tc.expectedNonWhitespace {
58 | 				t.Errorf("Expected non-whitespace count %d, got %d", tc.expectedNonWhitespace, result.NonWhitespaceCount)
59 | 			}
60 | 		})
61 | 	}
62 | }
63 | 
```

--------------------------------------------------------------------------------
/cmd/charcount/main.go:
--------------------------------------------------------------------------------

```go
 1 | package main
 2 | 
 3 | import (
 4 | 	"bufio"
 5 | 	"flag"
 6 | 	"fmt"
 7 | 	"os"
 8 | 	"strings"
 9 | 
10 | 	"github.com/Atotti/mozisu-mcp-server/pkg/charcount"
11 | )
12 | 
13 | func main() {
14 | 	// Parse command-line flags
15 | 	interactive := flag.Bool("i", false, "Run in interactive mode")
16 | 	flag.Parse()
17 | 
18 | 	// Get the text to count
19 | 	var text string
20 | 
21 | 	if *interactive {
22 | 		// Interactive mode
23 | 		fmt.Println("Character Count Tool")
24 | 		fmt.Println("===================")
25 | 		fmt.Println("Enter text to count characters (Ctrl+D to exit):")
26 | 
27 | 		scanner := bufio.NewScanner(os.Stdin)
28 | 		for {
29 | 			fmt.Print("> ")
30 | 			if !scanner.Scan() {
31 | 				break
32 | 			}
33 | 
34 | 			text = scanner.Text()
35 | 			printCharacterCounts(text)
36 | 		}
37 | 
38 | 		if err := scanner.Err(); err != nil {
39 | 			fmt.Fprintf(os.Stderr, "Error reading input: %v\n", err)
40 | 			os.Exit(1)
41 | 		}
42 | 	} else {
43 | 		// Command-line mode
44 | 		args := flag.Args()
45 | 		if len(args) == 0 {
46 | 			fmt.Println("Please provide text to count characters.")
47 | 			fmt.Println("Usage: charcount [text] or charcount -i for interactive mode")
48 | 			os.Exit(1)
49 | 		}
50 | 
51 | 		text = strings.Join(args, " ")
52 | 		printCharacterCounts(text)
53 | 	}
54 | }
55 | 
56 | func printCharacterCounts(text string) {
57 | 	fmt.Println("DEBUG: Starting character count")
58 | 
59 | 	// 共通パッケージを使用して文字数をカウント
60 | 	result := charcount.Count(text)
61 | 
62 | 	fmt.Printf("\nText: %s\n", result.Text)
63 | 	fmt.Printf("Total characters: %d\n", result.TotalCount)
64 | 	fmt.Printf("Non-whitespace characters: %d\n", result.NonWhitespaceCount)
65 | 	fmt.Println("----------------------------")
66 | 
67 | 	// Write to stderr as well for debugging
68 | 	os.Stderr.WriteString(fmt.Sprintf("DEBUG: Completed character count for '%s'\n", text))
69 | }
70 | 
```

--------------------------------------------------------------------------------
/main_test.go:
--------------------------------------------------------------------------------

```go
 1 | package main
 2 | 
 3 | import (
 4 | 	"testing"
 5 | 
 6 | 	"github.com/Atotti/mozisu-mcp-server/pkg/charcount"
 7 | )
 8 | 
 9 | // TestCountCharacters tests the character counting functionality
10 | func TestCountCharacters(t *testing.T) {
11 | 	// テストケース
12 | 	testCases := []struct {
13 | 		name                  string
14 | 		input                 string
15 | 		expectedTotal         int
16 | 		expectedNonWhitespace int
17 | 	}{
18 | 		{
19 | 			name:                  "ASCII only",
20 | 			input:                 "Hello, World!",
21 | 			expectedTotal:         13,
22 | 			expectedNonWhitespace: 12,
23 | 		},
24 | 		{
25 | 			name:                  "Japanese characters",
26 | 			input:                 "こんにちは世界!",
27 | 			expectedTotal:         8,
28 | 			expectedNonWhitespace: 8,
29 | 		},
30 | 		{
31 | 			name:                  "Mixed with emojis",
32 | 			input:                 "Hello 世界 😊🚀",
33 | 			expectedTotal:         11,
34 | 			expectedNonWhitespace: 9,
35 | 		},
36 | 		{
37 | 			name:                  "Empty string",
38 | 			input:                 "",
39 | 			expectedTotal:         0,
40 | 			expectedNonWhitespace: 0,
41 | 		},
42 | 		{
43 | 			name:                  "Whitespace only",
44 | 			input:                 "   \t\n",
45 | 			expectedTotal:         5,
46 | 			expectedNonWhitespace: 0,
47 | 		},
48 | 	}
49 | 
50 | 	// 各テストケースを実行
51 | 	for _, tc := range testCases {
52 | 		t.Run(tc.name, func(t *testing.T) {
53 | 			// 共通パッケージを使用して文字数をカウント
54 | 			result := charcount.Count(tc.input)
55 | 
56 | 			// 結果を検証
57 | 			if result.TotalCount != tc.expectedTotal {
58 | 				t.Errorf("Expected total count %d, got %d", tc.expectedTotal, result.TotalCount)
59 | 			}
60 | 			if result.NonWhitespaceCount != tc.expectedNonWhitespace {
61 | 				t.Errorf("Expected non-whitespace count %d, got %d", tc.expectedNonWhitespace, result.NonWhitespaceCount)
62 | 			}
63 | 		})
64 | 	}
65 | }
66 | 
```

--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------

```yaml
 1 | name: CI
 2 | 
 3 | on:
 4 |   push:
 5 |     branches: [ main ]
 6 |   pull_request:
 7 |     branches: [ main ]
 8 | 
 9 | jobs:
10 |   lint:
11 |     name: Lint
12 |     runs-on: ubuntu-latest
13 |     steps:
14 |       - name: Checkout code
15 |         uses: actions/checkout@v3
16 | 
17 |       - name: Set up Go
18 |         uses: actions/setup-go@v4
19 |         with:
20 |           go-version: '1.23'
21 |           cache: true
22 | 
23 |       - name: Install golangci-lint
24 |         run: |
25 |           curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.55.2
26 | 
27 |       - name: Install Task
28 |         run: |
29 |           sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b ~/.local/bin
30 |           echo "$HOME/.local/bin" >> $GITHUB_PATH
31 | 
32 |       - name: Run linter
33 |         run: task lint
34 | 
35 |   test:
36 |     name: Test
37 |     runs-on: ubuntu-latest
38 |     strategy:
39 |       matrix:
40 |         go-version: ['1.21', '1.22', '1.23']
41 |     steps:
42 |       - name: Checkout code
43 |         uses: actions/checkout@v3
44 | 
45 |       - name: Set up Go ${{ matrix.go-version }}
46 |         uses: actions/setup-go@v4
47 |         with:
48 |           go-version: ${{ matrix.go-version }}
49 |           cache: true
50 | 
51 |       - name: Install Task
52 |         run: |
53 |           sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b ~/.local/bin
54 |           echo "$HOME/.local/bin" >> $GITHUB_PATH
55 | 
56 |       - name: Run tests
57 |         run: task test
58 | 
59 |   build:
60 |     name: Build
61 |     runs-on: ubuntu-latest
62 |     needs: [lint, test]
63 |     steps:
64 |       - name: Checkout code
65 |         uses: actions/checkout@v3
66 | 
67 |       - name: Set up Go
68 |         uses: actions/setup-go@v4
69 |         with:
70 |           go-version: '1.23'
71 |           cache: true
72 | 
73 |       - name: Install Task
74 |         run: |
75 |           sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b ~/.local/bin
76 |           echo "$HOME/.local/bin" >> $GITHUB_PATH
77 | 
78 |       - name: Build applications
79 |         run: task build
80 | 
81 |       - name: Upload artifacts
82 |         uses: actions/upload-artifact@v3
83 |         with:
84 |           name: binaries
85 |           path: bin/
86 | 
```

--------------------------------------------------------------------------------
/cmd/test/test_client.go:
--------------------------------------------------------------------------------

```go
  1 | package main
  2 | 
  3 | import (
  4 | 	"encoding/json"
  5 | 	"fmt"
  6 | 	"os/exec"
  7 | )
  8 | 
  9 | // JSON-RPC request structure
 10 | type Request struct {
 11 | 	JsonRPC string      `json:"jsonrpc"`
 12 | 	ID      int         `json:"id"`
 13 | 	Method  string      `json:"method"`
 14 | 	Params  interface{} `json:"params"`
 15 | }
 16 | 
 17 | // CallToolRequest parameters
 18 | type CallToolParams struct {
 19 | 	Name      string                 `json:"name"`
 20 | 	Arguments map[string]interface{} `json:"arguments"`
 21 | }
 22 | 
 23 | func RunTest() {
 24 | 	// Start the MCP server as a subprocess
 25 | 	cmd := exec.Command("go", "run", "../../main.go")
 26 | 
 27 | 	// Set up pipes for stdin and stdout
 28 | 	stdin, err := cmd.StdinPipe()
 29 | 	if err != nil {
 30 | 		fmt.Println("Error creating stdin pipe:", err)
 31 | 		return
 32 | 	}
 33 | 
 34 | 	stdout, err := cmd.StdoutPipe()
 35 | 	if err != nil {
 36 | 		fmt.Println("Error creating stdout pipe:", err)
 37 | 		return
 38 | 	}
 39 | 
 40 | 	// Start the server
 41 | 	if err := cmd.Start(); err != nil {
 42 | 		fmt.Println("Error starting server:", err)
 43 | 		return
 44 | 	}
 45 | 
 46 | 	// Create a request to call the count_characters tool
 47 | 	request := Request{
 48 | 		JsonRPC: "2.0",
 49 | 		ID:      1,
 50 | 		Method:  "call_tool",
 51 | 		Params: CallToolParams{
 52 | 			Name: "count_characters",
 53 | 			Arguments: map[string]interface{}{
 54 | 				"text": "こんにちは世界!Hello World! 😊🚀",
 55 | 			},
 56 | 		},
 57 | 	}
 58 | 
 59 | 	// Marshal the request to JSON
 60 | 	requestJSON, err := json.Marshal(request)
 61 | 	if err != nil {
 62 | 		fmt.Println("Error marshaling request:", err)
 63 | 		return
 64 | 	}
 65 | 
 66 | 	// Add a newline to the request
 67 | 	requestJSON = append(requestJSON, '\n')
 68 | 
 69 | 	// Send the request to the server
 70 | 	_, err = stdin.Write(requestJSON)
 71 | 	if err != nil {
 72 | 		fmt.Println("Error writing to stdin:", err)
 73 | 		return
 74 | 	}
 75 | 
 76 | 	// Read the response
 77 | 	buf := make([]byte, 4096)
 78 | 	n, err := stdout.Read(buf)
 79 | 	if err != nil {
 80 | 		fmt.Println("Error reading from stdout:", err)
 81 | 		return
 82 | 	}
 83 | 
 84 | 	// Print the response
 85 | 	fmt.Println("Response from server:")
 86 | 	fmt.Println(string(buf[:n]))
 87 | 
 88 | 	// Test with another example
 89 | 	request.ID = 2
 90 | 	request.Method = "call_tool"
 91 | 	request.Params = CallToolParams{
 92 | 		Name: "count_characters",
 93 | 		Arguments: map[string]interface{}{
 94 | 			"text": "スペースを 含む 日本語 テキスト with English and 絵文字😊",
 95 | 		},
 96 | 	}
 97 | 
 98 | 	// Marshal the request to JSON
 99 | 	requestJSON, err = json.Marshal(request)
100 | 	if err != nil {
101 | 		fmt.Println("Error marshaling request:", err)
102 | 		return
103 | 	}
104 | 
105 | 	// Add a newline to the request
106 | 	requestJSON = append(requestJSON, '\n')
107 | 
108 | 	// Send the request to the server
109 | 	_, err = stdin.Write(requestJSON)
110 | 	if err != nil {
111 | 		fmt.Println("Error writing to stdin:", err)
112 | 		return
113 | 	}
114 | 
115 | 	// Read the response
116 | 	n, err = stdout.Read(buf)
117 | 	if err != nil {
118 | 		fmt.Println("Error reading from stdout:", err)
119 | 		return
120 | 	}
121 | 
122 | 	// Print the response
123 | 	fmt.Println("\nResponse from server (second test):")
124 | 	fmt.Println(string(buf[:n]))
125 | 
126 | 	// Kill the server process
127 | 	cmd.Process.Kill()
128 | }
129 | 
```

--------------------------------------------------------------------------------
/cmd/test/mcp_client.go:
--------------------------------------------------------------------------------

```go
  1 | package main
  2 | 
  3 | import (
  4 | 	"bufio"
  5 | 	"encoding/json"
  6 | 	"fmt"
  7 | 	"io"
  8 | 	"os/exec"
  9 | 	"time"
 10 | )
 11 | 
 12 | // MCP protocol request
 13 | type MCPRequest struct {
 14 | 	JsonRPC string      `json:"jsonrpc"`
 15 | 	ID      int         `json:"id"`
 16 | 	Method  string      `json:"method"`
 17 | 	Params  interface{} `json:"params"`
 18 | }
 19 | 
 20 | // MCP protocol response
 21 | type MCPResponse struct {
 22 | 	JsonRPC string          `json:"jsonrpc"`
 23 | 	ID      int             `json:"id"`
 24 | 	Result  json.RawMessage `json:"result,omitempty"`
 25 | 	Error   *struct {
 26 | 		Code    int    `json:"code"`
 27 | 		Message string `json:"message"`
 28 | 	} `json:"error,omitempty"`
 29 | }
 30 | 
 31 | func main() {
 32 | 	fmt.Println("Starting MCP protocol test...")
 33 | 
 34 | 	// Start the MCP server
 35 | 	cmd := exec.Command("go", "run", "../../main.go")
 36 | 
 37 | 	stdin, _ := cmd.StdinPipe()
 38 | 	stdout, _ := cmd.StdoutPipe()
 39 | 
 40 | 	cmd.Start()
 41 | 
 42 | 	// Give the server a moment to start up
 43 | 	time.Sleep(500 * time.Millisecond)
 44 | 
 45 | 	// Create a reader for the stdout
 46 | 	reader := bufio.NewReader(stdout)
 47 | 
 48 | 	// First, try to list available tools
 49 | 	listToolsRequest := MCPRequest{
 50 | 		JsonRPC: "2.0",
 51 | 		ID:      1,
 52 | 		Method:  "listTools",
 53 | 		Params:  struct{}{},
 54 | 	}
 55 | 
 56 | 	// Send the request
 57 | 	requestJSON, _ := json.Marshal(listToolsRequest)
 58 | 	fmt.Printf("Request: %s\n", requestJSON)
 59 | 	io.WriteString(stdin, string(requestJSON)+"\n")
 60 | 
 61 | 	// Read the response
 62 | 	responseStr, _ := reader.ReadString('\n')
 63 | 	fmt.Printf("Response: %s\n\n", responseStr)
 64 | 
 65 | 	// Try to parse the response
 66 | 	var response MCPResponse
 67 | 	json.Unmarshal([]byte(responseStr), &response)
 68 | 
 69 | 	// If we got an error, try some other common method names
 70 | 	if response.Error != nil {
 71 | 		methods := []string{
 72 | 			"list_tools",
 73 | 			"tools.list",
 74 | 			"get_tools",
 75 | 			"tools",
 76 | 		}
 77 | 
 78 | 		for i, method := range methods {
 79 | 			listToolsRequest.ID = i + 2
 80 | 			listToolsRequest.Method = method
 81 | 
 82 | 			requestJSON, _ := json.Marshal(listToolsRequest)
 83 | 			fmt.Printf("Trying method: %s\n", method)
 84 | 			fmt.Printf("Request: %s\n", requestJSON)
 85 | 
 86 | 			io.WriteString(stdin, string(requestJSON)+"\n")
 87 | 			responseStr, _ := reader.ReadString('\n')
 88 | 			fmt.Printf("Response: %s\n\n", responseStr)
 89 | 		}
 90 | 	}
 91 | 
 92 | 	// Now try to call our count_characters tool directly
 93 | 	callToolRequest := MCPRequest{
 94 | 		JsonRPC: "2.0",
 95 | 		ID:      10,
 96 | 		Method:  "callTool",
 97 | 		Params: map[string]interface{}{
 98 | 			"name": "count_characters",
 99 | 			"arguments": map[string]interface{}{
100 | 				"text": "こんにちは世界!Hello World! 😊🚀",
101 | 			},
102 | 		},
103 | 	}
104 | 
105 | 	// Try different method names for calling a tool
106 | 	callMethods := []string{
107 | 		"callTool",
108 | 		"call_tool",
109 | 		"tool.call",
110 | 		"execute",
111 | 		"run",
112 | 	}
113 | 
114 | 	for i, method := range callMethods {
115 | 		callToolRequest.ID = 10 + i
116 | 		callToolRequest.Method = method
117 | 
118 | 		requestJSON, _ := json.Marshal(callToolRequest)
119 | 		fmt.Printf("Trying method: %s\n", method)
120 | 		fmt.Printf("Request: %s\n", requestJSON)
121 | 
122 | 		io.WriteString(stdin, string(requestJSON)+"\n")
123 | 		responseStr, _ := reader.ReadString('\n')
124 | 		fmt.Printf("Response: %s\n\n", responseStr)
125 | 	}
126 | 
127 | 	// Kill the server
128 | 	cmd.Process.Kill()
129 | 	fmt.Println("Test completed.")
130 | }
131 | 
```

--------------------------------------------------------------------------------
/cmd/webserver/main.go:
--------------------------------------------------------------------------------

```go
  1 | package main
  2 | 
  3 | import (
  4 | 	"encoding/json"
  5 | 	"log"
  6 | 	"net/http"
  7 | 
  8 | 	"github.com/Atotti/mozisu-mcp-server/internal/server"
  9 | 	"github.com/Atotti/mozisu-mcp-server/pkg/charcount"
 10 | )
 11 | 
 12 | func main() {
 13 | 	// Define HTTP handlers
 14 | 	mux := http.NewServeMux()
 15 | 	mux.HandleFunc("/", handleHome)
 16 | 	mux.HandleFunc("/count", handleCount)
 17 | 
 18 | 	// サーバー設定
 19 | 	config := server.DefaultConfig()
 20 | 	config.Port = 8080
 21 | 
 22 | 	// サーバーを起動
 23 | 	log.Println("Starting character count web server...")
 24 | 	if err := server.RunHTTPServer(mux, config); err != nil {
 25 | 		log.Fatalf("Server error: %v\n", err)
 26 | 	}
 27 | }
 28 | 
 29 | // handleHome serves the home page with a simple form
 30 | func handleHome(w http.ResponseWriter, r *http.Request) {
 31 | 	html := `
 32 | <!DOCTYPE html>
 33 | <html>
 34 | <head>
 35 |     <title>Character Count Tool</title>
 36 |     <style>
 37 |         body {
 38 |             font-family: Arial, sans-serif;
 39 |             max-width: 800px;
 40 |             margin: 0 auto;
 41 |             padding: 20px;
 42 |         }
 43 |         textarea {
 44 |             width: 100%;
 45 |             height: 150px;
 46 |             margin-bottom: 10px;
 47 |         }
 48 |         button {
 49 |             padding: 8px 16px;
 50 |             background-color: #4CAF50;
 51 |             color: white;
 52 |             border: none;
 53 |             cursor: pointer;
 54 |         }
 55 |         #result {
 56 |             margin-top: 20px;
 57 |             padding: 10px;
 58 |             border: 1px solid #ddd;
 59 |             border-radius: 4px;
 60 |             display: none;
 61 |         }
 62 |     </style>
 63 | </head>
 64 | <body>
 65 |     <h1>Character Count Tool</h1>
 66 |     <p>Enter text below to count characters:</p>
 67 | 
 68 |     <textarea id="text" placeholder="Enter text here..."></textarea>
 69 |     <button onclick="countCharacters()">Count Characters</button>
 70 | 
 71 |     <div id="result"></div>
 72 | 
 73 |     <script>
 74 |         function countCharacters() {
 75 |             const text = document.getElementById('text').value;
 76 | 
 77 |             fetch('/count', {
 78 |                 method: 'POST',
 79 |                 headers: {
 80 |                     'Content-Type': 'application/json',
 81 |                 },
 82 |                 body: JSON.stringify({ text: text }),
 83 |             })
 84 |             .then(response => response.json())
 85 |             .then(data => {
 86 |                 const resultDiv = document.getElementById('result');
 87 |                 resultDiv.innerHTML =
 88 |                     '<h2>Results:</h2>' +
 89 |                     '<p><strong>Text:</strong> ' + data.text + '</p>' +
 90 |                     '<p><strong>Total characters:</strong> ' + data.totalCount + '</p>' +
 91 |                     '<p><strong>Non-whitespace characters:</strong> ' + data.nonWhitespaceCount + '</p>';
 92 |                 resultDiv.style.display = 'block';
 93 |             })
 94 |             .catch(error => {
 95 |                 console.error('Error:', error);
 96 |                 alert('An error occurred while counting characters.');
 97 |             });
 98 |         }
 99 |     </script>
100 | </body>
101 | </html>
102 | `
103 | 	w.Header().Set("Content-Type", "text/html")
104 | 	if _, err := w.Write([]byte(html)); err != nil {
105 | 		log.Printf("Error writing response: %v", err)
106 | 	}
107 | }
108 | 
109 | // handleCount processes the character count request
110 | func handleCount(w http.ResponseWriter, r *http.Request) {
111 | 	// Only allow POST requests
112 | 	if r.Method != http.MethodPost {
113 | 		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
114 | 		return
115 | 	}
116 | 
117 | 	// Parse the request body
118 | 	var request struct {
119 | 		Text string `json:"text"`
120 | 	}
121 | 
122 | 	decoder := json.NewDecoder(r.Body)
123 | 	if err := decoder.Decode(&request); err != nil {
124 | 		http.Error(w, "Invalid request body", http.StatusBadRequest)
125 | 		return
126 | 	}
127 | 
128 | 	// 共通パッケージを使用して文字数をカウント
129 | 	result := charcount.Count(request.Text)
130 | 
131 | 	// Create the response
132 | 	response := struct {
133 | 		Text               string `json:"text"`
134 | 		TotalCount         int    `json:"totalCount"`
135 | 		NonWhitespaceCount int    `json:"nonWhitespaceCount"`
136 | 	}{
137 | 		Text:               result.Text,
138 | 		TotalCount:         result.TotalCount,
139 | 		NonWhitespaceCount: result.NonWhitespaceCount,
140 | 	}
141 | 
142 | 	// Send the response
143 | 	w.Header().Set("Content-Type", "application/json")
144 | 	if err := json.NewEncoder(w).Encode(response); err != nil {
145 | 		log.Printf("Error encoding JSON response: %v", err)
146 | 	}
147 | }
148 | 
```