Expose Tools Over MCP
flowai-harness can expose runtime tools as Model Context Protocol (MCP) servers over stdio or Streamable HTTP. Use this when an MCP-aware client should call Python-defined custom...
flowai-harness can expose runtime tools as Model Context Protocol (MCP)
servers over stdio or Streamable HTTP. Use this when an MCP-aware client should
call Python-defined custom tools or built-in Flow AI toolkits directly.
Custom Python Tools
Python callbacks must run inside the Python process that hosts the MCP server.
Build a small runtime with flowai_harness.mcp.create_mcp_runtime(...):
from flowai_harness import define_tool
from flowai_harness import mcp
echo = define_tool(
name="echo",
description="Echo text.",
input_schema={
"type": "object",
"properties": {"text": {"type": "string"}},
"required": ["text"],
},
)(lambda args, ctx: {"text": args["text"]})
runtime = mcp.create_mcp_runtime(tools=[echo])Tool handlers may be sync or async: the echo handler above is a plain lambda,
and async def handlers (as used in the other guides) work the same here.
Serve it over stdio for subprocess-based MCP clients:
import asyncio
from flowai_harness import mcp
asyncio.run(mcp.serve_stdio(runtime, agent="mcp"))Or serve it over Streamable HTTP:
import asyncio
from flowai_harness import mcp
asyncio.run(
mcp.serve_http(
runtime,
agent="mcp",
host="127.0.0.1",
port=8765,
path="/mcp",
transport="streamable-http",
allowed_origins=["http://localhost:3000"],
)
)Built-In Toolkits
Toolkit servers use the same runtime helper. Toolkits that need catalogs, KV, or
target databases receive those Rust-owned dependencies through
data_environment.
from flowai_harness import mcp
runtime = mcp.create_mcp_runtime(
toolkits=["catalog"],
tenant="acme",
data_environment=data_environment,
)If data_environment includes tenant_id, pass the same value as tenant.
The runtime rejects mismatches instead of silently reading another tenant's
catalog scope.
Verify the Tools Are Exposed
Before wiring a client, list the MCP tool metadata the server will advertise:
from flowai_harness import mcp
for tool in mcp.list_tools(runtime, agent="mcp"):
print(tool["name"], "-", tool["description"])For the echo runtime above this prints:
echo - Echo text.list_tools returns the same names and schemas an MCP client sees, so an
empty or unexpected list means the runtime wiring is wrong — fix that before
debugging client configuration.
CLI Usage
Use flowai-harness mcp python MODULE:OBJECT ... when your server needs
Python callbacks. The target can be a runtime object or a callable factory.
flowai-harness mcp python my_app:build_runtime --agent mcp
flowai-harness mcp python my_app:build_runtime --agent mcp --transport streamable-http --port 8765Use flowai-harness mcp toolkit ... for Rust-native toolkit-only servers.
That path is implemented by the thin Rust flowai-harness-cli crate and does
not import Python modules.
flowai-harness mcp toolkit --toolkit catalog --data-environment data-environment.toml --agent mcp --tenant-id acme
flowai-harness mcp toolkit --toolkit catalog --data-environment data-environment.toml --agent mcp --tenant-id acme --transport streamable-http --port 8765For stdio MCP clients, configure the client command as the console script plus the same arguments. For example:
{
"command": "flowai-harness",
"args": ["mcp", "python", "my_app:build_runtime", "--agent", "mcp"]
}For HTTP-capable MCP clients, start the server first and point the client at
the Streamable HTTP endpoint, such as http://127.0.0.1:8765/mcp.
Constraints
- Supported transports are stdio and Streamable HTTP.
- Streamable HTTP is the current HTTP transport; legacy HTTP+SSE endpoints are intentionally unsupported in this build.
- HTTP servers bind to
127.0.0.1by default. - HTTP origin validation is enabled by default. Use repeated
--allow-originflags orallowed_origins=[...]for browser clients. - Toolkit servers use tenant
flowai-mcpby default. Usetenant=...or--tenant-id ...when reusing a scopeddata_environment. - Direct MCP serving exposes direct tools only by default. Recursive agent tools
are omitted.
expose_agent_toolsand--expose-agent-toolsare reserved for future recursive agent-tool support; the runtime-generatedagentstoolkit is not supported in this mode. - Approval-gated tools need a noninteractive policy; otherwise direct MCP tool calls return a tool error instead of waiting indefinitely.
- Python callbacks execute in the Python process hosting the MCP server.
- Tool schemas are forwarded from Flow AI tool definitions.
- Structured tracing fields for bound Streamable HTTP endpoints are not emitted yet. The CLI prints the bound endpoint URL to stderr; use that to point clients at the server.
Common errors
| Error | Fix |
|---|---|
| MCP client cannot start the server | Use the console script command plus the same arguments you tested in a shell. |
| HTTP client is rejected by origin validation | Add the browser origin with --allow-origin or allowed_origins=[...]. |
| Catalog toolkit cannot read data | Pass tenant or --tenant-id that matches data_environment["tenant_id"], and include the required catalog and search config. |
| Approval-gated tool hangs or returns an error | Use a noninteractive approval policy for direct MCP serving. |
