MCPcopy Create free account
hub / github.com/PerpetualSoftware/pad / executeRequest

Method executeRequest

internal/mcp/dispatch_http.go:445–494  ·  view source on GitHub ↗

executeRequest builds + serves + packages a single HTTP request against the wrapped handler. Pulled out of Dispatch so the special-case methods (dispatchItemUpdate, future RMW commands) can reuse the same auth-context + recorder + response-shaping path. Scope enforcement lives in buildAuthedRequest

(
	ctx context.Context,
	cmdKey string,
	user *models.User,
	method, urlPath string,
	body []byte,
)

Source from the content-addressed store, hash-verified

443// through this method. Codex review #369 round 2 caught the leak that
444// motivated centralizing the check.
445func (d *HTTPHandlerDispatcher) executeRequest(
446 ctx context.Context,
447 cmdKey string,
448 user *models.User,
449 method, urlPath string,
450 body []byte,
451) (*mcp.CallToolResult, error) {
452 req, err := d.buildAuthedRequest(ctx, method, urlPath, body, user)
453 if err != nil {
454 // Most build-request failures are scope-rejection from
455 // buildAuthedRequest's TokenScopeAllows check (PATCH on a
456 // read-only token, etc.). Surface as permission_denied so
457 // agents see the same code as a backend 403, not a
458 // generic server_error.
459 if strings.HasPrefix(err.Error(), "permission_denied:") {
460 return NewErrorResult(ErrorPayload{
461 Code: ErrPermissionDenied,
462 Message: fmt.Sprintf("%s: %s", cmdKey, err.Error()),
463 Hint: "Token scope does not permit this operation. Re-issue with the required scopes (read for GET; write for POST/PATCH; admin for workspace settings).",
464 }), nil
465 }
466 // PLAN-1933 DR-4: the RequireVerifiedEmail gate rejected this
467 // write because the cloud user hasn't verified their email.
468 // Surface as permission_denied (the closest closed-set code) so
469 // agents branch consistently with a backend 403.
470 if strings.HasPrefix(err.Error(), errEmailNotVerifiedPrefix+":") {
471 return NewErrorResult(ErrorPayload{
472 Code: ErrPermissionDenied,
473 Message: fmt.Sprintf("%s: %s", cmdKey, err.Error()),
474 Hint: "Verify your email address (check your inbox for the verification link) before creating or editing content.",
475 }), nil
476 }
477 return dispatcherErrorResult(cmdKey, "build request", err), nil
478 }
479
480 rec := httptest.NewRecorder()
481 d.Handler.ServeHTTP(rec, req)
482 // Use req.Context() (NOT the outer ctx) so the workspace lister
483 // sees everything buildHTTPRequest + d.Apply attached:
484 // WithCurrentUser, WithAPITokenAuth, and any TokenAllowedWorkspaces
485 // the dispatcher's Apply hook layered on. Tests that drive
486 // executeRequest with context.Background() + a UserResolver get
487 // the user via req.Context(), not via the outer ctx — without
488 // this fix the lister would silently return empty hints in
489 // those test paths and (more critically) in any production
490 // dispatcher that attaches token state via Apply rather than
491 // inheriting from the inbound request's ctx. Codex review #379
492 // round 1.
493 return packageHTTPResponse(req.Context(), cmdKey, rec.Result(), d.Lister)
494}
495
496// buildAuthedRequest constructs an in-process HTTP request against
497// the wrapped handler with the user attached via WithCurrentUser AND

Callers 13

dispatchItemDepsMethod · 0.95
postLibraryItemMethod · 0.95
DispatchMethod · 0.95
dispatchItemUpdateMethod · 0.95
dispatchProjectNextMethod · 0.95
dispatchItemNoteMethod · 0.95
dispatchItemDecideMethod · 0.95

Calls 6

buildAuthedRequestMethod · 0.95
NewErrorResultFunction · 0.85
dispatcherErrorResultFunction · 0.85
packageHTTPResponseFunction · 0.85
ErrorMethod · 0.45
ServeHTTPMethod · 0.45