@@ -20,6 +20,7 @@ import (
2020 "github.com/gptscript-ai/gptscript/pkg/builtin"
2121 "github.com/gptscript-ai/gptscript/pkg/cache"
2222 "github.com/gptscript-ai/gptscript/pkg/hash"
23+ "github.com/gptscript-ai/gptscript/pkg/mcp"
2324 "github.com/gptscript-ai/gptscript/pkg/openapi"
2425 "github.com/gptscript-ai/gptscript/pkg/parser"
2526 "github.com/gptscript-ai/gptscript/pkg/system"
@@ -155,7 +156,23 @@ func loadOpenAPI(prg *types.Program, data []byte) *openapi3.T {
155156 return openAPIDocument
156157}
157158
158- func readTool (ctx context.Context , cache * cache.Client , prg * types.Program , base * source , targetToolName , defaultModel string ) ([]types.Tool , error ) {
159+ func processMCP (ctx context.Context , tool []types.Tool , mcpLoader MCPLoader ) (result []types.Tool , _ error ) {
160+ for _ , t := range tool {
161+ if t .IsMCP () {
162+ mcpTools , err := mcpLoader .Load (ctx , t )
163+ if err != nil {
164+ return nil , fmt .Errorf ("error loading MCP tools: %w" , err )
165+ }
166+ result = append (result , mcpTools ... )
167+ } else {
168+ result = append (result , t )
169+ }
170+ }
171+
172+ return result , nil
173+ }
174+
175+ func readTool (ctx context.Context , cache * cache.Client , mcp MCPLoader , prg * types.Program , base * source , targetToolName , defaultModel string ) ([]types.Tool , error ) {
159176 data := base .Content
160177
161178 var (
@@ -212,6 +229,11 @@ func readTool(ctx context.Context, cache *cache.Client, prg *types.Program, base
212229 return nil , fmt .Errorf ("no tools found in %s" , base )
213230 }
214231
232+ tools , err := processMCP (ctx , tools , mcp )
233+ if err != nil {
234+ return nil , err
235+ }
236+
215237 var (
216238 localTools = types.ToolSet {}
217239 targetTools []types.Tool
@@ -279,17 +301,17 @@ func readTool(ctx context.Context, cache *cache.Client, prg *types.Program, base
279301 localTools [strings .ToLower (tool .Name )] = tool
280302 }
281303
282- return linkAll (ctx , cache , prg , base , targetTools , localTools , defaultModel )
304+ return linkAll (ctx , cache , mcp , prg , base , targetTools , localTools , defaultModel )
283305}
284306
285- 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 ) {
307+ 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 ) {
286308 localToolsMapping := make (map [string ]string , len (tools ))
287309 for _ , localTool := range localTools {
288310 localToolsMapping [strings .ToLower (localTool .Name )] = localTool .ID
289311 }
290312
291313 for _ , tool := range tools {
292- tool , err := link (ctx , cache , prg , base , tool , localTools , localToolsMapping , defaultModel )
314+ tool , err := link (ctx , cache , mcp , prg , base , tool , localTools , localToolsMapping , defaultModel )
293315 if err != nil {
294316 return nil , err
295317 }
@@ -298,7 +320,7 @@ func linkAll(ctx context.Context, cache *cache.Client, prg *types.Program, base
298320 return
299321}
300322
301- 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 ) {
323+ 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 ) {
302324 if existing , ok := prg .ToolSet [tool .ID ]; ok {
303325 return existing , nil
304326 }
@@ -323,7 +345,7 @@ func link(ctx context.Context, cache *cache.Client, prg *types.Program, base *so
323345 linkedTool = existing
324346 } else {
325347 var err error
326- linkedTool , err = link (ctx , cache , prg , base , localTool , localTools , localToolsMapping , defaultModel )
348+ linkedTool , err = link (ctx , cache , mcp , prg , base , localTool , localTools , localToolsMapping , defaultModel )
327349 if err != nil {
328350 return types.Tool {}, fmt .Errorf ("failed linking %s at %s: %w" , targetToolName , base , err )
329351 }
@@ -333,7 +355,7 @@ func link(ctx context.Context, cache *cache.Client, prg *types.Program, base *so
333355 toolNames [targetToolName ] = struct {}{}
334356 } else {
335357 toolName , subTool := types .SplitToolRef (targetToolName )
336- resolvedTools , err := resolve (ctx , cache , prg , base , toolName , subTool , defaultModel )
358+ resolvedTools , err := resolve (ctx , cache , mcp , prg , base , toolName , subTool , defaultModel )
337359 if err != nil {
338360 return types.Tool {}, fmt .Errorf ("failed resolving %s from %s: %w" , targetToolName , base , err )
339361 }
@@ -373,7 +395,7 @@ func ProgramFromSource(ctx context.Context, content, subToolName string, opts ..
373395 prg := types.Program {
374396 ToolSet : types.ToolSet {},
375397 }
376- tools , err := readTool (ctx , opt .Cache , & prg , & source {
398+ tools , err := readTool (ctx , opt .Cache , opt . MCPLoader , & prg , & source {
377399 Content : []byte (content ),
378400 Path : locationPath ,
379401 Name : locationName ,
@@ -390,13 +412,19 @@ type Options struct {
390412 Cache * cache.Client
391413 Location string
392414 DefaultModel string
415+ MCPLoader MCPLoader
416+ }
417+
418+ type MCPLoader interface {
419+ Load (ctx context.Context , tool types.Tool ) ([]types.Tool , error )
393420}
394421
395422func complete (opts ... Options ) (result Options ) {
396423 for _ , opt := range opts {
397424 result .Cache = types .FirstSet (opt .Cache , result .Cache )
398425 result .Location = types .FirstSet (opt .Location , result .Location )
399426 result .DefaultModel = types .FirstSet (opt .DefaultModel , result .DefaultModel )
427+ result .MCPLoader = types .FirstSet (opt .MCPLoader , result .MCPLoader )
400428 }
401429
402430 if result .Location == "" {
@@ -407,6 +435,10 @@ func complete(opts ...Options) (result Options) {
407435 result .DefaultModel = builtin .GetDefaultModel ()
408436 }
409437
438+ if result .MCPLoader == nil {
439+ result .MCPLoader = mcp .DefaultLoader
440+ }
441+
410442 return
411443}
412444
@@ -430,15 +462,15 @@ func Program(ctx context.Context, name, subToolName string, opts ...Options) (ty
430462 Name : name ,
431463 ToolSet : types.ToolSet {},
432464 }
433- tools , err := resolve (ctx , opt .Cache , & prg , & source {}, name , subToolName , opt .DefaultModel )
465+ tools , err := resolve (ctx , opt .Cache , opt . MCPLoader , & prg , & source {}, name , subToolName , opt .DefaultModel )
434466 if err != nil {
435467 return types.Program {}, err
436468 }
437469 prg .EntryToolID = tools [0 ].ID
438470 return prg , nil
439471}
440472
441- func resolve (ctx context.Context , cache * cache.Client , prg * types.Program , base * source , name , subTool , defaultModel string ) ([]types.Tool , error ) {
473+ func resolve (ctx context.Context , cache * cache.Client , mcp MCPLoader , prg * types.Program , base * source , name , subTool , defaultModel string ) ([]types.Tool , error ) {
442474 if subTool == "" {
443475 t , ok := builtin .DefaultModel (name , defaultModel )
444476 if ok {
@@ -452,7 +484,7 @@ func resolve(ctx context.Context, cache *cache.Client, prg *types.Program, base
452484 return nil , err
453485 }
454486
455- result , err := readTool (ctx , cache , prg , s , subTool , defaultModel )
487+ result , err := readTool (ctx , cache , mcp , prg , s , subTool , defaultModel )
456488 if err != nil {
457489 return nil , err
458490 }
0 commit comments