Commit Graph

7 Commits

Author SHA1 Message Date
Christian Gick
17b92f8514 fix(mcp-bridge): unique wire ids to avoid concurrent session collisions
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 11s
LiteLLM opens a fresh MCP session per tool call. Two concurrent sessions
both send id=1 (tools/list + tools/call) which overwrite each other in
the shared pending-map keyed by the inbound id. One of the two calls
never gets a response and times out.

Assign a monotonic demux-N wire id per forwardMcpCall. The caller's
original id is echoed back in the HTTP response by the route handler.

SB-48

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-14 09:30:26 +03:00
Christian Gick
c83e12fb63 fix(mcp-demux): handle Streamable-HTTP handshake correctly
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 17s
LiteLLM opens a fresh MCP session per tools/call: initialize →
notifications/initialized → tools/call. Demux forwarded everything
to the WS unchanged, so:

- notifications/initialized (no id) hung forwardMcpCall waiting on
  a response id, and the 200 JSON-RPC body confused the SDK reader
  into cancelling the subsequent tools/call ("duplicate response
  suppressed").
- initialize added an unnecessary WS round-trip coupled to
  extension availability.

Answer initialize locally, return 202 empty for notifications/*,
set explicit Content-Type + Mcp-Session-Id on the handshake.

SB-48

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-14 09:15:38 +03:00
Christian Gick
5d6e7f7a80 ci: add Gitea Actions build & deploy workflow
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 10s
Builds on push to main, deploys to infra VM via SSH, health-checks
the /health endpoint after restart.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:11:19 +03:00
Christian Gick
4d8ecbb6be fix(litellm): sanitize customer ID in MCP server alias
LiteLLM rejects server names containing `-`, but customer IDs are
UUIDs. Replace `-` with `_` in both the MCP server alias and key alias.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:08:07 +03:00
Christian Gick
52c2e9eca5 feat(agiliton-account): per-customer LiteLLM MCP server provisioning
At first login, provisionMcpServer() creates a sitebridge-{customer_id}
entry in LiteLLM DB via POST /v1/mcp/server, pointing to the customer's
demux URL. The virtual key is then scoped to ["sitebridge-{customer_id}"]
so LiteLLM routes tool calls only to that customer's WebSocket.

Also adds AGILITON_ACCOUNT_URL config for self-referencing in MCP URLs.

CF-3032

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 16:18:02 +03:00
Christian Gick
21780d3e45 fix(deploy): correct docker-compose networks to match infra VM
Use postgres_default, redis_default, agiliton-api external networks.
Remove depends_on (services are in separate compose stacks).

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 16:09:13 +03:00
Christian Gick
7ab23554c0 feat(agiliton-account): Phase 1 service scaffold
TypeScript + Fastify service implementing:
- Google + Microsoft SSO (POST /v1/auth/sso/{google,microsoft})
- JWT issuance + LiteLLM virtual key provisioning on first login
- AES-256-GCM encrypted virtual key storage in Postgres
- Conversation CRUD (GET/POST/DELETE /v1/conversations, /messages)
- GDPR export + soft-delete (/v1/me/export, /v1/me/delete)
- WebSocket MCP bridge (/v1/mcp-bridge) with JWT auth
- MCP demux endpoint (/mcp/demux/:customer_id/mcp) for LiteLLM tool routing
- DB migration script creating sb_customers, sb_conversations, sb_messages
- 9 unit tests (bridge + crypto), all passing
- Dockerfile + docker-compose targeting port 4100

CF-3032

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 16:06:16 +03:00