iflow-search-openapi
OpenAPI 3.1 tool server for iFlow Search (心流搜索) — exposes iflow_web_search, iflow_image_search, and iflow_web_fetch over plain HTTP so platforms that consume OpenAPI tool catalogues (Open WebUI, Coze, …) can wire them in directly.
- Core SDK:
iflow-search— this package wraps it; do not skip installing it (it is a transitive dependency, sopip installhandles it). - Sibling adapters:
iflow-search-mcp(MCP stdio server),iflow-search-langchain(LangChain tools). - API docs: https://platform.iflow.cn/docs/
- Status: stable (
0.1.0).
Install
pip install iflow-search-openapi
Run
export IFLOW_API_KEY="your-iflow-api-key"
iflow-search-openapi
Output (stderr):
[iflow-search-openapi] v0.1.0 listening on http://127.0.0.1:8787 — bearer auth DISABLED (open mode)
By default the server binds 127.0.0.1:8787 — local-only. Set IFLOW_OPENAPI_HOST=0.0.0.0 to expose it to a LAN or a container network. See Configuration for the full env list.
Endpoints
| Method | Path | Description |
|---|---|---|
GET |
/health |
Liveness probe — {"ok": true, "version": "..."} |
GET |
/openapi.json |
OpenAPI 3.1 schema (auto-generated from Pydantic models) |
POST |
/tools/iflow_web_search |
{"query": "...", "count": 3} |
POST |
/tools/iflow_image_search |
{"query": "...", "count": 3} |
POST |
/tools/iflow_web_fetch |
{"url": "https://example.com"} |
Each tool route declares an explicit OpenAPI operationId matching its path-level name (iflow_web_search, iflow_image_search, iflow_web_fetch). Tool hosts such as Open WebUI and Coze dispatch by operationId and surface it as the tool name to the consuming LLM — pinning them keeps the LLM-facing names stable across releases.
Success envelope
{
"ok": true,
"data": {
"query": "latest LLM benchmarks",
"results": [
{"title": "...", "url": "https://...", "snippet": "...", "position": 1}
],
"took_ms": 142
}
}
Field names are snake_case. The core SDK's raw (upstream envelope) is excluded by default — it bloats LLM context for fields the model cannot act on.
Error envelope
{
"ok": false,
"error": {
"code": "business_rate_limited",
"message": "Rate limit exceeded.",
"status_code": 429
}
}
code is a stable string; switch on it (not on HTTP status alone) for retry/backoff decisions. The full code table is in docs/design/python-openapi-design.md §8.3.
Use with Open WebUI
- Run
iflow-search-openapisomewhere Open WebUI can reach.- Same host as Open WebUI: defaults are fine.
- Open WebUI in Docker, this server on the host: bind with
IFLOW_OPENAPI_HOST=0.0.0.0and usehttp://host.docker.internal:<port>from inside the container.
- In Open WebUI → Settings → Admin Settings → Tools → External Tool Servers → Add Connection, paste the server URL (e.g.
http://host.docker.internal:8787). The path defaults toopenapi.json. - If you set
IFLOW_OPENAPI_AUTH_TOKEN, choose Bearer auth and paste the token. Otherwise leave auth as None — the server is open, exactly as configured. - Open WebUI fetches
/openapi.jsonand registers the three tools. They appear asiflow_web_search,iflow_image_search,iflow_web_fetchin the model's tool list (matching the explicitoperationIdvalues).
If Open WebUI runs in a browser on a different origin from this server, set IFLOW_OPENAPI_CORS_ORIGIN=https://your-open-webui-host.
The same registration can be driven over HTTP for headless setups — POST to /api/v1/configs/tool_servers on Open WebUI with a TOOL_SERVER_CONNECTIONS payload mirroring the UI fields above.
Use with Coze
- Run
iflow-search-openapisomewhere Coze can reach. - Coze → Plugins → Create plugin → Import from OpenAPI → URL
http://your-host:8787/openapi.json. - Provide the bearer token (
IFLOW_OPENAPI_AUTH_TOKEN) when prompted. - The three tools appear as plugin actions; attach to a bot as usual.
Authentication
Two distinct credentials:
| Credential | Direction | Source |
|---|---|---|
IFLOW_API_KEY |
this server → iFlow API | env, required |
IFLOW_OPENAPI_AUTH_TOKEN |
external client → this server | env, optional |
When IFLOW_OPENAPI_AUTH_TOKEN is unset, the server is open: any caller that can reach the socket can invoke the tools. Intended for local dev or behind a private network / reverse proxy.
When set, all routes except /health require Authorization: Bearer <token>. The compare is constant-time. /openapi.json is also gated so the schema (which advertises the server as an iFlow proxy) stays behind the bearer.
IFLOW_API_KEY is never echoed in any response, log line, OpenAPI schema, or startup banner — only its presence is implied by the server having started successfully.
Configuration
All configuration is via environment variables. No .env loader. No CLI flags. No config file.
| Variable | Required | Default | Notes |
|---|---|---|---|
IFLOW_API_KEY |
yes | — | iFlow API key. Read once at startup, never echoed. |
IFLOW_BASE_URL |
no | core default | Override iFlow API base URL (staging/proxy). |
IFLOW_TIMEOUT_MS |
no | 30000 |
Per-request timeout in milliseconds. |
IFLOW_OPENAPI_HOST |
no | 127.0.0.1 |
Bind address. Use 0.0.0.0 for LAN/container exposure. |
IFLOW_OPENAPI_PORT |
no | 8787 |
Bind port. |
IFLOW_OPENAPI_AUTH_TOKEN |
no | unset (open mode) | Bearer token required from external callers when set. |
IFLOW_OPENAPI_CORS_ORIGIN |
no | unset (no CORS) | * or an exact origin (https://host[:port]). |
IFLOW_OPENAPI_CLIENT |
no | unset | Free-form host name (e.g. open-webui). Banner only — not on the wire. |
Heroku / App Engine / fly.io — bridging PORT
This package uses IFLOW_OPENAPI_PORT instead of the generic PORT so a platform's auto-injected port can't silently take over the bind. If your platform requires PORT, bridge it in your start command:
IFLOW_OPENAPI_PORT="$PORT" IFLOW_OPENAPI_HOST=0.0.0.0 iflow-search-openapi
CORS
IFLOW_OPENAPI_CORS_ORIGIN:
- unset — no CORS headers; server is intended for same-origin or server-to-server use.
*— wildcard allow-origin.http(s)://host[:port]— exact-origin allow.
Anything with a path, query, fragment, or non-printable character is rejected at startup with ConfigError and exit code 1 — header-injection guard.
Preflight (OPTIONS) short-circuits before the bearer check and returns HTTP 200 with the correct Access-Control-Allow-* headers, so browser-side tool importers (Open WebUI) can complete preflight without a token.
Access-Control-Allow-Headers is Content-Type, Authorization, X-Session-Id. X-Session-Id is allowed for Open WebUI compatibility; the adapter does not read it.
Attribution
The adapter does not construct any Authorization, IFlow-*, or User-Agent header itself — that's the core SDK's job. Outbound requests to iFlow carry:
| Header | Value |
|---|---|
Authorization |
Bearer <IFLOW_API_KEY> |
IFlow-Source |
openapi |
IFlow-Integration |
iflow-search-openapi |
IFlow-Integration-Version |
this package's __version__ |
User-Agent |
iflow-search-openapi/<version> |
IFLOW_OPENAPI_CLIENT is not forwarded as a wire header (that namespace belongs to MCP transports). It appears in the startup banner only.
What's not included in this release
- TLS termination — put a reverse proxy in front.
- Streaming / SSE / WebSocket — iFlow Search is request/response.
- Per-platform packages (no
iflow-search-open-webui, noiflow-search-coze). - A public Python embedding API (
build_app(...)is underscore-prefixed and not part of the contract). .envfile loading, a CLI flag for the API key, or any config file.- Per-request access logs — operators put a reverse proxy in front for those.
Public Python surface
from iflow_search_openapi import __version__
That is the only supported import in MVP. Internal modules (_app, _routes, _auth, etc.) are underscore-prefixed; they may be reorganised without notice. The stable contract is the HTTP surface, not the Python surface.
Local development
From packages/iflow-search-openapi/:
python -m pip install -e ".[dev]"
python -m pytest -q
python -m ruff check .
python -m mypy src/iflow_search_openapi
python -m build
Real-API smoke
cd packages/iflow-search-openapi
export IFLOW_API_KEY="your-api-key"
export IFLOW_OPENAPI_SMOKE=1
python scripts/smoke_real_api.py
The script:
- Is opt-in — without
IFLOW_OPENAPI_SMOKE=1it refuses to call the live API. - Reads
IFLOW_API_KEYfrom the environment only — never from disk. - Redacts the key in all log output.
- Does not write any file.
License
Metadata
Release files for iflow-search-openapi 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| iflow_search_openapi-0.1.0.tar.gz | 19.4 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| iflow_search_openapi-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 45.0 kB
Release files / iflow_search_openapi-0.1.0.tar.gz
| Download URL | iflow_search_openapi-0.1.0.tar.gz |
|---|---|
| Size | 19.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b18a883df4cc308aad98cd3d9a1fc49828764bafeebc243260712708f60c265b
|
|
BLAKE2b-256 checksum How to use checksums |
602c262a3067c63356d236c998b452c50a2ac0b752c1dc0605f09c6d7f9f5056
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|
Release files / iflow_search_openapi-0.1.0-py3-none-any.whl
| Download URL | iflow_search_openapi-0.1.0-py3-none-any.whl |
|---|---|
| Size | 25.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6c696b07aa943ac3d189d7620b84fd891b05120e9af52e6cdf875b80593a2156
|
|
BLAKE2b-256 checksum How to use checksums |
6708da16c06662cc3dfb304a8bed56a5abcac10d9995f41d56404d3a7286ea22
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|
Security for iflow-search-openapi 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.