falaw.bridges.mcp#

MCP bridge: expose every falaw tool as an MCP tool.

Like bridges/skill.py, this is a thin adapter over falaw.registry.list_tools() — adding a new falaw tool automatically adds an MCP tool, no edit here. Built on fastmcp (the federation’s MCP library; see lookbook/mcp.py for the canonical pattern).

Two entry points:

  • register_tools() — add falaw’s tools to an existing FastMCP server. This is what an aggregating server (reelee’s MCP server, which composes falaw + nw + artful + lacing) calls.

  • build_mcp_server() — build a standalone FastMCP server exposing just falaw. serve() runs it over stdio.

The server’s instructions reach the model before any tool call, so they are behaviour-driving text and are guarded like code: unresolved_tool_references() reports every tool name or name_* family a piece of prose names that the registry does not hold. An aggregating server should run it over its own composed preamble too.

fastmcp is an optional dependency: pip install falaw[mcp].

Module Attributes

FREE_TAG

Tag marking a tool that makes no vendor call — docs/registry upkeep only.

COSTED_TOOLS

Snapshot of costed_tools() for consumers that want a constant.

Functions

build_mcp_server(*[, name, tools])

Build a standalone FastMCP server exposing every falaw tool.

costed_tools()

Names of the falaw tools that spend money — the metering SSOT.

register_tools(server, *[, tools, prefix])

Register every falaw ToolSpec on server (a FastMCP).

serve(*[, transport])

Run the standalone falaw MCP server.

unresolved_tool_references(text, *[, tool_names])

Tool names and name_* families named in text that do not exist.

falaw.bridges.mcp.COSTED_TOOLS = ('animate_face', 'apply_note_to_beat', 'apply_note_to_scene', 'cast_character', 'cast_voice', 'composite_character_in_environment', 'edit_image', 'establish_environment', 'generate_audio', 'generate_image', 'generate_image_with_refs', 'image_to_video', 'lipsync', 'llm_complete', 'parse_screenplay', 'remove_background', 'render_beat', 'render_scene', 'render_shot', 'storyboard_shot', 'talking_avatar_from_text', 'text_to_speech', 'text_to_video', 'upscale_image', 'voice_clone')#

Snapshot of costed_tools() for consumers that want a constant. Prefer the function when tools may be registered after import.

falaw.bridges.mcp.FREE_TAG = 'maintenance'#

Tag marking a tool that makes no vendor call — docs/registry upkeep only. Everything else reaches fal.ai or an LLM and therefore spends money.

falaw.bridges.mcp.build_mcp_server(*, name='falaw', tools=None)[source]#

Build a standalone FastMCP server exposing every falaw tool.

Raises ImportError with an install hint if fastmcp is missing.

falaw.bridges.mcp.costed_tools()[source]#

Names of the falaw tools that spend money — the metering SSOT.

Every genre package in the federation exposes this so an aggregating connector can gate spend from one source of truth per package (braidio.mcp.COSTED_TOOLS, muvid.mcp.COSTED_TOOLS). falaw had none, so its 24 money-spending tools — the raw fal.ai operations, including text_to_video and render_scene — reached an aggregating connector completely unmetered (thorwhalen/reelee#265).

Derived from the registry, not hand-listed, matching this module’s existing contract that adding a falaw tool needs no edit here. The consequence is the safe one: a newly-registered tool is **costed by default** and must be explicitly tagged FREE_TAG to be exempt. Forgetting the tag over-meters a free tool (annoying); the inverse would let a new money-spender through a credit cap (a billing hole).

Return type:

tuple[str, ...]

falaw.bridges.mcp.register_tools(server, *, tools=None, prefix='')[source]#

Register every falaw ToolSpec on server (a FastMCP).

Parameters:
  • server (Any) – A fastmcp.FastMCP instance (or anything with a compatible .tool(fn, *, name, description, tags) method).

  • tools (Optional[Iterable[ToolSpec]]) – The tools to register; defaults to the whole falaw registry.

  • prefix (str) – Optional name prefix (e.g. "falaw_") so an aggregating server can namespace falaw’s tools away from another package’s.

Return type:

list[str]

Returns:

The MCP tool names registered (in registry order).

falaw.bridges.mcp.serve(*, transport='stdio', **kwargs)[source]#

Run the standalone falaw MCP server.

stdio is the default transport — what Claude Desktop and the Anthropic SDK expect when launching an MCP server as a subprocess.

Return type:

None

falaw.bridges.mcp.unresolved_tool_references(text, *, tool_names=None)[source]#

Tool names and name_* families named in text that do not exist.

Behaviour-driving prose — the server instructions, a tool description, an aggregating connector’s composed preamble — names tools, and a call-site sweep cannot see prose. Nothing derives one from the other, so nothing failed when _INSTRUCTIONS spent months telling every model to “use the plan_* tools to inspect cost before spending” while the registry held no such tool (thorwhalen/falaw#47). This is the check that now fails instead.

Parameters:
  • text (str) – The prose to scan.

  • tool_names (Optional[Iterable[str]]) – The names that count as existing; defaults to the falaw registry. An aggregating server that registered falaw under a prefix should pass what register_tools() returned, so falaw_generate_image resolves.

Return type:

tuple[str, ...]

Returns:

The unresolved references, deduplicated, in order of first appearance.

>>> unresolved_tool_references("Use the refresh_* tools.")
()
>>> unresolved_tool_references("Use the plan_* tools to inspect cost.")
('plan_*',)