Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions internal/mcpserver/dispatch.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,18 @@ import (
// refresh, retry, account scoping, and base URL resolution, so the
// dispatcher only assembles paths and bodies.
//
// The four verbs serve every model operation. The two services serve the
// composite actions (see composite.go), which are SDK compositions rather
// than single requests and so cannot be assembled from a method and a path.
// The four verbs serve every model operation but the feed's two poll lanes.
// The recordings and comments services serve the composite actions (see
// composite.go), which are SDK compositions rather than single requests and so
// cannot be assembled from a method and a path. The event feed service serves
// poll_events and poll_inbox, whose refusals carry the data a consumer resumes
// from and whose bodies the verbs above throw away (see feed.go).
//
// Every one of them is required rather than probed for. The catalog derives
// from the model and always carries these actions, so a client that satisfied
// only the verbs would advertise actions it then failed as internal errors —
// a promise nothing keeps. Required here, that mismatch cannot exist, and the
// compiler is what says so.
type API interface {
Get(ctx context.Context, path string) (*basecamp.Response, error)
Post(ctx context.Context, path string, body any) (*basecamp.Response, error)
Expand All @@ -34,6 +43,7 @@ type API interface {

Recordings() *basecamp.RecordingsService
Comments() *basecamp.CommentsService
EventFeed() *basecamp.EventFeedService
}

// The CLI hands its account-scoped client straight to New.
Expand Down Expand Up @@ -71,6 +81,12 @@ func (d dispatcher) handle(ctx context.Context, dom gateway.Domain, op gateway.O
return gateway.ErrorResult("%v", err), nil
}

if isFeedOperation(full.ID) {
// The feed's refusals carry the data a consumer resumes from, which
// the raw path throws away; see feed.go.
return d.dispatchFeed(ctx, full, params), nil
}

path, body, err := buildRequest(full, params)
if err != nil {
return gateway.ErrorResult("%v", err), nil
Expand Down
Loading