@@ -20,6 +20,7 @@ import (
20
20
"github.com/gptscript-ai/gptscript/pkg/builtin"
21
21
"github.com/gptscript-ai/gptscript/pkg/cache"
22
22
"github.com/gptscript-ai/gptscript/pkg/hash"
23
+ "github.com/gptscript-ai/gptscript/pkg/mcp"
23
24
"github.com/gptscript-ai/gptscript/pkg/openapi"
24
25
"github.com/gptscript-ai/gptscript/pkg/parser"
25
26
"github.com/gptscript-ai/gptscript/pkg/system"
@@ -155,7 +156,23 @@ func loadOpenAPI(prg *types.Program, data []byte) *openapi3.T {
155
156
return openAPIDocument
156
157
}
157
158
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 ) {
159
176
data := base .Content
160
177
161
178
var (
@@ -212,6 +229,11 @@ func readTool(ctx context.Context, cache *cache.Client, prg *types.Program, base
212
229
return nil , fmt .Errorf ("no tools found in %s" , base )
213
230
}
214
231
232
+ tools , err := processMCP (ctx , tools , mcp )
233
+ if err != nil {
234
+ return nil , err
235
+ }
236
+
215
237
var (
216
238
localTools = types.ToolSet {}
217
239
targetTools []types.Tool
@@ -279,17 +301,17 @@ func readTool(ctx context.Context, cache *cache.Client, prg *types.Program, base
279
301
localTools [strings .ToLower (tool .Name )] = tool
280
302
}
281
303
282
- return linkAll (ctx , cache , prg , base , targetTools , localTools , defaultModel )
304
+ return linkAll (ctx , cache , mcp , prg , base , targetTools , localTools , defaultModel )
283
305
}
284
306
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 ) {
286
308
localToolsMapping := make (map [string ]string , len (tools ))
287
309
for _ , localTool := range localTools {
288
310
localToolsMapping [strings .ToLower (localTool .Name )] = localTool .ID
289
311
}
290
312
291
313
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 )
293
315
if err != nil {
294
316
return nil , err
295
317
}
@@ -298,7 +320,7 @@ func linkAll(ctx context.Context, cache *cache.Client, prg *types.Program, base
298
320
return
299
321
}
300
322
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 ) {
302
324
if existing , ok := prg .ToolSet [tool .ID ]; ok {
303
325
return existing , nil
304
326
}
@@ -323,7 +345,7 @@ func link(ctx context.Context, cache *cache.Client, prg *types.Program, base *so
323
345
linkedTool = existing
324
346
} else {
325
347
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 )
327
349
if err != nil {
328
350
return types.Tool {}, fmt .Errorf ("failed linking %s at %s: %w" , targetToolName , base , err )
329
351
}
@@ -333,7 +355,7 @@ func link(ctx context.Context, cache *cache.Client, prg *types.Program, base *so
333
355
toolNames [targetToolName ] = struct {}{}
334
356
} else {
335
357
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 )
337
359
if err != nil {
338
360
return types.Tool {}, fmt .Errorf ("failed resolving %s from %s: %w" , targetToolName , base , err )
339
361
}
@@ -373,7 +395,7 @@ func ProgramFromSource(ctx context.Context, content, subToolName string, opts ..
373
395
prg := types.Program {
374
396
ToolSet : types.ToolSet {},
375
397
}
376
- tools , err := readTool (ctx , opt .Cache , & prg , & source {
398
+ tools , err := readTool (ctx , opt .Cache , opt . MCPLoader , & prg , & source {
377
399
Content : []byte (content ),
378
400
Path : locationPath ,
379
401
Name : locationName ,
@@ -390,13 +412,19 @@ type Options struct {
390
412
Cache * cache.Client
391
413
Location string
392
414
DefaultModel string
415
+ MCPLoader MCPLoader
416
+ }
417
+
418
+ type MCPLoader interface {
419
+ Load (ctx context.Context , tool types.Tool ) ([]types.Tool , error )
393
420
}
394
421
395
422
func complete (opts ... Options ) (result Options ) {
396
423
for _ , opt := range opts {
397
424
result .Cache = types .FirstSet (opt .Cache , result .Cache )
398
425
result .Location = types .FirstSet (opt .Location , result .Location )
399
426
result .DefaultModel = types .FirstSet (opt .DefaultModel , result .DefaultModel )
427
+ result .MCPLoader = types .FirstSet (opt .MCPLoader , result .MCPLoader )
400
428
}
401
429
402
430
if result .Location == "" {
@@ -407,6 +435,10 @@ func complete(opts ...Options) (result Options) {
407
435
result .DefaultModel = builtin .GetDefaultModel ()
408
436
}
409
437
438
+ if result .MCPLoader == nil {
439
+ result .MCPLoader = mcp .DefaultLoader
440
+ }
441
+
410
442
return
411
443
}
412
444
@@ -430,15 +462,15 @@ func Program(ctx context.Context, name, subToolName string, opts ...Options) (ty
430
462
Name : name ,
431
463
ToolSet : types.ToolSet {},
432
464
}
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 )
434
466
if err != nil {
435
467
return types.Program {}, err
436
468
}
437
469
prg .EntryToolID = tools [0 ].ID
438
470
return prg , nil
439
471
}
440
472
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 ) {
442
474
if subTool == "" {
443
475
t , ok := builtin .DefaultModel (name , defaultModel )
444
476
if ok {
@@ -452,7 +484,7 @@ func resolve(ctx context.Context, cache *cache.Client, prg *types.Program, base
452
484
return nil , err
453
485
}
454
486
455
- result , err := readTool (ctx , cache , prg , s , subTool , defaultModel )
487
+ result , err := readTool (ctx , cache , mcp , prg , s , subTool , defaultModel )
456
488
if err != nil {
457
489
return nil , err
458
490
}
0 commit comments