SCAL-336134: Add developer examples related to chat history for spotter mcp server - #67
Open
mouryabalabhadra wants to merge 1 commit into
Open
SCAL-336134: Add developer examples related to chat history for spotter mcp server#67mouryabalabhadra wants to merge 1 commit into
mouryabalabhadra wants to merge 1 commit into
Conversation
…er mcp server
### Summary
Brings the `python-react-agent-simple-ui` example up to date with the Spotter 3 MCP toolset, and fixes three things that made it unreliable to run: embed auth, chart rendering after an answer expires, and CSP-blocked iframes.
## Changes
### Spotter 3 naming
- `claude_agent_mcp_server_v2.py` → `claude_agent_with_spotter3_mcp_server.py`
- `claude_agent_mcp_server_v2_with_chat_history.py` → `claude_agent_with_spotter3_mcp_server_and_chat_history.py`
- README and `env.template` re-worded off `v1`/`v2` onto Spotter 3 terms, and the
OpenAI / Azure OpenAI (v1) documentation removed.
### Embed authentication — fixes the "Duplicate token" alert
The client's `getAuthToken` returned one constant `VITE_TS_AUTH_TOKEN`. The SDK
requires a *fresh* token per call: once that static token stops verifying, the SDK
reports a duplicate token and the callback can never recover, because it hands back
the same string.
- New `GET /api/ts-token` on both servers, minting a short-lived token per request via
`POST /api/rest/2.0/auth/token/full`.
- Configured with `TS_EMBED_USERNAME` + `TS_SECRET_KEY` (or `TS_EMBED_PASSWORD`);
`TS_TOKEN_VALIDITY_SEC` sets the lifetime, default 1800s.
- With no minting credentials set, the endpoint falls back to the static token so the
demo still runs, and logs why.
- Client `getAuthToken` now fetches that endpoint, and `autoLogin: true` renews before
expiry. No ThoughtSpot token is bundled into the frontend any more.
### Chart rendering after an answer expires
A ThoughtSpot answer object lives ~8 hours. The chat history stored each answer's
`iframe_url` and `answer_id` (which is really a `{session_id, gen_no}` pair), so
reopening an older conversation rendered a row of dead embeds.
- The server no longer persists those fields, and strips them on read too, so rows
written before this change take the same path.
- `GET /api/conversations/{id}` now returns each answer's `answer_index` plus the
conversation's `analytical_session_id`; the client emits a resolver placeholder and
the Visual Embed SDK resolves a live URL. **Requires the SDK change in PR 2.**
- `reconcile_answers` asks `getConversation` how many answers each turn actually has,
rather than trusting the stored copy. This also recovers answers from turns whose
SSE stream was cut off mid-flight: the Agent finishes regardless, so the answer
exists on ThoughtSpot's side even when the app recorded none of it.
### Raw session updates
`TS_MCP_API_VERSION` now defaults to `latest`, and the update readers accept both the
server's digested shape and the Agent's raw shape (`text-chunk` vs `text_chunk`,
`metadata.type == "thinking"` vs `is_thinking`, …), so
`&enable-raw-session-updates=true` can be turned on through `TS_MCP_URL` without a
code change. Intermediate "thinking" answers are filtered out — one three-question
chat produced eleven answer updates but a single settled one — which also keeps our
answer ordering aligned with `getConversation`'s.
### CSP / ports
The cluster's `frame-ancestors` allowlists `http://localhost:8000`, not Vite's default
5173, so the embed iframe was blocked and rendered as `chrome-error://chromewebdata/`.
Vite now serves on 8000 with `strictPort`, and proxies `/api` to the backend on 8001.
### System theme
`App.css` moved fully onto CSS custom properties with a `prefers-color-scheme: dark`
block (no hardcoded colours left bypassing the tokens), and the embed itself gets
matching dark `customizations` variables so the chart doesn't stay white inside a dark
page.
### Misc
- `AnswerFrame` removed: answer iframes are injected as markup so React owns only the
wrapper and doesn't fight the renderer's `replaceWith()`.
- Dependency bumps: `anthropic>=1.2.0,<2`, `mcp>=2.1.1,<3`, `httpx` → `httpx2`,
FastAPI/uvicorn; `@thoughtspot/visual-embed-sdk` `1.45.3-mcp.2` → `1.51.1`.
- `.gitignore`: local `*.db` / `-wal` / `-shm` chat-history files.
## Testing
- Live chats through both servers: answers stream, embeds render, follow-up turns
reuse the same analytical session.
- `/api/ts-token` verified minting: `minted: true`, a different token per call, and
the minted token authenticates against `/callosum/v1/session/isactive`.
- `/api/conversations` list/open/delete exercised against the stored database.
- Client `vite build` passes.
Not verified: the expired-answer replay path against a genuinely >8h-old conversation.
The cluster's REST layer was returning 502 during that window, so it has only been
exercised via the SDK's unit tests and against live (unexpired) conversations.
## Merge order
The past-chat replay depends on the `startAutoMCPFrameRenderer` change in PR 2. Local
development currently works because `node_modules/@thoughtspot/visual-embed-sdk` is
npm-linked to a local SDK checkout, but `package.json` pins `^1.51.1` from the
registry, which does not include it. **Land and release the SDK change, then bump the
pin here** — otherwise a fresh `npm install` will render past-chat answers as iframes
with no session parameters.
## Notes
`server/agent.py` (the OpenAI/Azure v1 backend) and the `openai` entry in
`requirements.txt` are left in place but are no longer documented. Say if they should
be removed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Brings the
python-react-agent-simple-uiexample up to date with the Spotter 3 MCP toolset, and fixes three things that made it unreliable to run: embed auth, chart rendering after an answer expires, and CSP-blocked iframes.Changes
Spotter 3 naming
claude_agent_mcp_server_v2.py→claude_agent_with_spotter3_mcp_server.pyclaude_agent_mcp_server_v2_with_chat_history.py→claude_agent_with_spotter3_mcp_server_and_chat_history.pyenv.templatere-worded offv1/v2onto Spotter 3 terms, and the OpenAI / Azure OpenAI (v1) documentation removed.Embed authentication — fixes the "Duplicate token" alert The client's
getAuthTokenreturned one constantVITE_TS_AUTH_TOKEN. The SDK requires a fresh token per call: once that static token stops verifying, the SDK reports a duplicate token and the callback can never recover, because it hands back the same string.GET /api/ts-tokenon both servers, minting a short-lived token per request viaPOST /api/rest/2.0/auth/token/full.Chart rendering after an answer expires
A ThoughtSpot answer object lives ~8 hours. The chat history stored each answer's
iframe_urlandanswer_id(which is really a{session_id, gen_no}pair), so reopening an older conversation rendered a row of dead embeds.GET /api/conversations/{id}now returns each answer'sanswer_indexplus the conversation'sanalytical_session_id; the client emits a resolver placeholder and the Visual Embed SDK resolves a live URL. Requires the SDK change in PR 2.reconcile_answersasksgetConversationhow many answers each turn actually has, rather than trusting the stored copy. This also recovers answers from turns whose SSE stream was cut off mid-flight: the Agent finishes regardless, so the answer exists on ThoughtSpot's side even when the app recorded none of it.Raw session updates
TS_MCP_API_VERSIONnow defaults tolatest, and the update readers accept both the server's digested shape and the Agent's raw shape (text-chunkvstext_chunk,metadata.type == "thinking"vsis_thinking, …), so&enable-raw-session-updates=truecan be turned on throughTS_MCP_URLwithout a code change. Intermediate "thinking" answers are filtered out — one three-question chat produced eleven answer updates but a single settled one — which also keeps our answer ordering aligned withgetConversation's.System theme
App.cssmoved fully onto CSS custom properties with aprefers-color-scheme: darkblock (no hardcoded colours left bypassing the tokens), and the embed itself gets matching darkcustomizationsvariables so the chart doesn't stay white inside a dark page.Misc
AnswerFrameremoved: answer iframes are injected as markup so React owns only the wrapper and doesn't fight the renderer'sreplaceWith().anthropic>=1.2.0,<2,mcp>=2.1.1,<3,httpx→httpx2, FastAPI/uvicorn;@thoughtspot/visual-embed-sdk1.45.3-mcp.2→1.51.1..gitignore: local*.db/-wal/-shmchat-history files.Testing
/api/ts-tokenverified minting:minted: true, a different token per call, and the minted token authenticates against/callosum/v1/session/isactive./api/conversationslist/open/delete exercised against the stored database.vite buildpasses.Notes
server/agent.py(the OpenAI/Azure v1 backend) and theopenaientry inrequirements.txtare left in place but are no longer documented. Say if they should be removed.