Skip to content

Commit e162d0b

Browse files
committed
Better support remote MCP servers references by their name in the MCP Catalog
Signed-off-by: David Gageot <david.gageot@docker.com>
1 parent b560484 commit e162d0b

6 files changed

Lines changed: 75 additions & 5 deletions

File tree

examples/apify.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env cagent run
2+
version: "2"
3+
4+
agents:
5+
root:
6+
model: openai/gpt-4o
7+
description: Agent knowledgeable in Apify.
8+
instruction: |
9+
You are an AI assistant with a deep understanding of Apify.
10+
Your responses should be clear, concise, and focused on providing accurate information about
11+
Apify concepts, best practices, and usage.
12+
toolsets:
13+
- type: mcp
14+
ref: docker:apify

pkg/gateway/catalog.go

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,33 @@ import (
1313
const DockerCatalogURL = "https://desktop.docker.com/mcp/catalog/v3/catalog.yaml"
1414

1515
func RequiredEnvVars(ctx context.Context, serverName string) ([]Secret, error) {
16+
server, err := ServerSpec(ctx, serverName)
17+
if err != nil {
18+
return nil, err
19+
}
20+
21+
// TODO(dga): until the MCP Gateway supports oauth with cagent,
22+
// we ignore every secret listed on `remote` servers and assume
23+
// we can use oauth by connecting directly to the server's url.
24+
if server.Type == "remote" {
25+
return nil, nil
26+
}
27+
28+
return server.Secrets, nil
29+
}
30+
31+
func ServerSpec(ctx context.Context, serverName string) (Server, error) {
1632
catalog, err := readCatalogOnce()
1733
if err != nil {
18-
return nil, fmt.Errorf("failed to fetch MCP catalog: %w", err)
34+
return Server{}, fmt.Errorf("failed to fetch MCP catalog: %w", err)
1935
}
2036

2137
server, ok := catalog[serverName]
2238
if !ok {
23-
return nil, fmt.Errorf("MCP server %q not found in MCP catalog", serverName)
39+
return Server{}, fmt.Errorf("MCP server %q not found in MCP catalog", serverName)
2440
}
2541

26-
return server.Secrets, nil
42+
return server, nil
2743
}
2844

2945
// Read the MCP Catalog only once and cache the result.

pkg/gateway/catalog_test.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,34 @@ import (
77
"github.com/stretchr/testify/require"
88
)
99

10-
func TestRequiredEnvVars(t *testing.T) {
10+
func TestRequiredEnvVars_local(t *testing.T) {
1111
secrets, err := RequiredEnvVars(t.Context(), "github-official")
1212
require.NoError(t, err)
1313

1414
assert.Len(t, secrets, 1)
1515
assert.Equal(t, "GITHUB_PERSONAL_ACCESS_TOKEN", secrets[0].Env)
1616
assert.Equal(t, "github.personal_access_token", secrets[0].Name)
1717
}
18+
19+
func TestRequiredEnvVars_remote(t *testing.T) {
20+
secrets, err := RequiredEnvVars(t.Context(), "apify")
21+
require.NoError(t, err)
22+
23+
assert.Empty(t, secrets)
24+
}
25+
26+
func TestServerSpec_local(t *testing.T) {
27+
server, err := ServerSpec(t.Context(), "fetch")
28+
require.NoError(t, err)
29+
30+
assert.Equal(t, "server", server.Type)
31+
}
32+
33+
func TestServerSpec_remote(t *testing.T) {
34+
server, err := ServerSpec(t.Context(), "apify")
35+
require.NoError(t, err)
36+
37+
assert.Equal(t, "remote", server.Type)
38+
assert.Equal(t, "https://mcp.apify.com", server.Remote.URL)
39+
assert.Equal(t, "streamable-http", server.Remote.TransportType)
40+
}

pkg/gateway/types.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@ type topLevel struct {
77
type Catalog map[string]Server
88

99
type Server struct {
10+
Type string `json:"type"`
1011
Secrets []Secret `json:"secrets,omitempty"`
12+
Remote Remote `json:"remote,omitempty"`
13+
}
14+
15+
type Remote struct {
16+
URL string `json:"url"`
17+
TransportType string `json:"transport_type"`
1118
}
1219

1320
type Secret struct {

pkg/teamloader/teamloader.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,16 @@ func createTool(ctx context.Context, toolset latest.Toolset, a *latest.AgentConf
346346

347347
case toolset.Type == "mcp" && toolset.Ref != "":
348348
mcpServerName := gateway.ParseServerRef(toolset.Ref)
349+
serverSpec, err := gateway.ServerSpec(ctx, mcpServerName)
350+
if err != nil {
351+
return nil, fmt.Errorf("fetching MCP server spec for %q: %w", mcpServerName, err)
352+
}
353+
354+
// TODO(dga): until the MCP Gateway supports oauth with cagent, we fetch the remote url and directly connect to it.
355+
if serverSpec.Type == "remote" {
356+
return mcp.NewRemoteToolset(serverSpec.Remote.URL, serverSpec.Remote.TransportType, nil, toolset.Tools, runtimeConfig.RedirectURI)
357+
}
358+
349359
return mcp.NewGatewayToolset(mcpServerName, toolset.Config, toolset.Tools, envProvider), nil
350360

351361
case toolset.Type == "mcp" && toolset.Command != "":

pkg/tools/mcp/remote.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ func (c *remoteMCPClient) Initialize(ctx context.Context, request *mcp.Initializ
9292
Endpoint: c.url,
9393
HTTPClient: httpClient,
9494
}
95-
case "streamable":
95+
case "streamable", "streamable-http":
9696
transport = &mcp.StreamableClientTransport{
9797
Endpoint: c.url,
9898
HTTPClient: httpClient,

0 commit comments

Comments
 (0)