-
Notifications
You must be signed in to change notification settings - Fork 874
fix(mcp): accept empty text and blob resource contents #952
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -223,6 +223,40 @@ func TestParseResourceContents(t *testing.T) { | |
| assert.Contains(t, err.Error(), "uri is missing") | ||
| }) | ||
|
|
||
| t.Run("empty text resource", func(t *testing.T) { | ||
| contentMap := map[string]any{ | ||
| "uri": "file:///empty.txt", | ||
| "mimeType": "text/plain", | ||
| "text": "", | ||
| } | ||
|
|
||
| result, err := ParseResourceContents(contentMap) | ||
| require.NoError(t, err) | ||
|
|
||
| textRes, ok := result.(TextResourceContents) | ||
| require.True(t, ok) | ||
| assert.Equal(t, "file:///empty.txt", textRes.URI) | ||
| assert.Equal(t, "text/plain", textRes.MIMEType) | ||
| assert.Empty(t, textRes.Text) | ||
| }) | ||
|
|
||
| t.Run("empty blob resource", func(t *testing.T) { | ||
| contentMap := map[string]any{ | ||
| "uri": "file:///empty.bin", | ||
| "mimeType": "application/octet-stream", | ||
| "blob": "", | ||
| } | ||
|
|
||
| result, err := ParseResourceContents(contentMap) | ||
| require.NoError(t, err) | ||
|
|
||
| blobRes, ok := result.(BlobResourceContents) | ||
| require.True(t, ok) | ||
| assert.Equal(t, "file:///empty.bin", blobRes.URI) | ||
| assert.Equal(t, "application/octet-stream", blobRes.MIMEType) | ||
| assert.Empty(t, blobRes.Blob) | ||
| }) | ||
|
|
||
| t.Run("no text or blob", func(t *testing.T) { | ||
| contentMap := map[string]any{ | ||
| "uri": "file:///test", | ||
|
|
@@ -232,6 +266,40 @@ func TestParseResourceContents(t *testing.T) { | |
| assert.Error(t, err) | ||
| assert.Contains(t, err.Error(), "unsupported resource type") | ||
| }) | ||
|
|
||
| t.Run("non-string text falls through", func(t *testing.T) { | ||
| contentMap := map[string]any{ | ||
| "uri": "file:///test", | ||
| "text": 42, | ||
| } | ||
|
|
||
| _, err := ParseResourceContents(contentMap) | ||
| assert.Error(t, err) | ||
| assert.Contains(t, err.Error(), "unsupported resource type") | ||
|
Comment on lines
+276
to
+278
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -eu
file="$(fd -t f -p 'mcp/utils_additional_test.go' | head -n 1)"
printf '%s\n' "== test context =="
sed -n '250,290p' "$file"
printf '%s\n' "== parser declarations and call sites =="
rg -n -A35 -B10 'func ParseResourceContents|ParseResourceContents\(' --glob '*.go' .Repository: mark3labs/mcp-go Length of output: 21542 🏁 Script executed: #!/bin/bash
set -eu
file="$(fd -t f -p 'mcp/utils_additional_test.go' | head -n 1)"
sed -n '250,290p' "$file"
rg -n -A35 -B10 'func ParseResourceContents|ParseResourceContents\(' --glob '*.go' .Repository: mark3labs/mcp-go Length of output: 21482 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '== parser terminal branch =='
sed -n '821,865p' mcp/utils.go
printf '%s\n' '== standalone nil-error probe =='
cat >/tmp/nil_error_probe.go <<'EOF'
package main
import "fmt"
func main() {
var err error
defer func() {
if r := recover(); r != nil {
fmt.Printf("err.Error() panics with %T\n", r)
}
}()
_ = err.Error()
fmt.Println("err.Error() did not panic")
}
EOF
go run /tmp/nil_error_probe.go
rm -f /tmp/nil_error_probe.goRepository: mark3labs/mcp-go Length of output: 1526 🏁 Script executed: #!/bin/bash
set -eu
sed -n '821,865p' mcp/utils.go
cat >/tmp/nil_error_probe.go <<'EOF'
package main
import "fmt"
func main() {
var err error
defer func() {
if r := recover(); r != nil {
fmt.Printf("err.Error() panics with %T\n", r)
}
}()
_ = err.Error()
fmt.Println("err.Error() did not panic")
}
EOF
go run /tmp/nil_error_probe.goRepository: mark3labs/mcp-go Length of output: 1464 Use 🤖 Prompt for AI Agents |
||
| }) | ||
| } | ||
|
|
||
| // Test that a resources/read response carrying an empty text resource round | ||
| // trips through ParseReadResourceResult, which is the path Client.ReadResource | ||
| // takes. | ||
|
|
||
| func TestParseReadResourceResultEmptyText(t *testing.T) { | ||
| payload, err := json.Marshal(ReadResourceResult{ | ||
| Contents: []ResourceContents{ | ||
| TextResourceContents{URI: "file:///empty.txt", MIMEType: "text/plain"}, | ||
| }, | ||
| }) | ||
| require.NoError(t, err) | ||
|
|
||
| raw := json.RawMessage(payload) | ||
| result, err := ParseReadResourceResult(&raw) | ||
| require.NoError(t, err) | ||
| require.Len(t, result.Contents, 1) | ||
|
|
||
| textRes, ok := result.Contents[0].(TextResourceContents) | ||
| require.True(t, ok) | ||
| assert.Equal(t, "file:///empty.txt", textRes.URI) | ||
| assert.Empty(t, textRes.Text) | ||
| } | ||
|
|
||
| // Test ParseGetPromptResult with malformed JSON | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Use a table-driven test for the added cases.
The empty text, empty blob, and non-string text cases repeat setup and assertions in separate
t.Runblocks. RefactorTestParseResourceContentsto usetests := []struct{ name, ... }and iterate over the table.As per coding guidelines,
**/*_test.gofiles must implement table-driven tests withtests := []struct{ name, ... }.Also applies to: 270-279
🤖 Prompt for AI Agents
Source: Coding guidelines