@@ -2,11 +2,7 @@ package buildkite
22
33import (
44 "context"
5- "encoding/json"
65 "errors"
7- "fmt"
8- "io"
9- "net/http"
106
117 "github.com/buildkite/buildkite-mcp-server/pkg/trace"
128 "github.com/buildkite/go-buildkite/v4"
@@ -18,17 +14,6 @@ type JobsClient interface {
1814 UnblockJob (ctx context.Context , org string , pipeline string , buildNumber string , jobID string , opt * buildkite.JobUnblockOptions ) (buildkite.Job , * buildkite.Response , error )
1915}
2016
21- // GetJobsArgs struct for typed parameters
22- type GetJobsArgs struct {
23- OrgSlug string `json:"org_slug"`
24- PipelineSlug string `json:"pipeline_slug"`
25- BuildNumber string `json:"build_number"`
26- JobState string `json:"job_state"`
27- IncludeAgent bool `json:"include_agent"`
28- Page int `json:"page"`
29- PerPage int `json:"perPage"`
30- }
31-
3217// GetJobLogsArgs struct for typed parameters
3318type GetJobLogsArgs struct {
3419 OrgSlug string `json:"org_slug"`
@@ -46,127 +31,6 @@ type UnblockJobArgs struct {
4631 Fields map [string ]string `json:"fields,omitempty"`
4732}
4833
49- func GetJobs (client BuildsClient ) (tool mcp.Tool , handler mcp.TypedToolHandlerFunc [GetJobsArgs ], scopes []string ) {
50- return mcp .NewTool ("get_jobs" ,
51- mcp .WithDescription ("Get all jobs for a specific build including their state, timing, commands, and execution details" ),
52- mcp .WithString ("org_slug" ,
53- mcp .Required (),
54- ),
55- mcp .WithString ("pipeline_slug" ,
56- mcp .Required (),
57- ),
58- mcp .WithString ("build_number" ,
59- mcp .Required (),
60- ),
61- mcp .WithString ("job_state" ,
62- mcp .Description ("Filter jobs by state. Supports actual states (scheduled, running, passed, failed, canceled, skipped, etc.)" ),
63- ),
64- mcp .WithBoolean ("include_agent" ,
65- mcp .Description ("Include detailed agent information in the response. When false (default), only agent ID is included to reduce response size." ),
66- ),
67- mcp .WithNumber ("page" ,
68- mcp .Description ("Page number for pagination (min 1)" ),
69- mcp .Min (1 ),
70- ),
71- mcp .WithNumber ("perPage" ,
72- mcp .Description ("Results per page for pagination (min 1, max 50)" ),
73- mcp .Min (1 ),
74- mcp .Max (50 ),
75- ),
76- mcp .WithToolAnnotation (mcp.ToolAnnotation {
77- Title : "Get Jobs" ,
78- ReadOnlyHint : mcp .ToBoolPtr (true ),
79- }),
80- ),
81- func (ctx context.Context , request mcp.CallToolRequest , args GetJobsArgs ) (* mcp.CallToolResult , error ) {
82- ctx , span := trace .Start (ctx , "buildkite.GetJobs" )
83- defer span .End ()
84-
85- // Validate required parameters
86- if args .OrgSlug == "" {
87- return mcp .NewToolResultError ("org_slug parameter is required" ), nil
88- }
89- if args .PipelineSlug == "" {
90- return mcp .NewToolResultError ("pipeline_slug parameter is required" ), nil
91- }
92- if args .BuildNumber == "" {
93- return mcp .NewToolResultError ("build_number parameter is required" ), nil
94- }
95-
96- // Set defaults for pagination
97- page := args .Page
98- if page == 0 {
99- page = 1
100- }
101- perPage := args .PerPage
102- if perPage == 0 {
103- perPage = 30
104- }
105-
106- paginationParams := ClientSidePaginationParams {
107- Page : page ,
108- PerPage : perPage ,
109- }
110-
111- span .SetAttributes (
112- attribute .String ("org_slug" , args .OrgSlug ),
113- attribute .String ("pipeline_slug" , args .PipelineSlug ),
114- attribute .String ("build_number" , args .BuildNumber ),
115- attribute .String ("job_state" , args .JobState ),
116- attribute .Bool ("include_agent" , args .IncludeAgent ),
117- attribute .Int ("page" , paginationParams .Page ),
118- attribute .Int ("per_page" , paginationParams .PerPage ),
119- )
120-
121- build , resp , err := client .Get (ctx , args .OrgSlug , args .PipelineSlug , args .BuildNumber , & buildkite.BuildGetOptions {})
122- if err != nil {
123- return mcp .NewToolResultError (err .Error ()), nil
124- }
125-
126- if resp .StatusCode != http .StatusOK {
127- body , err := io .ReadAll (resp .Body )
128- if err != nil {
129- return nil , fmt .Errorf ("failed to read response body: %w" , err )
130- }
131- return mcp .NewToolResultError (fmt .Sprintf ("failed to get build: %s" , string (body ))), nil
132- }
133-
134- jobs := build .Jobs
135-
136- // Filter jobs by state if specified
137- if args .JobState != "" {
138- filteredJobs := make ([]buildkite.Job , 0 )
139- for _ , job := range build .Jobs {
140- if job .State == args .JobState {
141- filteredJobs = append (filteredJobs , job )
142- }
143- }
144- jobs = filteredJobs
145- }
146-
147- // Remove agent details if not requested to reduce response size, but keep agent ID
148- if ! args .IncludeAgent {
149- jobsWithoutAgent := make ([]buildkite.Job , len (jobs ))
150- for i , job := range jobs {
151- jobCopy := job
152- // Keep only the agent ID, remove all other verbose agent details
153- jobCopy .Agent = buildkite.Agent {ID : job .Agent .ID }
154- jobsWithoutAgent [i ] = jobCopy
155- }
156- jobs = jobsWithoutAgent
157- }
158-
159- // Always apply client-side pagination
160- result := applyClientSidePagination (jobs , paginationParams )
161- r , err := json .Marshal (& result )
162- if err != nil {
163- return nil , fmt .Errorf ("failed to marshal jobs: %w" , err )
164- }
165-
166- return mcp .NewToolResultText (string (r )), nil
167- }, []string {"read_builds" }
168- }
169-
17034func UnblockJob (client JobsClient ) (tool mcp.Tool , handler mcp.TypedToolHandlerFunc [UnblockJobArgs ], scopes []string ) {
17135 return mcp .NewTool ("unblock_job" ,
17236 mcp .WithDescription ("Unblock a blocked job in a Buildkite build to allow it to continue execution" ),
0 commit comments