Documentation index for AI agents: see /llms.txt. Markdown versions of every page are available at <path>.md or via Accept: text/markdown.
Guides

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 8765

Use 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 8765

For 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.1 by default.
  • HTTP origin validation is enabled by default. Use repeated --allow-origin flags or allowed_origins=[...] for browser clients.
  • Toolkit servers use tenant flowai-mcp by default. Use tenant=... or --tenant-id ... when reusing a scoped data_environment.
  • Direct MCP serving exposes direct tools only by default. Recursive agent tools are omitted. expose_agent_tools and --expose-agent-tools are reserved for future recursive agent-tool support; the runtime-generated agents toolkit 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

ErrorFix
MCP client cannot start the serverUse the console script command plus the same arguments you tested in a shell.
HTTP client is rejected by origin validationAdd the browser origin with --allow-origin or allowed_origins=[...].
Catalog toolkit cannot read dataPass 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 errorUse a noninteractive approval policy for direct MCP serving.