What a component learns about the request it serves.
scope is the host's principal (the current user, organization, or
anything the host puts there); token and scopes are set when the
endpoint has authorization; inputs holds the client's answers
(elicitation, sampling, roots) on a retry; progress reports progress
to the client when it asked for it; task is the task ID when the
component runs as a task (see Sake.Tasks); assigns holds what the
server's middleware decided for this request (see Sake.Middleware).
base_url is the URL of the MCP endpoint the request reached, as the
client reaches it: scheme, host, the port when it is not the scheme's
default, and the endpoint's path, without a query or a trailing slash
("https://example.com/acme/mcp"). A tool builds absolute URLs to its
own host from it, such as a link the person opens or a one-time upload
URL:
def execute(%{name: name}, ctx) do
uri = URI.parse(ctx.base_url)
token = MyApp.Uploads.grant(ctx.scope, name)
{:ok, %{upload_url: URI.to_string(%{uri | path: "/uploads/" <> token})}}
endSake.Plug sets it from the request; on an endpoint with auth: true
its origin is the issuer's, as for the token's audience, and on an
external authorization server with url:, that url:'s (see
Sake.Auth.External). Behind a proxy that does not rewrite the
request, put Plug.RewriteOn before the endpoint (see "Behind a proxy"
in the security guide). It is nil where there is no HTTP request:
over stdio (Sake.Stdio) and in Sake.Test's in-memory client unless
the test passes base_url:, so a tool that needs it should say so when
it is missing.
Summary
Types
@type t() :: %Sake.Context{ assigns: term(), base_url: term(), client_capabilities: term(), client_info: term(), conn_assigns: term(), era: term(), inputs: term(), log_level: term(), method: term(), progress: term(), protocol_version: term(), request_id: term(), reraise: term(), scope: term(), scopes: term(), secret: term(), server: term(), task: term(), token: term(), trace: term(), transport: term() }