Files
funstat-mcp-go/internal/app/app.go
你的用户名 8d1ce4598d Initial commit: FunStat MCP Server Go implementation
- Telegram integration for customer statistics
- MCP server implementation with rate limiting
- Cache system for performance optimization
- Multi-language support
- RESTful API endpoints

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-04 15:28:06 +08:00

154 lines
3.4 KiB
Go

package app
import (
"context"
"fmt"
"strconv"
"strings"
tgclient "funstatmcp/internal/telegram"
)
type App struct {
cfg Config
client *tgclient.Client
}
func New(cfg Config) (*App, error) {
client, err := tgclient.New(cfg.Telegram)
if err != nil {
return nil, err
}
return &App{
cfg: cfg,
client: client,
}, nil
}
func (a *App) Close() error {
return nil
}
func (a *App) SendCommand(ctx context.Context, command string, useCache bool) (string, error) {
return a.client.SendCommand(ctx, command, useCache)
}
func (a *App) CallTool(ctx context.Context, name string, args map[string]any) (string, error) {
switch name {
case "funstat_search":
query, err := requireString(args, "query")
if err != nil {
return "", err
}
return a.client.SendCommand(ctx, fmt.Sprintf("/search %s", query), true)
case "funstat_topchat":
category := optionalString(args, "category")
if category != "" {
return a.client.SendCommand(ctx, fmt.Sprintf("/topchat %s", category), true)
}
return a.client.SendCommand(ctx, "/topchat", true)
case "funstat_text":
text, err := requireString(args, "text")
if err != nil {
return "", err
}
return a.client.SendCommand(ctx, fmt.Sprintf("/text %s", text), true)
case "funstat_human":
nameArg, err := requireString(args, "name")
if err != nil {
return "", err
}
return a.client.SendCommand(ctx, fmt.Sprintf("/human %s", nameArg), true)
case "funstat_user_info":
identifier, err := requireString(args, "identifier")
if err != nil {
return "", err
}
identifier = strings.TrimSpace(identifier)
if identifier == "" {
return "", fmt.Errorf("identifier cannot be empty")
}
return a.client.SendCommand(ctx, fmt.Sprintf("/user_info %s", identifier), true)
case "funstat_user_messages":
identifier, err := requireString(args, "identifier")
if err != nil {
return "", err
}
var maxPagesPtr *int
if value, ok := args["max_pages"]; ok {
v, err := toInt(value)
if err != nil {
return "", fmt.Errorf("max_pages must be an integer: %w", err)
}
maxPagesPtr = &v
}
return a.client.FetchUserMessages(ctx, identifier, maxPagesPtr)
case "funstat_balance":
return a.client.SendCommand(ctx, "/balance", true)
case "funstat_menu":
return a.client.SendCommand(ctx, "/menu", true)
case "funstat_start":
return a.client.SendCommand(ctx, "/start", true)
default:
return "", fmt.Errorf("unknown tool: %s", name)
}
}
func requireString(args map[string]any, key string) (string, error) {
value, ok := args[key]
if !ok {
return "", fmt.Errorf("missing required argument: %s", key)
}
str, ok := value.(string)
if !ok {
return "", fmt.Errorf("argument %s must be a string", key)
}
str = strings.TrimSpace(str)
if str == "" {
return "", fmt.Errorf("argument %s cannot be empty", key)
}
return str, nil
}
func optionalString(args map[string]any, key string) string {
if value, ok := args[key]; ok {
if str, ok := value.(string); ok {
return strings.TrimSpace(str)
}
}
return ""
}
func toInt(value any) (int, error) {
switch v := value.(type) {
case float64:
return int(v), nil
case float32:
return int(v), nil
case int:
return v, nil
case int32:
return int(v), nil
case int64:
return int(v), nil
case string:
parsed, err := strconv.Atoi(strings.TrimSpace(v))
if err != nil {
return 0, err
}
return parsed, nil
default:
return 0, fmt.Errorf("unsupported type %T", value)
}
}