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
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.
105 lines
2.6 KiB
Go
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
|
|
}
|