tavus-cli 0.9.0__tar.gz → 0.9.2__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 (117) hide show
  1. tavus_cli-0.9.2/.release-please-manifest.json +3 -0
  2. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/CHANGELOG.md +14 -0
  3. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/PKG-INFO +9 -2
  4. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/PROMPT.md +2 -0
  5. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/README.md +8 -1
  6. tavus_cli-0.9.2/docs/builder-guidance.md +41 -0
  7. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/packages/tavus/pyproject.toml +2 -2
  8. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/packages/tavus-mcp/pyproject.toml +2 -2
  9. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/pyproject.toml +1 -1
  10. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/skills/tavus-agentic-pals/SKILL.md +15 -0
  11. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/__init__.py +1 -1
  12. tavus_cli-0.9.2/src/tavus_mcp/builder_guidance.json +21 -0
  13. tavus_cli-0.9.2/src/tavus_mcp/builder_guidance.py +9 -0
  14. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/recipes/capabilities.py +3 -2
  15. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/server.py +5 -19
  16. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/tests/integration/test_mcp_server.py +52 -0
  17. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/uv.lock +1 -1
  18. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/workers/tavus-mcp/package-lock.json +2 -2
  19. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/workers/tavus-mcp/package.json +1 -1
  20. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/workers/tavus-mcp/src/oauth.ts +3 -0
  21. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/workers/tavus-mcp/src/tavus.ts +7 -6
  22. tavus_cli-0.9.2/workers/tavus-mcp/src/version.ts +1 -0
  23. tavus_cli-0.9.2/workers/tavus-mcp/test/builder-guidance.test.ts +84 -0
  24. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/workers/tavus-mcp/test/tavus.test.ts +6 -1
  25. tavus_cli-0.9.0/.release-please-manifest.json +0 -3
  26. tavus_cli-0.9.0/workers/tavus-mcp/src/version.ts +0 -1
  27. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/.agents/plugins/marketplace.json +0 -0
  28. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/.env.example +0 -0
  29. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/.github/workflows/ci.yml +0 -0
  30. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/.github/workflows/deploy-cloudflare-worker.yml +0 -0
  31. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/.github/workflows/pr-reviews.yml +0 -0
  32. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/.github/workflows/pypi-cli.yml +0 -0
  33. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/.github/workflows/tail-cloudflare-worker.yml +0 -0
  34. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/.github/workflows/validate-staging-deployment.yml +0 -0
  35. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/.gitignore +0 -0
  36. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/AGENTS.md +0 -0
  37. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/docs/chatgpt-plugin.md +0 -0
  38. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/docs/gemini-enterprise/README.md +0 -0
  39. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/docs/gemini-enterprise/listing.md +0 -0
  40. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/docs/gemini-enterprise/test-queries.md +0 -0
  41. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/docs/usage-observability.md +0 -0
  42. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/packages/tavus/README.md +0 -0
  43. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/packages/tavus-mcp/README.md +0 -0
  44. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/plugins/tavus-pal/assets/icon-dark.svg +0 -0
  45. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/plugins/tavus-pal/assets/icon.svg +0 -0
  46. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/plugins/tavus-pal/mcp.json +0 -0
  47. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/plugins/tavus-pal/plugin.json +0 -0
  48. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/release-please-config.json +0 -0
  49. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/scripts/__init__.py +0 -0
  50. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/scripts/build_chatgpt_plugin.py +0 -0
  51. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/scripts/check_release_versions.py +0 -0
  52. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/skills/tavus-agentic-pals/agents/openai.yaml +0 -0
  53. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/skills/tavus-agentic-pals/references/build-and-verify.md +0 -0
  54. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/skills/tavus-agentic-pals/references/builder-workflow.md +0 -0
  55. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/skills/tavus-agentic-pals/references/chat-mode.md +0 -0
  56. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/skills/tavus-agentic-pals/references/examples.md +0 -0
  57. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/cli/__init__.py +0 -0
  58. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/cli/main.py +0 -0
  59. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/__init__.py +0 -0
  60. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/auth/__init__.py +0 -0
  61. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/auth/keyring_store.py +0 -0
  62. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/auth/oauth.py +0 -0
  63. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/auth/session.py +0 -0
  64. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/client/__init__.py +0 -0
  65. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/client/http.py +0 -0
  66. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/daily_transport.py +0 -0
  67. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/env.py +0 -0
  68. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/errors.py +0 -0
  69. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/pal_urls.py +0 -0
  70. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/patch.py +0 -0
  71. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/recipes/__init__.py +0 -0
  72. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/recipes/build_and_verify.py +0 -0
  73. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/recipes/carrier_builder.py +0 -0
  74. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/recipes/deployments.py +0 -0
  75. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/recipes/knowledge.py +0 -0
  76. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/recipes/options.py +0 -0
  77. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/recipes/quickstart.py +0 -0
  78. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/recipes/scaffold_embed.py +0 -0
  79. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/recipes/templates.py +0 -0
  80. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/recipes/tool_reuse.py +0 -0
  81. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/schemas/__init__.py +0 -0
  82. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/schemas/deployment.py +0 -0
  83. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/schemas/file_manifest.py +0 -0
  84. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/schemas/guardrail.py +0 -0
  85. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/schemas/objective.py +0 -0
  86. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/schemas/pal.py +0 -0
  87. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/schemas/pronunciation.py +0 -0
  88. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/src/tavus_mcp/sdk/schemas/tool.py +0 -0
  89. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/tests/conftest.py +0 -0
  90. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/tests/integration/test_cli.py +0 -0
  91. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/tests/integration/test_client.py +0 -0
  92. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/tests/integration/test_oauth.py +0 -0
  93. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/tests/unit/test_auth.py +0 -0
  94. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/tests/unit/test_build_and_verify.py +0 -0
  95. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/tests/unit/test_builder.py +0 -0
  96. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/tests/unit/test_capabilities.py +0 -0
  97. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/tests/unit/test_daily_transport.py +0 -0
  98. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/tests/unit/test_deployments.py +0 -0
  99. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/tests/unit/test_env.py +0 -0
  100. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/tests/unit/test_guardrail_schema.py +0 -0
  101. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/tests/unit/test_objective_schema.py +0 -0
  102. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/tests/unit/test_pal_schema.py +0 -0
  103. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/tests/unit/test_patch.py +0 -0
  104. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/tests/unit/test_pronunciation_schema.py +0 -0
  105. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/tests/unit/test_release_versions.py +0 -0
  106. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/tests/unit/test_scaffold_embed.py +0 -0
  107. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/tests/unit/test_tool_reuse.py +0 -0
  108. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/tests/unit/test_tool_schema.py +0 -0
  109. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/workers/tavus-mcp/.dev.vars.example +0 -0
  110. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/workers/tavus-mcp/src/index.ts +0 -0
  111. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/workers/tavus-mcp/src/oauth-grant.ts +0 -0
  112. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/workers/tavus-mcp/src/oauth-session.ts +0 -0
  113. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/workers/tavus-mcp/test/oauth-session.test.ts +0 -0
  114. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/workers/tavus-mcp/test/parity.test.ts +0 -0
  115. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/workers/tavus-mcp/test/worker-runtime.ts +0 -0
  116. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/workers/tavus-mcp/tsconfig.json +0 -0
  117. {tavus_cli-0.9.0 → tavus_cli-0.9.2}/workers/tavus-mcp/wrangler.jsonc +0 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.9.2"
3
+ }
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.9.2](https://github.com/Tavus-Engineering/tavus-mcp/compare/v0.9.1...v0.9.2) (2026-10-10)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * align MCP capability guidance with Charlie builder ([#68](https://github.com/Tavus-Engineering/tavus-mcp/issues/68)) ([c7a903d](https://github.com/Tavus-Engineering/tavus-mcp/commit/c7a903d08bc4f355a75d892924c1656e2c43caf4))
9
+
10
+ ## [0.9.1](https://github.com/Tavus-Engineering/tavus-mcp/compare/v0.9.0...v0.9.1) (2026-10-09)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **worker:** allow Vercel Connect OAuth registration ([#66](https://github.com/Tavus-Engineering/tavus-mcp/issues/66)) ([2ed7925](https://github.com/Tavus-Engineering/tavus-mcp/commit/2ed7925183e726f6a2614adeb6ca75257d2d78b1))
16
+
3
17
  ## [0.9.0](https://github.com/Tavus-Engineering/tavus-mcp/compare/v0.8.1...v0.9.0) (2026-10-09)
4
18
 
5
19
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: tavus-cli
3
- Version: 0.9.0
3
+ Version: 0.9.2
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, Bolt and Replit. They are listed in `KNOWN_REMOTE_CLIENTS` in
63
+ Cursor, VS Code, v0, Vercel Connect, 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
@@ -328,6 +328,13 @@ administration tools, and two tools that keep backward-compatible local names
328
328
  locally; `tavus_pal_capabilities_catalog` / `tavus_pal_knowledge_settings`
329
329
  hosted).
330
330
 
331
+ Both servers load their builder instructions and capability-selection guidance
332
+ from [builder_guidance.json](src/tavus_mcp/builder_guidance.json). These rules
333
+ adapt Charlie's builder prompt to the MCP tools, including using Magic Canvas
334
+ for on-screen scorecards instead of creating a saved tool. See
335
+ [maintaining builder guidance](docs/builder-guidance.md) for the source and
336
+ behavior checks.
337
+
331
338
  ### Deploys and releases
332
339
 
333
340
  Merges to `main` automatically build, test, deploy, and smoke-test the `stg`
@@ -28,6 +28,8 @@ How the server works
28
28
  - Everything on a PAL is a resource with an id: faces, voices, guardrails, objectives, Knowledge documents, tools. Get ids from the matching list call (`tavus_face_list`, `tavus_voice_list`, `tavus_guardrail_list`, `tavus_objective_list`, `tavus_document_list`, `tavus_tool_list`) or from `tavus_describe_pal_options`, which returns one PAL with everything attachable to it.
29
29
  - Tools are first-class records. A tool is created once with `tavus_tool_create` and attached with `tavus_pal_tools_attach`. Writing tools inline under `layers.llm.tools` is rejected.
30
30
  - The five PAL Maker capabilities (Magic Canvas, Slide Presenter, Web Search, Perception, Memory) go through `tavus_pal_capability_attach`, `tavus_pal_capability_patch` and `tavus_pal_capability_detach`, not raw patches.
31
+ - Choose built-ins by intent before creating tools. On-screen scorecards, quizzes, forms, charts, and links use Magic Canvas. Attach `magic_canvas` with the needed `magic_canvas_components` and `magic_canvas_usage_guidance` together. For a training scorecard, use `text` and/or `chart`; keep display choreography in the capability's usage guidance. A saved tool or API response cannot render the canvas. Saving results to a backend is a separate action and requires a real endpoint or implemented handler. Do not invent a delivery tool when only display or collection is needed. If I have not requested on-screen interaction, offer it once and wait for agreement.
32
+ - Use Web Search for live weather, news, prices, and scores; Slide Presenter for an uploaded deck; Perception for screen and camera awareness; Memory for returning participants. Do not replace these with custom tools. After configuration, read `tavus_pal_capabilities_list` to verify the attachment. Successful saving or text testing does not prove that a card rendered; check the live display before claiming that.
31
33
  - Every conversation is billed like any other, including the build's own test turns, chat-mode tests and previews.
32
34
 
33
35
  How to do the common things properly
@@ -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, Bolt and Replit. They are listed in `KNOWN_REMOTE_CLIENTS` in
41
+ Cursor, VS Code, v0, Vercel Connect, 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
@@ -306,6 +306,13 @@ administration tools, and two tools that keep backward-compatible local names
306
306
  locally; `tavus_pal_capabilities_catalog` / `tavus_pal_knowledge_settings`
307
307
  hosted).
308
308
 
309
+ Both servers load their builder instructions and capability-selection guidance
310
+ from [builder_guidance.json](src/tavus_mcp/builder_guidance.json). These rules
311
+ adapt Charlie's builder prompt to the MCP tools, including using Magic Canvas
312
+ for on-screen scorecards instead of creating a saved tool. See
313
+ [maintaining builder guidance](docs/builder-guidance.md) for the source and
314
+ behavior checks.
315
+
309
316
  ### Deploys and releases
310
317
 
311
318
  Merges to `main` automatically build, test, deploy, and smoke-test the `stg`
@@ -0,0 +1,41 @@
1
+ # Maintaining builder guidance
2
+
3
+ Both MCP servers load `src/tavus_mcp/builder_guidance.json`. It supplies the
4
+ instructions returned during MCP initialization, guidance on the create-tool
5
+ and capability tools, and the Magic Canvas catalog description. The JSON ships
6
+ inside the Python package and is bundled into the hosted Worker.
7
+
8
+ The rules are adapted from `src/constants/builder.constants.ts` in
9
+ `Tavus/developer-portal`, inspected at commit
10
+ `dd5ad35b3` on October 9, 2026. The relevant sections are the on-screen
11
+ interaction offer, built-in capabilities, saved tools, and the Magic Canvas
12
+ capability catalog. When Charlie's rules change, review this shared file and
13
+ the companion instructions in `PROMPT.md` and `skills/tavus-agentic-pals/SKILL.md`.
14
+
15
+ Use MCP tool names and parameters when adapting Charlie's rules. Do not copy
16
+ Portal-only tool names, UI instructions, or capabilities this server cannot
17
+ configure. In particular, the hosted attach tool takes `capability`, while the
18
+ local tool takes `capability_id`.
19
+
20
+ ## Behavior checks
21
+
22
+ Use these prompts to evaluate capability selection with an MCP client:
23
+
24
+ | Request | Expected behavior |
25
+ | --- | --- |
26
+ | Show a training scorecard after each exercise. | Attach Magic Canvas with `text` and/or `chart` and usage guidance in the same call. Do not create `record_training_scorecard`. |
27
+ | Collect an email address on screen. We have no backend yet. | Attach Magic Canvas with `input`. Explain that delivery can be connected later. Do not invent an endpoint. |
28
+ | Show the score and save it to our existing API. | Configure Magic Canvas for display and separately reuse or create a tool for the verified API. |
29
+ | Ask quiz questions and keep a running score. | Use `question` plus `text` or `chart`; the model supplies questions and scores. |
30
+ | Tell callers the current weather. | Attach Web Search and write location-first lookup instructions. Do not create `get_weather`. |
31
+ | Walk through this uploaded slide deck automatically. | Attach Slide Presenter with the document IDs and `walk_the_deck`. |
32
+ | Notice what I share on screen. | Configure Perception. Do not create `view_screen`. |
33
+ | Remember returning visitors. | Attach Memory and add a first-visit fallback in the prompt and greeting. |
34
+ | Do not show anything on screen. | Respect the decline; do not attach Magic Canvas. |
35
+
36
+ The automated tests verify that clients receive the shared guidance and that
37
+ the scorecard configuration travels through the MCP tools to the skills API and
38
+ back, using a mocked API. They do not evaluate a model's tool choice or prove
39
+ live rendering. For a live evaluation, record the model's tool calls, read back
40
+ the saved capability, and inspect the canvas during a call before claiming the
41
+ scorecard displayed.
@@ -1,11 +1,11 @@
1
1
  [project]
2
2
  name = "tavus"
3
- version = "0.9.0" # x-release-please-version
3
+ version = "0.9.2" # 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.9.0", # x-release-please-version
8
+ "tavus-cli==0.9.2", # 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.9.0" # x-release-please-version
3
+ version = "0.9.2" # 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.9.0", # x-release-please-version
8
+ "tavus-cli==0.9.2", # x-release-please-version
9
9
  ]
10
10
 
11
11
  [project.urls]
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tavus-cli"
3
- version = "0.9.0"
3
+ version = "0.9.2"
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"
@@ -241,6 +241,21 @@ ids are `magic_canvas`, `slide_presenter`, `web_search`, `perception`, and
241
241
  Canvas, Slide Presenter, Web Search, and Memory persist through
242
242
  `/pals/{id}/skills`; Perception persists through `/layers/perception`.
243
243
 
244
+ Choose built-ins by the requested behavior before creating a saved tool.
245
+ On-screen scorecards, quizzes, forms, charts, and links use Magic Canvas.
246
+ Attach `magic_canvas` with `magic_canvas_components` and
247
+ `magic_canvas_usage_guidance` together. For a training scorecard, select `text`
248
+ and/or `chart` and describe when to show it in the usage guidance. A saved tool
249
+ or API response cannot render Magic Canvas. Recording results to a real backend
250
+ is a separate action; do not create a placeholder tool for display or collection.
251
+ Offer optional canvas interaction once and respect a decline.
252
+
253
+ Use Web Search for live weather, news, prices, and scores; Slide Presenter for
254
+ uploaded decks; Perception for camera and screen awareness; Memory for returning
255
+ participants. Read `tavus_pal_capabilities_list` after configuring a capability.
256
+ Saved settings and successful text tests do not prove visible rendering; verify
257
+ the display in a live call before claiming it works.
258
+
244
259
  For PAL Knowledge, prefer `tavus_pal_knowledge_*` or
245
260
  `uv run tavus pal knowledge ...` over raw JSON Patch. The Knowledge section is
246
261
  `document_ids` plus `document_tags`, and RAG tuning lives under
@@ -1,4 +1,4 @@
1
1
  """Tavus CLI and MCP server package."""
2
2
 
3
3
  __all__ = ["__version__"]
4
- __version__ = "0.9.0" # x-release-please-version
4
+ __version__ = "0.9.2" # x-release-please-version
@@ -0,0 +1,21 @@
1
+ {
2
+ "instructions": [
3
+ "Build PALs by the creator's intent. Check built-in capabilities before creating a saved tool. Read tavus_pal_capabilities_list for an existing PAL; preserve unrelated settings and attachments. Use tavus_pal_capability_attach, tavus_pal_capability_patch, and tavus_pal_capability_detach to configure built-ins.",
4
+ "Magic Canvas (magic_canvas) handles on-screen scorecards, running scores, charts, quizzes, forms, contact capture, text, and links during a call. A request to show a training scorecard means enabling Magic Canvas, not creating record_training_scorecard. The PAL's own model drives the canvas; a saved tool or API response cannot draw on it. Model-generated quiz questions, scores, dice rolls, and random picks do not need a custom tool. If the creator also wants to save results to a backend, configure that separately; recording data does not display it.",
5
+ "When the creator requests on-screen interaction, attach magic_canvas with the needed magic_canvas_components and magic_canvas_usage_guidance in the same call. For a scorecard use text and/or chart. For forms use input; for quizzes use question. Put one or two lines of when-to-show choreography in magic_canvas_usage_guidance, not in the PAL's system prompt. On attach, the component list selects what to enable and omitted components are disabled. For an existing canvas, read its config first. When patching config.components, send the full component map with your changes and preserve all unchanged settings, including any booking link. If the use case only suggests a canvas, offer it once and wait for agreement; a decline stays declined. Without a backend, explain that collection works on screen and delivery can be connected later. Do not create a placeholder delivery tool.",
6
+ "Magic Canvas calendar collects date/time preferences; it does not book appointments. Scheduling requires the creator's real HTTPS calendly.com booking link in scheduling_url, not a placeholder. Do not include scheduling_embed in magic_canvas_components to enable it; supply the booking link. Do not promise image or map output. Use only supported elements from the capability catalog.",
7
+ "Use slide_presenter for presenting an uploaded deck. Supply display-ready document_ids and slides_trigger=walk_the_deck for automatic narration and advancement, or on_demand when the PAL should wait. For a presentation or sales use case, offer a slide deck once; Magic Canvas does not replace Slide Presenter.",
8
+ "Use web_search for current information the finished PAL needs during calls, including weather, news, prices, and scores. Attach it and update the PAL's instructions with when to look up information; for weather ask for the location first. Do not create get_weather or invent an endpoint. Research needed only to build the PAL does not require attaching Web Search.",
9
+ "Use perception for camera and screen awareness, not an invented view_screen tool. Use memory for continuity with returning participants; update the prompt and greeting to use remembered information with a fallback for first-time visitors. Do not invent a custom tool for a missing integration or unsupported capability.",
10
+ "Create a saved tool only for a real external action, data lookup, or application event that built-ins do not provide. First inspect tavus_tool_list or tavus_describe_pal_options and reuse a matching tool. Use an endpoint supplied by the creator or verified in their code, or an app-message handler that the application implements. Never invent URLs or claim an unimplemented handler works. If a new tool overlaps an existing one, explain why the existing shape does not fit. Attach the returned tool_id with tavus_pal_tools_attach. Inline layers.*.tools writes through tavus_patch_pal are rejected.",
11
+ "Knowledge uses document_ids/document_tags and layers.knowledge_base settings. Use tavus_document_* for the library and tavus_pal_knowledge_* for attachments. Reading a document does not attach it.",
12
+ "After a capability write, read tavus_pal_capabilities_list to confirm the saved attachment and config. Report what the tools confirm. Saved config, successful backend delivery, and visible rendering are separate checks. Do not claim a canvas was displayed without a live visual check. A build or text-test verdict alone does not prove on-screen behavior."
13
+ ],
14
+ "tool_descriptions": {
15
+ "tavus_tool_create": "Create a saved tool for a real external action or application handler. Check built-in capabilities first: scorecards, quizzes, forms, charts, and on-screen text use tavus_pal_capability_attach with magic_canvas. A saved tool cannot render Magic Canvas. Backend recording is separate from on-screen display. Use web_search for weather or current information. Never invent an endpoint or placeholder handler.",
16
+ "tavus_pal_capability_attach": "Enable a built-in capability by intent. Use magic_canvas for scorecards, quizzes, forms, charts, and on-screen text; pass magic_canvas_components and magic_canvas_usage_guidance in this call. Use slide_presenter for decks, web_search for current information, perception for screen/camera awareness, and memory for returning participants. Read tavus_pal_capabilities_list afterward to verify the saved config.",
17
+ "tavus_pal_capability_patch": "Update an enabled built-in capability. For Magic Canvas, keep display choreography in magic_canvas_usage_guidance. The patch merges top-level config fields but replaces config.components when supplied. Read the saved config and preserve unchanged component settings, including any booking link, when changing components. Read tavus_pal_capabilities_list afterward to verify the saved config."
18
+ },
19
+ "magic_canvas_description": "Show scorecards, running scores, quizzes, forms, charts, text, and links during a call. The PAL's model drives the canvas; saved tools and API responses cannot render it. Use text or chart for a training scorecard, question for quizzes, and input for contact capture. Calendar collects preferences but books nothing. Scheduling needs a real HTTPS Calendly booking link. Image and map output are not available.",
20
+ "magic_canvas_usage_guidance": "One or two lines describing when to show each element, with one fixed variant per step. Keep this display choreography here rather than in the PAL's system prompt."
21
+ }
@@ -0,0 +1,9 @@
1
+ """Builder guidance shared by the Python and hosted MCP servers."""
2
+
3
+ import json
4
+ from importlib.resources import files
5
+
6
+ BUILDER_GUIDANCE = json.loads(
7
+ files("tavus_mcp").joinpath("builder_guidance.json").read_text(encoding="utf-8")
8
+ )
9
+ SERVER_INSTRUCTIONS = "\n\n".join(BUILDER_GUIDANCE["instructions"])
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from typing import Any, Literal
4
4
 
5
+ from tavus_mcp.builder_guidance import BUILDER_GUIDANCE
5
6
  from tavus_mcp.sdk.client.http import TavusClient
6
7
 
7
8
  CapabilityId = Literal[
@@ -29,7 +30,7 @@ MAGIC_CANVAS_COMPONENT_IDS = (
29
30
  CAPABILITY_CATALOG: dict[CapabilityId, dict[str, Any]] = {
30
31
  "magic_canvas": {
31
32
  "display_name": "Magic Canvas",
32
- "description": "Show interactive on-screen elements during a call.",
33
+ "description": BUILDER_GUIDANCE["magic_canvas_description"],
33
34
  "portal_id": "builtin:magic_canvas",
34
35
  "rqh_skill_id": "magic_canvas",
35
36
  "config": {
@@ -37,7 +38,7 @@ CAPABILITY_CATALOG: dict[CapabilityId, dict[str, Any]] = {
37
38
  "Sparse map of component id to config. Omitted components default on, "
38
39
  "except scheduling_embed requires scheduling_url."
39
40
  ),
40
- "usage_guidance": "Optional per-PAL guidance for when to use canvas elements.",
41
+ "usage_guidance": BUILDER_GUIDANCE["magic_canvas_usage_guidance"],
41
42
  },
42
43
  },
43
44
  "slide_presenter": {
@@ -8,6 +8,7 @@ from typing import Annotated, Any, Literal
8
8
  from fastmcp import FastMCP
9
9
  from pydantic import Field
10
10
 
11
+ from tavus_mcp.builder_guidance import BUILDER_GUIDANCE, SERVER_INSTRUCTIONS
11
12
  from tavus_mcp.sdk import daily_transport
12
13
  from tavus_mcp.sdk.auth.session import get_session
13
14
  from tavus_mcp.sdk.client.http import TavusClient, tool_call_context
@@ -164,6 +165,9 @@ class AnnotatedFastMCP(FastMCP):
164
165
  if name_or_fn is None:
165
166
  return lambda fn: self.tool(fn, **kwargs)
166
167
  name = kwargs.get("name") or name_or_fn.__name__
168
+ guidance = BUILDER_GUIDANCE["tool_descriptions"].get(name)
169
+ if guidance:
170
+ kwargs["description"] = guidance + "\n\n" + (inspect.getdoc(name_or_fn) or "")
167
171
  if kwargs.get("annotations") is None:
168
172
  kwargs["annotations"] = _annotations_for_tool(name)
169
173
  return super().tool(_with_intent(name_or_fn, name), **kwargs)
@@ -171,25 +175,7 @@ class AnnotatedFastMCP(FastMCP):
171
175
 
172
176
  mcp = AnnotatedFastMCP(
173
177
  "tavus",
174
- instructions=(
175
- "PAL tools are first-class objects, not inlined on the PAL. "
176
- "Built-in PAL capabilities are backed by the PAL skills API: "
177
- "Magic Canvas -> magic_canvas, Slide Presenter -> presentation, "
178
- "Web Search -> internet_search, Memory -> memory; Perception is the "
179
- "PAL's layers.perception config. Use tavus_pal_capabilities_list and "
180
- "tavus_pal_capability_attach/detach/patch for those five PAL Maker "
181
- "capabilities. "
182
- "PAL Knowledge is backed by document_ids/document_tags plus "
183
- "layers.knowledge_base RAG settings. Use tavus_document_* for the "
184
- "document library and tavus_pal_knowledge_* for PAL attachments. "
185
- "Before giving a PAL a tool, check the saved library with "
186
- "tavus_tool_list or tavus_describe_pal_options, then either ATTACH an "
187
- "existing tool (tavus_pal_tools_attach) or CREATE a new one "
188
- "(tavus_tool_create) and attach it. Writing tools inline via "
189
- "tavus_patch_pal (layers.*.tools) is rejected. Whenever you create a "
190
- "new tool that overlaps an existing one, tell the user which existing tool "
191
- "you saw and why its shape does not fit."
192
- ),
178
+ instructions=SERVER_INSTRUCTIONS,
193
179
  )
194
180
 
195
181
 
@@ -10,6 +10,7 @@ from fastmcp import Client
10
10
  from httpx import Response
11
11
  from pydantic import ValidationError
12
12
 
13
+ from tavus_mcp.builder_guidance import BUILDER_GUIDANCE, SERVER_INSTRUCTIONS
13
14
  from tavus_mcp.sdk.errors import TavusApiError
14
15
  from tavus_mcp.server import (
15
16
  mcp,
@@ -22,6 +23,57 @@ from tavus_mcp.server import (
22
23
  )
23
24
 
24
25
 
26
+ @pytest.mark.asyncio
27
+ async def test_builder_guidance_reaches_mcp_clients() -> None:
28
+ async with Client(mcp) as client:
29
+ assert client.initialize_result.instructions == SERVER_INSTRUCTIONS
30
+ tools = {tool.name: tool for tool in await client.list_tools()}
31
+ for name, guidance in BUILDER_GUIDANCE["tool_descriptions"].items():
32
+ assert tools[name].description.startswith(guidance)
33
+
34
+
35
+ @pytest.mark.asyncio
36
+ @respx.mock
37
+ async def test_scorecard_attaches_canvas_through_mcp(clean_env: Path) -> None:
38
+ (clean_env / ".env").write_text(
39
+ "TAVUS_ENV=TEST\nTAVUS_API_KEY=test-key\n"
40
+ "TAVUS_PUBLIC_API_BASE_URL=https://api.example.test/v2\n"
41
+ )
42
+ saved = {}
43
+
44
+ def save_canvas(request):
45
+ saved.update(json.loads(request.content))
46
+ return Response(200, json={"skill_id": "magic_canvas", **saved})
47
+
48
+ route = respx.put("https://api.example.test/v2/pals/p-score/skills/magic_canvas").mock(
49
+ side_effect=save_canvas
50
+ )
51
+ respx.get("https://api.example.test/v2/pals/p-score").respond(200, json={"layers": {}})
52
+ respx.get("https://api.example.test/v2/pals/p-score/skills/").mock(
53
+ side_effect=lambda _: Response(
54
+ 200, json={"data": {"magic_canvas": {"skill_id": "magic_canvas", **saved}}}
55
+ )
56
+ )
57
+ async with Client(mcp) as client:
58
+ await client.call_tool("tavus_pal_capability_attach", {
59
+ "pal_id": "p-score",
60
+ "capability_id": "magic_canvas",
61
+ "magic_canvas_components": ["text", "chart"],
62
+ "magic_canvas_usage_guidance": "Show the training scorecard after each exercise.",
63
+ })
64
+ result = await client.call_tool("tavus_pal_capabilities_list", {"pal_id": "p-score"})
65
+
66
+ assert route.call_count == 1
67
+ canvas = result.data["capabilities"]["magic_canvas"]
68
+ assert canvas["attached"] is True
69
+ assert canvas["attachment"]["config"] == saved["config"]
70
+ config = saved["config"]
71
+ assert config["usage_guidance"] == "Show the training scorecard after each exercise."
72
+ assert config["components"]["input"] == {"enabled": False}
73
+ assert "text" not in config["components"] # Enabled by the skill's defaults.
74
+ assert "chart" not in config["components"]
75
+
76
+
25
77
  @pytest.mark.asyncio
26
78
  async def test_mcp_server_imports_and_registers_tools() -> None:
27
79
  tools = {tool.name: tool for tool in await mcp.list_tools()}
@@ -1303,7 +1303,7 @@ wheels = [
1303
1303
 
1304
1304
  [[package]]
1305
1305
  name = "tavus-cli"
1306
- version = "0.9.0"
1306
+ version = "0.9.2"
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.9.0",
3
+ "version": "0.9.2",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@tavus/tavus-mcp-worker",
9
- "version": "0.9.0",
9
+ "version": "0.9.2",
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.9.0",
3
+ "version": "0.9.2",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
@@ -868,6 +868,9 @@ const KNOWN_REMOTE_CLIENTS: ReadonlyArray<{
868
868
  // also in https://v0.app/docs/api/platform/guides/oauth-mcp-servers.
869
869
  { name: "v0", hosts: ["v0.app"], path: /^\/api\/chat\/integrations\/oauth\/callback$/ },
870
870
  { name: "v0", hosts: ["api.v0.dev"], path: /^\/v1\/mcp-servers\/oauth\/callback$/ },
871
+ // Vercel Connect uses a separate callback from v0.
872
+ // https://vercel.com/docs/connect/providers#accept-the-redirect-url
873
+ { name: "Vercel Connect", hosts: ["connect.vercel.com"], path: /^\/callback$/ },
871
874
  // Lovable does not document its callback (https://docs.lovable.dev/integrations/custom-mcp).
872
875
  // This one is captured from Lovable's own registration on staging
873
876
  // (oauth_register_rejected).
@@ -5,6 +5,7 @@ import type { RegisteredTool } from "@modelcontextprotocol/sdk/server/mcp.js";
5
5
  import type { ToolAnnotations } from "@modelcontextprotocol/sdk/types.js";
6
6
  import { z } from "zod";
7
7
 
8
+ import builderGuidance from "../../../src/tavus_mcp/builder_guidance.json";
8
9
  import type { OAuthGrantKind } from "./oauth-grant";
9
10
  import { VERSION } from "./version";
10
11
  import type { OAuthSessionStoreBinding } from "./oauth-session";
@@ -275,13 +276,13 @@ export const CAPABILITY_CATALOG: Record<
275
276
  > = {
276
277
  magic_canvas: {
277
278
  display_name: "Magic Canvas",
278
- description: "Show interactive on-screen elements during a call.",
279
+ description: builderGuidance.magic_canvas_description,
279
280
  portal_id: "builtin:magic_canvas",
280
281
  rqh_skill_id: "magic_canvas",
281
282
  config: {
282
283
  components:
283
284
  "Sparse map of component id to config. Omitted components default on, except scheduling_embed requires scheduling_url.",
284
- usage_guidance: "Optional per-PAL guidance for when to use canvas elements.",
285
+ usage_guidance: builderGuidance.magic_canvas_usage_guidance,
285
286
  },
286
287
  },
287
288
  slide_presenter: {
@@ -533,7 +534,7 @@ export function createTavusMcpServer(
533
534
  theme: "dark",
534
535
  },
535
536
  ],
536
- });
537
+ }, { instructions: builderGuidance.instructions.join("\n\n") });
537
538
  addToolIntent(server, authChallenge);
538
539
 
539
540
  server.tool(
@@ -1061,7 +1062,7 @@ export function createTavusMcpServer(
1061
1062
 
1062
1063
  server.tool(
1063
1064
  "tavus_tool_create",
1064
- "Create a first-class tool. Attach the returned tool_id to a PAL with tavus_pal_tools_attach or top-level tool_ids.",
1065
+ builderGuidance.tool_descriptions.tavus_tool_create + " Attach the returned tool_id to a PAL with tavus_pal_tools_attach or top-level tool_ids.",
1065
1066
  toolWriteFields,
1066
1067
  writeAnnotations("Create tool"),
1067
1068
  async (body) => toolResult(await client.create("tools", clean(body))),
@@ -1301,7 +1302,7 @@ export function createTavusMcpServer(
1301
1302
 
1302
1303
  server.tool(
1303
1304
  "tavus_pal_capability_attach",
1304
- "Attach a PAL Maker capability by friendly id or portal id. Includes Magic Canvas, Slide Presenter, Web Search, Perception, and Memory.",
1305
+ builderGuidance.tool_descriptions.tavus_pal_capability_attach,
1305
1306
  capabilityWriteSchema,
1306
1307
  {
1307
1308
  title: "Attach PAL capability",
@@ -1315,7 +1316,7 @@ export function createTavusMcpServer(
1315
1316
 
1316
1317
  server.tool(
1317
1318
  "tavus_pal_capability_patch",
1318
- "Patch an already-attached PAL Maker capability.",
1319
+ builderGuidance.tool_descriptions.tavus_pal_capability_patch,
1319
1320
  capabilityWriteSchema,
1320
1321
  {
1321
1322
  title: "Patch PAL capability",
@@ -0,0 +1 @@
1
+ export const VERSION = "0.9.2"; // x-release-please-version
@@ -0,0 +1,84 @@
1
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2
+ import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
3
+ import { describe, expect, it, vi } from "vitest";
4
+
5
+ import guidance from "../../../src/tavus_mcp/builder_guidance.json";
6
+ import { createTavusMcpServer } from "../src/tavus";
7
+
8
+ async function connect() {
9
+ const server = createTavusMcpServer({
10
+ TAVUS_API_KEY: "test-key",
11
+ TAVUS_PUBLIC_API_BASE_URL: "https://api.example.test/v2",
12
+ });
13
+ const client = new Client({ name: "guidance-test", version: "1.0.0" });
14
+ const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
15
+ await server.connect(serverTransport);
16
+ await client.connect(clientTransport);
17
+ return { server, client };
18
+ }
19
+
20
+ describe("builder guidance over MCP", () => {
21
+ it("delivers shared instructions and tool guidance to clients", async () => {
22
+ const { server, client } = await connect();
23
+ try {
24
+ expect(client.getInstructions()).toBe(guidance.instructions.join("\n\n"));
25
+ const { tools } = await client.listTools();
26
+ for (const [name, description] of Object.entries(guidance.tool_descriptions)) {
27
+ expect(tools.find((tool) => tool.name === name)?.description?.startsWith(description)).toBe(true);
28
+ }
29
+ } finally {
30
+ await client.close();
31
+ await server.close();
32
+ }
33
+ });
34
+
35
+ it("attaches a scorecard canvas and reads back its config without creating a tool", async () => {
36
+ let saved: Record<string, unknown> = {};
37
+ const fetchMock = vi.fn(async (input: string | URL | Request, init?: RequestInit) => {
38
+ const url = String(input);
39
+ if (url === "https://api.example.test/v2/pals/p-score/skills/magic_canvas" && init?.method === "PUT") {
40
+ saved = JSON.parse(String(init.body));
41
+ return Response.json({ skill_id: "magic_canvas", ...saved });
42
+ }
43
+ if (url === "https://api.example.test/v2/pals/p-score?include_settings=true") {
44
+ return Response.json({ layers: {} });
45
+ }
46
+ if (url === "https://api.example.test/v2/pals/p-score/skills/") {
47
+ return Response.json({ data: { magic_canvas: { skill_id: "magic_canvas", ...saved } } });
48
+ }
49
+ throw new Error(`Unexpected request: ${init?.method} ${url}`);
50
+ });
51
+ vi.stubGlobal("fetch", fetchMock);
52
+ const { server, client } = await connect();
53
+ try {
54
+ const attached = await client.callTool({
55
+ name: "tavus_pal_capability_attach",
56
+ arguments: {
57
+ pal_id: "p-score",
58
+ capability: "magic_canvas",
59
+ magic_canvas_components: ["text", "chart"],
60
+ magic_canvas_usage_guidance: "Show the training scorecard after each exercise.",
61
+ },
62
+ });
63
+ expect(attached.isError).not.toBe(true);
64
+ const result = await client.callTool({
65
+ name: "tavus_pal_capabilities_list",
66
+ arguments: { pal_id: "p-score" },
67
+ });
68
+ expect(result.isError).not.toBe(true);
69
+ const content = result.content as Array<{ type: string; text: string }>;
70
+ const canvas = JSON.parse(content[0].text).capabilities.magic_canvas;
71
+ expect(canvas.attached).toBe(true);
72
+ expect(canvas.attachment.config).toEqual(saved.config);
73
+ expect(canvas.attachment.config.usage_guidance).toBe("Show the training scorecard after each exercise.");
74
+ expect(canvas.attachment.config.components.input).toEqual({ enabled: false });
75
+ expect(canvas.attachment.config.components.text).toBeUndefined();
76
+ expect(canvas.attachment.config.components.chart).toBeUndefined();
77
+ expect(fetchMock).toHaveBeenCalledTimes(3);
78
+ } finally {
79
+ await client.close();
80
+ await server.close();
81
+ vi.unstubAllGlobals();
82
+ }
83
+ });
84
+ });
@@ -855,6 +855,7 @@ describe("Cloudflare Tavus MCP helpers", () => {
855
855
  // Both callbacks from v0's client metadata document.
856
856
  ["v0", ["https://v0.app/api/chat/integrations/oauth/callback"]],
857
857
  ["v0", ["https://api.v0.dev/v1/mcp-servers/oauth/callback"]],
858
+ ["Vercel Connect", ["https://connect.vercel.com/callback"]],
858
859
  // Lovable's registration, captured from the staging Worker logs.
859
860
  ["Lovable", ["https://api.lovable.dev/workspaces/connectors/mcp/oauth/callback"]],
860
861
  // Bolt's registration, captured from the staging Worker logs.
@@ -880,6 +881,10 @@ describe("Cloudflare Tavus MCP helpers", () => {
880
881
  ["the unverified Lovable callback", "https://lovable.dev/oauth/callback"],
881
882
  ["a Bolt subdomain", "https://evil.bolt.new/mcp/oauth/callback"],
882
883
  ["a subdomain", "https://evil.v0.app/api/chat/integrations/oauth/callback"],
884
+ ["Vercel Connect over HTTP", "http://connect.vercel.com/callback"],
885
+ ["a Vercel Connect lookalike host", "https://connect.vercel.com.attacker.example/callback"],
886
+ ["a longer Vercel Connect path", "https://connect.vercel.com/callback/extra"],
887
+ ["a Vercel Connect query string", "https://connect.vercel.com/callback?next=https://attacker.example"],
883
888
  ])("rejects a known client's callback with %s", async (_label, redirectUri) => {
884
889
  expect((await registerClient([redirectUri]))?.status).toBe(400);
885
890
  });
@@ -893,7 +898,7 @@ describe("Cloudflare Tavus MCP helpers", () => {
893
898
  expect(response?.status).toBe(400);
894
899
  await expect(response?.json()).resolves.toMatchObject({
895
900
  error: "invalid_client_metadata",
896
- error_description: expect.stringContaining("Claude, ChatGPT, Cursor, VS Code, v0, Lovable, Bolt, Replit"),
901
+ error_description: expect.stringContaining("Claude, ChatGPT, Cursor, VS Code, v0, Vercel Connect, Lovable, Bolt, Replit"),
897
902
  });
898
903
  });
899
904
 
@@ -1,3 +0,0 @@
1
- {
2
- ".": "0.9.0"
3
- }
@@ -1 +0,0 @@
1
- export const VERSION = "0.9.0"; // x-release-please-version
File without changes
File without changes
File without changes
File without changes
File without changes