aeat.entrypoints.mcp._server module¶
MCP server shell: the thin protocol wiring over the SDK-independent core.
The Model Context Protocol runtime is an optional dependency behind the
aeat-cli[agent] extra. serve() imports it lazily and, when it is absent,
refuses with the install hint and a non-zero exit instead of raising a raw
ModuleNotFoundError - the same graceful-degradation contract the Google,
browser, and Anthropic integrations follow. The tool list, annotations, and the
forbidden-live-write block are sourced from the SDK-independent core in this
package; call_tool runs the deterministic CLI in a subprocess and returns its
JSON envelope as structured content. Alongside the per-verb tools the server
advertises the search / execute meta-tools and the harness.load floor
tool (the universal operating-layer channel of ADR R4), and serves the operating
layer through real resources handlers - the concrete aeat:// skill / rule
/ persona set, the three aeat://<kind>/{name} templates, and a read
resolver - and through real prompts handlers: the guided-workflow catalogue
and each prompt’s embedded skill / rules, derived from _prompts.py.
build_server() owns that registration and is unit-tested against the real
SDK without the stdio transport.
Per D1 of 2026-07-01-agent-harness-adr, the server also enforces the
persona-scoped tool boundary declared in _persona_scope.py:
serve() resolves the active persona once, at startup, from the
AEAT_MCP_PERSONA environment variable via
active_persona(). When a persona is
active, _list_tools advertises only that persona’s in-scope tools
(filter_descriptors_for_persona()) and _call_tool refuses an
out-of-scope call (persona_scope_refusal()) before the global HITL
confirmation_for_tool gate runs. An unset/blank env var preserves the
full, unscoped tool surface - pre-D1 behaviour - for any un-personified
session. See _persona_scope.py’s module docstring for the known
family-granularity limitation (the three modelo-lifecycle personas share one
manifest family and are not distinguished by this gate).
- emit_missing_sdk_refusal()[source]¶
Write the agent-extra install hint to stderr and exit non-zero.
The graceful-degradation path taken when the MCP SDK is absent. Exposed so the refusal contract is unit-tested directly, in any environment, rather than relying on the SDK being absent at test time.
- Return type:
- serve()[source]¶
Run the
aeat-mcpstdio server, or refuse if the SDK is not installed.Resolves the active persona from
AEAT_MCP_PERSONAbefore touching the SDK, so an invalid persona value fails with the instructiveactive_persona()error regardless of whether the optional SDK is installed.- Return type:
- filter_descriptors_for_persona(descriptors, *, persona)[source]¶
Narrow
descriptorsto the tools inpersona’s live-manifest scope.persona=None(no active persona) returnsdescriptorsunchanged - the full, unscoped surface. This is the_list_tools-side half of D1; it is SDK-independent and pure so it is unit-tested directly.- Return type:
- Returns:
The subset of
McpToolDescriptorentries in scope for persona.- Parameters:
descriptors (tuple[McpToolDescriptor, ...])
persona (AgentPersona | None)
- persona_scope_refusal(*, persona, command_key)[source]¶
Return a refusal message when
command_keyis outsidepersona’s scope.Returns
Nonewhen the call may proceed to the global HITL gate: either no persona is active, or the command is in the active persona’s declared scope. This is the_call_tool-side half of D1; it runs BEFOREconfirmation_for_tool()so an out-of-scope call is refused before HITL policy is even consulted.- Return type:
- Parameters:
persona (AgentPersona | None)
command_key (str)
- build_sdk_tools(descriptors)[source]¶
Adapt the SDK-independent descriptors into MCP SDK
Toolobjects.Lazily imports the SDK types so the module still imports (and
servestill refuses gracefully) when theaeat-cli[agent]extra is absent. Exposed at module level so the adaptation - including the mutability-to-annotation projection - is unit-tested against the real SDK types when they are installed.- Return type:
list[Tool]- Parameters:
descriptors (tuple[McpToolDescriptor, ...])
- build_meta_sdk_tools()[source]¶
Build the SDK
Toolobjects for the core-surface meta-tools.Lazily imports the SDK
Tooltype so the module still imports when theaeat-cli[agent]extra is absent. Exposed at module level so the meta-tool surface is unit-tested against the real SDK types when they are installed.- Return type:
list[Tool]- Returns:
The
search,execute,toolsets, anddescribemcp.types.Toolobjects.
- build_server(descriptors, *, persona=None, telemetry=None, surface_mode=SurfaceMode.CORE)[source]¶
Build the MCP
Serverwith the tool, prompt, and resource handlers.Registers the persona-scoped per-verb tools plus the
search/executemeta-tools and theharness.loadfloor tool, and the operating-layerpromptsandresourceshandlers so the server advertises those capabilities during negotiation. Extracted from the stdio runner so the handler registration and capability negotiation are unit-tested against the real SDK.personascopes the per-verb tool list and the direct call-tool refusal per D1; the meta-tools and the floor tool are always advertised andexecuteapplies the persona gate internally.- Return type:
Server- Returns:
The configured
mcp.server.Server.- Parameters:
descriptors (tuple[McpToolDescriptor, ...])
persona (AgentPersona | None)
telemetry (SessionTelemetryWriter | None)
surface_mode (SurfaceMode)
- server_initialization_options(server)[source]¶
Build the negotiated initialization options for
server.Declares
tools.listChangedbecause the console emitstools/list_changedwhen a toolset is activated (ADRmcp-progressive-discoveryP3). Centralised so production (_run_server()) and the capability-posture conformance test negotiate the SAME capability set and cannot drift.- Return type:
- Parameters:
server (Server)