Skip to content

Commit e7cc633

Browse files
authored
Add campaigns tool (#56)
Expose campaigns (without checks) as a new tool. Default filter only shows in progress campaigns
1 parent 0e924f4 commit e7cc633

File tree

3 files changed

+85
-1
lines changed

3 files changed

+85
-1
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
kind: Added
2+
body: Add campaigns tool for listing campaigns
3+
time: 2025-06-13T10:06:09.286358-03:00

src/cmd/root.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,22 @@ type serializedCheckResults struct {
9191
NextLevel *serializedLevel
9292
}
9393

94+
type serializedCampaign struct {
95+
Id string
96+
Name string
97+
ProjectBrief string
98+
Status string
99+
CheckStats opslevel.Stats
100+
HtmlURL string
101+
ServiceStats opslevel.Stats
102+
Filter *opslevel.FilterId
103+
Owner *opslevel.TeamId
104+
StartDate *iso8601.Time
105+
EndedDate *iso8601.Time
106+
TargetDate *iso8601.Time
107+
Reminder *opslevel.CampaignReminder
108+
}
109+
94110
// newToolResult creates a CallToolResult for the passed object handling any json marshaling errors
95111
func newToolResult(obj any, err error) (*mcp.CallToolResult, error) {
96112
if err != nil {
@@ -513,6 +529,71 @@ var rootCmd = &cobra.Command{
513529
return newToolResult(result, nil)
514530
})
515531

532+
// Register campaigns tool
533+
s.AddTool(
534+
mcp.NewTool(
535+
"campaigns",
536+
mcp.WithDescription("Get all the campaigns in the OpsLevel account. Campaigns are used to track and manage initiatives or projects within OpsLevel."),
537+
mcp.WithString("status", mcp.Description("Filter campaigns by status, default is 'in_progress'"), mcp.Enum(opslevel.AllCampaignStatusEnum...)),
538+
mcp.WithToolAnnotation(mcp.ToolAnnotation{
539+
Title: "Campaigns in OpsLevel",
540+
ReadOnlyHint: &trueValue,
541+
DestructiveHint: &falseValue,
542+
IdempotentHint: &trueValue,
543+
OpenWorldHint: &trueValue,
544+
}),
545+
),
546+
func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
547+
args := &opslevel.ListCampaignsVariables{}
548+
status := req.GetString("status", "")
549+
if status != "" {
550+
status_enum := opslevel.CampaignStatusEnum(status)
551+
args.Status = &status_enum
552+
}
553+
554+
resp, err := client.ListCampaigns(args)
555+
if err != nil {
556+
return mcp.NewToolResultErrorFromErr("failed to list campaigns", err), nil
557+
}
558+
var campaigns []serializedCampaign
559+
for _, node := range resp.Nodes {
560+
c := serializedCampaign{
561+
Id: string(node.Id),
562+
Name: node.Name,
563+
ProjectBrief: node.ProjectBrief,
564+
Status: string(node.Status),
565+
HtmlURL: node.HtmlUrl,
566+
CheckStats: node.CheckStats,
567+
ServiceStats: node.ServiceStats,
568+
}
569+
if node.Owner != (opslevel.TeamId{}) {
570+
c.Owner = &node.Owner
571+
}
572+
if node.StartDate != (iso8601.Time{}) {
573+
c.StartDate = &node.StartDate
574+
}
575+
if node.EndedDate != (iso8601.Time{}) {
576+
c.EndedDate = &node.EndedDate
577+
}
578+
if node.TargetDate != (iso8601.Time{}) {
579+
c.TargetDate = &node.TargetDate
580+
}
581+
if len(node.Reminder.Channels) > 0 {
582+
c.Reminder = &node.Reminder
583+
}
584+
if node.Filter != (opslevel.FilterId{}) {
585+
c.Filter = &node.Filter
586+
}
587+
if node.CheckStats != (opslevel.Stats{}) {
588+
c.CheckStats = node.CheckStats
589+
}
590+
591+
campaigns = append(campaigns, c)
592+
}
593+
594+
return newToolResult(campaigns, err)
595+
})
596+
516597
log.Info().Msg("Starting MCP server...")
517598
if err := server.ServeStdio(s); err != nil {
518599
if err == context.Canceled {

0 commit comments

Comments
 (0)