Skip to content

SCAL-336134: Add developer examples related to chat history for spotter mcp server - #67

Open
mouryabalabhadra wants to merge 1 commit into
mainfrom
SCAL-336134
Open

SCAL-336134: Add developer examples related to chat history for spotter mcp server#67
mouryabalabhadra wants to merge 1 commit into
mainfrom
SCAL-336134

Conversation

@mouryabalabhadra

@mouryabalabhadra mouryabalabhadra commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

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.pyclaude_agent_with_spotter3_mcp_server.py
  • claude_agent_mcp_server_v2_with_chat_history.pyclaude_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.

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.

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, httpxhttpx2, FastAPI/uvicorn; @thoughtspot/visual-embed-sdk 1.45.3-mcp.21.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.

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.

…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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant