Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# AGENTS.md

Python SDK for the [Behavioral Signals API](https://behavioralsignals.readme.io/): voice behavior
analysis and audio/video deepfake detection, plus an optional MCP server. Setup, code style and
pull request steps are in [CONTRIBUTING.md](CONTRIBUTING.md).

## Map

- `src/behavioralsignals/client.py`: `Client`, which holds the `behavioral` and `deepfakes` clients.
- `src/behavioralsignals/behavioral.py`, `deepfakes.py`: the two APIs. `base.py`: HTTP requests,
errors, the wait loop behind `wait_for_result`, and the gRPC channel.
- `src/behavioralsignals/models.py`: pydantic models of requests and responses.
`configuration.py`: API URLs and timeouts.
- `src/behavioralsignals/mcp_server.py`: the MCP server (`behavioralsignals-mcp`).
- `src/behavioralsignals/generated/`: gRPC code generated from `protos/api.proto`.
- `examples/`: batch and streaming scripts. `tests/`: pytest tests.

## Commands

```bash
uv sync -p 3.10 --extra dev # see CONTRIBUTING.md
uv run pytest
uv run ruff check
uv run ruff format
uv run mypy src
```

CI runs `ruff check`, `ruff format --check`, `mypy src` and `pytest` on Python 3.10 to 3.13. It
also runs the tests with the lowest versions allowed in `pyproject.toml`, and needs 90% coverage.

## Rules

- Support Python 3.10: no newer syntax or modules.
- If you change `pyproject.toml`, run `uv lock` and commit `uv.lock`; CI fails otherwise.
- `Behavioral` and `Deepfakes` repeat the audio methods; change both.
- Don't edit `generated/` by hand; regenerate it (see CONTRIBUTING.md).
- Tests never call the API and need no credentials. Fake HTTP as `tests/test_client.py` does.
- `mcp` is an optional extra: never import `mcp_server` from `__init__.py`.
- `mcp_server.py` must never print to stdout; stdout carries the MCP protocol.
- When a public method or MCP tool changes, update the README method table, `examples/`, and
the MCP tools and README MCP section if they use it.
- Never commit credentials.
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@AGENTS.md
79 changes: 79 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ See the [API documentation](https://behavioralsignals.readme.io/) for details. I
* [Deepfakes API Streaming Mode](#deepfakes-api-streaming-mode)
* [Available Methods](#available-methods)
* [Error Handling](#error-handling)
* [Use with AI assistants (MCP)](#use-with-ai-assistants-mcp)
* [Running the MCP server manually](#running-the-mcp-server-manually)

## Features

Expand All @@ -57,6 +59,8 @@ See the [API documentation](https://behavioralsignals.readme.io/) for details. I
- Speaker Diarization
- Language Identification

- **MCP server**: Let AI assistants such as Claude and Cursor analyze files for you. See [Use with AI assistants (MCP)](#use-with-ai-assistants-mcp).

## Requirements

* `Python3.10+`,
Expand Down Expand Up @@ -305,3 +309,78 @@ except BehavioralSignalsError as error:

`BehavioralSignalsError` is a subclass of `Exception`, so code that catches `Exception` keeps working.
Network problems raise the usual `requests` exceptions, such as `requests.ConnectionError`.

## Use with AI assistants (MCP)

The SDK includes an [MCP](https://modelcontextprotocol.io/) server (available since version 0.7.0), so AI assistants such as Claude Code, Codex, Claude Desktop and Cursor can analyze audio and video files for you.
The setups below start the server with `uvx`, so install [uv](https://docs.astral.sh/uv/) first.

The server reads your credentials from `BEHAVIORALSIGNALS_CID` and `BEHAVIORALSIGNALS_API_KEY` (see [API Key Setup](#api-key-setup)).
Your assistant starts the server, so set them in the assistant's config, as shown below.

**Claude Code.** With the two variables set in your shell, run:

```bash
claude mcp add --env BEHAVIORALSIGNALS_CID="$BEHAVIORALSIGNALS_CID" \
Comment thread
lefteris12 marked this conversation as resolved.
Resolved
--env BEHAVIORALSIGNALS_API_KEY="$BEHAVIORALSIGNALS_API_KEY" --transport stdio \
behavioralsignals -- uvx --python ">=3.10" --from "behavioralsignals[mcp]" behavioralsignals-mcp
```

This adds the server for you in the current project only. Your key stays out of your shell history and out of the repository.

**Codex.** With the two variables set in your shell, run:

```bash
codex mcp add behavioralsignals --env BEHAVIORALSIGNALS_CID="$BEHAVIORALSIGNALS_CID" \
--env BEHAVIORALSIGNALS_API_KEY="$BEHAVIORALSIGNALS_API_KEY" \
-- uvx --python ">=3.10" --from "behavioralsignals[mcp]" behavioralsignals-mcp
```

This adds the server for all your projects, in `~/.codex/config.toml`.

**Claude Desktop and Cursor.** Add this to `claude_desktop_config.json` (in Claude Desktop, Settings > Developer > Edit Config) or to `~/.cursor/mcp.json`:

```json
{
"mcpServers": {
"behavioralsignals": {
"command": "uvx",
"args": ["--python", ">=3.10", "--from", "behavioralsignals[mcp]", "behavioralsignals-mcp"],
"env": {
"BEHAVIORALSIGNALS_CID": "your_cid",
"BEHAVIORALSIGNALS_API_KEY": "your_api_key"
}
}
}
}
```

If the app cannot find `uvx`, use its full path (run `which uvx` to find it).

The server has 4 tools:

| Tool | What it does |
|---|---|
| `analyze_behavior` | Uploads an audio file or S3 presigned URL for behavioral analysis and returns the results |
| `detect_deepfake` | Uploads an audio or video file, or an S3 presigned URL, for deepfake detection and returns the results |
| `get_result` | Returns the results of a process, in pages, optionally only for some tasks |
| `list_processes` | Lists your processes, newest first, with the reason when one failed |

Notes:
* Each upload uses credits, and the files you name are sent to the Behavioral Signals API.
* The upload tools wait up to `wait_seconds` (45 by default, 50 at most). If processing takes longer, they return the process ID, and the assistant checks it later with `get_result`.
* Don't commit config files that contain your API key.

### Running the MCP server manually

With uv installed, you can run it without installing anything else:

```bash
uvx --python ">=3.10" --from "behavioralsignals[mcp]" behavioralsignals-mcp
```

Or install it with pip and run `behavioralsignals-mcp`:

```bash
pip install "behavioralsignals[mcp]"
```
9 changes: 7 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[project]
name = "behavioralsignals"
version = "0.6.0"
version = "0.7.0"
description = "Official Python SDK for the Behavioral Signals API: voice emotion/behavior analysis and audio/video deepfake detection"
readme = "README.md"
authors = [{ name = "Behavioral Signal Technologies" }]
requires-python = ">=3.10"
license = { file = "LICENSE" }
keywords = ["emotion-recognition", "speech", "voice", "deepfake-detection", "audio", "video", "grpc", "sdk"]
keywords = ["emotion-recognition", "speech", "voice", "deepfake-detection", "audio", "video", "grpc", "sdk", "mcp"]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
Expand Down Expand Up @@ -34,13 +34,18 @@ dependencies = [
[project.optional-dependencies]
dev = [
"grpcio-tools>=1.73.1",
"mcp>=2.2.0,<3",
"mypy==2.3.1",
"pytest>=8",
"pytest-cov>=7",
"ruff==0.16.8",
"types-grpcio>=1.83.0",
"types-protobuf>=7.35.1",
]
mcp = ["mcp>=2.2.0,<3"]

[project.scripts]
behavioralsignals-mcp = "behavioralsignals.mcp_server:main"

[project.urls]
Homepage = "https://behavioralsignals.com/"
Expand Down
2 changes: 1 addition & 1 deletion src/behavioralsignals/behavioral.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def list_processes(
page_size (int): Number of processes per page (default is 1000).
sort (str): Sort order for the processes, should be "asc" or "desc". Defaults to "asc".
start_date (str, optional: Filter processes created on or after this date (YYYY-MM-DD).
end_date (str, optional): Filter processes created on or before this date (YYYY-MM-DD).
end_date (str, optional): Filter processes created before this date (YYYY-MM-DD).
Returns:
ProcessListResponse: A list of processes associated with the user.
"""
Expand Down
4 changes: 2 additions & 2 deletions src/behavioralsignals/deepfakes.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def list_processes(
page_size (int): Number of processes per page (default is 1000).
sort (str): Sort order for the processes, should be "asc" or "desc". Defaults to "asc".
start_date (str, optional: Filter processes created on or after this date (YYYY-MM-DD).
end_date (str, optional): Filter processes created on or before this date (YYYY-MM-DD).
end_date (str, optional): Filter processes created before this date (YYYY-MM-DD).
Returns:
ProcessListResponse: A list of processes associated with the user.
"""
Expand Down Expand Up @@ -323,7 +323,7 @@ def list_video_processes(
page_size (int): Number of processes per page (default is 1000).
sort (str): Sort order for the processes, should be "asc" or "desc". Defaults to "asc".
start_date (str, optional: Filter processes created on or after this date (YYYY-MM-DD).
end_date (str, optional): Filter processes created on or before this date (YYYY-MM-DD).
end_date (str, optional): Filter processes created before this date (YYYY-MM-DD).
Returns:
ProcessListResponse: A list of video processes associated with the user.
"""
Expand Down
Loading
Loading