Skip to content

Mcp #965

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

Merged
merged 9 commits into from
May 5, 2025
Merged

Mcp #965

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ require (
github.com/gptscript-ai/chat-completion-client v0.0.0-20250224164718-139cb4507b1d
github.com/gptscript-ai/cmd v0.0.0-20240802230653-326b7baf6fcb
github.com/gptscript-ai/go-gptscript v0.9.6-0.20250204133419-744b25b84a61
github.com/gptscript-ai/tui v0.0.0-20250204145344-33cd15de4cee
github.com/gptscript-ai/tui v0.0.0-20250419050840-5e79e16786c9
github.com/hexops/autogold/v2 v2.2.1
github.com/hexops/valast v1.4.4
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056
github.com/mark3labs/mcp-go v0.25.0
github.com/mholt/archives v0.1.0
github.com/pkoukk/tiktoken-go v0.1.7
github.com/pkoukk/tiktoken-go-loader v0.0.2-0.20240522064338-c17e8bc0f699
Expand Down Expand Up @@ -113,6 +114,7 @@ require (
github.com/skeema/knownhosts v1.2.2 // indirect
github.com/sorairolake/lzip-go v0.3.5 // indirect
github.com/sourcegraph/go-diff-patch v0.0.0-20240223163233-798fd1e94a8e // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
github.com/therootcompany/xz v1.0.1 // indirect
github.com/tidwall/match v1.1.1 // indirect
Expand All @@ -122,6 +124,7 @@ require (
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
github.com/yuin/goldmark v1.5.4 // indirect
github.com/yuin/goldmark-emoji v1.0.2 // indirect
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
Expand Down
10 changes: 8 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,8 @@ github.com/gptscript-ai/cmd v0.0.0-20240802230653-326b7baf6fcb h1:ky2J2CzBOskC7J
github.com/gptscript-ai/cmd v0.0.0-20240802230653-326b7baf6fcb/go.mod h1:DJAo1xTht1LDkNYFNydVjTHd576TC7MlpsVRl3oloVw=
github.com/gptscript-ai/go-gptscript v0.9.6-0.20250204133419-744b25b84a61 h1:QxLjsLOYlsVLPwuRkP0Q8EcAoZT1s8vU2ZBSX0+R6CI=
github.com/gptscript-ai/go-gptscript v0.9.6-0.20250204133419-744b25b84a61/go.mod h1:/FVuLwhz+sIfsWUgUHWKi32qT0i6+IXlUlzs70KKt/Q=
github.com/gptscript-ai/tui v0.0.0-20250204145344-33cd15de4cee h1:70PHW6Xw70yNNZ5aX936XqcMLwNmfMZpCV3FCOGKpxE=
github.com/gptscript-ai/tui v0.0.0-20250204145344-33cd15de4cee/go.mod h1:iwHxuueg2paOak7zIg0ESBWx7A0wIHGopAratbgaPNY=
github.com/gptscript-ai/tui v0.0.0-20250419050840-5e79e16786c9 h1:wQC8sKyeGA50WnCEG+Jo5FNRIkuX3HX8d3ubyWCCoI8=
github.com/gptscript-ai/tui v0.0.0-20250419050840-5e79e16786c9/go.mod h1:iwHxuueg2paOak7zIg0ESBWx7A0wIHGopAratbgaPNY=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
Expand Down Expand Up @@ -270,6 +270,8 @@ github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mark3labs/mcp-go v0.25.0 h1:UUpcMT3L5hIhuDy7aifj4Bphw4Pfx1Rf8mzMXDe8RQw=
github.com/mark3labs/mcp-go v0.25.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
Expand Down Expand Up @@ -361,6 +363,8 @@ github.com/sorairolake/lzip-go v0.3.5 h1:ms5Xri9o1JBIWvOFAorYtUNik6HI3HgBTkISiqu
github.com/sorairolake/lzip-go v0.3.5/go.mod h1:N0KYq5iWrMXI0ZEXKXaS9hCyOjZUQdBDEIbXfoUwbdk=
github.com/sourcegraph/go-diff-patch v0.0.0-20240223163233-798fd1e94a8e h1:H+jDTUeF+SVd4ApwnSFoew8ZwGNRfgb9EsZc7LcocAg=
github.com/sourcegraph/go-diff-patch v0.0.0-20240223163233-798fd1e94a8e/go.mod h1:VsUklG6OQo7Ctunu0gS3AtEOCEc2kMB6r5rKzxAes58=
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
Expand Down Expand Up @@ -406,6 +410,8 @@ github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavM
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
github.com/yuin/goldmark v1.3.7/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.5.4 h1:2uY/xC0roWy8IBEGLgB1ywIoEJFGmRrX21YQcvGZzjU=
Expand Down
2 changes: 1 addition & 1 deletion pkg/cli/gptscript.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ func (r *GPTScript) listTools(ctx context.Context, gptScript *gptscript.GPTScrip
// Don't print instructions
tool.Instructions = ""

lines = append(lines, tool.String())
lines = append(lines, tool.Print())
}
fmt.Println(strings.Join(lines, "\n---\n"))
return nil
Expand Down
21 changes: 21 additions & 0 deletions pkg/engine/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ type Engine struct {
RuntimeManager RuntimeManager
Env []string
Progress chan<- types.CompletionStatus
MCPRunner MCPRunner
}

type MCPRunner interface {
Run(ctx context.Context, progress chan<- types.CompletionStatus, tool types.Tool, input string) (string, error)
}

type State struct {
Expand Down Expand Up @@ -307,6 +312,17 @@ func populateMessageParams(ctx Context, completion *types.CompletionRequest, too
return nil
}

func (e *Engine) runMCPInvoke(ctx Context, tool types.Tool, input string) (*Return, error) {
output, err := e.MCPRunner.Run(ctx.Ctx, e.Progress, tool, input)
if err != nil {
return nil, fmt.Errorf("failed to run MCP invoke: %w", err)
}

return &Return{
Result: &output,
}, nil
}

func (e *Engine) runCommandTools(ctx Context, tool types.Tool, input string) (*Return, error) {
if tool.IsHTTP() {
return e.runHTTP(ctx, tool, input)
Expand Down Expand Up @@ -342,6 +358,10 @@ func (e *Engine) Start(ctx Context, input string) (ret *Return, err error) {
}
}()

if tool.IsMCPInvoke() {
return e.runMCPInvoke(ctx, tool, input)
}

if tool.IsCommand() {
return e.runCommandTools(ctx, tool, input)
}
Expand Down Expand Up @@ -378,6 +398,7 @@ func addUpdateSystem(ctx Context, tool types.Tool, msgs []types.CompletionMessag
instructions = append(instructions, context.Content)
}

tool.Instructions = strings.TrimPrefix(tool.Instructions, types.PromptPrefix)
if tool.Instructions != "" {
instructions = append(instructions, tool.Instructions)
}
Expand Down
55 changes: 44 additions & 11 deletions pkg/loader/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/gptscript-ai/gptscript/pkg/builtin"
"github.com/gptscript-ai/gptscript/pkg/cache"
"github.com/gptscript-ai/gptscript/pkg/hash"
"github.com/gptscript-ai/gptscript/pkg/mcp"
"github.com/gptscript-ai/gptscript/pkg/openapi"
"github.com/gptscript-ai/gptscript/pkg/parser"
"github.com/gptscript-ai/gptscript/pkg/system"
Expand Down Expand Up @@ -155,7 +156,23 @@ func loadOpenAPI(prg *types.Program, data []byte) *openapi3.T {
return openAPIDocument
}

func readTool(ctx context.Context, cache *cache.Client, prg *types.Program, base *source, targetToolName, defaultModel string) ([]types.Tool, error) {
func processMCP(ctx context.Context, tool []types.Tool, mcpLoader MCPLoader) (result []types.Tool, _ error) {
for _, t := range tool {
if t.IsMCP() {
mcpTools, err := mcpLoader.Load(ctx, t)
if err != nil {
return nil, fmt.Errorf("error loading MCP tools: %w", err)
}
result = append(result, mcpTools...)
} else {
result = append(result, t)
}
}

return result, nil
}

func readTool(ctx context.Context, cache *cache.Client, mcp MCPLoader, prg *types.Program, base *source, targetToolName, defaultModel string) ([]types.Tool, error) {
data := base.Content

var (
Expand Down Expand Up @@ -212,6 +229,11 @@ func readTool(ctx context.Context, cache *cache.Client, prg *types.Program, base
return nil, fmt.Errorf("no tools found in %s", base)
}

tools, err := processMCP(ctx, tools, mcp)
if err != nil {
return nil, err
}

var (
localTools = types.ToolSet{}
targetTools []types.Tool
Expand Down Expand Up @@ -279,17 +301,17 @@ func readTool(ctx context.Context, cache *cache.Client, prg *types.Program, base
localTools[strings.ToLower(tool.Name)] = tool
}

return linkAll(ctx, cache, prg, base, targetTools, localTools, defaultModel)
return linkAll(ctx, cache, mcp, prg, base, targetTools, localTools, defaultModel)
}

func linkAll(ctx context.Context, cache *cache.Client, prg *types.Program, base *source, tools []types.Tool, localTools types.ToolSet, defaultModel string) (result []types.Tool, _ error) {
func linkAll(ctx context.Context, cache *cache.Client, mcp MCPLoader, prg *types.Program, base *source, tools []types.Tool, localTools types.ToolSet, defaultModel string) (result []types.Tool, _ error) {
localToolsMapping := make(map[string]string, len(tools))
for _, localTool := range localTools {
localToolsMapping[strings.ToLower(localTool.Name)] = localTool.ID
}

for _, tool := range tools {
tool, err := link(ctx, cache, prg, base, tool, localTools, localToolsMapping, defaultModel)
tool, err := link(ctx, cache, mcp, prg, base, tool, localTools, localToolsMapping, defaultModel)
if err != nil {
return nil, err
}
Expand All @@ -298,7 +320,7 @@ func linkAll(ctx context.Context, cache *cache.Client, prg *types.Program, base
return
}

func link(ctx context.Context, cache *cache.Client, prg *types.Program, base *source, tool types.Tool, localTools types.ToolSet, localToolsMapping map[string]string, defaultModel string) (types.Tool, error) {
func link(ctx context.Context, cache *cache.Client, mcp MCPLoader, prg *types.Program, base *source, tool types.Tool, localTools types.ToolSet, localToolsMapping map[string]string, defaultModel string) (types.Tool, error) {
if existing, ok := prg.ToolSet[tool.ID]; ok {
return existing, nil
}
Expand All @@ -323,7 +345,7 @@ func link(ctx context.Context, cache *cache.Client, prg *types.Program, base *so
linkedTool = existing
} else {
var err error
linkedTool, err = link(ctx, cache, prg, base, localTool, localTools, localToolsMapping, defaultModel)
linkedTool, err = link(ctx, cache, mcp, prg, base, localTool, localTools, localToolsMapping, defaultModel)
if err != nil {
return types.Tool{}, fmt.Errorf("failed linking %s at %s: %w", targetToolName, base, err)
}
Expand All @@ -333,7 +355,7 @@ func link(ctx context.Context, cache *cache.Client, prg *types.Program, base *so
toolNames[targetToolName] = struct{}{}
} else {
toolName, subTool := types.SplitToolRef(targetToolName)
resolvedTools, err := resolve(ctx, cache, prg, base, toolName, subTool, defaultModel)
resolvedTools, err := resolve(ctx, cache, mcp, prg, base, toolName, subTool, defaultModel)
if err != nil {
return types.Tool{}, fmt.Errorf("failed resolving %s from %s: %w", targetToolName, base, err)
}
Expand Down Expand Up @@ -373,7 +395,7 @@ func ProgramFromSource(ctx context.Context, content, subToolName string, opts ..
prg := types.Program{
ToolSet: types.ToolSet{},
}
tools, err := readTool(ctx, opt.Cache, &prg, &source{
tools, err := readTool(ctx, opt.Cache, opt.MCPLoader, &prg, &source{
Content: []byte(content),
Path: locationPath,
Name: locationName,
Expand All @@ -390,13 +412,20 @@ type Options struct {
Cache *cache.Client
Location string
DefaultModel string
MCPLoader MCPLoader
}

type MCPLoader interface {
Load(ctx context.Context, tool types.Tool) ([]types.Tool, error)
Close() error
}

func complete(opts ...Options) (result Options) {
for _, opt := range opts {
result.Cache = types.FirstSet(opt.Cache, result.Cache)
result.Location = types.FirstSet(opt.Location, result.Location)
result.DefaultModel = types.FirstSet(opt.DefaultModel, result.DefaultModel)
result.MCPLoader = types.FirstSet(opt.MCPLoader, result.MCPLoader)
}

if result.Location == "" {
Expand All @@ -407,6 +436,10 @@ func complete(opts ...Options) (result Options) {
result.DefaultModel = builtin.GetDefaultModel()
}

if result.MCPLoader == nil {
result.MCPLoader = mcp.DefaultLoader
}

return
}

Expand All @@ -430,15 +463,15 @@ func Program(ctx context.Context, name, subToolName string, opts ...Options) (ty
Name: name,
ToolSet: types.ToolSet{},
}
tools, err := resolve(ctx, opt.Cache, &prg, &source{}, name, subToolName, opt.DefaultModel)
tools, err := resolve(ctx, opt.Cache, opt.MCPLoader, &prg, &source{}, name, subToolName, opt.DefaultModel)
if err != nil {
return types.Program{}, err
}
prg.EntryToolID = tools[0].ID
return prg, nil
}

func resolve(ctx context.Context, cache *cache.Client, prg *types.Program, base *source, name, subTool, defaultModel string) ([]types.Tool, error) {
func resolve(ctx context.Context, cache *cache.Client, mcp MCPLoader, prg *types.Program, base *source, name, subTool, defaultModel string) ([]types.Tool, error) {
if subTool == "" {
t, ok := builtin.DefaultModel(name, defaultModel)
if ok {
Expand All @@ -452,7 +485,7 @@ func resolve(ctx context.Context, cache *cache.Client, prg *types.Program, base
return nil, err
}

result, err := readTool(ctx, cache, prg, s, subTool, defaultModel)
result, err := readTool(ctx, cache, mcp, prg, s, subTool, defaultModel)
if err != nil {
return nil, err
}
Expand Down
28 changes: 19 additions & 9 deletions pkg/loader/openapi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func TestLoadOpenAPI(t *testing.T) {
}
datav3, err := os.ReadFile("testdata/openapi_v3.yaml")
require.NoError(t, err)
_, err = readTool(context.Background(), nil, &prgv3, &source{Content: datav3}, "", "")
_, err = readTool(context.Background(), nil, fakeMCPLoader{}, &prgv3, &source{Content: datav3}, "", "")
require.NoError(t, err, "failed to read openapi v3")
require.Equal(t, 3, numOpenAPITools(prgv3.ToolSet), "expected 3 openapi tools")

Expand All @@ -35,7 +35,7 @@ func TestLoadOpenAPI(t *testing.T) {
}
datav2, err := os.ReadFile("testdata/openapi_v2.json")
require.NoError(t, err)
_, err = readTool(context.Background(), nil, &prgv2json, &source{Content: datav2}, "", "")
_, err = readTool(context.Background(), nil, fakeMCPLoader{}, &prgv2json, &source{Content: datav2}, "", "")
require.NoError(t, err, "failed to read openapi v2")
require.Equal(t, 3, numOpenAPITools(prgv2json.ToolSet), "expected 3 openapi tools")

Expand All @@ -44,7 +44,7 @@ func TestLoadOpenAPI(t *testing.T) {
}
datav2, err = os.ReadFile("testdata/openapi_v2.yaml")
require.NoError(t, err)
_, err = readTool(context.Background(), nil, &prgv2yaml, &source{Content: datav2}, "", "")
_, err = readTool(context.Background(), nil, fakeMCPLoader{}, &prgv2yaml, &source{Content: datav2}, "", "")
require.NoError(t, err, "failed to read openapi v2 (yaml)")
require.Equal(t, 3, numOpenAPITools(prgv2yaml.ToolSet), "expected 3 openapi tools")

Expand All @@ -57,7 +57,7 @@ func TestOpenAPIv3(t *testing.T) {
}
datav3, err := os.ReadFile("testdata/openapi_v3.yaml")
require.NoError(t, err)
_, err = readTool(context.Background(), nil, &prgv3, &source{Content: datav3}, "", "")
_, err = readTool(context.Background(), nil, fakeMCPLoader{}, &prgv3, &source{Content: datav3}, "", "")
require.NoError(t, err)

autogold.ExpectFile(t, prgv3.ToolSet, autogold.Dir("testdata/openapi"))
Expand All @@ -69,7 +69,7 @@ func TestOpenAPIv3NoOperationIDs(t *testing.T) {
}
datav3, err := os.ReadFile("testdata/openapi_v3_no_operation_ids.yaml")
require.NoError(t, err)
_, err = readTool(context.Background(), nil, &prgv3, &source{Content: datav3}, "", "")
_, err = readTool(context.Background(), nil, fakeMCPLoader{}, &prgv3, &source{Content: datav3}, "", "")
require.NoError(t, err)

autogold.ExpectFile(t, prgv3.ToolSet, autogold.Dir("testdata/openapi"))
Expand All @@ -81,7 +81,7 @@ func TestOpenAPIv2(t *testing.T) {
}
datav2, err := os.ReadFile("testdata/openapi_v2.yaml")
require.NoError(t, err)
_, err = readTool(context.Background(), nil, &prgv2, &source{Content: datav2}, "", "")
_, err = readTool(context.Background(), nil, fakeMCPLoader{}, &prgv2, &source{Content: datav2}, "", "")
require.NoError(t, err)

autogold.ExpectFile(t, prgv2.ToolSet, autogold.Dir("testdata/openapi"))
Expand All @@ -94,7 +94,7 @@ func TestOpenAPIv3Revamp(t *testing.T) {
}
datav3, err := os.ReadFile("testdata/openapi_v3.yaml")
require.NoError(t, err)
_, err = readTool(context.Background(), nil, &prgv3, &source{Content: datav3}, "", "")
_, err = readTool(context.Background(), nil, fakeMCPLoader{}, &prgv3, &source{Content: datav3}, "", "")
require.NoError(t, err)

autogold.ExpectFile(t, prgv3.ToolSet, autogold.Dir("testdata/openapi"))
Expand All @@ -107,7 +107,7 @@ func TestOpenAPIv3NoOperationIDsRevamp(t *testing.T) {
}
datav3, err := os.ReadFile("testdata/openapi_v3_no_operation_ids.yaml")
require.NoError(t, err)
_, err = readTool(context.Background(), nil, &prgv3, &source{Content: datav3}, "", "")
_, err = readTool(context.Background(), nil, fakeMCPLoader{}, &prgv3, &source{Content: datav3}, "", "")
require.NoError(t, err)

autogold.ExpectFile(t, prgv3.ToolSet, autogold.Dir("testdata/openapi"))
Expand All @@ -120,8 +120,18 @@ func TestOpenAPIv2Revamp(t *testing.T) {
}
datav2, err := os.ReadFile("testdata/openapi_v2.yaml")
require.NoError(t, err)
_, err = readTool(context.Background(), nil, &prgv2, &source{Content: datav2}, "", "")
_, err = readTool(context.Background(), nil, fakeMCPLoader{}, &prgv2, &source{Content: datav2}, "", "")
require.NoError(t, err)

autogold.ExpectFile(t, prgv2.ToolSet, autogold.Dir("testdata/openapi"))
}

type fakeMCPLoader struct{}

func (fakeMCPLoader) Load(context.Context, types.Tool) ([]types.Tool, error) {
return nil, nil
}

func (fakeMCPLoader) Close() error {
return nil
}
Loading