Skip to main content
Version: 2.24

Hayhooks

Hayhooks is a web application you can use to serve Haystack pipelines through HTTP endpoints. This page provides an overview of the main features of Hayhooks.

:::info Hayhooks GitHub

You can find the code and an in-depth explanation of the features in the Hayhooks GitHub repository. :::

Overview​

Hayhooks simplifies the deployment of Haystack pipelines as REST APIs. It allows you to:

  • Expose Haystack pipelines as HTTP endpoints, including OpenAI-compatible chat endpoints,
  • Customize logic while keeping minimal boilerplate,
  • Deploy pipelines quickly and efficiently.

Installation​

Install Hayhooks using pip:

shell
pip install hayhooks

TheΒ hayhooksΒ package ships both the server and the client component, and the client is capable of starting the server. From a shell, start the server with:

shell
$ hayhooks run
INFO: Started server process [44782]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://localhost:1416 (Press CTRL+C to quit)

Check Status​

From a different shell, you can query the status of the server with:

shell
$ hayhooks status
Hayhooks server is up and running.

Configuration​

Hayhooks can be configured in three ways:

  1. Using an .env file in the project root.
  2. Passing environment variables when running the command.
  3. Using command-line arguments with hayhooks run.

Environment Variables​

VariableDescription
HAYHOOKS_HOSTHost address for the server
HAYHOOKS_PORTPort for the server
HAYHOOKS_PIPELINES_DIRDirectory containing pipelines
HAYHOOKS_ROOT_PATHRoot path of the server
HAYHOOKS_ADDITIONAL_PYTHON_PATHAdditional Python paths to include
HAYHOOKS_DISABLE_SSLDisable SSL verification (boolean)
HAYHOOKS_SHOW_TRACEBACKSShow error tracebacks (boolean)

CORS Settings​

VariableDescription
HAYHOOKS_CORS_ALLOW_ORIGINSList of allowed origins (default: [*])
HAYHOOKS_CORS_ALLOW_METHODSList of allowed HTTP methods (default: [*])
HAYHOOKS_CORS_ALLOW_HEADERSList of allowed headers (default: [*])
HAYHOOKS_CORS_ALLOW_CREDENTIALSAllow credentials (default: false)
HAYHOOKS_CORS_ALLOW_ORIGIN_REGEXRegex pattern for allowed origins (default: null)
HAYHOOKS_CORS_EXPOSE_HEADERSHeaders to expose in response (default: [])
HAYHOOKS_CORS_MAX_AGEMax age for preflight responses (default: 600)

Running Hayhooks​

To start the server:

shell
hayhooks run

This will launch Hayhooks at HAYHOOKS_HOST:HAYHOOKS_PORT.

Deploying a Pipeline​

Steps​

  1. Prepare a pipeline definition (.yml file) and a pipeline_wrapper.py file.

  2. Deploy the pipeline:

    shell
    hayhooks pipeline deploy-files -n my_pipeline my_pipeline_dir
  3. Access the pipeline at {pipeline_name}/run endpoint.

Pipeline Wrapper​

A PipelineWrapper class is required to wrap the pipeline:

python
from pathlib import Path
from haystack import Pipeline
from hayhooks import BasePipelineWrapper


class PipelineWrapper(BasePipelineWrapper):
def setup(self) -> None:
pipeline_yaml = (Path(__file__).parent / "pipeline.yml").read_text()
self.pipeline = Pipeline.loads(pipeline_yaml)

def run_api(self, input_text: str) -> str:
result = self.pipeline.run({"input": {"text": input_text}})
return result["output"]["text"]

File Uploads​

Hayhooks enables handling file uploads in your pipeline wrapper’s run_api method by including files: Optional[List[UploadFile]] = None as an argument.

python
def run_api(self, files: Optional[List[UploadFile]] = None) -> str:
if files and len(files) > 0:
filenames = [f.filename for f in files if f.filename is not None]
file_contents = [f.file.read() for f in files]
return f"Received files: {', '.join(filenames)}"
return "No files received"

Hayhooks automatically processes uploaded files and passes them to the run_api method when present. The HTTP request must be a multipart/form-data request.

Combining Files and Parameters​

Hayhooks also supports handling both files and additional parameters in the same request by including them as arguments in run_api:

python
def run_api(
self,
files: Optional[List[UploadFile]] = None,
additional_param: str = "default",
) -> str: ...

Running Pipelines from the CLI​

With JSON-Compatible Parameters​

You can execute a pipeline through the command line using the hayhooks pipeline run command. Internally, this triggers the run_api method of the pipeline wrapper, passing parameters as a JSON payload.

This method is ideal for testing deployed pipelines from the CLI without writing additional code.

shell
hayhooks pipeline run <pipeline_name> --param 'question="Is this recipe vegan?"'

With File Uploads​

To execute a pipeline that requires a file input, use a multipart/form-data request. You can submit both files and parameters in the same request.

Ensure the deployed pipeline supports file handling.

shell
## Upload a directory
hayhooks pipeline run <pipeline_name> --dir files_to_index

## Upload a single file
hayhooks pipeline run <pipeline_name> --file file.pdf

## Upload multiple files
hayhooks pipeline run <pipeline_name> --dir files_to_index --file file1.pdf --file file2.pdf

## Upload a file with an additional parameter
hayhooks pipeline run <pipeline_name> --file file.pdf --param 'question="Is this recipe vegan?"'

MCP Support​

MCP Server​

Hayhooks supports the Model Context Protocol (MCP) and can act as an MCP Server. It automatically lists your deployed pipelines as MCP Tools using Server-Sent Events (SSE) as the transport method.

To start the Hayhooks MCP server, run:

shell
hayhooks mcp run

This starts the server at HAYHOOKS_MCP_HOST:HAYHOOKS_MCP_PORT.

Creating a PipelineWrapper​

To expose a Haystack pipeline as an MCP Tool, you need a PipelineWrapper with the following properties:

  • name: The tool's name
  • description: The tool's description
  • inputSchema: A JSON Schema object for the tool's input parameters

For each deployed pipeline, Hayhooks will:

  1. Use the pipeline wrapper name as the MCP Tool name,
  2. Use the run_api method's docstring as the MCP Tool description (if present),
  3. Generate a Pydantic model from the run_api method arguments.

PipelineWrapper Example​

python
from pathlib import Path
from typing import List
from haystack import Pipeline
from hayhooks import BasePipelineWrapper


class PipelineWrapper(BasePipelineWrapper):
def setup(self) -> None:
pipeline_yaml = (Path(__file__).parent / "chat_with_website.yml").read_text()
self.pipeline = Pipeline.loads(pipeline_yaml)

def run_api(self, urls: List[str], question: str) -> str:
"""
Ask a question about one or more websites using a Haystack pipeline.
"""
result = self.pipeline.run(
{"fetcher": {"urls": urls}, "prompt": {"query": question}},
)
return result["llm"]["replies"][0]

Skipping MCP Tool Listing​

To deploy a pipeline without listing it as an MCP Tool, set skip_mcp = True in your class:

python
class PipelineWrapper(BasePipelineWrapper):
# This will skip the MCP Tool listing
skip_mcp = True

def setup(self) -> None: ...

def run_api(self, urls: List[str], question: str) -> str: ...

OpenAI Compatibility​

Hayhooks supports OpenAI-compatible endpoints through the run_chat_completion method.

python
from hayhooks import BasePipelineWrapper, get_last_user_message


class PipelineWrapper(BasePipelineWrapper):
def run_chat_completion(self, model: str, messages: list, body: dict):
question = get_last_user_message(messages)
return self.pipeline.run({"query": question})

Streaming Responses​

Hayhooks provides a streaming_generator utility to stream pipeline output to the client:

python
from hayhooks import streaming_generator


def run_chat_completion(self, model: str, messages: list, body: dict):
question = get_last_user_message(messages)
return streaming_generator(
pipeline=self.pipeline,
pipeline_run_args={"query": question},
)

Running Programmatically​

Hayhooks can be embedded in a FastAPI application:

python
import uvicorn
from hayhooks.settings import settings
from fastapi import Request
from hayhooks import create_app

## Create the Hayhooks app
hayhooks = create_app()


## Add a custom route
@hayhooks.get("/custom")
async def custom_route():
return {"message": "Hi, this is a custom route!"}


## Add a custom middleware
@hayhooks.middleware("http")
async def custom_middleware(request: Request, call_next):
response = await call_next(request)
response.headers["X-Custom-Header"] = "custom-header-value"
return response


if __name__ == "__main__":
uvicorn.run("app:hayhooks", host=settings.host, port=settings.port)