package api import ( "net/http" "git.golem15.com/golem15/summercms/modules/bouncer" ) // The MCP view of the material answers (D-17, D-21): a material's body may // hold transcript text, so an answer to an MCP tool call leaves it out // unless the call asks for it with include_body, and a write answer never // echoes it. Plain HTTP answers are unchanged. // viaMCP reports whether r is an MCP tool call: a request pier dispatched // in-process with the api_token marker. The marker lives on the context // only, so an HTTP request can never carry it. func viaMCP(r *http.Request) bool { _, ok := bouncer.Dispatched(r.Context(), "api_token") return ok } // includeBody reports whether r asks for the material body // (include_body=true or 1). func includeBody(r *http.Request) bool { return flag(r, "include_body") } // bodyOmitted reports whether leaving body out hides content. func bodyOmitted(body *string) bool { return body != nil && *body != "" } // mcpMaterialDetailJSON is a published material under MCP without its body: // the list fields and the files, with body_omitted when a non-empty body was // left out. Body shadows the embedded one and stays nil. type mcpMaterialDetailJSON struct { materialDetailJSON Body *string `json:"body,omitempty"` BodyOmitted bool `json:"body_omitted,omitempty"` } // mcpManagedMaterialJSON is a managed material under MCP without its body. type mcpManagedMaterialJSON struct { managedMaterialJSON Body *string `json:"body,omitempty"` BodyOmitted bool `json:"body_omitted,omitempty"` } // mcpManagedMaterialDetailJSON is a managed material with its files under // MCP without its body. type mcpManagedMaterialDetailJSON struct { mcpManagedMaterialJSON Files []fileJSON `json:"files"` } // materialView is the answer of GET /materials/{id} (student): unchanged // over plain HTTP; under MCP (mcp) without the body unless withBody. func materialView(d materialDetailJSON, mcp, withBody bool) any { if !mcp || withBody { return d } return mcpMaterialDetailJSON{materialDetailJSON: d, BodyOmitted: bodyOmitted(d.Body)} } // managedMaterialView is a managed material: unchanged over plain HTTP; // under MCP (mcp) without the body unless withBody (a write answer passes // false, so it never echoes the body). func managedMaterialView(m managedMaterialJSON, mcp, withBody bool) any { if !mcp || withBody { return m } return mcpManagedMaterialJSON{managedMaterialJSON: m, BodyOmitted: bodyOmitted(m.Body)} } // managedMaterialDetailView is a managed material with its files, under the // same rule as managedMaterialView. func managedMaterialDetailView(d managedMaterialDetailJSON, mcp, withBody bool) any { if !mcp || withBody { return d } return mcpManagedMaterialDetailJSON{ mcpManagedMaterialJSON: mcpManagedMaterialJSON{managedMaterialJSON: d.managedMaterialJSON, BodyOmitted: bodyOmitted(d.Body)}, Files: d.Files, } }