Runtime client context

Runtime client context for a Klea chat run.

A TUI process can describe the environment its per-session bundled MCP server should run in: the working directory, the interpreter, and the environment variables. The context is deliberately not persisted: it is per-run runtime data, forwarded with each chat request and applied to the spawned tool server for that run.

The server only accepts it from a loopback peer. The context selects the working directory and environment of a spawned child process, which is equivalent to allowing arbitrary code selection, so a remote peer must not be able to supply it.

See devdocs/adr/0055-runtime-client-mcp-context.md and devdocs/system/session-mcp-context.md.

File: utils_pkg/klea_utils/client_context.py

Copyright 2026 Ankur Sinha Author: Ankur Sinha <sanjay DOT ankur AT gmail DOT com>

class klea_utils.client_context.ClientContext(*, cwd: str | None = None, env: dict[str, str]=<factory>, interpreter: str | None = None, stores_config: str | None = None)[source]

Bases: BaseModel

Client-supplied environment for one chat run.

All fields are optional, so a client can override only what it needs. An omitted working directory or interpreter leaves the backend’s default in place; an omitted environment keeps the inherited environment (minus the virtual-environment variables stripped by klea_utils.mcp.spawn.bundled_server_config()).

Parameters:
  • cwd – Working directory for the bundled MCP server. Must be an absolute, existing directory once validated.

  • env – Environment variables for the bundled MCP server. The caller’s values win over the inherited environment.

  • interpreter – Python interpreter used to run the bundled MCP server. Must be an absolute, executable file once validated.

  • stores_config – Stores configuration JSON file the bundled MCP server should search for this run, overriding the deployment default. Must resolve to an absolute path to an existing regular file; a relative value is resolved against cwd.

model_config = {'extra': 'forbid'}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

stores_config: str | None

Per-session stores configuration file (a stores JSON document) the bundled MCP server should search instead of the deployment default. The client supplies the path for one run; the server carries it in the MCP request metadata, never as a tool argument, and re-validates it as untrusted input. None keeps the host configuration.

klea_utils.client_context.MAX_ENV_BYTES = 65536

Maximum serialised size of the environment mapping, in UTF-8 bytes.

klea_utils.client_context.MAX_ENV_VARS = 256

Maximum number of environment variables accepted in a client context.

klea_utils.client_context.client_context_fingerprint(context: ClientContext | Mapping[str, Any] | None) → str[source]

Return a stable fingerprint for context.

Two contexts with the same cwd, interpreter, and environment (regardless of mapping order) produce the same fingerprint. None and an empty context both produce the empty string.

Parameters:

context – A validated context, a mapping, or None.

Returns:

A hex digest, or "" for no context.

klea_utils.client_context.client_context_from_context(context: Any | None) → ClientContext | None[source]

Return the client-context slice of a LangGraph runtime context.

Tolerates a KleaRunContext, a plain dict, or None. The value is not re-validated against the filesystem: it was validated at the request boundary.

Parameters:

context – The runtime context from get_runtime().context.

Returns:

The client context, or None when absent.

klea_utils.client_context.validate_client_context(raw: ClientContext | Mapping[str, Any] | None, *, peer_host: str | None) → ClientContext | None[source]

Validate a client-supplied context for the current request.

The context is accepted only from a loopback peer. A malformed context is rejected rather than silently trimmed, so a frontend never believes isolation is active when it is not.

Parameters:
  • raw – The request’s client context, already parsed or as a mapping.

  • peer_host – The request socket peer host (request.client.host).

Returns:

The validated context, or None when raw is None or contains no fields.

Raises:

ClientContextError – If the peer is not loopback or the context is malformed.