mirror of
https://github.com/lukaszraczylo/mcp-captcharesolver.git
synced 2026-10-16 01:07:54 +00:00
initial commit
This commit is contained in:
@@ -19,7 +19,10 @@ type Config struct {
|
||||
APIKey string
|
||||
Model string
|
||||
AudioModel string
|
||||
HTTPPath string
|
||||
LogLevel string
|
||||
Transport string
|
||||
HTTPAddr string
|
||||
Timeout time.Duration
|
||||
MaxTokens int
|
||||
}
|
||||
@@ -28,7 +31,11 @@ var validProviders = map[string]bool{
|
||||
"anthropic": true, "openai": true, "openai-compatible": true, "gemini": true,
|
||||
}
|
||||
|
||||
// Load reads CAPTCHA_LLM_* env vars and returns a validated Config.
|
||||
var validTransports = map[string]bool{
|
||||
"stdio": true, "http": true,
|
||||
}
|
||||
|
||||
// Load reads CAPTCHA_LLM_* and CAPTCHA_TRANSPORT_* env vars and returns a validated Config.
|
||||
func Load() (Config, error) {
|
||||
c := Config{
|
||||
Provider: os.Getenv("CAPTCHA_LLM_PROVIDER"),
|
||||
@@ -37,18 +44,29 @@ func Load() (Config, error) {
|
||||
Model: os.Getenv("CAPTCHA_LLM_MODEL"),
|
||||
AudioModel: os.Getenv("CAPTCHA_LLM_AUDIO_MODEL"),
|
||||
LogLevel: envOr("CAPTCHA_LOG_LEVEL", "info"),
|
||||
Transport: envOr("CAPTCHA_TRANSPORT", "stdio"),
|
||||
HTTPAddr: envOr("CAPTCHA_HTTP_ADDR", ":8080"),
|
||||
HTTPPath: envOr("CAPTCHA_HTTP_PATH", "/mcp"),
|
||||
MaxTokens: 1024,
|
||||
Timeout: 60 * time.Second,
|
||||
}
|
||||
if !validProviders[c.Provider] {
|
||||
return Config{}, fmt.Errorf("CAPTCHA_LLM_PROVIDER must be one of anthropic|openai|openai-compatible|gemini, got %q", c.Provider)
|
||||
}
|
||||
if !validTransports[c.Transport] {
|
||||
return Config{}, fmt.Errorf("CAPTCHA_TRANSPORT must be one of stdio|http, got %q", c.Transport)
|
||||
}
|
||||
if c.APIKey == "" && c.BaseURL == "" {
|
||||
return Config{}, fmt.Errorf("CAPTCHA_LLM_API_KEY is required (or set CAPTCHA_LLM_BASE_URL for a keyless local endpoint)")
|
||||
}
|
||||
if c.Model == "" {
|
||||
return Config{}, fmt.Errorf("CAPTCHA_LLM_MODEL is required")
|
||||
}
|
||||
if c.Transport == "http" {
|
||||
if c.HTTPPath == "" || c.HTTPPath[0] != '/' {
|
||||
return Config{}, fmt.Errorf("CAPTCHA_HTTP_PATH must be an absolute path beginning with '/', got %q", c.HTTPPath)
|
||||
}
|
||||
}
|
||||
if v := os.Getenv("CAPTCHA_LLM_MAX_TOKENS"); v != "" {
|
||||
n, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
|
||||
@@ -21,7 +21,25 @@ func TestLoad(t *testing.T) {
|
||||
},
|
||||
want: Config{
|
||||
Provider: "anthropic", APIKey: "k", Model: "claude-opus-4-8",
|
||||
LogLevel: "info", MaxTokens: 1024, Timeout: 60 * time.Second,
|
||||
LogLevel: "info", Transport: "stdio", HTTPAddr: ":8080", HTTPPath: "/mcp",
|
||||
MaxTokens: 1024, Timeout: 60 * time.Second,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "valid http transport",
|
||||
env: map[string]string{
|
||||
"CAPTCHA_LLM_PROVIDER": "openai-compatible",
|
||||
"CAPTCHA_LLM_BASE_URL": "http://localhost:11434/v1",
|
||||
"CAPTCHA_LLM_MODEL": "qwen2.5vl",
|
||||
"CAPTCHA_TRANSPORT": "http",
|
||||
"CAPTCHA_HTTP_ADDR": "127.0.0.1:9090",
|
||||
"CAPTCHA_HTTP_PATH": "/mcp",
|
||||
},
|
||||
want: Config{
|
||||
Provider: "openai-compatible", BaseURL: "http://localhost:11434/v1",
|
||||
Model: "qwen2.5vl",
|
||||
LogLevel: "info", Transport: "http", HTTPAddr: "127.0.0.1:9090", HTTPPath: "/mcp",
|
||||
MaxTokens: 1024, Timeout: 60 * time.Second,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -34,6 +52,23 @@ func TestLoad(t *testing.T) {
|
||||
env: map[string]string{"CAPTCHA_LLM_PROVIDER": "nope", "CAPTCHA_LLM_API_KEY": "k", "CAPTCHA_LLM_MODEL": "m"},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "bad transport",
|
||||
env: map[string]string{
|
||||
"CAPTCHA_LLM_PROVIDER": "openai", "CAPTCHA_LLM_API_KEY": "k", "CAPTCHA_LLM_MODEL": "m",
|
||||
"CAPTCHA_TRANSPORT": "quic",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "http transport with relative path",
|
||||
env: map[string]string{
|
||||
"CAPTCHA_LLM_PROVIDER": "openai", "CAPTCHA_LLM_API_KEY": "k", "CAPTCHA_LLM_MODEL": "m",
|
||||
"CAPTCHA_TRANSPORT": "http",
|
||||
"CAPTCHA_HTTP_PATH": "mcp",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user