From 417499bf2f52622d87e9881ffbaeaaa521b1cc33 Mon Sep 17 00:00:00 2001 From: Tai Groot Date: Thu, 16 Oct 2025 02:36:05 -0400 Subject: [PATCH] upgrade mcp library --- go.mod | 13 +- go.sum | 47 +----- internal/ximcp/server.go | 15 +- internal/ximcp/tools.go | 340 +++++++++++++++------------------------ main.go | 14 +- 5 files changed, 159 insertions(+), 270 deletions(-) diff --git a/go.mod b/go.mod index 0ef7bc2..7bbc4e5 100644 --- a/go.mod +++ b/go.mod @@ -1,26 +1,19 @@ module github.com/taigrr/elevenlabs-mcp -go 1.24.6 +go 1.25.2 require ( github.com/gopxl/beep/v2 v2.1.1 - github.com/mark3labs/mcp-go v0.37.0 + github.com/modelcontextprotocol/go-sdk v1.0.0 github.com/taigrr/elevenlabs v0.1.18 ) require ( - github.com/bahlo/generic-list-go v0.2.0 // indirect - github.com/buger/jsonparser v1.1.1 // indirect github.com/ebitengine/oto/v3 v3.3.3 // indirect github.com/ebitengine/purego v0.8.4 // indirect - github.com/google/uuid v1.6.0 // indirect + github.com/google/jsonschema-go v0.3.0 // indirect github.com/hajimehoshi/go-mp3 v0.3.4 // indirect - github.com/invopop/jsonschema v0.13.0 // indirect - github.com/mailru/easyjson v0.9.0 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/spf13/cast v1.9.2 // indirect - github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/yosida95/uritemplate/v3 v3.0.2 // indirect golang.org/x/sys v0.35.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 92ab692..31af9b4 100644 --- a/go.sum +++ b/go.sum @@ -1,65 +1,34 @@ -github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= -github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= -github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= -github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/ebitengine/oto/v3 v3.3.2 h1:VTWBsKX9eb+dXzaF4jEwQbs4yWIdXukJ0K40KgkpYlg= -github.com/ebitengine/oto/v3 v3.3.2/go.mod h1:MZeb/lwoC4DCOdiTIxYezrURTw7EvK/yF863+tmBI+U= github.com/ebitengine/oto/v3 v3.3.3 h1:m6RV69OqoXYSWCDsHXN9rc07aDuDstGHtait7HXSM7g= github.com/ebitengine/oto/v3 v3.3.3/go.mod h1:MZeb/lwoC4DCOdiTIxYezrURTw7EvK/yF863+tmBI+U= -github.com/ebitengine/purego v0.8.0 h1:JbqvnEzRvPpxhCJzJJ2y0RbiZ8nyjccVUrSM3q+GvvE= -github.com/ebitengine/purego v0.8.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= -github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= -github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/jsonschema-go v0.3.0 h1:6AH2TxVNtk3IlvkkhjrtbUc4S8AvO0Xii0DxIygDg+Q= +github.com/google/jsonschema-go v0.3.0/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE= github.com/gopxl/beep/v2 v2.1.1 h1:6FYIYMm2qPAdWkjX+7xwKrViS1x0Po5kDMdRkq8NVbU= github.com/gopxl/beep/v2 v2.1.1/go.mod h1:ZAm9TGQ9lvpoiFLd4zf5B1IuyxZhgRACMId1XJbaW0E= github.com/hajimehoshi/go-mp3 v0.3.4 h1:NUP7pBYH8OguP4diaTZ9wJbUbk3tC0KlfzsEpWmYj68= github.com/hajimehoshi/go-mp3 v0.3.4/go.mod h1:fRtZraRFcWb0pu7ok0LqyFhCUrPeMsGRSVop0eemFmo= github.com/hajimehoshi/oto/v2 v2.3.1/go.mod h1:seWLbgHH7AyUMYKfKYT9pg7PhUu9/SisyJvNTT+ASQo= -github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E= -github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= -github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= -github.com/mark3labs/mcp-go v0.37.0 h1:BywvZLPRT6Zx6mMG/MJfxLSZQkTGIcJSEGKsvr4DsoQ= -github.com/mark3labs/mcp-go v0.37.0/go.mod h1:T7tUa2jO6MavG+3P25Oy/jR7iCeJPHImCZHRymCn39g= +github.com/modelcontextprotocol/go-sdk v1.0.0 h1:Z4MSjLi38bTgLrd/LjSmofqRqyBiVKRyQSJgw8q8V74= +github.com/modelcontextprotocol/go-sdk v1.0.0/go.mod h1:nYtYQroQ2KQiM0/SbyEPUWQ6xs4B95gJjEalc9AQyOs= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= -github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/cast v1.9.2 h1:SsGfm7M8QOFtEzumm7UZrZdLLquNdzFYfIbEXntcFbE= -github.com/spf13/cast v1.9.2/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/taigrr/elevenlabs v0.1.18 h1:ZvRsLjzV4ov6Rdls7MNFKvcknLc527RR6beV6pjukJU= github.com/taigrr/elevenlabs v0.1.18/go.mod h1:ardwj7FGIQbpvRl+UpdRzVnxOuo7QQxqC3YhFcvY1gM= -github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= -github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4= github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4= golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= -golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= +golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/ximcp/server.go b/internal/ximcp/server.go index 6353835..91388b1 100644 --- a/internal/ximcp/server.go +++ b/internal/ximcp/server.go @@ -9,7 +9,7 @@ import ( "github.com/gopxl/beep/v2" "github.com/gopxl/beep/v2/speaker" - "github.com/mark3labs/mcp-go/server" + "github.com/modelcontextprotocol/go-sdk/mcp" "github.com/taigrr/elevenlabs/client" "github.com/taigrr/elevenlabs/client/types" ) @@ -24,7 +24,7 @@ const ( ) type Server struct { - mcpServer *server.MCPServer + mcpServer *mcp.Server client client.Client voices []types.VoiceResponseModel currentVoice *types.VoiceResponseModel @@ -32,7 +32,7 @@ type Server struct { playMutex sync.Mutex } -func NewServer(mcpServer *server.MCPServer) (*Server, error) { +func NewServer() (*mcp.Server, error) { apiKey := os.Getenv("XI_API_KEY") if apiKey == "" { return nil, fmt.Errorf("XI_API_KEY environment variable is required") @@ -40,6 +40,11 @@ func NewServer(mcpServer *server.MCPServer) (*Server, error) { elevenClient := client.New(apiKey) + mcpServer := mcp.NewServer(&mcp.Implementation{ + Name: "ElevenLabs MCP Server", + Version: "1.0.0", + }, nil) + s := &Server{ client: elevenClient, mcpServer: mcpServer, @@ -53,7 +58,9 @@ func NewServer(mcpServer *server.MCPServer) (*Server, error) { return nil, fmt.Errorf("failed to initialize speaker: %w", err) } - return s, nil + s.setupTools() + + return mcpServer, nil } func (s *Server) initializeVoices() error { diff --git a/internal/ximcp/tools.go b/internal/ximcp/tools.go index 0c04279..2a512e6 100644 --- a/internal/ximcp/tools.go +++ b/internal/ximcp/tools.go @@ -5,203 +5,142 @@ import ( "fmt" "strings" - "github.com/mark3labs/mcp-go/mcp" - "github.com/mark3labs/mcp-go/server" + "github.com/modelcontextprotocol/go-sdk/mcp" "github.com/taigrr/elevenlabs/client/types" ) -func (s *Server) SetupTools() { - s.mcpServer.AddTool(s.say()) - s.mcpServer.AddTool(s.read()) - s.mcpServer.AddTool(s.play()) - s.mcpServer.AddTool(s.setVoice()) - s.mcpServer.AddTool(s.getVoices()) - s.mcpServer.AddTool(s.history()) +type SayArgs struct { + Text string `json:"text" jsonschema:"Text to convert to speech"` } -func (s *Server) say() (mcp.Tool, server.ToolHandlerFunc) { - tool := mcp.Tool{ +type ReadArgs struct { + FilePath string `json:"file_path" jsonschema:"Path to the text file to read and convert to speech"` +} + +type PlayArgs struct { + FilePath string `json:"file_path" jsonschema:"Path to the audio file to play"` +} + +type SetVoiceArgs struct { + VoiceID string `json:"voice_id" jsonschema:"ID of the voice to use"` +} + +func (s *Server) setupTools() { + mcp.AddTool(s.mcpServer, &mcp.Tool{ Name: "say", Description: "Convert text to speech, save as MP3 file, and play the audio", - InputSchema: mcp.ToolInputSchema{ - Type: "object", - Properties: map[string]any{ - "text": map[string]any{ - "type": "string", - "description": "Text to convert to speech", - }, - }, - Required: []string{"text"}, - }, - } + }, s.say) - handler := func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - text, err := request.RequireString("text") - if err != nil { - return nil, err - } - - filepath, err := s.GenerateAudio(text) - if err != nil { - return nil, err - } - - s.PlayAudioAsync(filepath) - - return &mcp.CallToolResult{ - Content: []mcp.Content{ - mcp.TextContent{ - Type: "text", - Text: fmt.Sprintf("Audio generated, saved to %s, and playing", filepath), - }, - }, - }, nil - } - return tool, handler -} - -func (s *Server) read() (mcp.Tool, server.ToolHandlerFunc) { - tool := mcp.Tool{ + mcp.AddTool(s.mcpServer, &mcp.Tool{ Name: "read", Description: "Read a text file and convert it to speech, saving as MP3", - InputSchema: mcp.ToolInputSchema{ - Type: "object", - Properties: map[string]any{ - "file_path": map[string]any{ - "type": "string", - "description": "Path to the text file to read and convert to speech", - }, - }, - Required: []string{"file_path"}, - }, - } + }, s.read) - handler := func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - filePath, err := request.RequireString("file_path") - if err != nil { - return nil, err - } - - audioPath, err := s.ReadFileToAudio(filePath) - if err != nil { - return nil, err - } - - return &mcp.CallToolResult{ - Content: []mcp.Content{ - mcp.TextContent{ - Type: "text", - Text: fmt.Sprintf("File '%s' converted to speech and saved to: %s", filePath, audioPath), - }, - }, - }, nil - } - return tool, handler -} - -func (s *Server) play() (mcp.Tool, server.ToolHandlerFunc) { - tool := mcp.Tool{ + mcp.AddTool(s.mcpServer, &mcp.Tool{ Name: "play", Description: "Play an audio file", - InputSchema: mcp.ToolInputSchema{ - Type: "object", - Properties: map[string]any{ - "file_path": map[string]any{ - "type": "string", - "description": "Path to the audio file to play", - }, - }, - Required: []string{"file_path"}, - }, - } + }, s.play) - handler := func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - filePath, err := request.RequireString("file_path") - if err != nil { - return nil, err - } - - s.PlayAudioAsync(filePath) - - return &mcp.CallToolResult{ - Content: []mcp.Content{ - mcp.TextContent{ - Type: "text", - Text: fmt.Sprintf("Playing audio file: %s", filePath), - }, - }, - }, nil - } - return tool, handler -} - -func (s *Server) setVoice() (mcp.Tool, server.ToolHandlerFunc) { - tool := mcp.Tool{ + mcp.AddTool(s.mcpServer, &mcp.Tool{ Name: "set_voice", Description: "Set the voice to use for text-to-speech generation", - InputSchema: mcp.ToolInputSchema{ - Type: "object", - Properties: map[string]any{ - "voice_id": map[string]any{ - "type": "string", - "description": "ID of the voice to use", - }, - }, - Required: []string{"voice_id"}, - }, - } + }, s.setVoice) - handler := func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - voiceID, err := request.RequireString("voice_id") - if err != nil { - return nil, err - } - - selectedVoice, err := s.SetVoice(voiceID) - if err != nil { - return nil, err - } - - return &mcp.CallToolResult{ - Content: []mcp.Content{ - mcp.TextContent{ - Type: "text", - Text: fmt.Sprintf("Voice set to: %s (%s)", selectedVoice.Name, selectedVoice.VoiceID), - }, - }, - }, nil - } - return tool, handler -} - -func (s *Server) getVoices() (mcp.Tool, server.ToolHandlerFunc) { - tool := mcp.Tool{ + mcp.AddTool(s.mcpServer, &mcp.Tool{ Name: "get_voices", Description: "Get list of available voices and show the currently selected one", - InputSchema: mcp.ToolInputSchema{ - Type: "object", - Properties: map[string]any{}, - }, - } + }, s.getVoices) - handler := func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - voices, currentVoice, err := s.GetVoices() - if err != nil { - return nil, err - } - - voiceList := s.formatVoiceList(voices, currentVoice) + mcp.AddTool(s.mcpServer, &mcp.Tool{ + Name: "history", + Description: "List available audio files with text summaries", + }, s.history) +} +func (s *Server) say(ctx context.Context, req *mcp.CallToolRequest, args SayArgs) (*mcp.CallToolResult, any, error) { + filepath, err := s.GenerateAudio(args.Text) + if err != nil { return &mcp.CallToolResult{ Content: []mcp.Content{ - mcp.TextContent{ - Type: "text", - Text: voiceList, - }, + &mcp.TextContent{Text: fmt.Sprintf("Error: %v", err)}, }, - }, nil + IsError: true, + }, nil, nil } - return tool, handler + + s.PlayAudioAsync(filepath) + + return &mcp.CallToolResult{ + Content: []mcp.Content{ + &mcp.TextContent{Text: fmt.Sprintf("Audio generated, saved to %s, and playing", filepath)}, + }, + }, nil, nil +} + +func (s *Server) read(ctx context.Context, req *mcp.CallToolRequest, args ReadArgs) (*mcp.CallToolResult, any, error) { + audioPath, err := s.ReadFileToAudio(args.FilePath) + if err != nil { + return &mcp.CallToolResult{ + Content: []mcp.Content{ + &mcp.TextContent{Text: fmt.Sprintf("Error: %v", err)}, + }, + IsError: true, + }, nil, nil + } + + return &mcp.CallToolResult{ + Content: []mcp.Content{ + &mcp.TextContent{Text: fmt.Sprintf("File '%s' converted to speech and saved to: %s", args.FilePath, audioPath)}, + }, + }, nil, nil +} + +func (s *Server) play(ctx context.Context, req *mcp.CallToolRequest, args PlayArgs) (*mcp.CallToolResult, any, error) { + s.PlayAudioAsync(args.FilePath) + + return &mcp.CallToolResult{ + Content: []mcp.Content{ + &mcp.TextContent{Text: fmt.Sprintf("Playing audio file: %s", args.FilePath)}, + }, + }, nil, nil +} + +func (s *Server) setVoice(ctx context.Context, req *mcp.CallToolRequest, args SetVoiceArgs) (*mcp.CallToolResult, any, error) { + selectedVoice, err := s.SetVoice(args.VoiceID) + if err != nil { + return &mcp.CallToolResult{ + Content: []mcp.Content{ + &mcp.TextContent{Text: fmt.Sprintf("Error: %v", err)}, + }, + IsError: true, + }, nil, nil + } + + return &mcp.CallToolResult{ + Content: []mcp.Content{ + &mcp.TextContent{Text: fmt.Sprintf("Voice set to: %s (%s)", selectedVoice.Name, selectedVoice.VoiceID)}, + }, + }, nil, nil +} + +func (s *Server) getVoices(ctx context.Context, req *mcp.CallToolRequest, args struct{}) (*mcp.CallToolResult, any, error) { + voices, currentVoice, err := s.GetVoices() + if err != nil { + return &mcp.CallToolResult{ + Content: []mcp.Content{ + &mcp.TextContent{Text: fmt.Sprintf("Error: %v", err)}, + }, + IsError: true, + }, nil, nil + } + + voiceList := s.formatVoiceList(voices, currentVoice) + + return &mcp.CallToolResult{ + Content: []mcp.Content{ + &mcp.TextContent{Text: voiceList}, + }, + }, nil, nil } func (s *Server) formatVoiceList(voices []types.VoiceResponseModel, currentVoice *types.VoiceResponseModel) string { @@ -227,45 +166,32 @@ func (s *Server) formatVoiceList(voices []types.VoiceResponseModel, currentVoice return voiceList.String() } -func (s *Server) history() (mcp.Tool, server.ToolHandlerFunc) { - tool := mcp.Tool{ - Name: "history", - Description: "List available audio files with text summaries", - InputSchema: mcp.ToolInputSchema{ - Type: "object", - Properties: map[string]any{}, - }, - } - - handler := func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - audioFiles, err := s.GetAudioHistory() - if err != nil { - return nil, err - } - - if len(audioFiles) == 0 { - return &mcp.CallToolResult{ - Content: []mcp.Content{ - mcp.TextContent{ - Type: "text", - Text: "No audio files found", - }, - }, - }, nil - } - - historyList := s.formatHistoryList(audioFiles) - +func (s *Server) history(ctx context.Context, req *mcp.CallToolRequest, args struct{}) (*mcp.CallToolResult, any, error) { + audioFiles, err := s.GetAudioHistory() + if err != nil { return &mcp.CallToolResult{ Content: []mcp.Content{ - mcp.TextContent{ - Type: "text", - Text: historyList, - }, + &mcp.TextContent{Text: fmt.Sprintf("Error: %v", err)}, }, - }, nil + IsError: true, + }, nil, nil } - return tool, handler + + if len(audioFiles) == 0 { + return &mcp.CallToolResult{ + Content: []mcp.Content{ + &mcp.TextContent{Text: "No audio files found"}, + }, + }, nil, nil + } + + historyList := s.formatHistoryList(audioFiles) + + return &mcp.CallToolResult{ + Content: []mcp.Content{ + &mcp.TextContent{Text: historyList}, + }, + }, nil, nil } func (s *Server) formatHistoryList(audioFiles []AudioFile) string { diff --git a/main.go b/main.go index 7ddb8c8..221498b 100644 --- a/main.go +++ b/main.go @@ -1,26 +1,20 @@ package main import ( + "context" "log" - "github.com/mark3labs/mcp-go/server" + "github.com/modelcontextprotocol/go-sdk/mcp" "github.com/taigrr/elevenlabs-mcp/internal/ximcp" ) func main() { - mcpServer := server.NewMCPServer( - "ElevenLabs MCP Server", - "1.0.0", - server.WithToolCapabilities(true), - ) - elevenServer, err := ximcp.NewServer(mcpServer) + server, err := ximcp.NewServer() if err != nil { log.Fatalf("Failed to create ElevenLabs server: %v", err) } - elevenServer.SetupTools() - - if err := server.ServeStdio(mcpServer); err != nil { + if err := server.Run(context.Background(), &mcp.StdioTransport{}); err != nil { log.Fatalf("Failed to serve MCP server: %v", err) } }