chore: initial release v0.1.0
forge-toolkit: хелперы для разработки MCP-серверов на Go. - toolkit: args/schema/result/env/probe/server - toolkit/validate: валидаторы синтаксиса - configreload: live-reload конфига по контент-хэшу - docs: ARCHITECTURE, quickstart, mcp-contract - template/ и examples/hello-tool/ - CI (Gitea Actions), лицензия Apache-2.0
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
package toolkit
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
// RequestArgs распаковывает сырые аргументы tool-вызова в map[string]any.
|
||||
// Битый JSON / пустые аргументы → пустая карта (валидация — в хендлерах).
|
||||
func RequestArgs(req *mcp.CallToolRequest) map[string]any {
|
||||
if req == nil || req.Params == nil || len(req.Params.Arguments) == 0 {
|
||||
return map[string]any{}
|
||||
}
|
||||
var a map[string]any
|
||||
if err := json.Unmarshal(req.Params.Arguments, &a); err != nil {
|
||||
return map[string]any{}
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// GetString возвращает строковый аргумент или def. Не-строки приводятся к
|
||||
// строке через %v (терпимость к числам/булевым от моделей).
|
||||
func GetString(args map[string]any, key, def string) string {
|
||||
v, ok := args[key]
|
||||
if !ok || v == nil {
|
||||
return def
|
||||
}
|
||||
if s, ok := v.(string); ok {
|
||||
return s
|
||||
}
|
||||
return fmt.Sprintf("%v", v)
|
||||
}
|
||||
|
||||
// RequireString возвращает непустой строковый аргумент или ошибку.
|
||||
func RequireString(args map[string]any, key string) (string, error) {
|
||||
v, ok := args[key]
|
||||
if !ok || v == nil {
|
||||
return "", fmt.Errorf("missing required argument '%s'", key)
|
||||
}
|
||||
s, ok := v.(string)
|
||||
if !ok || s == "" {
|
||||
return "", fmt.Errorf("argument '%s' must be a non-empty string", key)
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// GetInt возвращает целочисленный аргумент или def. Принимает float64
|
||||
// (обычный JSON-числовой тип), int и строку с числом.
|
||||
func GetInt(args map[string]any, key string, def int) int {
|
||||
v, ok := args[key]
|
||||
if !ok || v == nil {
|
||||
return def
|
||||
}
|
||||
switch n := v.(type) {
|
||||
case float64:
|
||||
return int(n)
|
||||
case int:
|
||||
return n
|
||||
case string:
|
||||
if i, err := strconv.Atoi(n); err == nil {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
// GetBool возвращает булев аргумент или def.
|
||||
func GetBool(args map[string]any, key string, def bool) bool {
|
||||
v, ok := args[key]
|
||||
if !ok || v == nil {
|
||||
return def
|
||||
}
|
||||
if b, ok := v.(bool); ok {
|
||||
return b
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
// GetStringArray возвращает непустой срез непустых строк. ok=false, если
|
||||
// аргумента нет, он не массив или после фильтрации пуст.
|
||||
func GetStringArray(args map[string]any, key string) ([]string, bool) {
|
||||
v, ok := args[key]
|
||||
if !ok || v == nil {
|
||||
return nil, false
|
||||
}
|
||||
arr, ok := v.([]any)
|
||||
if !ok || len(arr) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
var out []string
|
||||
for _, item := range arr {
|
||||
if s, ok := item.(string); ok && s != "" {
|
||||
out = append(out, s)
|
||||
}
|
||||
}
|
||||
if len(out) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
return out, true
|
||||
}
|
||||
|
||||
// GetIntArray возвращает непустой срез int (float64/int элементы).
|
||||
func GetIntArray(args map[string]any, key string) ([]int, bool) {
|
||||
v, ok := args[key]
|
||||
if !ok || v == nil {
|
||||
return nil, false
|
||||
}
|
||||
arr, ok := v.([]any)
|
||||
if !ok || len(arr) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
var out []int
|
||||
for _, item := range arr {
|
||||
switch n := item.(type) {
|
||||
case float64:
|
||||
out = append(out, int(n))
|
||||
case int:
|
||||
out = append(out, n)
|
||||
}
|
||||
}
|
||||
if len(out) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
return out, true
|
||||
}
|
||||
|
||||
// GetStringMap разбирает объект со строковыми значениями (напр. заголовки).
|
||||
func GetStringMap(args map[string]any, key string) map[string]string {
|
||||
v, ok := args[key]
|
||||
if !ok || v == nil {
|
||||
return nil
|
||||
}
|
||||
m, ok := v.(map[string]any)
|
||||
if !ok || len(m) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := make(map[string]string, len(m))
|
||||
for k, val := range m {
|
||||
if s, ok := val.(string); ok {
|
||||
out[k] = s
|
||||
}
|
||||
}
|
||||
if len(out) == 0 {
|
||||
return nil
|
||||
}
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user