- Introduce `MCPServer` to support connecting to MCP servers via stdio, SSE, or HTTP. - Implement tool fetching, management, and invocation through MCP. - Add `WithMCPServer` method to `ToolBox` for seamless tool integration. - Extend schema package to handle raw JSON schemas for MCP tools. - Update documentation with MCP usage guidelines and examples.
135 lines
2.8 KiB
Go
135 lines
2.8 KiB
Go
package schema
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"reflect"
|
|
|
|
"github.com/openai/openai-go"
|
|
"google.golang.org/genai"
|
|
)
|
|
|
|
// Raw represents a raw JSON schema that is passed through directly.
|
|
// This is used for MCP tools where we receive the schema from the server.
|
|
type Raw struct {
|
|
schema map[string]any
|
|
}
|
|
|
|
// NewRaw creates a new Raw schema from a map.
|
|
func NewRaw(schema map[string]any) Raw {
|
|
if schema == nil {
|
|
schema = map[string]any{
|
|
"type": "object",
|
|
"properties": map[string]any{},
|
|
}
|
|
}
|
|
return Raw{schema: schema}
|
|
}
|
|
|
|
// NewRawFromJSON creates a new Raw schema from JSON bytes.
|
|
func NewRawFromJSON(data []byte) (Raw, error) {
|
|
var schema map[string]any
|
|
if err := json.Unmarshal(data, &schema); err != nil {
|
|
return Raw{}, fmt.Errorf("failed to parse JSON schema: %w", err)
|
|
}
|
|
return NewRaw(schema), nil
|
|
}
|
|
|
|
func (r Raw) OpenAIParameters() openai.FunctionParameters {
|
|
return openai.FunctionParameters(r.schema)
|
|
}
|
|
|
|
func (r Raw) GoogleParameters() *genai.Schema {
|
|
return mapToGenaiSchema(r.schema)
|
|
}
|
|
|
|
func (r Raw) AnthropicInputSchema() map[string]any {
|
|
return r.schema
|
|
}
|
|
|
|
func (r Raw) Required() bool {
|
|
return false
|
|
}
|
|
|
|
func (r Raw) Description() string {
|
|
if desc, ok := r.schema["description"].(string); ok {
|
|
return desc
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (r Raw) FromAny(val any) (reflect.Value, error) {
|
|
return reflect.ValueOf(val), nil
|
|
}
|
|
|
|
func (r Raw) SetValueOnField(obj reflect.Value, val reflect.Value) {
|
|
// No-op for raw schemas
|
|
}
|
|
|
|
// mapToGenaiSchema converts a map[string]any JSON schema to genai.Schema
|
|
func mapToGenaiSchema(m map[string]any) *genai.Schema {
|
|
if m == nil {
|
|
return nil
|
|
}
|
|
|
|
schema := &genai.Schema{}
|
|
|
|
// Type
|
|
if t, ok := m["type"].(string); ok {
|
|
switch t {
|
|
case "string":
|
|
schema.Type = genai.TypeString
|
|
case "number":
|
|
schema.Type = genai.TypeNumber
|
|
case "integer":
|
|
schema.Type = genai.TypeInteger
|
|
case "boolean":
|
|
schema.Type = genai.TypeBoolean
|
|
case "array":
|
|
schema.Type = genai.TypeArray
|
|
case "object":
|
|
schema.Type = genai.TypeObject
|
|
}
|
|
}
|
|
|
|
// Description
|
|
if desc, ok := m["description"].(string); ok {
|
|
schema.Description = desc
|
|
}
|
|
|
|
// Enum
|
|
if enum, ok := m["enum"].([]any); ok {
|
|
for _, e := range enum {
|
|
if s, ok := e.(string); ok {
|
|
schema.Enum = append(schema.Enum, s)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Properties (for objects)
|
|
if props, ok := m["properties"].(map[string]any); ok {
|
|
schema.Properties = make(map[string]*genai.Schema)
|
|
for k, v := range props {
|
|
if vm, ok := v.(map[string]any); ok {
|
|
schema.Properties[k] = mapToGenaiSchema(vm)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Required
|
|
if req, ok := m["required"].([]any); ok {
|
|
for _, r := range req {
|
|
if s, ok := r.(string); ok {
|
|
schema.Required = append(schema.Required, s)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Items (for arrays)
|
|
if items, ok := m["items"].(map[string]any); ok {
|
|
schema.Items = mapToGenaiSchema(items)
|
|
}
|
|
|
|
return schema
|
|
}
|