Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit2eb1887

Browse files
committed
Add UpdateGist tool
1 parent3c47964 commit2eb1887

File tree

3 files changed

+245
-0
lines changed

3 files changed

+245
-0
lines changed

‎pkg/github/gists.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,83 @@ func CreateGist(getClient GetClientFn, t translations.TranslationHelperFunc) (to
165165
returnmcp.NewToolResultText(string(r)),nil
166166
}
167167
}
168+
169+
// UpdateGist creates a tool to edit an existing gist
170+
funcUpdateGist(getClientGetClientFn,t translations.TranslationHelperFunc) (tool mcp.Tool,handler server.ToolHandlerFunc) {
171+
returnmcp.NewTool("update_gist",
172+
mcp.WithDescription(t("TOOL_UPDATE_GIST_DESCRIPTION","Update an existing gist")),
173+
mcp.WithString("gist_id",
174+
mcp.Required(),
175+
mcp.Description("ID of the gist to update"),
176+
),
177+
mcp.WithString("description",
178+
mcp.Description("Updated description of the gist"),
179+
),
180+
mcp.WithString("filename",
181+
mcp.Required(),
182+
mcp.Description("Filename to update or create"),
183+
),
184+
mcp.WithString("content",
185+
mcp.Required(),
186+
mcp.Description("Content for the file"),
187+
),
188+
),
189+
func(ctx context.Context,request mcp.CallToolRequest) (*mcp.CallToolResult,error) {
190+
gistID,err:=requiredParam[string](request,"gist_id")
191+
iferr!=nil {
192+
returnmcp.NewToolResultError(err.Error()),nil
193+
}
194+
195+
description,err:=OptionalParam[string](request,"description")
196+
iferr!=nil {
197+
returnmcp.NewToolResultError(err.Error()),nil
198+
}
199+
200+
filename,err:=requiredParam[string](request,"filename")
201+
iferr!=nil {
202+
returnmcp.NewToolResultError(err.Error()),nil
203+
}
204+
205+
content,err:=requiredParam[string](request,"content")
206+
iferr!=nil {
207+
returnmcp.NewToolResultError(err.Error()),nil
208+
}
209+
210+
files:=make(map[github.GistFilename]github.GistFile)
211+
files[github.GistFilename(filename)]= github.GistFile{
212+
Filename:github.Ptr(filename),
213+
Content:github.Ptr(content),
214+
}
215+
216+
gist:=&github.Gist{
217+
Files:files,
218+
Description:github.Ptr(description),
219+
}
220+
221+
client,err:=getClient(ctx)
222+
iferr!=nil {
223+
returnnil,fmt.Errorf("failed to get GitHub client: %w",err)
224+
}
225+
226+
updatedGist,resp,err:=client.Gists.Edit(ctx,gistID,gist)
227+
iferr!=nil {
228+
returnnil,fmt.Errorf("failed to update gist: %w",err)
229+
}
230+
deferfunc() {_=resp.Body.Close() }()
231+
232+
ifresp.StatusCode!=http.StatusOK {
233+
body,err:=io.ReadAll(resp.Body)
234+
iferr!=nil {
235+
returnnil,fmt.Errorf("failed to read response body: %w",err)
236+
}
237+
returnmcp.NewToolResultError(fmt.Sprintf("failed to update gist: %s",string(body))),nil
238+
}
239+
240+
r,err:=json.Marshal(updatedGist)
241+
iferr!=nil {
242+
returnnil,fmt.Errorf("failed to marshal response: %w",err)
243+
}
244+
245+
returnmcp.NewToolResultText(string(r)),nil
246+
}
247+
}

‎pkg/github/gists_test.go

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,3 +341,167 @@ func Test_CreateGist(t *testing.T) {
341341
})
342342
}
343343
}
344+
345+
funcTest_UpdateGist(t*testing.T) {
346+
// Verify tool definition
347+
mockClient:=github.NewClient(nil)
348+
tool,_:=UpdateGist(stubGetClientFn(mockClient),translations.NullTranslationHelper)
349+
350+
assert.Equal(t,"update_gist",tool.Name)
351+
assert.NotEmpty(t,tool.Description)
352+
assert.Contains(t,tool.InputSchema.Properties,"gist_id")
353+
assert.Contains(t,tool.InputSchema.Properties,"description")
354+
assert.Contains(t,tool.InputSchema.Properties,"filename")
355+
assert.Contains(t,tool.InputSchema.Properties,"content")
356+
357+
// Verify required parameters
358+
assert.Contains(t,tool.InputSchema.Required,"gist_id")
359+
assert.Contains(t,tool.InputSchema.Required,"filename")
360+
assert.Contains(t,tool.InputSchema.Required,"content")
361+
362+
// Setup mock data for test cases
363+
updatedGist:=&github.Gist{
364+
ID:github.Ptr("existing-gist-id"),
365+
Description:github.Ptr("Updated Test Gist"),
366+
HTMLURL:github.Ptr("https://gist.github.com/user/existing-gist-id"),
367+
Public:github.Ptr(true),
368+
UpdatedAt:&github.Timestamp{Time:time.Now()},
369+
Owner:&github.User{Login:github.Ptr("user")},
370+
Files:map[github.GistFilename]github.GistFile{
371+
"updated.go": {
372+
Filename:github.Ptr("updated.go"),
373+
Content:github.Ptr("package main\n\nfunc main() {\n\tfmt.Println(\"Updated Gist!\")\n}"),
374+
},
375+
},
376+
}
377+
378+
tests:= []struct {
379+
namestring
380+
mockedClient*http.Client
381+
requestArgsmap[string]interface{}
382+
expectErrorbool
383+
expectedErrMsgstring
384+
expectedGist*github.Gist
385+
}{
386+
{
387+
name:"update gist successfully",
388+
mockedClient:mock.NewMockedHTTPClient(
389+
mock.WithRequestMatchHandler(
390+
mock.PatchGistsByGistId,
391+
mockResponse(t,http.StatusOK,updatedGist),
392+
),
393+
),
394+
requestArgs:map[string]interface{}{
395+
"gist_id":"existing-gist-id",
396+
"filename":"updated.go",
397+
"content":"package main\n\nfunc main() {\n\tfmt.Println(\"Updated Gist!\")\n}",
398+
"description":"Updated Test Gist",
399+
},
400+
expectError:false,
401+
expectedGist:updatedGist,
402+
},
403+
{
404+
name:"missing required gist_id",
405+
mockedClient:mock.NewMockedHTTPClient(),
406+
requestArgs:map[string]interface{}{
407+
"filename":"updated.go",
408+
"content":"updated content",
409+
"description":"Updated Test Gist",
410+
},
411+
expectError:true,
412+
expectedErrMsg:"missing required parameter: gist_id",
413+
},
414+
{
415+
name:"missing required filename",
416+
mockedClient:mock.NewMockedHTTPClient(),
417+
requestArgs:map[string]interface{}{
418+
"gist_id":"existing-gist-id",
419+
"content":"updated content",
420+
"description":"Updated Test Gist",
421+
},
422+
expectError:true,
423+
expectedErrMsg:"missing required parameter: filename",
424+
},
425+
{
426+
name:"missing required content",
427+
mockedClient:mock.NewMockedHTTPClient(),
428+
requestArgs:map[string]interface{}{
429+
"gist_id":"existing-gist-id",
430+
"filename":"updated.go",
431+
"description":"Updated Test Gist",
432+
},
433+
expectError:true,
434+
expectedErrMsg:"missing required parameter: content",
435+
},
436+
{
437+
name:"api returns error",
438+
mockedClient:mock.NewMockedHTTPClient(
439+
mock.WithRequestMatchHandler(
440+
mock.PatchGistsByGistId,
441+
http.HandlerFunc(func(w http.ResponseWriter,_*http.Request) {
442+
w.WriteHeader(http.StatusNotFound)
443+
_,_=w.Write([]byte(`{"message": "Not Found"}`))
444+
}),
445+
),
446+
),
447+
requestArgs:map[string]interface{}{
448+
"gist_id":"nonexistent-gist-id",
449+
"filename":"updated.go",
450+
"content":"package main",
451+
"description":"Updated Test Gist",
452+
},
453+
expectError:true,
454+
expectedErrMsg:"failed to update gist",
455+
},
456+
}
457+
458+
for_,tc:=rangetests {
459+
t.Run(tc.name,func(t*testing.T) {
460+
// Setup client with mock
461+
client:=github.NewClient(tc.mockedClient)
462+
_,handler:=UpdateGist(stubGetClientFn(client),translations.NullTranslationHelper)
463+
464+
// Create call request
465+
request:=createMCPRequest(tc.requestArgs)
466+
467+
// Call handler
468+
result,err:=handler(context.Background(),request)
469+
470+
// Verify results
471+
iftc.expectError {
472+
iferr!=nil {
473+
assert.Contains(t,err.Error(),tc.expectedErrMsg)
474+
}else {
475+
// For errors returned as part of the result, not as an error
476+
assert.NotNil(t,result)
477+
textContent:=getTextResult(t,result)
478+
assert.Contains(t,textContent.Text,tc.expectedErrMsg)
479+
}
480+
return
481+
}
482+
483+
require.NoError(t,err)
484+
assert.NotNil(t,result)
485+
486+
// Parse the result and get the text content
487+
textContent:=getTextResult(t,result)
488+
489+
// Unmarshal and verify the result
490+
vargist*github.Gist
491+
err=json.Unmarshal([]byte(textContent.Text),&gist)
492+
require.NoError(t,err)
493+
494+
assert.Equal(t,*tc.expectedGist.ID,*gist.ID)
495+
assert.Equal(t,*tc.expectedGist.Description,*gist.Description)
496+
assert.Equal(t,*tc.expectedGist.HTMLURL,*gist.HTMLURL)
497+
498+
// Verify file content
499+
forfilename,expectedFile:=rangetc.expectedGist.Files {
500+
actualFile,exists:=gist.Files[filename]
501+
assert.True(t,exists)
502+
assert.Equal(t,*expectedFile.Filename,*actualFile.Filename)
503+
assert.Equal(t,*expectedFile.Content,*actualFile.Content)
504+
}
505+
})
506+
}
507+
}

‎pkg/github/tools.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ func InitToolsets(passedToolsets []string, readOnly bool, getClient GetClientFn,
8888
).
8989
AddWriteTools(
9090
toolsets.NewServerTool(CreateGist(getClient,t)),
91+
toolsets.NewServerTool(UpdateGist(getClient,t)),
9192
)
9293

9394
// Add toolsets to the group

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp