mirror of
https://github.com/taigrr/elevenlabs-mcp.git
synced 2026-04-02 03:08:57 -07:00
upgrade mcp library
This commit is contained in:
13
go.mod
13
go.mod
@@ -1,26 +1,19 @@
|
|||||||
module github.com/taigrr/elevenlabs-mcp
|
module github.com/taigrr/elevenlabs-mcp
|
||||||
|
|
||||||
go 1.24.6
|
go 1.25.2
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gopxl/beep/v2 v2.1.1
|
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
|
github.com/taigrr/elevenlabs v0.1.18
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
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/oto/v3 v3.3.3 // indirect
|
||||||
github.com/ebitengine/purego v0.8.4 // 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/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/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
|
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
|
||||||
golang.org/x/sys v0.35.0 // indirect
|
golang.org/x/sys v0.35.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
|
||||||
)
|
)
|
||||||
|
|||||||
47
go.sum
47
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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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 h1:m6RV69OqoXYSWCDsHXN9rc07aDuDstGHtait7HXSM7g=
|
||||||
github.com/ebitengine/oto/v3 v3.3.3/go.mod h1:MZeb/lwoC4DCOdiTIxYezrURTw7EvK/yF863+tmBI+U=
|
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 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
|
||||||
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
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/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/jsonschema-go v0.3.0 h1:6AH2TxVNtk3IlvkkhjrtbUc4S8AvO0Xii0DxIygDg+Q=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/jsonschema-go v0.3.0/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
|
||||||
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/gopxl/beep/v2 v2.1.1 h1:6FYIYMm2qPAdWkjX+7xwKrViS1x0Po5kDMdRkq8NVbU=
|
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/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 h1:NUP7pBYH8OguP4diaTZ9wJbUbk3tC0KlfzsEpWmYj68=
|
||||||
github.com/hajimehoshi/go-mp3 v0.3.4/go.mod h1:fRtZraRFcWb0pu7ok0LqyFhCUrPeMsGRSVop0eemFmo=
|
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/hajimehoshi/oto/v2 v2.3.1/go.mod h1:seWLbgHH7AyUMYKfKYT9pg7PhUu9/SisyJvNTT+ASQo=
|
||||||
github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=
|
github.com/modelcontextprotocol/go-sdk v1.0.0 h1:Z4MSjLi38bTgLrd/LjSmofqRqyBiVKRyQSJgw8q8V74=
|
||||||
github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
|
github.com/modelcontextprotocol/go-sdk v1.0.0/go.mod h1:nYtYQroQ2KQiM0/SbyEPUWQ6xs4B95gJjEalc9AQyOs=
|
||||||
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/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
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 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
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 h1:ZvRsLjzV4ov6Rdls7MNFKvcknLc527RR6beV6pjukJU=
|
||||||
github.com/taigrr/elevenlabs v0.1.18/go.mod h1:ardwj7FGIQbpvRl+UpdRzVnxOuo7QQxqC3YhFcvY1gM=
|
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 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
|
||||||
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
|
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.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 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
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 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/gopxl/beep/v2"
|
"github.com/gopxl/beep/v2"
|
||||||
"github.com/gopxl/beep/v2/speaker"
|
"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"
|
||||||
"github.com/taigrr/elevenlabs/client/types"
|
"github.com/taigrr/elevenlabs/client/types"
|
||||||
)
|
)
|
||||||
@@ -24,7 +24,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
mcpServer *server.MCPServer
|
mcpServer *mcp.Server
|
||||||
client client.Client
|
client client.Client
|
||||||
voices []types.VoiceResponseModel
|
voices []types.VoiceResponseModel
|
||||||
currentVoice *types.VoiceResponseModel
|
currentVoice *types.VoiceResponseModel
|
||||||
@@ -32,7 +32,7 @@ type Server struct {
|
|||||||
playMutex sync.Mutex
|
playMutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(mcpServer *server.MCPServer) (*Server, error) {
|
func NewServer() (*mcp.Server, error) {
|
||||||
apiKey := os.Getenv("XI_API_KEY")
|
apiKey := os.Getenv("XI_API_KEY")
|
||||||
if apiKey == "" {
|
if apiKey == "" {
|
||||||
return nil, fmt.Errorf("XI_API_KEY environment variable is required")
|
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)
|
elevenClient := client.New(apiKey)
|
||||||
|
|
||||||
|
mcpServer := mcp.NewServer(&mcp.Implementation{
|
||||||
|
Name: "ElevenLabs MCP Server",
|
||||||
|
Version: "1.0.0",
|
||||||
|
}, nil)
|
||||||
|
|
||||||
s := &Server{
|
s := &Server{
|
||||||
client: elevenClient,
|
client: elevenClient,
|
||||||
mcpServer: mcpServer,
|
mcpServer: mcpServer,
|
||||||
@@ -53,7 +58,9 @@ func NewServer(mcpServer *server.MCPServer) (*Server, error) {
|
|||||||
return nil, fmt.Errorf("failed to initialize speaker: %w", err)
|
return nil, fmt.Errorf("failed to initialize speaker: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return s, nil
|
s.setupTools()
|
||||||
|
|
||||||
|
return mcpServer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) initializeVoices() error {
|
func (s *Server) initializeVoices() error {
|
||||||
|
|||||||
@@ -5,203 +5,142 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/mark3labs/mcp-go/mcp"
|
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||||
"github.com/mark3labs/mcp-go/server"
|
|
||||||
"github.com/taigrr/elevenlabs/client/types"
|
"github.com/taigrr/elevenlabs/client/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) SetupTools() {
|
type SayArgs struct {
|
||||||
s.mcpServer.AddTool(s.say())
|
Text string `json:"text" jsonschema:"Text to convert to speech"`
|
||||||
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())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) say() (mcp.Tool, server.ToolHandlerFunc) {
|
type ReadArgs struct {
|
||||||
tool := mcp.Tool{
|
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",
|
Name: "say",
|
||||||
Description: "Convert text to speech, save as MP3 file, and play the audio",
|
Description: "Convert text to speech, save as MP3 file, and play the audio",
|
||||||
InputSchema: mcp.ToolInputSchema{
|
}, s.say)
|
||||||
Type: "object",
|
|
||||||
Properties: map[string]any{
|
|
||||||
"text": map[string]any{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Text to convert to speech",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Required: []string{"text"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
handler := func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
mcp.AddTool(s.mcpServer, &mcp.Tool{
|
||||||
text, err := request.RequireString("text")
|
Name: "read",
|
||||||
if err != nil {
|
Description: "Read a text file and convert it to speech, saving as MP3",
|
||||||
return nil, err
|
}, s.read)
|
||||||
}
|
|
||||||
|
|
||||||
filepath, err := s.GenerateAudio(text)
|
mcp.AddTool(s.mcpServer, &mcp.Tool{
|
||||||
|
Name: "play",
|
||||||
|
Description: "Play an audio file",
|
||||||
|
}, s.play)
|
||||||
|
|
||||||
|
mcp.AddTool(s.mcpServer, &mcp.Tool{
|
||||||
|
Name: "set_voice",
|
||||||
|
Description: "Set the voice to use for text-to-speech generation",
|
||||||
|
}, s.setVoice)
|
||||||
|
|
||||||
|
mcp.AddTool(s.mcpServer, &mcp.Tool{
|
||||||
|
Name: "get_voices",
|
||||||
|
Description: "Get list of available voices and show the currently selected one",
|
||||||
|
}, s.getVoices)
|
||||||
|
|
||||||
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return &mcp.CallToolResult{
|
||||||
|
Content: []mcp.Content{
|
||||||
|
&mcp.TextContent{Text: fmt.Sprintf("Error: %v", err)},
|
||||||
|
},
|
||||||
|
IsError: true,
|
||||||
|
}, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
s.PlayAudioAsync(filepath)
|
s.PlayAudioAsync(filepath)
|
||||||
|
|
||||||
return &mcp.CallToolResult{
|
return &mcp.CallToolResult{
|
||||||
Content: []mcp.Content{
|
Content: []mcp.Content{
|
||||||
mcp.TextContent{
|
&mcp.TextContent{Text: fmt.Sprintf("Audio generated, saved to %s, and playing", filepath)},
|
||||||
Type: "text",
|
|
||||||
Text: fmt.Sprintf("Audio generated, saved to %s, and playing", filepath),
|
|
||||||
},
|
},
|
||||||
},
|
}, nil, nil
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
return tool, handler
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) read() (mcp.Tool, server.ToolHandlerFunc) {
|
func (s *Server) read(ctx context.Context, req *mcp.CallToolRequest, args ReadArgs) (*mcp.CallToolResult, any, error) {
|
||||||
tool := mcp.Tool{
|
audioPath, err := s.ReadFileToAudio(args.FilePath)
|
||||||
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"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
handler := func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
||||||
filePath, err := request.RequireString("file_path")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return &mcp.CallToolResult{
|
||||||
}
|
Content: []mcp.Content{
|
||||||
|
&mcp.TextContent{Text: fmt.Sprintf("Error: %v", err)},
|
||||||
audioPath, err := s.ReadFileToAudio(filePath)
|
},
|
||||||
if err != nil {
|
IsError: true,
|
||||||
return nil, err
|
}, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return &mcp.CallToolResult{
|
return &mcp.CallToolResult{
|
||||||
Content: []mcp.Content{
|
Content: []mcp.Content{
|
||||||
mcp.TextContent{
|
&mcp.TextContent{Text: fmt.Sprintf("File '%s' converted to speech and saved to: %s", args.FilePath, audioPath)},
|
||||||
Type: "text",
|
|
||||||
Text: fmt.Sprintf("File '%s' converted to speech and saved to: %s", filePath, audioPath),
|
|
||||||
},
|
},
|
||||||
},
|
}, nil, nil
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
return tool, handler
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) play() (mcp.Tool, server.ToolHandlerFunc) {
|
func (s *Server) play(ctx context.Context, req *mcp.CallToolRequest, args PlayArgs) (*mcp.CallToolResult, any, error) {
|
||||||
tool := mcp.Tool{
|
s.PlayAudioAsync(args.FilePath)
|
||||||
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"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
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{
|
return &mcp.CallToolResult{
|
||||||
Content: []mcp.Content{
|
Content: []mcp.Content{
|
||||||
mcp.TextContent{
|
&mcp.TextContent{Text: fmt.Sprintf("Playing audio file: %s", args.FilePath)},
|
||||||
Type: "text",
|
|
||||||
Text: fmt.Sprintf("Playing audio file: %s", filePath),
|
|
||||||
},
|
},
|
||||||
},
|
}, nil, nil
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
return tool, handler
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) setVoice() (mcp.Tool, server.ToolHandlerFunc) {
|
func (s *Server) setVoice(ctx context.Context, req *mcp.CallToolRequest, args SetVoiceArgs) (*mcp.CallToolResult, any, error) {
|
||||||
tool := mcp.Tool{
|
selectedVoice, err := s.SetVoice(args.VoiceID)
|
||||||
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"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
handler := func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
||||||
voiceID, err := request.RequireString("voice_id")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return &mcp.CallToolResult{
|
||||||
}
|
Content: []mcp.Content{
|
||||||
|
&mcp.TextContent{Text: fmt.Sprintf("Error: %v", err)},
|
||||||
selectedVoice, err := s.SetVoice(voiceID)
|
},
|
||||||
if err != nil {
|
IsError: true,
|
||||||
return nil, err
|
}, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return &mcp.CallToolResult{
|
return &mcp.CallToolResult{
|
||||||
Content: []mcp.Content{
|
Content: []mcp.Content{
|
||||||
mcp.TextContent{
|
&mcp.TextContent{Text: fmt.Sprintf("Voice set to: %s (%s)", selectedVoice.Name, selectedVoice.VoiceID)},
|
||||||
Type: "text",
|
|
||||||
Text: fmt.Sprintf("Voice set to: %s (%s)", selectedVoice.Name, selectedVoice.VoiceID),
|
|
||||||
},
|
},
|
||||||
},
|
}, nil, nil
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
return tool, handler
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) getVoices() (mcp.Tool, server.ToolHandlerFunc) {
|
func (s *Server) getVoices(ctx context.Context, req *mcp.CallToolRequest, args struct{}) (*mcp.CallToolResult, any, error) {
|
||||||
tool := 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{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
handler := func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
||||||
voices, currentVoice, err := s.GetVoices()
|
voices, currentVoice, err := s.GetVoices()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return &mcp.CallToolResult{
|
||||||
|
Content: []mcp.Content{
|
||||||
|
&mcp.TextContent{Text: fmt.Sprintf("Error: %v", err)},
|
||||||
|
},
|
||||||
|
IsError: true,
|
||||||
|
}, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
voiceList := s.formatVoiceList(voices, currentVoice)
|
voiceList := s.formatVoiceList(voices, currentVoice)
|
||||||
|
|
||||||
return &mcp.CallToolResult{
|
return &mcp.CallToolResult{
|
||||||
Content: []mcp.Content{
|
Content: []mcp.Content{
|
||||||
mcp.TextContent{
|
&mcp.TextContent{Text: voiceList},
|
||||||
Type: "text",
|
|
||||||
Text: voiceList,
|
|
||||||
},
|
},
|
||||||
},
|
}, nil, nil
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
return tool, handler
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) formatVoiceList(voices []types.VoiceResponseModel, currentVoice *types.VoiceResponseModel) string {
|
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()
|
return voiceList.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) history() (mcp.Tool, server.ToolHandlerFunc) {
|
func (s *Server) history(ctx context.Context, req *mcp.CallToolRequest, args struct{}) (*mcp.CallToolResult, any, error) {
|
||||||
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()
|
audioFiles, err := s.GetAudioHistory()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return &mcp.CallToolResult{
|
||||||
|
Content: []mcp.Content{
|
||||||
|
&mcp.TextContent{Text: fmt.Sprintf("Error: %v", err)},
|
||||||
|
},
|
||||||
|
IsError: true,
|
||||||
|
}, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(audioFiles) == 0 {
|
if len(audioFiles) == 0 {
|
||||||
return &mcp.CallToolResult{
|
return &mcp.CallToolResult{
|
||||||
Content: []mcp.Content{
|
Content: []mcp.Content{
|
||||||
mcp.TextContent{
|
&mcp.TextContent{Text: "No audio files found"},
|
||||||
Type: "text",
|
|
||||||
Text: "No audio files found",
|
|
||||||
},
|
},
|
||||||
},
|
}, nil, nil
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
historyList := s.formatHistoryList(audioFiles)
|
historyList := s.formatHistoryList(audioFiles)
|
||||||
|
|
||||||
return &mcp.CallToolResult{
|
return &mcp.CallToolResult{
|
||||||
Content: []mcp.Content{
|
Content: []mcp.Content{
|
||||||
mcp.TextContent{
|
&mcp.TextContent{Text: historyList},
|
||||||
Type: "text",
|
|
||||||
Text: historyList,
|
|
||||||
},
|
},
|
||||||
},
|
}, nil, nil
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
return tool, handler
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) formatHistoryList(audioFiles []AudioFile) string {
|
func (s *Server) formatHistoryList(audioFiles []AudioFile) string {
|
||||||
|
|||||||
14
main.go
14
main.go
@@ -1,26 +1,20 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/mark3labs/mcp-go/server"
|
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||||
"github.com/taigrr/elevenlabs-mcp/internal/ximcp"
|
"github.com/taigrr/elevenlabs-mcp/internal/ximcp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
mcpServer := server.NewMCPServer(
|
server, err := ximcp.NewServer()
|
||||||
"ElevenLabs MCP Server",
|
|
||||||
"1.0.0",
|
|
||||||
server.WithToolCapabilities(true),
|
|
||||||
)
|
|
||||||
elevenServer, err := ximcp.NewServer(mcpServer)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to create ElevenLabs server: %v", err)
|
log.Fatalf("Failed to create ElevenLabs server: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
elevenServer.SetupTools()
|
if err := server.Run(context.Background(), &mcp.StdioTransport{}); err != nil {
|
||||||
|
|
||||||
if err := server.ServeStdio(mcpServer); err != nil {
|
|
||||||
log.Fatalf("Failed to serve MCP server: %v", err)
|
log.Fatalf("Failed to serve MCP server: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user