tavus-cli 0.8.0__tar.gz → 0.9.0__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 (114) hide show
  1. tavus_cli-0.9.0/.release-please-manifest.json +3 -0
  2. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/CHANGELOG.md +19 -0
  3. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/PKG-INFO +2 -2
  4. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/README.md +1 -1
  5. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/docs/chatgpt-plugin.md +6 -0
  6. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/packages/tavus/pyproject.toml +2 -2
  7. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/packages/tavus-mcp/pyproject.toml +2 -2
  8. tavus_cli-0.9.0/plugins/tavus-pal/plugin.json +99 -0
  9. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/pyproject.toml +1 -1
  10. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/__init__.py +1 -1
  11. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/recipes/deployments.py +7 -1
  12. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/tests/unit/test_deployments.py +8 -0
  13. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/uv.lock +1 -1
  14. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/workers/tavus-mcp/package-lock.json +2 -2
  15. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/workers/tavus-mcp/package.json +1 -1
  16. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/workers/tavus-mcp/src/index.ts +6 -1
  17. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/workers/tavus-mcp/src/oauth.ts +50 -18
  18. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/workers/tavus-mcp/src/tavus.ts +34 -3
  19. tavus_cli-0.9.0/workers/tavus-mcp/src/version.ts +1 -0
  20. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/workers/tavus-mcp/test/oauth-session.test.ts +48 -2
  21. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/workers/tavus-mcp/test/tavus.test.ts +31 -6
  22. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/workers/tavus-mcp/wrangler.jsonc +3 -0
  23. tavus_cli-0.8.0/.release-please-manifest.json +0 -3
  24. tavus_cli-0.8.0/plugins/tavus-pal/plugin.json +0 -45
  25. tavus_cli-0.8.0/workers/tavus-mcp/src/version.ts +0 -1
  26. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/.agents/plugins/marketplace.json +0 -0
  27. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/.env.example +0 -0
  28. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/.github/workflows/ci.yml +0 -0
  29. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/.github/workflows/deploy-cloudflare-worker.yml +0 -0
  30. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/.github/workflows/pr-reviews.yml +0 -0
  31. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/.github/workflows/pypi-cli.yml +0 -0
  32. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/.github/workflows/tail-cloudflare-worker.yml +0 -0
  33. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/.github/workflows/validate-staging-deployment.yml +0 -0
  34. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/.gitignore +0 -0
  35. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/AGENTS.md +0 -0
  36. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/PROMPT.md +0 -0
  37. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/docs/gemini-enterprise/README.md +0 -0
  38. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/docs/gemini-enterprise/listing.md +0 -0
  39. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/docs/gemini-enterprise/test-queries.md +0 -0
  40. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/docs/usage-observability.md +0 -0
  41. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/packages/tavus/README.md +0 -0
  42. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/packages/tavus-mcp/README.md +0 -0
  43. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/plugins/tavus-pal/assets/icon-dark.svg +0 -0
  44. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/plugins/tavus-pal/assets/icon.svg +0 -0
  45. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/plugins/tavus-pal/mcp.json +0 -0
  46. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/release-please-config.json +0 -0
  47. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/scripts/__init__.py +0 -0
  48. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/scripts/build_chatgpt_plugin.py +0 -0
  49. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/scripts/check_release_versions.py +0 -0
  50. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/skills/tavus-agentic-pals/SKILL.md +0 -0
  51. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/skills/tavus-agentic-pals/agents/openai.yaml +0 -0
  52. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/skills/tavus-agentic-pals/references/build-and-verify.md +0 -0
  53. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/skills/tavus-agentic-pals/references/builder-workflow.md +0 -0
  54. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/skills/tavus-agentic-pals/references/chat-mode.md +0 -0
  55. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/skills/tavus-agentic-pals/references/examples.md +0 -0
  56. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/cli/__init__.py +0 -0
  57. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/cli/main.py +0 -0
  58. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/__init__.py +0 -0
  59. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/auth/__init__.py +0 -0
  60. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/auth/keyring_store.py +0 -0
  61. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/auth/oauth.py +0 -0
  62. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/auth/session.py +0 -0
  63. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/client/__init__.py +0 -0
  64. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/client/http.py +0 -0
  65. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/daily_transport.py +0 -0
  66. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/env.py +0 -0
  67. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/errors.py +0 -0
  68. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/pal_urls.py +0 -0
  69. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/patch.py +0 -0
  70. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/recipes/__init__.py +0 -0
  71. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/recipes/build_and_verify.py +0 -0
  72. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/recipes/capabilities.py +0 -0
  73. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/recipes/carrier_builder.py +0 -0
  74. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/recipes/knowledge.py +0 -0
  75. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/recipes/options.py +0 -0
  76. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/recipes/quickstart.py +0 -0
  77. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/recipes/scaffold_embed.py +0 -0
  78. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/recipes/templates.py +0 -0
  79. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/recipes/tool_reuse.py +0 -0
  80. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/schemas/__init__.py +0 -0
  81. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/schemas/deployment.py +0 -0
  82. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/schemas/file_manifest.py +0 -0
  83. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/schemas/guardrail.py +0 -0
  84. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/schemas/objective.py +0 -0
  85. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/schemas/pal.py +0 -0
  86. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/schemas/pronunciation.py +0 -0
  87. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/sdk/schemas/tool.py +0 -0
  88. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/src/tavus_mcp/server.py +0 -0
  89. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/tests/conftest.py +0 -0
  90. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/tests/integration/test_cli.py +0 -0
  91. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/tests/integration/test_client.py +0 -0
  92. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/tests/integration/test_mcp_server.py +0 -0
  93. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/tests/integration/test_oauth.py +0 -0
  94. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/tests/unit/test_auth.py +0 -0
  95. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/tests/unit/test_build_and_verify.py +0 -0
  96. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/tests/unit/test_builder.py +0 -0
  97. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/tests/unit/test_capabilities.py +0 -0
  98. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/tests/unit/test_daily_transport.py +0 -0
  99. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/tests/unit/test_env.py +0 -0
  100. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/tests/unit/test_guardrail_schema.py +0 -0
  101. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/tests/unit/test_objective_schema.py +0 -0
  102. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/tests/unit/test_pal_schema.py +0 -0
  103. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/tests/unit/test_patch.py +0 -0
  104. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/tests/unit/test_pronunciation_schema.py +0 -0
  105. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/tests/unit/test_release_versions.py +0 -0
  106. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/tests/unit/test_scaffold_embed.py +0 -0
  107. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/tests/unit/test_tool_reuse.py +0 -0
  108. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/tests/unit/test_tool_schema.py +0 -0
  109. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/workers/tavus-mcp/.dev.vars.example +0 -0
  110. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/workers/tavus-mcp/src/oauth-grant.ts +0 -0
  111. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/workers/tavus-mcp/src/oauth-session.ts +0 -0
  112. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/workers/tavus-mcp/test/parity.test.ts +0 -0
  113. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/workers/tavus-mcp/test/worker-runtime.ts +0 -0
  114. {tavus_cli-0.8.0 → tavus_cli-0.9.0}/workers/tavus-mcp/tsconfig.json +0 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.9.0"
3
+ }
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.9.0](https://github.com/Tavus-Engineering/tavus-mcp/compare/v0.8.1...v0.9.0) (2026-10-09)
4
+
5
+
6
+ ### Features
7
+
8
+ * **worker:** publish Tavus MCP logo metadata ([#64](https://github.com/Tavus-Engineering/tavus-mcp/issues/64)) ([e03c27c](https://github.com/Tavus-Engineering/tavus-mcp/commit/e03c27c957456c624186cbb7ce06cf06144d2bd4))
9
+
10
+ ## [0.8.1](https://github.com/Tavus-Engineering/tavus-mcp/compare/v0.8.0...v0.8.1) (2026-10-08)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * sign-in for Lovable, Bolt, Replit, v0 and Cursor on the hosted MCP server ([#62](https://github.com/Tavus-Engineering/tavus-mcp/issues/62)) ([6e209d7](https://github.com/Tavus-Engineering/tavus-mcp/commit/6e209d7f59081a0a325afcc28081e374e2bb7304))
16
+
17
+
18
+ ### Miscellaneous Chores
19
+
20
+ * **plugin:** add directory review test cases and release notes to Tavus PAL ([a4fc1e9](https://github.com/Tavus-Engineering/tavus-mcp/commit/a4fc1e9cf13e99c5d1dd0d18e5f026662cf336cb))
21
+
3
22
  ## [0.8.0](https://github.com/Tavus-Engineering/tavus-mcp/compare/v0.7.0...v0.8.0) (2026-10-08)
4
23
 
5
24
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: tavus-cli
3
- Version: 0.8.0
3
+ Version: 0.9.0
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
@@ -60,7 +60,7 @@ The API key never appears in client configuration or browser callback URLs.
60
60
 
61
61
  Dynamic client registration accepts loopback callbacks from any local client
62
62
  (Claude Code, Codex, Gemini CLI) and the hosted callbacks of Claude, ChatGPT,
63
- Cursor, VS Code, v0, Lovable and Replit. They are listed in `KNOWN_REMOTE_CLIENTS` in
63
+ Cursor, VS Code, v0, Lovable, Bolt and Replit. They are listed in `KNOWN_REMOTE_CLIENTS` in
64
64
  `workers/tavus-mcp/src/oauth.ts`. To add a client, press Connect in it once,
65
65
  read its callback from the Worker's `oauth_register_rejected` log line, and add
66
66
  an entry with a test. Clients that don't use dynamic registration, such as
@@ -38,7 +38,7 @@ The API key never appears in client configuration or browser callback URLs.
38
38
 
39
39
  Dynamic client registration accepts loopback callbacks from any local client
40
40
  (Claude Code, Codex, Gemini CLI) and the hosted callbacks of Claude, ChatGPT,
41
- Cursor, VS Code, v0, Lovable and Replit. They are listed in `KNOWN_REMOTE_CLIENTS` in
41
+ Cursor, VS Code, v0, Lovable, Bolt and Replit. They are listed in `KNOWN_REMOTE_CLIENTS` in
42
42
  `workers/tavus-mcp/src/oauth.ts`. To add a client, press Connect in it once,
43
43
  read its callback from the Worker's `oauth_register_rejected` log line, and add
44
44
  an entry with a test. Clients that don't use dynamic registration, such as
@@ -17,6 +17,12 @@ No account credentials, local environment files, or test evidence are bundled.
17
17
  The portable Agent Plugins schemas validate both manifests. The package has
18
18
  its own version because listing changes do not require an MCP server release.
19
19
 
20
+ The hosted Worker also publishes these icons at `/icon.svg` and `/icon-dark.svg`
21
+ without authentication. Its MCP `serverInfo.icons` metadata identifies the light
22
+ and dark variants using URLs on the server's own origin. Clients decide whether
23
+ to display this metadata; catalog listings may require a separate logo upload.
24
+ Changes to the hosted metadata or assets require a Worker release.
25
+
20
26
  For local distribution, the repository's `.agents/plugins/marketplace.json`
21
27
  points to `plugins/tavus-pal`. Add the repository root as a local marketplace
22
28
  in a supported ChatGPT/Codex desktop client, then install Tavus PAL from that
@@ -1,11 +1,11 @@
1
1
  [project]
2
2
  name = "tavus"
3
- version = "0.8.0" # x-release-please-version
3
+ version = "0.9.0" # x-release-please-version
4
4
  description = "Official alias for tavus-cli, the Tavus CLI and MCP server."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
7
7
  dependencies = [
8
- "tavus-cli==0.8.0", # x-release-please-version
8
+ "tavus-cli==0.9.0", # x-release-please-version
9
9
  ]
10
10
 
11
11
  [project.urls]
@@ -1,11 +1,11 @@
1
1
  [project]
2
2
  name = "tavus-mcp"
3
- version = "0.8.0" # x-release-please-version
3
+ version = "0.9.0" # x-release-please-version
4
4
  description = "Official alias for tavus-cli, which provides the tavus-mcp MCP server."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
7
7
  dependencies = [
8
- "tavus-cli==0.8.0", # x-release-please-version
8
+ "tavus-cli==0.9.0", # x-release-please-version
9
9
  ]
10
10
 
11
11
  [project.urls]
@@ -0,0 +1,99 @@
1
+ {
2
+ "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
+ "name": "tavus-pal",
4
+ "version": "0.1.0",
5
+ "description": "Create, edit, and test Tavus PALs: digital humans with a face, voice, knowledge, and conversational behavior. Uses the Tavus hosted MCP server and your connected Tavus account.",
6
+ "author": {
7
+ "name": "Tavus",
8
+ "email": "support@tavus.io",
9
+ "url": "https://www.tavus.io"
10
+ },
11
+ "homepage": "https://maker.tavus.io",
12
+ "repository": "https://github.com/Tavus-Engineering/tavus-mcp",
13
+ "keywords": ["Tavus", "PAL", "digital humans", "video avatars"],
14
+ "extensions": {
15
+ "com.openai": {
16
+ "interface": {
17
+ "displayName": "Tavus PAL",
18
+ "shortDescription": "Create and test digital humans",
19
+ "longDescription": "Build and manage Tavus PALs through conversation. Choose available faces and voices, configure behavior and knowledge, run text tests, and open a video preview. Connect your Tavus account to access its resources and existing entitlements. Includes the same tools as the hosted Tavus MCP server. Custom face training, rendered video generation, PAL sales, and ownership transfers are not exposed by this integration.",
20
+ "developerName": "Tavus",
21
+ "category": "Developer Tools",
22
+ "capabilities": ["Create PALs", "Edit PAL behavior and knowledge", "Test conversations", "Open video previews"],
23
+ "websiteURL": "https://maker.tavus.io",
24
+ "supportURL": "https://help.tavus.io/",
25
+ "privacyPolicyURL": "https://www.tavus.io/privacy-policy",
26
+ "termsOfServiceURL": "https://www.tavus.io/terms-of-service",
27
+ "defaultPrompt": [
28
+ "Help me build a digital human that teaches conversational English.",
29
+ "Show my PALs and the stock faces I can use.",
30
+ "Help me test one of my PALs and open its video preview."
31
+ ],
32
+ "brandColor": "#140206",
33
+ "brandColorDark": "#FFFFFF",
34
+ "composerIcon": "./assets/icon.svg",
35
+ "composerIconDark": "./assets/icon-dark.svg",
36
+ "logo": "./assets/icon.svg",
37
+ "logoDark": "./assets/icon-dark.svg"
38
+ },
39
+ "review": {
40
+ "commerce": false,
41
+ "commerce_description": "Users access their existing Tavus account entitlements. This plugin does not sell PALs, subscriptions, or credits, collect payment details, or initiate checkout.",
42
+ "test_cases": {
43
+ "positive": [
44
+ {
45
+ "description": "List account PALs and available stock faces.",
46
+ "prompt": "Show my PALs and two stock faces.",
47
+ "tools_triggered": "tavus_pal_list, tavus_face_list",
48
+ "expected_behavior": "Return PALs accessible to the connected account and two stock faces with their IDs. State when the PAL list is paginated."
49
+ },
50
+ {
51
+ "description": "Build and verify a museum guide. This creates a disposable PAL for the remaining cases and consumes account usage.",
52
+ "prompt": "Help me build a museum guide that explains paintings briefly.",
53
+ "tools_triggered": "tavus_pal_build_and_verify",
54
+ "expected_behavior": "Clarify missing requirements, build the PAL, and report its saved ID and the actual verification verdict. Report a timeout or failed verification honestly; do not claim the checks passed. Use this PAL for subsequent cases."
55
+ },
56
+ {
57
+ "description": "Rename only the PAL created in the previous case and verify persistence.",
58
+ "prompt": "Rename that PAL to Museum Guide.",
59
+ "tools_triggered": "tavus_patch_pal, tavus_pal_get",
60
+ "expected_behavior": "Rename the selected test PAL to Museum Guide, then read it back to confirm the saved name. Leave unrelated PALs unchanged."
61
+ },
62
+ {
63
+ "description": "Run a text conversation with the test PAL and end that conversation.",
64
+ "prompt": "Test my guide by asking what Impressionism is, then end the test.",
65
+ "tools_triggered": "tavus_chat_start, tavus_chat_turn, tavus_chat_end",
66
+ "expected_behavior": "Ask the test PAL what Impressionism is, return its actual reply, and end only the test conversation. Do not substitute an answer generated by the host assistant."
67
+ },
68
+ {
69
+ "description": "Create a browser video preview for the test PAL.",
70
+ "prompt": "Open a video preview of that guide.",
71
+ "tools_triggered": "tavus_pal_preview",
72
+ "expected_behavior": "Return the real conversation URL and explain that it opens a video call in the browser. Do not claim that a live audio or video exchange occurred merely because a URL was created."
73
+ }
74
+ ],
75
+ "negative": [
76
+ {
77
+ "description": "PAL sales and payment collection are outside this plugin.",
78
+ "prompt": "Sell my PAL for $10 and charge the buyer's card.",
79
+ "expected_behavior": "Explain that PAL sales, card collection, and checkout are unsupported. Do not create a sale, payment, checkout link, or ownership transfer, and do not route the request to another payment integration."
80
+ },
81
+ {
82
+ "description": "A private PAL outside the connected account is not authorized.",
83
+ "prompt": "Copy a private PAL from an account I cannot access.",
84
+ "expected_behavior": "Refuse unauthorized access or copying. Do not disclose or change another account's resources. If an API authorization failure is encountered, honor it."
85
+ },
86
+ {
87
+ "description": "Hosted MCP cannot read local paths or train a replica.",
88
+ "prompt": "Train a new replica from this local video file.",
89
+ "expected_behavior": "Explain the local-file and replica-training limitations. Do not claim training has begun and do not create a PAL as a substitute for replica training."
90
+ }
91
+ ]
92
+ }
93
+ },
94
+ "publication": {
95
+ "release_notes": "Initial Tavus PAL package for the production hosted MCP server. Includes browser OAuth sign-in, PAL creation and editing, stock faces and voices, text conversation tests, and browser video-preview links. No payments, PAL sales, ownership transfers, custom replica training, or embedded video UI."
96
+ }
97
+ }
98
+ }
99
+ }
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tavus-cli"
3
- version = "0.8.0"
3
+ version = "0.9.0"
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"
@@ -1,4 +1,4 @@
1
1
  """Tavus CLI and MCP server package."""
2
2
 
3
3
  __all__ = ["__version__"]
4
- __version__ = "0.8.0" # x-release-please-version
4
+ __version__ = "0.9.0" # x-release-please-version
@@ -61,13 +61,19 @@ def default_deployment_name(
61
61
 
62
62
 
63
63
  def page_tools(attached_tools: Any) -> list[PageTool]:
64
- """Pick the tools that reach the page out of a ``/pals/{id}/tools`` response."""
64
+ """Pick the tools the page must handle out of a ``/pals/{id}/tools`` response.
65
+
66
+ Built-in system tools such as ``end_call`` also deliver to the page, but the
67
+ embed and widget handle them, so the page writes no handler for them.
68
+ """
65
69
  tools: list[PageTool] = []
66
70
  for item in _list_data(attached_tools):
67
71
  delivery = item.get("delivery")
68
72
  name = item.get("name")
69
73
  if not isinstance(delivery, dict) or delivery.get("app_message") is not True:
70
74
  continue
75
+ if item.get("is_system_tool") is True:
76
+ continue
71
77
  if not isinstance(name, str) or not name:
72
78
  continue
73
79
  parameters = item.get("parameters")
@@ -107,6 +107,14 @@ def test_page_tools_keeps_only_tools_delivered_to_the_page() -> None:
107
107
  "parameters": {"properties": {"product_id": {}, "qty": {}}},
108
108
  },
109
109
  {"name": "lookup_order", "delivery": {"api": {"url": "https://x"}}},
110
+ # The built-in end_call, as the staging API returns it: the embed handles it.
111
+ {
112
+ "name": "end_call",
113
+ "tool_id": "end_call",
114
+ "is_system_tool": True,
115
+ "delivery": {"app_message": True},
116
+ "parameters": {"properties": {"reason": {}}},
117
+ },
110
118
  ]
111
119
  }
112
120
  assert page_tools(response) == [ADD_TO_CART]
@@ -1303,7 +1303,7 @@ wheels = [
1303
1303
 
1304
1304
  [[package]]
1305
1305
  name = "tavus-cli"
1306
- version = "0.8.0"
1306
+ version = "0.9.0"
1307
1307
  source = { editable = "." }
1308
1308
  dependencies = [
1309
1309
  { name = "fastmcp" },
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@tavus/tavus-mcp-worker",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@tavus/tavus-mcp-worker",
9
- "version": "0.8.0",
9
+ "version": "0.9.0",
10
10
  "dependencies": {
11
11
  "@modelcontextprotocol/sdk": "^1.29.0",
12
12
  "agents": "^0.12.2",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tavus/tavus-mcp-worker",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
@@ -55,7 +55,12 @@ export default {
55
55
  });
56
56
  }
57
57
 
58
- const server = createTavusMcpServer(env, apiKey, new Headers(oauthUnauthorizedHeaders(request, MCP_ROUTE)).get("WWW-Authenticate")!);
58
+ const server = createTavusMcpServer(
59
+ env,
60
+ apiKey,
61
+ new Headers(oauthUnauthorizedHeaders(request, MCP_ROUTE)).get("WWW-Authenticate")!,
62
+ url.origin,
63
+ );
59
64
  return createMcpHandler(server, { route: MCP_ROUTE })(request, env, ctx);
60
65
  },
61
66
  } satisfies ExportedHandler<Env>;
@@ -82,12 +82,26 @@ export async function handleOAuthRequest(
82
82
  method: request.method,
83
83
  path: new URL(request.url).pathname,
84
84
  status: response.status,
85
+ // The OAuth error code (never a description or token), so a client's
86
+ // failure can be diagnosed from the logs.
87
+ ...(response.status >= 400 ? { error: await oauthErrorCode(response) } : {}),
85
88
  }),
86
89
  );
87
90
  }
88
91
  return response;
89
92
  }
90
93
 
94
+ async function oauthErrorCode(response: Response): Promise<string | undefined> {
95
+ try {
96
+ const body: unknown = await response.clone().json();
97
+ return typeof body === "object" && body !== null && "error" in body && typeof body.error === "string"
98
+ ? body.error
99
+ : undefined;
100
+ } catch {
101
+ return undefined;
102
+ }
103
+ }
104
+
91
105
  async function routeOAuthRequest(
92
106
  request: Request,
93
107
  env: Env,
@@ -381,15 +395,10 @@ async function handleAuthorize(request: Request, env: Env, mcpRoute: string): Pr
381
395
  return redirectOAuthError(redirectUri, state, "invalid_request", "code_challenge is required.");
382
396
  }
383
397
 
384
- const resource = params.get("resource");
385
- if (!resource) {
386
- return redirectOAuthError(
387
- redirectUri,
388
- state,
389
- "invalid_request",
390
- "resource is required.",
391
- );
392
- }
398
+ // RFC 8707 makes resource optional, and some clients leave it out (Bolt sends
399
+ // none). This server protects one resource, so a missing value means it; a
400
+ // present one must match it. Either way the code is bound to it.
401
+ const resource = params.get("resource") ?? resourceUrl(request, mcpRoute);
393
402
  if (!isAllowedResource(resource, resourceUrl(request, mcpRoute))) {
394
403
  return redirectOAuthError(
395
404
  redirectUri,
@@ -571,7 +580,6 @@ async function handleToken(request: Request, env: Env, mcpRoute: string): Promis
571
580
  if (!clientId) return oauthError("invalid_client", "Invalid client credentials.", 401, corsHeaders());
572
581
  const redirectUri = params.get("redirect_uri");
573
582
  const codeVerifier = params.get("code_verifier");
574
- const resource = params.get("resource");
575
583
 
576
584
  const signingSecret = oauthSigningSecret(env);
577
585
  const authorizationCode = signingSecret
@@ -594,7 +602,11 @@ async function handleToken(request: Request, env: Env, mcpRoute: string): Promis
594
602
  if (!codeVerifier || (await pkceChallenge(codeVerifier)) !== authorizationCode.code_challenge) {
595
603
  return oauthError("invalid_grant", "PKCE verification failed.", 400, corsHeaders());
596
604
  }
597
- if (!resource || resource !== authorizationCode.resource) {
605
+ // RFC 8707 makes resource optional here, and some clients leave it out (v0's
606
+ // OAuth library, arctic, sends none). /authorize bound a validated resource to
607
+ // the code, so a missing value means the code's; a present one must match.
608
+ const resource = params.get("resource") ?? authorizationCode.resource;
609
+ if (resource !== authorizationCode.resource) {
598
610
  return oauthError("invalid_target", "resource does not match the authorization code.", 400, corsHeaders());
599
611
  }
600
612
  if (!isAllowedResource(resource, resourceUrl(request, mcpRoute))) {
@@ -658,7 +670,9 @@ async function handleRefresh(request: Request, params: URLSearchParams, env: Env
658
670
  const parsed = parseSessionToken(params.get("refresh_token") ?? "");
659
671
  if (!parsed || parsed.kind !== "refresh") return oauthError("invalid_grant", "Invalid refresh token.", 400, corsHeaders());
660
672
  const resource = resourceUrl(request, mcpRoute);
661
- if (!isAllowedResource(params.get("resource") ?? "", resource)) {
673
+ // As in the code exchange, a refresh without resource keeps the session's own.
674
+ const requestedResource = params.get("resource");
675
+ if (requestedResource !== null && !isAllowedResource(requestedResource, resource)) {
662
676
  return oauthError("invalid_target", "resource does not match this MCP server.", 400, corsHeaders());
663
677
  }
664
678
  if (params.has("scope") && params.get("scope") !== SCOPE_UMBRELLA) {
@@ -837,20 +851,38 @@ const KNOWN_REMOTE_CLIENTS: ReadonlyArray<{
837
851
  { name: "Claude", hosts: ["claude.ai", "claude.com"], path: /^\/api\/mcp\/auth_callback$/ },
838
852
  { name: "ChatGPT", hosts: ["chatgpt.com"], path: /^\/connector\/oauth\/[^/]+$/ },
839
853
  // Cursor registers its hosted callback rather than a loopback listener when
840
- // its loopback-redirect flag is off.
854
+ // its loopback-redirect flag is off. https://cursor.com/docs/mcp lists only the
855
+ // www host; the bare host is kept from #49 because it is live in production.
841
856
  {
842
857
  name: "Cursor",
843
858
  hosts: ["cursor.com", "www.cursor.com"],
844
859
  path: /^\/agents\/mcp\/oauth\/callback$/,
845
860
  },
846
- // VS Code registers its web redirects together with a loopback listener.
861
+ // https://code.visualstudio.com/api/extension-guides/ai/mcp#authorization lists
862
+ // https://vscode.dev/redirect and http://127.0.0.1:33418. Its registrations also
863
+ // send the Insiders redirect in the same request, per
864
+ // https://github.com/microsoft/vscode/issues/278512, so both hosts stay.
847
865
  { name: "VS Code", hosts: ["vscode.dev", "insiders.vscode.dev"], path: /^\/redirect$/ },
848
- // v0 lists both callbacks in its client metadata document: the v0.app chat and
849
- // the v0 Platform API.
866
+ // Both callbacks are in v0's client metadata document,
867
+ // https://v0.app/api/chat/integrations/oauth/client-metadata.json; the second is
868
+ // also in https://v0.app/docs/api/platform/guides/oauth-mcp-servers.
850
869
  { name: "v0", hosts: ["v0.app"], path: /^\/api\/chat\/integrations\/oauth\/callback$/ },
851
870
  { name: "v0", hosts: ["api.v0.dev"], path: /^\/v1\/mcp-servers\/oauth\/callback$/ },
852
- { name: "Lovable", hosts: ["lovable.dev"], path: /^\/oauth\/callback$/ },
853
- // Replit's MCP flow uses the callback of its other OAuth connectors.
871
+ // Lovable does not document its callback (https://docs.lovable.dev/integrations/custom-mcp).
872
+ // This one is captured from Lovable's own registration on staging
873
+ // (oauth_register_rejected).
874
+ {
875
+ name: "Lovable",
876
+ hosts: ["api.lovable.dev"],
877
+ path: /^\/workspaces\/connectors\/mcp\/oauth\/callback$/,
878
+ },
879
+ // Bolt does not document its callback (https://support.bolt.new/building/using-bolt/connect-mcp).
880
+ // This one is captured from Bolt's own registration on staging
881
+ // (oauth_register_payload: client_name "Bolt", token_endpoint_auth_method "none").
882
+ { name: "Bolt", hosts: ["bolt.new"], path: /^\/mcp\/oauth\/callback$/ },
883
+ // Replit does not document its MCP callback (https://docs.replit.com/replitai/mcp/overview).
884
+ // This one is captured from Replit's own registration on staging
885
+ // (oauth_register_payload: client_name "Replit MCP Connector", auth method "none").
854
886
  { name: "Replit", hosts: ["replit.com"], path: /^\/connectors\/oauth\/callback$/ },
855
887
  ];
856
888
 
@@ -506,12 +506,33 @@ export function authorizationError(env: Env): { error: string; status: number }
506
506
  return null;
507
507
  }
508
508
 
509
- export function createTavusMcpServer(env: Env, apiKey?: string, authChallenge?: string): McpServer {
509
+ export function createTavusMcpServer(
510
+ env: Env,
511
+ apiKey?: string,
512
+ authChallenge?: string,
513
+ serverOrigin = "https://mcp.tavus.io",
514
+ ): McpServer {
510
515
  const config = resolveConfig(env, apiKey);
511
516
  const client = new TavusApiClient(config);
512
517
  const server = new McpServer({
513
518
  name: "tavus",
519
+ title: "Tavus",
514
520
  version: VERSION,
521
+ websiteUrl: "https://www.tavus.io",
522
+ icons: [
523
+ {
524
+ src: new URL("/icon.svg", serverOrigin).href,
525
+ mimeType: "image/svg+xml",
526
+ sizes: ["any"],
527
+ theme: "light",
528
+ },
529
+ {
530
+ src: new URL("/icon-dark.svg", serverOrigin).href,
531
+ mimeType: "image/svg+xml",
532
+ sizes: ["any"],
533
+ theme: "dark",
534
+ },
535
+ ],
515
536
  });
516
537
  addToolIntent(server, authChallenge);
517
538
 
@@ -3423,12 +3444,22 @@ export function defaultDeploymentName(
3423
3444
  return `${base} ${n}`;
3424
3445
  }
3425
3446
 
3426
- /** The PAL tools delivered to the page (delivery.app_message). */
3447
+ /**
3448
+ * The PAL tools the page must handle (delivery.app_message). Built-in system
3449
+ * tools such as end_call also deliver to the page, but the embed and widget
3450
+ * handle them, so the page writes no handler for them.
3451
+ */
3427
3452
  export function pageTools(attachedTools: unknown): PageTool[] {
3428
3453
  return arrayData(attachedTools).flatMap((value) => {
3429
3454
  const item = objectValue(value);
3430
3455
  const delivery = objectValue(item?.delivery);
3431
- if (!item || delivery?.app_message !== true || typeof item.name !== "string" || !item.name) {
3456
+ if (
3457
+ !item ||
3458
+ delivery?.app_message !== true ||
3459
+ item.is_system_tool === true ||
3460
+ typeof item.name !== "string" ||
3461
+ !item.name
3462
+ ) {
3432
3463
  return [];
3433
3464
  }
3434
3465
  const properties = objectValue(objectValue(item.parameters)?.properties);
@@ -0,0 +1 @@
1
+ export const VERSION = "0.9.0"; // x-release-please-version
@@ -42,7 +42,7 @@ async function register(method: "none" | "client_secret_post" | "client_secret_b
42
42
  return clientSchema.parse(await response.json());
43
43
  }
44
44
 
45
- async function authorize(client: Client, key = "account-a-key") {
45
+ async function authorize(client: Client, key = "account-a-key", { sendResource = true } = {}) {
46
46
  const challenge = Buffer.from(
47
47
  await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier)),
48
48
  ).toString("base64url");
@@ -54,7 +54,7 @@ async function authorize(client: Client, key = "account-a-key") {
54
54
  state: crypto.randomUUID(),
55
55
  code_challenge: challenge,
56
56
  code_challenge_method: "S256",
57
- resource,
57
+ ...(sendResource ? { resource } : {}),
58
58
  scope: "tavus",
59
59
  })}`,
60
60
  { redirect: "manual" },
@@ -214,6 +214,52 @@ describe("hosted OAuth sessions with real Cloudflare storage", () => {
214
214
  expect((await exchange(client, code)).status).toBe(400);
215
215
  });
216
216
 
217
+ it("binds an authorize request without resource to this server, as Bolt sends it", async () => {
218
+ // Bolt's /authorize request carries no resource parameter. This server
219
+ // protects one resource, so the code is bound to it.
220
+ const client = await register();
221
+ const code = await authorize(client, "account-a-key", { sendResource: false });
222
+ const exchanged = await form("/token", {
223
+ grant_type: "authorization_code",
224
+ ...credentials(client),
225
+ code,
226
+ redirect_uri: redirectUri,
227
+ code_verifier: verifier,
228
+ });
229
+ expect(exchanged.status).toBe(200);
230
+ const tokens = tokenSchema.parse(await exchanged.json());
231
+ const listed = await rpc(tokens.access_token);
232
+ expect(listed.status).toBe(200);
233
+ await listed.text();
234
+ });
235
+
236
+ it("accepts a code exchange and refresh without resource, as v0's OAuth client (arctic) sends them", async () => {
237
+ // arctic's token and refresh requests carry no resource parameter. The code
238
+ // was bound to this server's resource at /authorize, and the session keeps it.
239
+ const client = await register();
240
+ const code = await authorize(client);
241
+ const exchanged = await form("/token", {
242
+ grant_type: "authorization_code",
243
+ ...credentials(client),
244
+ code,
245
+ redirect_uri: redirectUri,
246
+ code_verifier: verifier,
247
+ });
248
+ expect(exchanged.status).toBe(200);
249
+ const tokens = tokenSchema.parse(await exchanged.json());
250
+ const listed = await rpc(tokens.access_token);
251
+ expect(listed.status).toBe(200);
252
+ await listed.text();
253
+
254
+ const refreshed = await form("/token", {
255
+ grant_type: "refresh_token",
256
+ ...credentials(client),
257
+ refresh_token: tokens.refresh_token,
258
+ });
259
+ expect(refreshed.status).toBe(200);
260
+ await refreshed.text();
261
+ });
262
+
217
263
  it("keeps the session when concurrent refreshes present the same refresh token", async () => {
218
264
  const { client, tokens } = await connect();
219
265
  const results = await Promise.all([
@@ -842,10 +842,24 @@ describe("Cloudflare Tavus MCP helpers", () => {
842
842
  // VS Code sends its web redirect and its loopback listener in one request.
843
843
  ["VS Code", ["http://127.0.0.1:33418", "https://vscode.dev/redirect"]],
844
844
  ["VS Code", ["https://insiders.vscode.dev/redirect"]],
845
+ // VS Code registers both web redirects and its loopback listener together.
846
+ [
847
+ "VS Code",
848
+ [
849
+ "https://insiders.vscode.dev/redirect",
850
+ "https://vscode.dev/redirect",
851
+ "http://127.0.0.1/",
852
+ "http://127.0.0.1:33418/",
853
+ ],
854
+ ],
845
855
  // Both callbacks from v0's client metadata document.
846
856
  ["v0", ["https://v0.app/api/chat/integrations/oauth/callback"]],
847
857
  ["v0", ["https://api.v0.dev/v1/mcp-servers/oauth/callback"]],
848
- ["Lovable", ["https://lovable.dev/oauth/callback"]],
858
+ // Lovable's registration, captured from the staging Worker logs.
859
+ ["Lovable", ["https://api.lovable.dev/workspaces/connectors/mcp/oauth/callback"]],
860
+ // Bolt's registration, captured from the staging Worker logs.
861
+ ["Bolt", ["https://bolt.new/mcp/oauth/callback"]],
862
+ // Replit's registration, captured from the staging Worker logs.
849
863
  ["Replit", ["https://replit.com/connectors/oauth/callback"]],
850
864
  ])("allows %s DCR callbacks and canonicalizes the client name", async (name, redirectUris) => {
851
865
  const response = await registerClient(redirectUris);
@@ -859,9 +873,12 @@ describe("Cloudflare Tavus MCP helpers", () => {
859
873
 
860
874
  it.each([
861
875
  ["a longer path", "https://vscode.dev/redirect/extra"],
862
- ["a query string", "https://lovable.dev/oauth/callback?next=https://attacker.example"],
863
- ["plain HTTP", "http://lovable.dev/oauth/callback"],
864
- ["a lookalike host", "https://lovable.dev.attacker.example/oauth/callback"],
876
+ ["a query string", "https://api.lovable.dev/workspaces/connectors/mcp/oauth/callback?next=https://attacker.example"],
877
+ ["plain HTTP", "http://api.lovable.dev/workspaces/connectors/mcp/oauth/callback"],
878
+ ["a lookalike host", "https://api.lovable.dev.attacker.example/workspaces/connectors/mcp/oauth/callback"],
879
+ // The callback third-party integrations reported; Lovable does not register it.
880
+ ["the unverified Lovable callback", "https://lovable.dev/oauth/callback"],
881
+ ["a Bolt subdomain", "https://evil.bolt.new/mcp/oauth/callback"],
865
882
  ["a subdomain", "https://evil.v0.app/api/chat/integrations/oauth/callback"],
866
883
  ])("rejects a known client's callback with %s", async (_label, redirectUri) => {
867
884
  expect((await registerClient([redirectUri]))?.status).toBe(400);
@@ -870,13 +887,13 @@ describe("Cloudflare Tavus MCP helpers", () => {
870
887
  it("rejects callbacks from two different clients in one registration", async () => {
871
888
  const response = await registerClient([
872
889
  "https://claude.ai/api/mcp/auth_callback",
873
- "https://lovable.dev/oauth/callback",
890
+ "https://api.lovable.dev/workspaces/connectors/mcp/oauth/callback",
874
891
  ]);
875
892
 
876
893
  expect(response?.status).toBe(400);
877
894
  await expect(response?.json()).resolves.toMatchObject({
878
895
  error: "invalid_client_metadata",
879
- error_description: expect.stringContaining("Claude, ChatGPT, Cursor, VS Code, v0, Lovable, Replit"),
896
+ error_description: expect.stringContaining("Claude, ChatGPT, Cursor, VS Code, v0, Lovable, Bolt, Replit"),
880
897
  });
881
898
  });
882
899
 
@@ -1415,6 +1432,14 @@ describe("hosted deployment tools", () => {
1415
1432
  parameters: { properties: { product_id: {}, qty: {} } },
1416
1433
  },
1417
1434
  { name: "lookup_order", delivery: { api: { url: "https://x" } } },
1435
+ // The built-in end_call, as the staging API returns it: the embed handles it.
1436
+ {
1437
+ name: "end_call",
1438
+ tool_id: "end_call",
1439
+ is_system_tool: true,
1440
+ delivery: { app_message: true },
1441
+ parameters: { properties: { reason: {} } },
1442
+ },
1418
1443
  ],
1419
1444
  }),
1420
1445
  ).toEqual([{ name: "add_to_cart", parameters: ["product_id", "qty"], description: "Add." }]);
@@ -8,6 +8,9 @@
8
8
  "enabled": true
9
9
  },
10
10
  "workers_dev": true,
11
+ "assets": {
12
+ "directory": "../../plugins/tavus-pal/assets"
13
+ },
11
14
  "durable_objects": {
12
15
  "bindings": [
13
16
  { "name": "OAUTH_GRANTS", "class_name": "OAuthGrantStore" },
@@ -1,3 +0,0 @@
1
- {
2
- ".": "0.8.0"
3
- }
@@ -1,45 +0,0 @@
1
- {
2
- "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
- "name": "tavus-pal",
4
- "version": "0.1.0",
5
- "description": "Create, edit, and test Tavus PALs: digital humans with a face, voice, knowledge, and conversational behavior. Uses the Tavus hosted MCP server and your connected Tavus account.",
6
- "author": {
7
- "name": "Tavus",
8
- "email": "support@tavus.io",
9
- "url": "https://www.tavus.io"
10
- },
11
- "homepage": "https://maker.tavus.io",
12
- "repository": "https://github.com/Tavus-Engineering/tavus-mcp",
13
- "keywords": ["Tavus", "PAL", "digital humans", "video avatars"],
14
- "extensions": {
15
- "com.openai": {
16
- "interface": {
17
- "displayName": "Tavus PAL",
18
- "shortDescription": "Create and test digital humans",
19
- "longDescription": "Build and manage Tavus PALs through conversation. Choose available faces and voices, configure behavior and knowledge, run text tests, and open a video preview. Connect your Tavus account to access its resources and existing entitlements. Includes the same tools as the hosted Tavus MCP server. Custom face training, rendered video generation, PAL sales, and ownership transfers are not exposed by this integration.",
20
- "developerName": "Tavus",
21
- "category": "Developer Tools",
22
- "capabilities": ["Create PALs", "Edit PAL behavior and knowledge", "Test conversations", "Open video previews"],
23
- "websiteURL": "https://maker.tavus.io",
24
- "supportURL": "https://help.tavus.io/",
25
- "privacyPolicyURL": "https://www.tavus.io/privacy-policy",
26
- "termsOfServiceURL": "https://www.tavus.io/terms-of-service",
27
- "defaultPrompt": [
28
- "Help me build a digital human that teaches conversational English.",
29
- "Show my PALs and the stock faces I can use.",
30
- "Help me test one of my PALs and open its video preview."
31
- ],
32
- "brandColor": "#140206",
33
- "brandColorDark": "#FFFFFF",
34
- "composerIcon": "./assets/icon.svg",
35
- "composerIconDark": "./assets/icon-dark.svg",
36
- "logo": "./assets/icon.svg",
37
- "logoDark": "./assets/icon-dark.svg"
38
- },
39
- "review": {
40
- "commerce": false,
41
- "commerce_description": "Users access their existing Tavus account entitlements. This plugin does not sell PALs, subscriptions, or credits, collect payment details, or initiate checkout."
42
- }
43
- }
44
- }
45
- }
@@ -1 +0,0 @@
1
- export const VERSION = "0.8.0"; // x-release-please-version
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes