Skip to content

Commit 37b8a53

Browse files
authored
feat: add mcp_servers field to app manifest (#580)
1 parent 0d384e6 commit 37b8a53

2 files changed

Lines changed: 79 additions & 0 deletions

File tree

internal/shared/types/app_manifest.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ type AppManifest struct {
4141
Workflows map[string]Workflow `json:"workflows,omitempty" yaml:"workflows,flow,omitempty"`
4242
OutgoingDomains *[]string `json:"outgoing_domains,omitempty" yaml:"outgoing_domains,flow,omitempty"`
4343
ExternalAuthProviders *ManifestAuthProviders `json:"external_auth_providers,omitempty" yaml:"external_auth_providers,flow,omitempty"`
44+
MCPServers map[string]MCPServer `json:"mcp_servers,omitempty" yaml:"mcp_servers,flow,omitempty"`
4445
}
4546

4647
type ManifestMetadata struct {
@@ -157,6 +158,13 @@ type ManifestAuthProviders struct {
157158
OAuth2 map[string]*RawJSON `json:"oauth2" yaml:"oauth2"`
158159
}
159160

161+
// MCPServer defines the configuration of an MCP server in the app manifest.
162+
type MCPServer struct {
163+
URL string `json:"url" yaml:"url"`
164+
AuthProviderKey string `json:"auth_provider_key,omitempty" yaml:"auth_provider_key,omitempty"`
165+
AuthType string `json:"auth_type,omitempty" yaml:"auth_type,omitempty"`
166+
}
167+
160168
type RawJSON struct {
161169
Data *yaml.MapSlice
162170
JSONData *json.RawMessage

internal/shared/types/app_manifest_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,77 @@ func Test_AppManifest_OAuthConfig_Scopes(t *testing.T) {
392392
}
393393
}
394394

395+
func Test_AppManifest_MCPServers(t *testing.T) {
396+
tests := map[string]struct {
397+
manifest AppManifest
398+
expectedJSON string
399+
}{
400+
"undefined mcp_servers are omitted": {
401+
manifest: AppManifest{},
402+
expectedJSON: `{"display_information":{"name":""}}`,
403+
},
404+
"nil mcp_servers are omitted": {
405+
manifest: AppManifest{MCPServers: nil},
406+
expectedJSON: `{"display_information":{"name":""}}`,
407+
},
408+
"mcp_servers with url only": {
409+
manifest: AppManifest{MCPServers: map[string]MCPServer{
410+
"acme": {URL: "https://mcp.acme.com/mcp", AuthType: "no_auth"},
411+
}},
412+
expectedJSON: `{"display_information":{"name":""},"mcp_servers":{"acme":{"url":"https://mcp.acme.com/mcp","auth_type":"no_auth"}}}`,
413+
},
414+
"mcp_servers with auth_provider_key": {
415+
manifest: AppManifest{MCPServers: map[string]MCPServer{
416+
"acme": {
417+
URL: "https://mcp.acme.com/mcp",
418+
AuthProviderKey: "acme",
419+
AuthType: "manual_auth",
420+
},
421+
}},
422+
expectedJSON: `{"display_information":{"name":""},"mcp_servers":{"acme":{"url":"https://mcp.acme.com/mcp","auth_provider_key":"acme","auth_type":"manual_auth"}}}`,
423+
},
424+
"mcp_servers with auth_type": {
425+
manifest: AppManifest{MCPServers: map[string]MCPServer{
426+
"acme": {
427+
URL: "https://mcp.acme.com/mcp",
428+
AuthType: "dynamic_client_registration",
429+
},
430+
}},
431+
expectedJSON: `{"display_information":{"name":""},"mcp_servers":{"acme":{"url":"https://mcp.acme.com/mcp","auth_type":"dynamic_client_registration"}}}`,
432+
},
433+
"mcp_servers with all fields": {
434+
manifest: AppManifest{MCPServers: map[string]MCPServer{
435+
"acme": {
436+
URL: "https://mcp.acme.com/mcp",
437+
AuthProviderKey: "acme",
438+
AuthType: "manual_auth",
439+
},
440+
}},
441+
expectedJSON: `{"display_information":{"name":""},"mcp_servers":{"acme":{"url":"https://mcp.acme.com/mcp","auth_provider_key":"acme","auth_type":"manual_auth"}}}`,
442+
},
443+
"multiple mcp_servers": {
444+
manifest: AppManifest{MCPServers: map[string]MCPServer{
445+
"acme": {URL: "https://mcp.acme.com/mcp", AuthType: "dynamic_client_registration"},
446+
"other": {URL: "https://mcp.other.com/mcp", AuthType: "no_auth"},
447+
}},
448+
},
449+
}
450+
for name, tc := range tests {
451+
t.Run(name, func(t *testing.T) {
452+
actualJSON, err := json.Marshal(tc.manifest)
453+
require.NoError(t, err)
454+
if tc.expectedJSON != "" {
455+
assert.Equal(t, tc.expectedJSON, string(actualJSON))
456+
}
457+
// Verify round-trip unmarshaling
458+
var unmarshaled AppManifest
459+
err = json.Unmarshal(actualJSON, &unmarshaled)
460+
require.NoError(t, err)
461+
assert.Equal(t, tc.manifest.MCPServers, unmarshaled.MCPServers)
462+
})
463+
}
464+
}
465+
395466
func Test_AppManifest_AppSettings_FunctionRuntime(t *testing.T) {
396467
tests := map[string]struct {
397468
settings *AppSettings

0 commit comments

Comments
 (0)