Files
ombi-mcp/internal/config/config.go
gronod 49bc0775de
Build and publish / Test and build (windows) (push) Failing after 11s
Build and publish / Test and build (darwin) (push) Successful in 1m32s
Build and publish / Test and build (linux) (push) Canceled after 0s
Build and publish / Build and publish Docker image (push) Canceled after 0s
Add HTTP/SSE transport alongside stdio (Phase 09)
Network MCP clients (e.g. browser-based frontends) can't spawn stdio
subprocesses, so the server now optionally serves the 2024-11-05 MCP
HTTP/SSE transport via MCP_TRANSPORT=sse and MCP_PORT (default 8080),
backed by the SDK's SSEHandler behind permissive CORS. stdio remains
the default and is behaviourally unchanged.
2026-09-18 21:13:09 +01:00

105 lines
2.6 KiB
Go

package config
import (
"errors"
"fmt"
"net/url"
"os"
"strconv"
"strings"
"time"
)
type AuthMode string
const (
AuthModeJWT AuthMode = "jwt"
AuthModeAPIKey AuthMode = "api_key"
)
type Transport string
const (
TransportStdio Transport = "stdio"
TransportSSE Transport = "sse"
)
type Config struct {
BaseURL *url.URL
AuthMode AuthMode
Username string
Password string
APIKey string
UserName string
EnabledBundles map[string]bool // keys: core, moderation, administration
HTTPTimeout time.Duration
Transport Transport
Port int
}
func Load() (*Config, error) {
c := &Config{
HTTPTimeout: 30 * time.Second,
EnabledBundles: map[string]bool{"core": true},
Transport: TransportStdio,
Port: 8080,
}
raw := os.Getenv("OMBI_URL")
if raw == "" {
return nil, errors.New("OMBI_URL is required")
}
u, err := url.Parse(raw)
if err != nil || u.Scheme == "" || u.Host == "" {
return nil, fmt.Errorf("OMBI_URL invalid: %q", raw)
}
if u.User != nil || u.RawQuery != "" || u.Fragment != "" {
return nil, errors.New("OMBI_URL must not contain credentials, query or fragment")
}
c.BaseURL = u
switch AuthMode(os.Getenv("OMBI_AUTH_MODE")) {
case AuthModeJWT:
c.AuthMode = AuthModeJWT
case AuthModeAPIKey:
c.AuthMode = AuthModeAPIKey
default:
return nil, errors.New("OMBI_AUTH_MODE must be \"jwt\" or \"api_key\"")
}
c.Username, c.Password = os.Getenv("OMBI_USERNAME"), os.Getenv("OMBI_PASSWORD")
c.APIKey, c.UserName = os.Getenv("OMBI_API_KEY"), os.Getenv("OMBI_USER_NAME")
if c.AuthMode == AuthModeJWT && (c.Username == "" || c.Password == "") {
return nil, errors.New("jwt mode requires OMBI_USERNAME and OMBI_PASSWORD")
}
if c.AuthMode == AuthModeAPIKey && c.APIKey == "" {
return nil, errors.New("api_key mode requires OMBI_API_KEY")
}
if b := os.Getenv("OMBI_BUNDLES"); b != "" {
c.EnabledBundles = map[string]bool{}
for _, s := range strings.Split(b, ",") {
s = strings.TrimSpace(s)
if s != "core" && s != "moderation" && s != "administration" {
return nil, fmt.Errorf("unknown bundle %q", s)
}
c.EnabledBundles[s] = true
}
}
switch t := os.Getenv("MCP_TRANSPORT"); t {
case "", string(TransportStdio):
c.Transport = TransportStdio
case string(TransportSSE):
c.Transport = TransportSSE
default:
return nil, fmt.Errorf("MCP_TRANSPORT must be %q or %q", TransportStdio, TransportSSE)
}
if p := os.Getenv("MCP_PORT"); p != "" {
n, err := strconv.Atoi(p)
if err != nil || n < 1 || n > 65535 {
return nil, fmt.Errorf("MCP_PORT invalid: %q", p)
}
c.Port = n
}
return c, nil
}