tavus-cli 0.3.4__tar.gz → 0.4.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/.github/workflows/pypi-cli.yml +52 -3
- tavus_cli-0.4.1/.release-please-manifest.json +3 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/CHANGELOG.md +15 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/PKG-INFO +5 -1
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/README.md +4 -0
- tavus_cli-0.4.1/packages/tavus/README.md +14 -0
- tavus_cli-0.4.1/packages/tavus/pyproject.toml +20 -0
- tavus_cli-0.4.1/packages/tavus-mcp/README.md +17 -0
- tavus_cli-0.4.1/packages/tavus-mcp/pyproject.toml +20 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/pyproject.toml +1 -1
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/release-please-config.json +8 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/scripts/check_release_versions.py +12 -1
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/__init__.py +1 -1
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/cli/main.py +1 -1
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/client/http.py +50 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/schemas/tool.py +1 -1
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/server.py +158 -9
- tavus_cli-0.4.1/tests/integration/test_mcp_server.py +213 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_release_versions.py +30 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/uv.lock +1 -1
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/workers/tavus-mcp/package-lock.json +2 -2
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/workers/tavus-mcp/package.json +1 -1
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/workers/tavus-mcp/src/tavus.ts +106 -8
- tavus_cli-0.4.1/workers/tavus-mcp/src/version.ts +1 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/workers/tavus-mcp/test/tavus.test.ts +191 -1
- tavus_cli-0.3.4/.release-please-manifest.json +0 -3
- tavus_cli-0.3.4/tests/integration/test_mcp_server.py +0 -79
- tavus_cli-0.3.4/workers/tavus-mcp/src/version.ts +0 -1
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/.env.example +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/.github/workflows/ci.yml +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/.github/workflows/deploy-cloudflare-worker.yml +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/.github/workflows/pr-reviews.yml +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/.github/workflows/tail-cloudflare-worker.yml +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/.github/workflows/validate-staging-deployment.yml +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/.gitignore +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/AGENTS.md +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/docs/gemini-enterprise/README.md +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/docs/gemini-enterprise/listing.md +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/docs/gemini-enterprise/test-queries.md +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/docs/usage-observability.md +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/scripts/__init__.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/skills/tavus-agentic-pals/SKILL.md +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/skills/tavus-agentic-pals/agents/openai.yaml +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/skills/tavus-agentic-pals/references/build-and-verify.md +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/skills/tavus-agentic-pals/references/builder-workflow.md +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/skills/tavus-agentic-pals/references/chat-mode.md +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/skills/tavus-agentic-pals/references/examples.md +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/cli/__init__.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/__init__.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/auth/__init__.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/auth/keyring_store.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/auth/oauth.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/auth/session.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/client/__init__.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/daily_transport.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/env.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/errors.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/pal_urls.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/patch.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/recipes/__init__.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/recipes/build_and_verify.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/recipes/capabilities.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/recipes/carrier_builder.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/recipes/knowledge.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/recipes/options.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/recipes/quickstart.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/recipes/scaffold_embed.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/recipes/templates.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/recipes/tool_reuse.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/schemas/__init__.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/schemas/file_manifest.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/schemas/guardrail.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/schemas/objective.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/schemas/pal.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/schemas/pronunciation.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/conftest.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/integration/test_cli.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/integration/test_client.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/integration/test_oauth.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_auth.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_build_and_verify.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_builder.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_capabilities.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_daily_transport.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_env.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_guardrail_schema.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_objective_schema.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_pal_schema.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_patch.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_pronunciation_schema.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_scaffold_embed.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_tool_reuse.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_tool_schema.py +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/workers/tavus-mcp/.dev.vars.example +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/workers/tavus-mcp/src/index.ts +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/workers/tavus-mcp/src/oauth-grant.ts +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/workers/tavus-mcp/src/oauth.ts +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/workers/tavus-mcp/test/parity.test.ts +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/workers/tavus-mcp/tsconfig.json +0 -0
- {tavus_cli-0.3.4 → tavus_cli-0.4.1}/workers/tavus-mcp/wrangler.jsonc +0 -0
|
@@ -149,7 +149,7 @@ jobs:
|
|
|
149
149
|
|
|
150
150
|
PARENT_SHA=$(git rev-parse "$RELEASE_SHA^")
|
|
151
151
|
UNEXPECTED=$(git diff --name-only "$PARENT_SHA" "$RELEASE_SHA" | grep -Ev \
|
|
152
|
-
'^(\.release-please-manifest\.json|CHANGELOG\.md|pyproject\.toml|uv\.lock|src/tavus_mcp/__init__\.py|workers/tavus-mcp/package\.json|workers/tavus-mcp/package-lock\.json|workers/tavus-mcp/src/version\.ts)$' || true)
|
|
152
|
+
'^(\.release-please-manifest\.json|CHANGELOG\.md|pyproject\.toml|uv\.lock|src/tavus_mcp/__init__\.py|workers/tavus-mcp/package\.json|workers/tavus-mcp/package-lock\.json|workers/tavus-mcp/src/version\.ts|packages/tavus/pyproject\.toml|packages/tavus-mcp/pyproject\.toml)$' || true)
|
|
153
153
|
if [ -n "$UNEXPECTED" ]; then
|
|
154
154
|
echo "::error::The release commit contains files that were not staged:"
|
|
155
155
|
echo "$UNEXPECTED"
|
|
@@ -195,7 +195,10 @@ jobs:
|
|
|
195
195
|
run: uv run pytest -q
|
|
196
196
|
|
|
197
197
|
- name: Build Python distributions
|
|
198
|
-
run:
|
|
198
|
+
run: |
|
|
199
|
+
uv build
|
|
200
|
+
uv build packages/tavus --out-dir dist
|
|
201
|
+
uv build packages/tavus-mcp --out-dir dist
|
|
199
202
|
|
|
200
203
|
- name: Set up Node.js
|
|
201
204
|
uses: actions/setup-node@v4
|
|
@@ -316,9 +319,55 @@ jobs:
|
|
|
316
319
|
name: tavus-cli-${{ needs.preflight.outputs.release_version }}
|
|
317
320
|
path: dist
|
|
318
321
|
|
|
319
|
-
- name: Publish Tavus CLI to PyPI
|
|
322
|
+
- name: Publish Tavus CLI and its alias packages to PyPI
|
|
320
323
|
run: uv publish --trusted-publishing always --check-url https://pypi.org/simple/ dist/*
|
|
321
324
|
|
|
325
|
+
notify-cvi-automations:
|
|
326
|
+
name: 'Notify #cvi-automations (prod deploy)'
|
|
327
|
+
needs: [preflight, production]
|
|
328
|
+
if: ${{ always() && !cancelled() && needs.preflight.result == 'success' }}
|
|
329
|
+
runs-on: ubuntu-latest
|
|
330
|
+
# A Slack or mention-resolution failure must not change the deploy result.
|
|
331
|
+
continue-on-error: true
|
|
332
|
+
timeout-minutes: 5
|
|
333
|
+
steps:
|
|
334
|
+
- name: Resolve release author mentions
|
|
335
|
+
id: mentions
|
|
336
|
+
continue-on-error: true
|
|
337
|
+
timeout-minutes: 2
|
|
338
|
+
uses: Tavus-Engineering/pr-changelog-action/release-mentions@main
|
|
339
|
+
with:
|
|
340
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
341
|
+
deploy-tag: ${{ needs.preflight.outputs.release_tag }}
|
|
342
|
+
environment: prod
|
|
343
|
+
|
|
344
|
+
- name: 'Post outcome to #cvi-automations'
|
|
345
|
+
env:
|
|
346
|
+
SLACK_BOT_TOKEN: ${{ secrets.CVI_BOT_SLACK_TOKEN }}
|
|
347
|
+
MENTIONS: ${{ steps.mentions.outputs.mentions }}
|
|
348
|
+
DEPLOY_RESULT: ${{ needs.production.result }}
|
|
349
|
+
RELEASE_TAG: ${{ needs.preflight.outputs.release_tag }}
|
|
350
|
+
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
351
|
+
run: |
|
|
352
|
+
set -euo pipefail
|
|
353
|
+
AUTHOR_TAGS="${MENTIONS:+${MENTIONS} }"
|
|
354
|
+
CVI_TEAM="<!subteam^S08HUM36HMZ>"
|
|
355
|
+
if [ "$DEPLOY_RESULT" = "success" ]; then
|
|
356
|
+
TEXT=":white_check_mark: ${AUTHOR_TAGS}Tavus MCP <${RUN_URL}|${RELEASE_TAG}> is live in production."
|
|
357
|
+
else
|
|
358
|
+
TEXT=":x: ${CVI_TEAM} Tavus MCP production deploy failed — <${RUN_URL}|run>."
|
|
359
|
+
fi
|
|
360
|
+
|
|
361
|
+
RESPONSE=$(curl --fail-with-body --silent --show-error \
|
|
362
|
+
--connect-timeout 5 --max-time 30 \
|
|
363
|
+
-X POST https://slack.com/api/chat.postMessage \
|
|
364
|
+
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" \
|
|
365
|
+
-H "Content-Type: application/json; charset=utf-8" \
|
|
366
|
+
--data "$(jq -n --arg channel "C0B9S5Y556V" --arg text "$TEXT" \
|
|
367
|
+
'{channel:$channel, text:$text, unfurl_links:false}')")
|
|
368
|
+
echo "$RESPONSE" | jq .
|
|
369
|
+
echo "$RESPONSE" | jq -e '.ok == true' >/dev/null
|
|
370
|
+
|
|
322
371
|
update-final-board:
|
|
323
372
|
name: Refresh Slack after production
|
|
324
373
|
needs: [preflight, update-pending-board, production]
|
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.4.1](https://github.com/Tavus-Engineering/tavus-mcp/compare/v0.4.0...v0.4.1) (2026-08-27)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* make MCP list tools compact and complete ([#33](https://github.com/Tavus-Engineering/tavus-mcp/issues/33)) ([9798cad](https://github.com/Tavus-Engineering/tavus-mcp/commit/9798cad82540a188162b1758731f04ae59f082f3))
|
|
9
|
+
|
|
10
|
+
## [0.4.0](https://github.com/Tavus-Engineering/tavus-mcp/compare/v0.3.4...v0.4.0) (2026-08-26)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* notify cvi-automations after MCP deploys ([#41](https://github.com/Tavus-Engineering/tavus-mcp/issues/41)) ([169d092](https://github.com/Tavus-Engineering/tavus-mcp/commit/169d092b6b9241256316e3d8f6a0a633319b70ef))
|
|
16
|
+
* publish tavus and tavus-mcp alias packages ([2c781a0](https://github.com/Tavus-Engineering/tavus-mcp/commit/2c781a059b1ef06acd2d4293239e41d568c4f0ce))
|
|
17
|
+
|
|
3
18
|
## [0.3.4](https://github.com/Tavus-Engineering/tavus-mcp/compare/v0.3.3...v0.3.4) (2026-08-25)
|
|
4
19
|
|
|
5
20
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: tavus-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Summary: Tavus CLI and MCP server for agentic PAL creation and editing.
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
6
|
Requires-Dist: fastmcp>=2.0.0
|
|
@@ -112,6 +112,10 @@ uv tool install tavus-cli
|
|
|
112
112
|
uvx --from tavus-cli tavus doctor
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
+
The `tavus` and `tavus-mcp` names on PyPI are official alias packages
|
|
116
|
+
(`packages/`) that only depend on `tavus-cli`; every release publishes all
|
|
117
|
+
three at the same version.
|
|
118
|
+
|
|
115
119
|
Sign in with `tavus auth login`. It opens the developer portal at
|
|
116
120
|
`/dev/cli-authorize` with a loopback callback; the portal mints an API key for
|
|
117
121
|
your signed-in user and the CLI stores it in the OS keychain, per environment.
|
|
@@ -90,6 +90,10 @@ uv tool install tavus-cli
|
|
|
90
90
|
uvx --from tavus-cli tavus doctor
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
+
The `tavus` and `tavus-mcp` names on PyPI are official alias packages
|
|
94
|
+
(`packages/`) that only depend on `tavus-cli`; every release publishes all
|
|
95
|
+
three at the same version.
|
|
96
|
+
|
|
93
97
|
Sign in with `tavus auth login`. It opens the developer portal at
|
|
94
98
|
`/dev/cli-authorize` with a loopback callback; the portal mints an API key for
|
|
95
99
|
your signed-in user and the CLI stores it in the OS keychain, per environment.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# tavus
|
|
2
|
+
|
|
3
|
+
Official alias for [`tavus-cli`](https://pypi.org/project/tavus-cli/), the
|
|
4
|
+
Tavus CLI and MCP server. Installing this package installs `tavus-cli`, which
|
|
5
|
+
provides the `tavus` command and the `tavus-mcp` MCP server.
|
|
6
|
+
|
|
7
|
+
Prefer installing the real package directly:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
uv tool install tavus-cli
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Source and documentation:
|
|
14
|
+
<https://github.com/Tavus-Engineering/tavus-mcp>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "tavus"
|
|
3
|
+
version = "0.4.1" # x-release-please-version
|
|
4
|
+
description = "Official alias for tavus-cli, the Tavus CLI and MCP server."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"tavus-cli==0.4.1", # x-release-please-version
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
[project.urls]
|
|
12
|
+
Homepage = "https://github.com/Tavus-Engineering/tavus-mcp"
|
|
13
|
+
|
|
14
|
+
[build-system]
|
|
15
|
+
requires = ["hatchling"]
|
|
16
|
+
build-backend = "hatchling.build"
|
|
17
|
+
|
|
18
|
+
# Metadata-only alias package: it ships no code of its own.
|
|
19
|
+
[tool.hatch.build.targets.wheel]
|
|
20
|
+
bypass-selection = true
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# tavus-mcp
|
|
2
|
+
|
|
3
|
+
Official alias for [`tavus-cli`](https://pypi.org/project/tavus-cli/).
|
|
4
|
+
Installing this package installs `tavus-cli`, which provides the `tavus-mcp`
|
|
5
|
+
stdio MCP server and the `tavus` command.
|
|
6
|
+
|
|
7
|
+
Prefer installing the real package directly:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
uvx --from 'tavus-cli[daily]' tavus-mcp
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The hosted MCP server needs no install at all: point your MCP client at
|
|
14
|
+
`https://mcp.tavus.io/mcp`.
|
|
15
|
+
|
|
16
|
+
Source and documentation:
|
|
17
|
+
<https://github.com/Tavus-Engineering/tavus-mcp>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "tavus-mcp"
|
|
3
|
+
version = "0.4.1" # x-release-please-version
|
|
4
|
+
description = "Official alias for tavus-cli, which provides the tavus-mcp MCP server."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"tavus-cli==0.4.1", # x-release-please-version
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
[project.urls]
|
|
12
|
+
Homepage = "https://github.com/Tavus-Engineering/tavus-mcp"
|
|
13
|
+
|
|
14
|
+
[build-system]
|
|
15
|
+
requires = ["hatchling"]
|
|
16
|
+
build-backend = "hatchling.build"
|
|
17
|
+
|
|
18
|
+
# Metadata-only alias package: it ships no code of its own.
|
|
19
|
+
[tool.hatch.build.targets.wheel]
|
|
20
|
+
bypass-selection = true
|
|
@@ -42,7 +42,7 @@ def collect_versions() -> dict[str, str]:
|
|
|
42
42
|
if not python_init or not worker_source or not lock_package:
|
|
43
43
|
raise ValueError("Could not read one or more release version fields")
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
versions = {
|
|
46
46
|
"release-please manifest": str(manifest["."]),
|
|
47
47
|
"pyproject.toml": str(pyproject["project"]["version"]),
|
|
48
48
|
"Python package": python_init.group(1),
|
|
@@ -52,6 +52,17 @@ def collect_versions() -> dict[str, str]:
|
|
|
52
52
|
"Worker package-lock root package": str(worker_lock["packages"][""]["version"]),
|
|
53
53
|
"Worker runtime": worker_source.group(1),
|
|
54
54
|
}
|
|
55
|
+
for alias in ("tavus", "tavus-mcp"):
|
|
56
|
+
alias_project = tomllib.loads(_read(f"packages/{alias}/pyproject.toml"))["project"]
|
|
57
|
+
pin = next(
|
|
58
|
+
(dep for dep in alias_project["dependencies"] if dep.startswith("tavus-cli==")),
|
|
59
|
+
None,
|
|
60
|
+
)
|
|
61
|
+
if pin is None:
|
|
62
|
+
raise ValueError(f"Alias package {alias} does not pin tavus-cli")
|
|
63
|
+
versions[f"{alias} alias package"] = str(alias_project["version"])
|
|
64
|
+
versions[f"{alias} alias tavus-cli pin"] = pin.removeprefix("tavus-cli==")
|
|
65
|
+
return versions
|
|
55
66
|
|
|
56
67
|
|
|
57
68
|
def check_versions(expected: str | None = None) -> str:
|
|
@@ -1462,7 +1462,7 @@ def tool_list(
|
|
|
1462
1462
|
page: int = typer.Option(1),
|
|
1463
1463
|
type: str = typer.Option("user", help="user | system | all"),
|
|
1464
1464
|
name_or_uuid: str | None = typer.Option(None),
|
|
1465
|
-
sort: str = typer.Option("
|
|
1465
|
+
sort: str = typer.Option("asc"),
|
|
1466
1466
|
json_output: bool = typer.Option(False, "--json"),
|
|
1467
1467
|
) -> None:
|
|
1468
1468
|
"""List tools."""
|
|
@@ -27,6 +27,20 @@ BUILDER_LLM_TIMEOUT_S = 120.0
|
|
|
27
27
|
CLIENT_SOURCE_HEADER = "X-Tavus-Client-Source"
|
|
28
28
|
|
|
29
29
|
|
|
30
|
+
def _public_pal_error_body(value: Any) -> Any:
|
|
31
|
+
"""Keep internal persona vocabulary out of public PAL errors."""
|
|
32
|
+
if isinstance(value, str):
|
|
33
|
+
return value.replace("persona_id", "pal_id")
|
|
34
|
+
if isinstance(value, list):
|
|
35
|
+
return [_public_pal_error_body(item) for item in value]
|
|
36
|
+
if isinstance(value, dict):
|
|
37
|
+
return {
|
|
38
|
+
str(key).replace("persona_id", "pal_id"): _public_pal_error_body(item)
|
|
39
|
+
for key, item in value.items()
|
|
40
|
+
}
|
|
41
|
+
return value
|
|
42
|
+
|
|
43
|
+
|
|
30
44
|
def _package_version() -> str:
|
|
31
45
|
try:
|
|
32
46
|
return version("tavus-cli")
|
|
@@ -128,6 +142,8 @@ class TavusClient:
|
|
|
128
142
|
body: Any = response.json()
|
|
129
143
|
except ValueError:
|
|
130
144
|
body = response.text
|
|
145
|
+
if path.strip("/").startswith("pals"):
|
|
146
|
+
body = _public_pal_error_body(body)
|
|
131
147
|
raise TavusApiError(
|
|
132
148
|
f"Tavus API {method.upper()} {path} failed with {response.status_code}",
|
|
133
149
|
status_code=response.status_code,
|
|
@@ -149,6 +165,40 @@ class Resource:
|
|
|
149
165
|
async def list(self, **params: Any) -> Any:
|
|
150
166
|
return await self.client.request("GET", f"/{self.name}", params=_clean(params))
|
|
151
167
|
|
|
168
|
+
async def list_all(
|
|
169
|
+
self,
|
|
170
|
+
*,
|
|
171
|
+
page_size: int = 100,
|
|
172
|
+
start_page: int = 1,
|
|
173
|
+
**params: Any,
|
|
174
|
+
) -> dict[str, Any]:
|
|
175
|
+
"""Collect a 1-indexed paginated resource without hiding later pages."""
|
|
176
|
+
data: list[Any] = []
|
|
177
|
+
total_count: int | None = None
|
|
178
|
+
for page in range(start_page, start_page + 100):
|
|
179
|
+
response = await self.list(limit=page_size, page=page, **params)
|
|
180
|
+
page_data = (
|
|
181
|
+
response.get("data", [])
|
|
182
|
+
if isinstance(response, dict)
|
|
183
|
+
else response
|
|
184
|
+
if isinstance(response, list)
|
|
185
|
+
else []
|
|
186
|
+
)
|
|
187
|
+
if not isinstance(page_data, list):
|
|
188
|
+
page_data = []
|
|
189
|
+
data.extend(page_data)
|
|
190
|
+
if isinstance(response, dict) and isinstance(response.get("total_count"), int):
|
|
191
|
+
total_count = response["total_count"]
|
|
192
|
+
if not page_data:
|
|
193
|
+
break
|
|
194
|
+
if total_count is not None and len(data) >= total_count:
|
|
195
|
+
break
|
|
196
|
+
if len(page_data) < page_size:
|
|
197
|
+
break
|
|
198
|
+
else:
|
|
199
|
+
raise RuntimeError(f"Tavus API {self.name} pagination exceeded 100 pages")
|
|
200
|
+
return {"data": data, "total_count": total_count or len(data)}
|
|
201
|
+
|
|
152
202
|
async def get(self, resource_id: str, **params: Any) -> Any:
|
|
153
203
|
return await self.client.request(
|
|
154
204
|
"GET",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import time
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Any, Literal
|
|
5
5
|
|
|
6
6
|
from fastmcp import FastMCP
|
|
7
7
|
|
|
@@ -31,7 +31,105 @@ from tavus_mcp.sdk.recipes.scaffold_embed import EmbedTarget, scaffold_embed
|
|
|
31
31
|
from tavus_mcp.sdk.recipes.templates import PalTemplate, pal_from_template
|
|
32
32
|
from tavus_mcp.sdk.recipes.tool_reuse import build_library_match_advisory
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
_READ_ONLY_TOOL_NAMES = {
|
|
35
|
+
"tavus_mcp_health_check",
|
|
36
|
+
"tavus_pal_list",
|
|
37
|
+
"tavus_pal_get",
|
|
38
|
+
"tavus_describe_pal_options",
|
|
39
|
+
"tavus_document_list",
|
|
40
|
+
"tavus_document_get",
|
|
41
|
+
"tavus_document_tags",
|
|
42
|
+
"tavus_document_chunks",
|
|
43
|
+
"tavus_pal_knowledge_list",
|
|
44
|
+
"tavus_skill_list",
|
|
45
|
+
"tavus_skill_get",
|
|
46
|
+
"tavus_pal_skills_list",
|
|
47
|
+
"tavus_pal_capability_catalog",
|
|
48
|
+
"tavus_pal_capabilities_list",
|
|
49
|
+
"tavus_face_list",
|
|
50
|
+
"tavus_scaffold_embed",
|
|
51
|
+
"tavus_resource_list",
|
|
52
|
+
"tavus_voice_list",
|
|
53
|
+
"tavus_guardrail_list",
|
|
54
|
+
"tavus_guardrail_get",
|
|
55
|
+
"tavus_guardrail_tags",
|
|
56
|
+
"tavus_objective_list",
|
|
57
|
+
"tavus_objective_get",
|
|
58
|
+
"tavus_objective_validate",
|
|
59
|
+
"tavus_tool_list",
|
|
60
|
+
"tavus_tool_get",
|
|
61
|
+
"tavus_pronunciation_dictionary_list",
|
|
62
|
+
"tavus_pronunciation_dictionary_get",
|
|
63
|
+
"tavus_pal_tools_list",
|
|
64
|
+
"tavus_builder_list",
|
|
65
|
+
"tavus_builder_get",
|
|
66
|
+
"tavus_builder_chat_history",
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
_DESTRUCTIVE_TOOL_NAMES = {
|
|
70
|
+
"tavus_pal_delete",
|
|
71
|
+
"tavus_pal_knowledge_remove",
|
|
72
|
+
"tavus_pal_knowledge_replace",
|
|
73
|
+
"tavus_pal_skill_detach",
|
|
74
|
+
"tavus_pal_capability_detach",
|
|
75
|
+
"tavus_conversation_end",
|
|
76
|
+
"tavus_guardrail_delete",
|
|
77
|
+
"tavus_objective_delete",
|
|
78
|
+
"tavus_tool_delete",
|
|
79
|
+
"tavus_pronunciation_dictionary_delete",
|
|
80
|
+
"tavus_pal_tools_detach",
|
|
81
|
+
"tavus_builder_delete",
|
|
82
|
+
"tavus_chat_end",
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _annotations_for_tool(name: str) -> dict[str, bool]:
|
|
87
|
+
if name in _READ_ONLY_TOOL_NAMES:
|
|
88
|
+
return {
|
|
89
|
+
"readOnlyHint": True,
|
|
90
|
+
"destructiveHint": False,
|
|
91
|
+
"idempotentHint": True,
|
|
92
|
+
"openWorldHint": True,
|
|
93
|
+
}
|
|
94
|
+
if name in _DESTRUCTIVE_TOOL_NAMES:
|
|
95
|
+
return {
|
|
96
|
+
"readOnlyHint": False,
|
|
97
|
+
"destructiveHint": True,
|
|
98
|
+
"idempotentHint": True,
|
|
99
|
+
"openWorldHint": True,
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
"readOnlyHint": False,
|
|
103
|
+
"destructiveHint": False,
|
|
104
|
+
"idempotentHint": False,
|
|
105
|
+
"openWorldHint": True,
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class AnnotatedFastMCP(FastMCP):
|
|
110
|
+
"""Apply a conservative annotation policy to every registered Tavus tool."""
|
|
111
|
+
|
|
112
|
+
def tool(self, name_or_fn: Any = None, **kwargs: Any) -> Any:
|
|
113
|
+
if name_or_fn is None and kwargs.get("annotations") is None:
|
|
114
|
+
|
|
115
|
+
def register(fn: Any) -> Any:
|
|
116
|
+
return super(AnnotatedFastMCP, self).tool(
|
|
117
|
+
fn,
|
|
118
|
+
annotations=_annotations_for_tool(kwargs.get("name") or fn.__name__),
|
|
119
|
+
**kwargs,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
return register
|
|
123
|
+
if callable(name_or_fn) and kwargs.get("annotations") is None:
|
|
124
|
+
kwargs["annotations"] = _annotations_for_tool(
|
|
125
|
+
kwargs.get("name") or name_or_fn.__name__
|
|
126
|
+
)
|
|
127
|
+
elif isinstance(name_or_fn, str) and kwargs.get("annotations") is None:
|
|
128
|
+
kwargs["annotations"] = _annotations_for_tool(name_or_fn)
|
|
129
|
+
return super().tool(name_or_fn, **kwargs)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
mcp = AnnotatedFastMCP(
|
|
35
133
|
"tavus",
|
|
36
134
|
instructions=(
|
|
37
135
|
"PAL tools are first-class objects, not inlined on the PAL. "
|
|
@@ -63,6 +161,47 @@ def _list_data(value: Any) -> list[Any]:
|
|
|
63
161
|
return []
|
|
64
162
|
|
|
65
163
|
|
|
164
|
+
def _summary_value(item: dict[str, Any], *names: str) -> Any:
|
|
165
|
+
for name in names:
|
|
166
|
+
if name in item:
|
|
167
|
+
return item[name]
|
|
168
|
+
return None
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _compact_list(value: Any, summarize: Any) -> dict[str, Any]:
|
|
172
|
+
data = [summarize(item) for item in _list_data(value) if isinstance(item, dict)]
|
|
173
|
+
result: dict[str, Any] = {"data": data, "returned_count": len(data)}
|
|
174
|
+
if isinstance(value, dict) and isinstance(value.get("total_count"), int):
|
|
175
|
+
result["total_count"] = value["total_count"]
|
|
176
|
+
else:
|
|
177
|
+
result["total_count"] = len(data)
|
|
178
|
+
return result
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def _pal_summary(item: dict[str, Any]) -> dict[str, Any]:
|
|
182
|
+
return {
|
|
183
|
+
"pal_id": _summary_value(item, "pal_id", "persona_id", "uuid"),
|
|
184
|
+
"name": _summary_value(item, "name", "pal_name", "persona_name"),
|
|
185
|
+
"description": _summary_value(
|
|
186
|
+
item,
|
|
187
|
+
"description",
|
|
188
|
+
"pal_description",
|
|
189
|
+
"persona_description",
|
|
190
|
+
),
|
|
191
|
+
"is_published": item.get("is_published"),
|
|
192
|
+
"pipeline_mode": item.get("pipeline_mode"),
|
|
193
|
+
"updated_at": item.get("updated_at"),
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _tool_summary(item: dict[str, Any]) -> dict[str, Any]:
|
|
198
|
+
return {
|
|
199
|
+
"tool_id": _summary_value(item, "tool_id", "uuid"),
|
|
200
|
+
"name": item.get("name"),
|
|
201
|
+
"is_system_tool": item.get("is_system_tool"),
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
|
|
66
205
|
def _response_shape(value: Any) -> str:
|
|
67
206
|
if isinstance(value, list):
|
|
68
207
|
return "list"
|
|
@@ -147,8 +286,10 @@ async def tavus_pal_list(
|
|
|
147
286
|
page: int = 0,
|
|
148
287
|
pal_type: str | None = None,
|
|
149
288
|
) -> Any:
|
|
289
|
+
"""List compact PAL summaries. Use ``tavus_pal_get`` for full settings."""
|
|
150
290
|
async with TavusClient.from_env(surface="mcp") as client:
|
|
151
|
-
|
|
291
|
+
response = await client.pals.list(limit=limit, page=page, pal_type=pal_type)
|
|
292
|
+
return _compact_list(response, _pal_summary)
|
|
152
293
|
|
|
153
294
|
|
|
154
295
|
@mcp.tool()
|
|
@@ -974,23 +1115,31 @@ async def tavus_objective_validate(
|
|
|
974
1115
|
|
|
975
1116
|
@mcp.tool()
|
|
976
1117
|
async def tavus_tool_list(
|
|
977
|
-
limit: int =
|
|
1118
|
+
limit: int | None = None,
|
|
978
1119
|
page: int = 1,
|
|
979
1120
|
type: str = "user",
|
|
980
1121
|
name_or_uuid: str | None = None,
|
|
981
|
-
sort:
|
|
1122
|
+
sort: Literal["asc", "desc"] = "asc",
|
|
982
1123
|
) -> Any:
|
|
983
|
-
"""List
|
|
1124
|
+
"""List compact tool summaries.
|
|
1125
|
+
|
|
1126
|
+
Omit ``limit`` to return every matching tool across all API pages. Set
|
|
1127
|
+
``limit`` and ``page`` when one explicit page is enough. ``type`` accepts
|
|
1128
|
+
``"user"``, ``"system"``, or ``"all"``; ``sort`` accepts ``"asc"`` or
|
|
1129
|
+
``"desc"``. Use ``tavus_tool_get`` for the full tool definition.
|
|
1130
|
+
"""
|
|
984
1131
|
params: dict[str, Any] = {
|
|
985
|
-
"limit": limit,
|
|
986
|
-
"page": page,
|
|
987
1132
|
"type": type,
|
|
988
1133
|
"sort": sort,
|
|
989
1134
|
}
|
|
990
1135
|
if name_or_uuid:
|
|
991
1136
|
params["name_or_uuid"] = name_or_uuid
|
|
992
1137
|
async with TavusClient.from_env(surface="mcp") as client:
|
|
993
|
-
|
|
1138
|
+
if limit is None:
|
|
1139
|
+
response = await client.tools.list_all(**params)
|
|
1140
|
+
else:
|
|
1141
|
+
response = await client.tools.list(limit=limit, page=page, **params)
|
|
1142
|
+
return _compact_list(response, _tool_summary)
|
|
994
1143
|
|
|
995
1144
|
|
|
996
1145
|
@mcp.tool()
|