Files
shinchan-zhai 16ebe0a64c feat(mcp): add context length guard to prevent oversized requests
* feat: add X-Client-ID header for claw402 monitoring

* feat(mcp): add context length guard to prevent oversized requests

- Add MaxContext field to Config (default 0 = no limit)
- Add WithMaxContext() option for setting model context limits
- Add context_guard.go: token estimation + message truncation
- Integrate guard into both BuildMCPRequestBody and BuildRequestBodyFromRequest
- Support both map[string]string and map[string]any message formats
- Truncates oldest non-system messages when estimated tokens exceed limit
- Always preserves system messages and keeps at least 1 non-system message
- Logs warning when truncation occurs for debugging

Usage: mcp.NewDeepSeekClient(mcp.WithMaxContext(131072))
2026-03-18 11:10:22 +08:00

74 lines
1.6 KiB
Go

package mcp
import (
"net/http"
"os"
"strconv"
"time"
"nofx/logger"
"nofx/security"
)
// Config client configuration (centralized management of all configurations)
type Config struct {
// Provider configuration
Provider string
APIKey string
BaseURL string
Model string
// Behavior configuration
MaxTokens int
MaxContext int // Model's max context window in tokens (0 = no limit)
Temperature float64
UseFullURL bool
// Retry configuration
MaxRetries int
RetryWaitBase time.Duration
RetryableErrors []string
// Timeout configuration
Timeout time.Duration
// Dependency injection
Logger Logger
HTTPClient *http.Client
}
// DefaultConfig returns default configuration
func DefaultConfig() *Config {
return &Config{
// Default values
MaxTokens: getEnvInt("AI_MAX_TOKENS", 2000),
Temperature: MCPClientTemperature,
MaxRetries: MaxRetryTimes,
RetryWaitBase: 2 * time.Second,
Timeout: DefaultTimeout,
RetryableErrors: retryableErrors,
// Default dependencies (use global logger)
Logger: logger.NewMCPLogger(),
HTTPClient: security.SafeHTTPClient(DefaultTimeout),
}
}
// getEnvInt reads integer from environment variable, returns default value if failed
func getEnvInt(key string, defaultValue int) int {
if val := os.Getenv(key); val != "" {
if parsed, err := strconv.Atoi(val); err == nil && parsed > 0 {
return parsed
}
}
return defaultValue
}
// getEnvString reads string from environment variable, returns default value if empty
func getEnvString(key string, defaultValue string) string {
if val := os.Getenv(key); val != "" {
return val
}
return defaultValue
}