internal/mcptools/get_channels.go
Rama main · réplica de lectura del repositorio original.
package mcptools
import (
"context"
"errors"
"log"
"strings"
"xprem/internal/types"
mcpprot "github.com/modelcontextprotocol/go-sdk/mcp"
)
type GetChannelsInput struct {
AppId string `json:"appId" jsonschema:"the app id, as returned by get_apps"`
Name string `json:"name,omitempty" jsonschema:"exact channel name, to fetch a single channel"`
Id string `json:"id,omitempty" jsonschema:"exact channel id, to fetch a single channel"`
}
// matchesChannel applies the optional name/id narrowing.
func matchesChannel(channel types.ChannelMapping, name string, id string) bool {
if name != "" && !strings.EqualFold(channel.ReleaseChannelName, name) {
return false
}
if id != "" && channel.ReleaseChannelId != id {
return false
}
return true
}
type GetChannelsOutput struct {
Channels []types.ChannelMapping `json:"channels"`
}
func getChannelsHandler(deps Deps) func(ctx context.Context, req *mcpprot.CallToolRequest, input GetChannelsInput) (*mcpprot.CallToolResult, GetChannelsOutput, error) {
return func(ctx context.Context, req *mcpprot.CallToolRequest, input GetChannelsInput) (*mcpprot.CallToolResult, GetChannelsOutput, error) {
principal := PrincipalFromRequest(req)
if principal == nil {
return nil, GetChannelsOutput{}, errors.New("no authenticated account on this session")
}
if err := requireAppVisible(ctx, deps, principal, input.AppId); err != nil {
return nil, GetChannelsOutput{}, err
}
channels, err := deps.Channels.GetChannels(ctx, input.AppId)
if err != nil {
log.Printf("mcp get_channels failed for app %s: %v", input.AppId, err)
return nil, GetChannelsOutput{}, errors.New("could not list the channels, try again later")
}
output := GetChannelsOutput{Channels: []types.ChannelMapping{}}
for _, channel := range channels {
if !matchesChannel(channel, input.Name, input.Id) {
continue
}
output.Channels = append(output.Channels, channel)
}
return nil, output, nil
}
}
func registerGetChannels(server *mcpprot.Server, deps Deps) {
mcpprot.AddTool(server, &mcpprot.Tool{
Name: "get_channels",
Description: "The release channels of an app (appId required, from get_apps), with their linked branch, current updates, and the active progressive rollout if any. Pass name or id to fetch a single channel.",
Annotations: &mcpprot.ToolAnnotations{Title: "List channels", ReadOnlyHint: true},
}, getChannelsHandler(deps))
}
type ChannelRolloutOutput struct {
ChannelName string `json:"channelName"`
Rollout types.ChannelRollout `json:"rollout"`
}
type GetChannelRolloutsOutput struct {
Rollouts []ChannelRolloutOutput `json:"rollouts"`
}
func getChannelRolloutsHandler(deps Deps) func(ctx context.Context, req *mcpprot.CallToolRequest, input GetChannelsInput) (*mcpprot.CallToolResult, GetChannelRolloutsOutput, error) {
return func(ctx context.Context, req *mcpprot.CallToolRequest, input GetChannelsInput) (*mcpprot.CallToolResult, GetChannelRolloutsOutput, error) {
principal := PrincipalFromRequest(req)
if principal == nil {
return nil, GetChannelRolloutsOutput{}, errors.New("no authenticated account on this session")
}
if err := requireAppVisible(ctx, deps, principal, input.AppId); err != nil {
return nil, GetChannelRolloutsOutput{}, err
}
channels, err := deps.Channels.GetChannels(ctx, input.AppId)
if err != nil {
log.Printf("mcp get_channel_rollouts failed for app %s: %v", input.AppId, err)
return nil, GetChannelRolloutsOutput{}, errors.New("could not list the channel rollouts, try again later")
}
output := GetChannelRolloutsOutput{Rollouts: []ChannelRolloutOutput{}}
for _, channel := range channels {
if channel.Rollout == nil {
continue
}
if !matchesChannel(channel, input.Name, input.Id) {
continue
}
output.Rollouts = append(output.Rollouts, ChannelRolloutOutput{
ChannelName: channel.ReleaseChannelName,
Rollout: *channel.Rollout,
})
}
return nil, output, nil
}
}
func registerGetChannelRollouts(server *mcpprot.Server, deps Deps) {
mcpprot.AddTool(server, &mcpprot.Tool{
Name: "get_channel_rollouts",
Description: "The active progressive rollouts between branches on the channels of an app (appId required). An empty list means no channel rollout is in progress. Pass name or id to check a single channel.",
Annotations: &mcpprot.ToolAnnotations{Title: "Channel rollouts", ReadOnlyHint: true},
}, getChannelRolloutsHandler(deps))
}