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.
Files changed (100) hide show
  1. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/.github/workflows/pypi-cli.yml +52 -3
  2. tavus_cli-0.4.1/.release-please-manifest.json +3 -0
  3. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/CHANGELOG.md +15 -0
  4. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/PKG-INFO +5 -1
  5. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/README.md +4 -0
  6. tavus_cli-0.4.1/packages/tavus/README.md +14 -0
  7. tavus_cli-0.4.1/packages/tavus/pyproject.toml +20 -0
  8. tavus_cli-0.4.1/packages/tavus-mcp/README.md +17 -0
  9. tavus_cli-0.4.1/packages/tavus-mcp/pyproject.toml +20 -0
  10. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/pyproject.toml +1 -1
  11. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/release-please-config.json +8 -0
  12. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/scripts/check_release_versions.py +12 -1
  13. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/__init__.py +1 -1
  14. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/cli/main.py +1 -1
  15. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/client/http.py +50 -0
  16. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/schemas/tool.py +1 -1
  17. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/server.py +158 -9
  18. tavus_cli-0.4.1/tests/integration/test_mcp_server.py +213 -0
  19. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_release_versions.py +30 -0
  20. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/uv.lock +1 -1
  21. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/workers/tavus-mcp/package-lock.json +2 -2
  22. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/workers/tavus-mcp/package.json +1 -1
  23. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/workers/tavus-mcp/src/tavus.ts +106 -8
  24. tavus_cli-0.4.1/workers/tavus-mcp/src/version.ts +1 -0
  25. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/workers/tavus-mcp/test/tavus.test.ts +191 -1
  26. tavus_cli-0.3.4/.release-please-manifest.json +0 -3
  27. tavus_cli-0.3.4/tests/integration/test_mcp_server.py +0 -79
  28. tavus_cli-0.3.4/workers/tavus-mcp/src/version.ts +0 -1
  29. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/.env.example +0 -0
  30. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/.github/workflows/ci.yml +0 -0
  31. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/.github/workflows/deploy-cloudflare-worker.yml +0 -0
  32. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/.github/workflows/pr-reviews.yml +0 -0
  33. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/.github/workflows/tail-cloudflare-worker.yml +0 -0
  34. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/.github/workflows/validate-staging-deployment.yml +0 -0
  35. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/.gitignore +0 -0
  36. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/AGENTS.md +0 -0
  37. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/docs/gemini-enterprise/README.md +0 -0
  38. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/docs/gemini-enterprise/listing.md +0 -0
  39. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/docs/gemini-enterprise/test-queries.md +0 -0
  40. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/docs/usage-observability.md +0 -0
  41. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/scripts/__init__.py +0 -0
  42. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/skills/tavus-agentic-pals/SKILL.md +0 -0
  43. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/skills/tavus-agentic-pals/agents/openai.yaml +0 -0
  44. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/skills/tavus-agentic-pals/references/build-and-verify.md +0 -0
  45. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/skills/tavus-agentic-pals/references/builder-workflow.md +0 -0
  46. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/skills/tavus-agentic-pals/references/chat-mode.md +0 -0
  47. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/skills/tavus-agentic-pals/references/examples.md +0 -0
  48. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/cli/__init__.py +0 -0
  49. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/__init__.py +0 -0
  50. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/auth/__init__.py +0 -0
  51. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/auth/keyring_store.py +0 -0
  52. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/auth/oauth.py +0 -0
  53. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/auth/session.py +0 -0
  54. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/client/__init__.py +0 -0
  55. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/daily_transport.py +0 -0
  56. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/env.py +0 -0
  57. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/errors.py +0 -0
  58. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/pal_urls.py +0 -0
  59. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/patch.py +0 -0
  60. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/recipes/__init__.py +0 -0
  61. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/recipes/build_and_verify.py +0 -0
  62. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/recipes/capabilities.py +0 -0
  63. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/recipes/carrier_builder.py +0 -0
  64. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/recipes/knowledge.py +0 -0
  65. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/recipes/options.py +0 -0
  66. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/recipes/quickstart.py +0 -0
  67. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/recipes/scaffold_embed.py +0 -0
  68. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/recipes/templates.py +0 -0
  69. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/recipes/tool_reuse.py +0 -0
  70. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/schemas/__init__.py +0 -0
  71. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/schemas/file_manifest.py +0 -0
  72. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/schemas/guardrail.py +0 -0
  73. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/schemas/objective.py +0 -0
  74. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/schemas/pal.py +0 -0
  75. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/src/tavus_mcp/sdk/schemas/pronunciation.py +0 -0
  76. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/conftest.py +0 -0
  77. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/integration/test_cli.py +0 -0
  78. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/integration/test_client.py +0 -0
  79. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/integration/test_oauth.py +0 -0
  80. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_auth.py +0 -0
  81. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_build_and_verify.py +0 -0
  82. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_builder.py +0 -0
  83. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_capabilities.py +0 -0
  84. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_daily_transport.py +0 -0
  85. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_env.py +0 -0
  86. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_guardrail_schema.py +0 -0
  87. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_objective_schema.py +0 -0
  88. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_pal_schema.py +0 -0
  89. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_patch.py +0 -0
  90. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_pronunciation_schema.py +0 -0
  91. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_scaffold_embed.py +0 -0
  92. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_tool_reuse.py +0 -0
  93. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/tests/unit/test_tool_schema.py +0 -0
  94. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/workers/tavus-mcp/.dev.vars.example +0 -0
  95. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/workers/tavus-mcp/src/index.ts +0 -0
  96. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/workers/tavus-mcp/src/oauth-grant.ts +0 -0
  97. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/workers/tavus-mcp/src/oauth.ts +0 -0
  98. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/workers/tavus-mcp/test/parity.test.ts +0 -0
  99. {tavus_cli-0.3.4 → tavus_cli-0.4.1}/workers/tavus-mcp/tsconfig.json +0 -0
  100. {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: uv build
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]
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.4.1"
3
+ }
@@ -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.4
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tavus-cli"
3
- version = "0.3.4"
3
+ version = "0.4.1"
4
4
  description = "Tavus CLI and MCP server for agentic PAL creation and editing."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -29,6 +29,14 @@
29
29
  {
30
30
  "type": "generic",
31
31
  "path": "workers/tavus-mcp/src/version.ts"
32
+ },
33
+ {
34
+ "type": "generic",
35
+ "path": "packages/tavus/pyproject.toml"
36
+ },
37
+ {
38
+ "type": "generic",
39
+ "path": "packages/tavus-mcp/pyproject.toml"
32
40
  }
33
41
  ]
34
42
  }
@@ -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
- return {
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:
@@ -1,4 +1,4 @@
1
1
  """Tavus CLI and MCP server package."""
2
2
 
3
3
  __all__ = ["__version__"]
4
- __version__ = "0.3.4" # x-release-please-version
4
+ __version__ = "0.4.1" # x-release-please-version
@@ -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("ascending"),
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",
@@ -249,7 +249,7 @@ class ToolListParams(BaseModel):
249
249
  limit: int = 25
250
250
  page: int = 1
251
251
  type: ToolListType = "user"
252
- sort: Literal["ascending", "descending"] = "ascending"
252
+ sort: Literal["asc", "desc"] = "asc"
253
253
  name_or_uuid: str | None = None
254
254
 
255
255
 
@@ -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
- mcp = FastMCP(
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
- return await client.pals.list(limit=limit, page=page, pal_type=pal_type)
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 = 25,
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: str = "ascending",
1122
+ sort: Literal["asc", "desc"] = "asc",
982
1123
  ) -> Any:
983
- """List tools. `type` is "user" / "system" / "all"."""
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
- return await client.tools.list(**params)
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()