Skip to content

Commit c8a844e

Browse files
Merge pull request github#193 from docker/slim/remotes
Support Remote without source
2 parents 7c20f73 + 2a031c6 commit c8a844e

File tree

5 files changed

+111
-3
lines changed

5 files changed

+111
-3
lines changed

cmd/build/main.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ func run(ctx context.Context, name string, listTools bool, pullCommunity bool) e
4242
return err
4343
}
4444

45+
// Skip build for remote servers - they don't need Docker images
46+
if server.Remote.URL != "" {
47+
fmt.Printf("✅ Build skipped for remote server %s\n", name)
48+
return nil
49+
}
50+
4551
isMcpImage := strings.HasPrefix(server.Image, "mcp/")
4652

4753
if isMcpImage {

cmd/validate/main.go

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ func run(name string) error {
5353
if err := isIconValid(name); err != nil {
5454
return err
5555
}
56+
if err := isRemoteValid(name); err != nil {
57+
return err
58+
}
5659

5760
return nil
5861
}
@@ -140,6 +143,13 @@ func IsLicenseValid(name string) error {
140143
if err != nil {
141144
return err
142145
}
146+
147+
// Skip license validation for remote servers without source
148+
if server.Source.Project == "" {
149+
fmt.Println("✅ License validation skipped (remote server)")
150+
return nil
151+
}
152+
143153
repository, err := client.GetProjectRepository(ctx, server.Source.Project)
144154
if err != nil {
145155
return err
@@ -179,12 +189,20 @@ func isIconValid(name string) error {
179189
fmt.Println("🛑 Icon is too large. It must be less than 2MB")
180190
return nil
181191
}
192+
193+
// Check content type for SVG support
194+
contentType := resp.Header.Get("Content-Type")
195+
if contentType == "image/svg+xml" {
196+
fmt.Println("✅ Icon is valid (SVG)")
197+
return nil
198+
}
199+
182200
img, format, err := image.DecodeConfig(resp.Body)
183201
if err != nil {
184202
return err
185203
}
186204
if format != "png" {
187-
fmt.Println("🛑 Icon is not a png. It must be a png")
205+
fmt.Println("🛑 Icon is not a png or svg. It must be a png or svg")
188206
return nil
189207
}
190208

@@ -197,6 +215,28 @@ func isIconValid(name string) error {
197215
return nil
198216
}
199217

218+
// check if the remote configuration is valid
219+
func isRemoteValid(name string) error {
220+
server, err := readServerYaml(name)
221+
if err != nil {
222+
return err
223+
}
224+
225+
// Skip validation for non-remote servers
226+
if server.Remote.URL == "" {
227+
fmt.Println("✅ Remote validation skipped (not a remote server)")
228+
return nil
229+
}
230+
231+
// Check that transport_type is not empty for remote servers
232+
if server.Remote.TransportType == "" {
233+
return fmt.Errorf("remote server must have a transport_type specified")
234+
}
235+
236+
fmt.Println("✅ Remote is valid")
237+
return nil
238+
}
239+
200240
func readServerYaml(name string) (servers.Server, error) {
201241
serverYaml, err := os.ReadFile(filepath.Join("servers", name, "server.yaml"))
202242
if err != nil {

pkg/catalog/tile.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func ToTile(ctx context.Context, server servers.Server) (Tile, error) {
4444
license := "Apache License 2.0"
4545
githubStars := 0
4646

47-
if server.Type == "server" {
47+
if server.Type == "server" && server.Remote.URL == "" {
4848
client := github.NewFromServer(server)
4949
repository, err := client.GetProjectRepository(ctx, upstream)
5050
if err != nil {
@@ -127,7 +127,7 @@ func ToTile(ctx context.Context, server servers.Server) (Tile, error) {
127127

128128
image := server.Image
129129

130-
if server.Type == "server" && image == "" {
130+
if server.Type == "server" && image == "" && server.Remote.URL == "" {
131131
return Tile{}, fmt.Errorf("no image for server: %s", server.Name)
132132
}
133133
if server.Type == "poci" && image != "" {
@@ -168,6 +168,15 @@ func ToTile(ctx context.Context, server servers.Server) (Tile, error) {
168168

169169
dateAdded := time.Now().Format(time.RFC3339)
170170

171+
var remote Remote
172+
if server.Remote.URL != "" {
173+
remote = Remote{
174+
TransportType: server.Remote.TransportType,
175+
URL: server.Remote.URL,
176+
Headers: server.Remote.Headers,
177+
}
178+
}
179+
171180
return Tile{
172181
Description: addDot(strings.TrimSpace(strings.ReplaceAll(description, "\n", " "))),
173182
Title: server.About.Title,
@@ -178,6 +187,7 @@ func ToTile(ctx context.Context, server servers.Server) (Tile, error) {
178187
ToolsURL: "http://desktop.docker.com/mcp/catalog/v" + strconv.Itoa(Version) + "/tools/" + server.Name + ".json",
179188
Source: source,
180189
Upstream: upstream,
190+
Remote: remote,
181191
Icon: server.About.Icon,
182192
Secrets: secrets,
183193
Env: env,

pkg/catalog/types.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ type Tile struct {
141141
// Source string `json:"source,omitempty" yaml:"source,omitempty"`
142142
Source string `json:"source" yaml:"source"`
143143
Upstream string `json:"upstream,omitempty" yaml:"upstream,omitempty"`
144+
Remote Remote `json:"remote,omitempty" yaml:"remote,omitempty"`
144145
Icon string `json:"icon" yaml:"icon"`
145146
Tools []servers.Tool `json:"tools" yaml:"tools"`
146147
Secrets []Secret `json:"secrets,omitempty" yaml:"secrets,omitempty"`
@@ -197,3 +198,47 @@ type Env struct {
197198
Name string `json:"name" yaml:"name"`
198199
Value string `json:"value" yaml:"value"`
199200
}
201+
202+
type Remote struct {
203+
TransportType string `json:"transport_type,omitempty" yaml:"transport_type,omitempty"`
204+
URL string `json:"url,omitempty" yaml:"url,omitempty"`
205+
Headers map[string]string `json:"headers,omitempty" yaml:"headers,omitempty"`
206+
}
207+
208+
func (r Remote) MarshalYAML() (interface{}, error) {
209+
mapNode := &yaml.Node{
210+
Kind: yaml.MappingNode,
211+
Content: []*yaml.Node{},
212+
}
213+
214+
if r.TransportType != "" {
215+
mapNode.Content = append(mapNode.Content,
216+
&yaml.Node{Kind: yaml.ScalarNode, Value: "transport_type"},
217+
&yaml.Node{Kind: yaml.ScalarNode, Value: r.TransportType})
218+
}
219+
220+
if r.URL != "" {
221+
mapNode.Content = append(mapNode.Content,
222+
&yaml.Node{Kind: yaml.ScalarNode, Value: "url"},
223+
&yaml.Node{Kind: yaml.ScalarNode, Value: r.URL})
224+
}
225+
226+
if len(r.Headers) > 0 {
227+
headersNode := &yaml.Node{
228+
Kind: yaml.MappingNode,
229+
Content: []*yaml.Node{},
230+
}
231+
232+
for k, v := range r.Headers {
233+
headersNode.Content = append(headersNode.Content,
234+
&yaml.Node{Kind: yaml.ScalarNode, Value: k},
235+
&yaml.Node{Kind: yaml.ScalarNode, Value: v, Style: yaml.DoubleQuotedStyle})
236+
}
237+
238+
mapNode.Content = append(mapNode.Content,
239+
&yaml.Node{Kind: yaml.ScalarNode, Value: "headers"},
240+
headersNode)
241+
}
242+
243+
return mapNode, nil
244+
}

pkg/servers/types.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ type Server struct {
3636
Meta Meta `yaml:"meta,omitempty" json:"meta,omitempty"`
3737
About About `yaml:"about,omitempty" json:"about,omitempty"`
3838
Source Source `yaml:"source,omitempty" json:"source,omitempty"`
39+
Remote Remote `yaml:"remote,omitempty" json:"remote,omitempty"`
3940
Run Run `yaml:"run,omitempty" json:"run,omitempty"`
4041
Config Config `yaml:"config,omitempty" json:"config,omitempty"`
4142
OAuth []OAuthProvider `yaml:"oauth,omitempty" json:"oauth,omitempty"`
@@ -104,6 +105,12 @@ type Source struct {
104105
BuildTarget string `yaml:"buildTarget,omitempty" json:"buildTarget,omitempty"`
105106
}
106107

108+
type Remote struct {
109+
TransportType string `yaml:"transport_type,omitempty" json:"transport_type,omitempty"`
110+
URL string `yaml:"url,omitempty" json:"url,omitempty"`
111+
Headers map[string]string `yaml:"headers,omitempty" json:"headers,omitempty"`
112+
}
113+
107114
type Run struct {
108115
Command []string `yaml:"command,omitempty" json:"command,omitempty"`
109116
Volumes []string `yaml:"volumes,omitempty" json:"volumes,omitempty"`

0 commit comments

Comments
 (0)