Skip to content

Commit 99d1b41

Browse files
authored
updates to mcp/go-sdk v1.0.0 (#67)
* updates to go-sdk 1.0.0 Signed-off-by: ChrisJBurns <[email protected]> * adds claude.md and fixes integration tests Signed-off-by: ChrisJBurns <[email protected]> * refines claude.md Signed-off-by: ChrisJBurns <[email protected]> --------- Signed-off-by: ChrisJBurns <[email protected]>
1 parent 1aaea18 commit 99d1b41

File tree

6 files changed

+220
-13
lines changed

6 files changed

+220
-13
lines changed

CLAUDE.md

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
# Claude Agent Context - GoFetch MCP Server
2+
3+
This document provides essential context for Claude agents working with the GoFetch MCP (Model Context Protocol) server repository.
4+
5+
## Project Overview
6+
7+
**GoFetch** is a Go implementation of an MCP server that retrieves web content. It's designed as a more efficient alternative to the original Python MCP fetch server, offering:
8+
9+
- **Lower memory usage** and **faster startup/shutdown**
10+
- **Single binary deployment** for enhanced security
11+
- **Better concurrent request handling**
12+
- **Container security** with non-root user and distroless images
13+
- **Multiple transport protocols** (SSE and StreamableHTTP)
14+
15+
## Architecture & Key Components
16+
17+
### Core Packages
18+
19+
1. **`pkg/config/`** - Server configuration management
20+
- Handles command-line flags and environment variables
21+
- Supports transport types: `sse` and `streamable-http`
22+
- Configuration for port, user agent, robots.txt compliance, proxy settings
23+
24+
2. **`pkg/server/`** - MCP server implementation
25+
- Main server logic with transport-specific handlers
26+
- Tool registration and request handling
27+
- Endpoint management for SSE and StreamableHTTP
28+
29+
3. **`pkg/fetcher/`** - HTTP content retrieval
30+
- Handles HTTP requests with proper headers
31+
- Integrates with robots.txt checking
32+
- Content processing and error handling
33+
34+
4. **`pkg/processor/`** - Content processing
35+
- HTML to Markdown conversion using `html-to-markdown`
36+
- Content extraction using `go-readability`
37+
- Text formatting with pagination and truncation
38+
39+
5. **`pkg/robots/`** - Robots.txt compliance
40+
- Fetches and parses robots.txt files
41+
- Validates URL access permissions
42+
- Configurable to ignore robots.txt rules
43+
44+
### Entry Point
45+
- **`cmd/server/main.go`** - Application entry point
46+
- Parses configuration
47+
- Creates and starts the fetch server
48+
- Handles graceful shutdown
49+
50+
## MCP Tool: `fetch`
51+
52+
The server provides a single MCP tool called `fetch` with these parameters:
53+
54+
```json
55+
{
56+
"name": "fetch",
57+
"arguments": {
58+
"url": "https://example.com", // Required: URL to fetch
59+
"max_length": 5000, // Optional: Max characters (default: 5000, max: 1000000)
60+
"start_index": 0, // Optional: Starting character index (default: 0)
61+
"raw": false // Optional: Return raw HTML vs markdown (default: false)
62+
}
63+
}
64+
```
65+
66+
## Transport Protocols
67+
68+
### 1. StreamableHTTP (Default - Recommended)
69+
- **Endpoint**: `http://localhost:8080/mcp`
70+
- **Session Management**: HTTP headers (`Mcp-Session-Id`)
71+
- **Communication**: Single endpoint for both streaming and commands
72+
- **Modern**: Preferred transport for new implementations
73+
74+
### 2. SSE (Legacy)
75+
- **SSE Endpoint**: `http://localhost:8080/sse` (server-to-client)
76+
- **Messages Endpoint**: `http://localhost:8080/messages` (client-to-server)
77+
- **Session Management**: Query parameters (`?sessionid=...`)
78+
- **Legacy**: Maintained for backward compatibility
79+
80+
## Configuration Options
81+
82+
### Command Line Flags
83+
```bash
84+
--transport string # Transport type: sse or streamable-http (default: streamable-http)
85+
--port int # Port number (default: 8080)
86+
--user-agent string # Custom User-Agent string
87+
--ignore-robots-txt # Ignore robots.txt rules
88+
--proxy-url string # Proxy URL for requests
89+
```
90+
91+
### Environment Variables
92+
```bash
93+
TRANSPORT=sse # Override transport type
94+
MCP_PORT=8080 # Override port number
95+
```
96+
97+
## Dependencies & Key Libraries
98+
99+
### Core Dependencies
100+
- **`github.com/modelcontextprotocol/go-sdk`** v1.0.0 - MCP SDK for Go (stable release)
101+
- **`github.com/JohannesKaufmann/html-to-markdown`** - HTML to Markdown conversion
102+
- **`github.com/go-shiori/go-readability`** - Content extraction
103+
- **`golang.org/x/net`** - HTTP client and HTML parsing
104+
105+
### Build & Development
106+
- **Go 1.24+** required
107+
- **Task** for build automation (see `Taskfile.yml`)
108+
- **golangci-lint** for code quality
109+
- **ko** for container image building
110+
111+
## Development Workflow
112+
113+
### Build Commands
114+
```bash
115+
task build # Build the application
116+
task run # Run the application
117+
task test # Run tests
118+
task test-integration # Run integration tests
119+
task lint # Run linting
120+
task fmt # Format code
121+
task clean # Clean build directory
122+
```
123+
124+
### Testing
125+
- Unit tests in each package (`*_test.go` files)
126+
- Integration tests in `test/` directory
127+
- `test/integration-test.sh` - Tests SSE and StreamableHTTP transports with tool calls
128+
- `test/integration-endpoints.sh` - Tests endpoint accessibility and responses
129+
- Requires `yardstick-client` for integration tests (installed via `go install`)
130+
131+
## Container Deployment
132+
133+
### Container Image
134+
- **Registry**: `ghcr.io/stackloklabs/gofetch/server`
135+
- **Security**: Non-root user, distroless image
136+
- **Signing**: Container signing with build provenance
137+
138+
## API Usage Examples
139+
140+
### StreamableHTTP Example
141+
```bash
142+
# Initialize session
143+
SESSION_ID=$(curl -s -D /dev/stderr -X POST "http://localhost:8080/mcp" \
144+
-H "Content-Type: application/json" \
145+
-H "Mcp-Protocol-Version: 2025-06-18" \
146+
-d '{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {...}}' \
147+
2>&1 >/dev/null | grep "Mcp-Session-Id:" | cut -d' ' -f2)
148+
149+
# Call fetch tool
150+
curl -X POST "http://localhost:8080/mcp" \
151+
-H "Content-Type: application/json" \
152+
-H "Mcp-Session-Id: $SESSION_ID" \
153+
-d '{"jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": {"name": "fetch", "arguments": {"url": "https://example.com"}}}'
154+
```
155+
156+
## Security Considerations
157+
158+
1. **Robots.txt Compliance**: Respects robots.txt by default (can be disabled)
159+
2. **User-Agent**: Configurable user agent string
160+
3. **Proxy Support**: HTTP proxy configuration
161+
4. **Container Security**: Non-root user, minimal attack surface
162+
5. **Content Limits**: Configurable content length limits
163+
164+
## Error Handling
165+
166+
The server handles various error conditions:
167+
- **HTTP errors**: Non-200 status codes
168+
- **Robots.txt violations**: Access denied by robots.txt
169+
- **Network errors**: Connection timeouts, DNS failures
170+
- **Content processing errors**: HTML parsing failures
171+
- **Configuration errors**: Invalid transport types, port conflicts
172+
173+
## Logging
174+
175+
The server provides comprehensive logging:
176+
- **Startup information**: Transport, port, user agent, endpoints
177+
- **Request logging**: URL fetching, HTTP status codes, content lengths
178+
- **Error logging**: Detailed error messages for debugging
179+
- **Session management**: Session creation and endpoint communication
180+
181+
## Performance Characteristics
182+
183+
- **Memory efficient**: Lower memory usage than Python implementation
184+
- **Fast startup**: Quick server initialization
185+
- **Concurrent handling**: Better request concurrency
186+
- **Content processing**: Efficient HTML to Markdown conversion
187+
- **Caching**: Robots.txt content caching for performance
188+
189+
## Integration Points
190+
191+
### MCP Protocol Compliance
192+
- Full MCP specification compliance (2025-06-18)
193+
- Tool registration and discovery
194+
- Session management with stateful/stateless support
195+
- Error handling and logging
196+
- Proper HTTP method support (GET for SSE, POST for requests, DELETE for session termination)
197+
198+
### External Dependencies
199+
- **Web content**: HTTP fetching with proper headers
200+
- **Robots.txt**: Automatic compliance checking
201+
- **Content extraction**: Readability-based content extraction
202+
- **Markdown conversion**: HTML to Markdown transformation
203+
204+
This context should help Claude agents understand the codebase structure, implementation details, and usage patterns for effective collaboration on the GoFetch MCP server project.

go.mod

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ toolchain go1.25.1
66

77
require (
88
github.com/JohannesKaufmann/html-to-markdown v1.6.0
9-
github.com/JohannesKaufmann/html-to-markdown/v2 v2.4.0
109
github.com/go-shiori/go-readability v0.0.0-20250217085726-9f5bf5ca7612
11-
github.com/modelcontextprotocol/go-sdk v0.5.0
10+
github.com/modelcontextprotocol/go-sdk v1.0.0
1211
golang.org/x/net v0.44.0
1312
)
1413

@@ -18,7 +17,7 @@ require (
1817
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de // indirect
1918
github.com/go-shiori/dom v0.0.0-20230515143342-73569d674e1c // indirect
2019
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f // indirect
21-
github.com/google/jsonschema-go v0.2.3 // indirect
20+
github.com/google/jsonschema-go v0.3.0 // indirect
2221
github.com/sebdah/goldie/v2 v2.7.1 // indirect
2322
github.com/sergi/go-diff v1.4.0 // indirect
2423
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect

go.sum

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
github.com/JohannesKaufmann/html-to-markdown v1.6.0 h1:04VXMiE50YYfCfLboJCLcgqF5x+rHJnb1ssNmqpLH/k=
22
github.com/JohannesKaufmann/html-to-markdown v1.6.0/go.mod h1:NUI78lGg/a7vpEJTz/0uOcYMaibytE4BUOQS8k78yPQ=
3-
github.com/JohannesKaufmann/html-to-markdown/v2 v2.4.0/go.mod h1:OLaKh+giepO8j7teevrNwiy/fwf8LXgoc9g7rwaE1jk=
43
github.com/PuerkitoBio/goquery v1.9.2 h1:4/wZksC3KgkQw7SQgkKotmKljk0M6V8TUvA8Wb4yPeE=
54
github.com/PuerkitoBio/goquery v1.9.2/go.mod h1:GHPCaP0ODyyxqcNoFGYlAprUFH81NuRPd0GX3Zu2Mvk=
65
github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
@@ -20,14 +19,14 @@ github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW
2019
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
2120
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
2221
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
23-
github.com/google/jsonschema-go v0.2.3 h1:dkP3B96OtZKKFvdrUSaDkL+YDx8Uw9uC4Y+eukpCnmM=
24-
github.com/google/jsonschema-go v0.2.3/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
22+
github.com/google/jsonschema-go v0.3.0 h1:6AH2TxVNtk3IlvkkhjrtbUc4S8AvO0Xii0DxIygDg+Q=
23+
github.com/google/jsonschema-go v0.3.0/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
2524
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
2625
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
2726
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
2827
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
29-
github.com/modelcontextprotocol/go-sdk v0.5.0 h1:WXRHx/4l5LF5MZboeIJYn7PMFCrMNduGGVapYWFgrF8=
30-
github.com/modelcontextprotocol/go-sdk v0.5.0/go.mod h1:degUj7OVKR6JcYbDF+O99Fag2lTSTbamZacbGTRTSGU=
28+
github.com/modelcontextprotocol/go-sdk v1.0.0 h1:Z4MSjLi38bTgLrd/LjSmofqRqyBiVKRyQSJgw8q8V74=
29+
github.com/modelcontextprotocol/go-sdk v1.0.0/go.mod h1:nYtYQroQ2KQiM0/SbyEPUWQ6xs4B95gJjEalc9AQyOs=
3130
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
3231
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
3332
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=

pkg/server/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ func (fs *FetchServer) startSSEServer() error {
174174
// Create SSE handler according to MCP specification
175175
sseHandler := mcp.NewSSEHandler(func(_ *http.Request) *mcp.Server {
176176
return fs.mcpServer
177-
})
177+
}, &mcp.SSEOptions{})
178178

179179
// Handle SSE endpoint
180180
mux.Handle("/sse", sseHandler)

test/integration-endpoints.sh

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,9 @@ else
8989
fi
9090

9191
echo "🔎 Checking /mcp (GET)"
92-
MCP_GET_STATUS=$(check_status GET "http://localhost:8081/mcp" "" "" || true)
93-
if [ "$MCP_GET_STATUS" = "200" ] || [ "$MCP_GET_STATUS" = "400" ]; then
92+
# GET without session should return 405 according to MCP spec for stateful servers
93+
MCP_GET_STATUS=$(curl -s -o /dev/null -m 5 -w "%{http_code}" -H 'Accept: text/event-stream' "http://localhost:8081/mcp" 2>/dev/null || echo "000")
94+
if [ "$MCP_GET_STATUS" = "200" ] || [ "$MCP_GET_STATUS" = "400" ] || [ "$MCP_GET_STATUS" = "405" ]; then
9495
echo "✓ /mcp endpoint reachable via GET ($MCP_GET_STATUS)"
9596
else
9697
echo "! /mcp endpoint GET not reachable (status: $MCP_GET_STATUS)"

test/integration-test.sh

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,12 @@ if docker ps | grep -q gofetch-sse-test; then
6767
fi
6868

6969
echo "🔧 Testing tool calling via SSE..."
70-
if yardstick-client -transport sse -address localhost -port 8080 -action=call-tool -tool=fetch -args='{"url":"https://example.com"}' | grep -q "This domain is for use in illustrative examples in documents"; then
70+
OUTPUT=$(yardstick-client -transport sse -address localhost -port 8080 -action=call-tool -tool=fetch -args='{"url":"https://example.com"}' 2>/dev/null)
71+
if echo "$OUTPUT" | grep -q "This domain is for use in illustrative examples in documents"; then
7172
echo "✅ SSE tool call returned expected output"
7273
else
7374
echo "! SSE tool call did not return expected output"
75+
echo "Output received: $OUTPUT"
7476
exit 1
7577
fi
7678
else
@@ -117,10 +119,12 @@ if docker ps | grep -q gofetch-http-test; then
117119
fi
118120

119121
echo "🔧 Testing tool calling via streamable-http..."
120-
if yardstick-client -transport streamable-http -address localhost -port 8081 -action=call-tool -tool=fetch -args='{"url":"https://example.com"}' | grep -q "This domain is for use in illustrative examples in documents"; then
122+
OUTPUT=$(yardstick-client -transport streamable-http -address localhost -port 8081 -action=call-tool -tool=fetch -args='{"url":"https://example.com"}' 2>/dev/null)
123+
if echo "$OUTPUT" | grep -q "This domain is for use in illustrative examples in documents"; then
121124
echo "✅ Streamable tool call returned expected output"
122125
else
123126
echo "! Streamable tool call did not return expected output"
127+
echo "Output received: $OUTPUT"
124128
exit 1
125129
fi
126130
else

0 commit comments

Comments
 (0)