package cli import ( "context" "io" "os" frameworkconfig "gitea.lclr.dev/AI/mcp-framework/config" frameworkmanifest "gitea.lclr.dev/AI/mcp-framework/manifest" frameworksecretstore "gitea.lclr.dev/AI/mcp-framework/secretstore" "email-mcp/internal/imapclient" "email-mcp/internal/mcpserver" "email-mcp/internal/secretstore" ) type runtimeFactories struct { newPrompter func(io.Reader, io.Writer) ConfigPrompter newConfigStore func() profileConfigStore openSecretStore func() (secretStore, error) newMailService func() mcpserver.MailService newRunner func(secretstore.Credential, mcpserver.MailService, io.Reader, io.Writer, io.Writer) MCPRunner loadManifest manifestLoader resolveExecutable executableResolver } func BuildApp(version string) *App { return buildApp(os.Stdin, os.Stdout, os.Stderr, version, runtimeFactories{}) } func buildApp(stdin io.Reader, stdout io.Writer, stderr io.Writer, version string, factories runtimeFactories) *App { factories = factories.withDefaults() return NewAppWithDependencies( factories.newPrompter(stdin, stderr), factories.newConfigStore(), factories.openSecretStore, factories.newMailService, factories.newRunner, factories.loadManifest, factories.resolveExecutable, stdin, stdout, stderr, version, ) } func (f runtimeFactories) withDefaults() runtimeFactories { if f.newPrompter == nil { f.newPrompter = func(input io.Reader, output io.Writer) ConfigPrompter { return NewInteractiveConfigPrompter(input, output) } } if f.newConfigStore == nil { f.newConfigStore = func() profileConfigStore { return frameworkconfig.NewStore[ProfileConfig]("email-mcp") } } if f.openSecretStore == nil { f.openSecretStore = func() (secretStore, error) { return frameworksecretstore.Open(frameworksecretstore.Options{ ServiceName: "email-mcp", BackendPolicy: frameworksecretstore.BackendAuto, }) } } if f.newMailService == nil { f.newMailService = func() mcpserver.MailService { return imapclient.NewService(imapclient.NewDefaultBackend()) } } if f.newRunner == nil { f.newRunner = func(cred secretstore.Credential, mail mcpserver.MailService, input io.Reader, output io.Writer, errOut io.Writer) MCPRunner { return mcpserver.NewRunner(mcpserver.New(staticCredentialStore{credential: cred}, mail), input, output, errOut) } } if f.loadManifest == nil { f.loadManifest = frameworkmanifest.LoadDefault } if f.resolveExecutable == nil { f.resolveExecutable = os.Executable } return f } type staticCredentialStore struct { credential secretstore.Credential } func (s staticCredentialStore) Save(_ context.Context, _ string, _ secretstore.Credential) error { return nil } func (s staticCredentialStore) Load(_ context.Context, _ string) (secretstore.Credential, error) { return s.credential, nil }