ZachLaik turns Mike into a plug-in platform

A new Connectors system lets users wire their own AI tools into Mike without touching the code.

integrationworkflow

ZachLaik is proposing that Mike stop being a closed box. Through a new Settings tab, users can point Mike at any Model Context Protocol server - an emerging standard for letting AI assistants talk to outside tools and data - and the chat assistant will discover the available tools and start using them in conversations. No fork, no redeploy.

Two sign-in paths are on offer: paste a URL and an API token for simpler setups, or click through a one-tap OAuth flow for services that support it (verified against a legal data lookup service called legaldatahunter.com). Tool calls show up inline in the chat with the server name, the tool used, and an expandable view of what was sent and received. Encryption of stored tokens and a curated directory of trusted connectors are flagged as follow-up work.

So what For legal-ops teams eyeing Mike, this is the difference between a fixed product and a platform their own vendors and internal tools can hook into.

View this fork on GitHub →

Spotted something wrong? Or know the PR text has fresher detail than the writeup above?

Commits in this thread

3 commits from ZachLaik/mike, oldest first. Source extracted verbatim from the harvested git log.

SHA Subject Author Date
277339f6 feat(mcp): add user-configurable MCP servers (URL + custom headers) Zacharie Laik 2026-05-04 ↗ GitHub
commit body
Lets users register Streamable-HTTP MCP servers from the Settings page.
Tools discovered from each enabled server are merged into the per-request
tool set under the `mcp__<slug>__<tool>` prefix and dispatched back to the
right server via runToolCalls. Headers (e.g. `Authorization: Bearer ...`)
are stored on the row.

Backend
- New `user_mcp_servers` table (RLS owner-only) with migration 001 + the
  same DDL inlined in the one-shot schema.
- `lib/mcp/{client,servers,types}.ts`: thin wrapper around
  @modelcontextprotocol/sdk's StreamableHTTPClientTransport, per-request
  loader, schema converter (MCP `inputSchema` -> Mike's OpenAIToolSchema)
  with 64-char tool-name truncation.
- `runLLMStream` and `runToolCalls` accept an optional `mcpServers` list;
  chat routes load + close clients in a try/finally.
- New `routes/mcpServers.ts` mounted at `/user/mcp-servers` with
  GET/POST/PATCH/DELETE plus `/test` for connect-and-list-tools probing.
  All handlers filter by user_id since the backend uses the service role
  key.

Frontend
- New `account/mcp` settings tab and page: add/edit/delete servers, toggle
  enabled, run test connection. Header values are masked in the form
  (type=password) and the GET endpoint returns header keys only.
- `mikeApi.ts`: typed CRUD wrappers.

Notes for review
- Header values are stored via the same RLS-only model used today for
  `user_profiles.claude_api_key`/`gemini_api_key`. Per-row encryption is
  a clean follow-up.
- OAuth-protected MCP servers are out of scope for this PR; a follow-up
  will add an OAuth 2.1 client (PKCE + dynamic client registration) so
  spec-conformant servers (e.g. https://legaldatahunter.com/mcp) work
  without manual token paste.
fad06aca feat(mcp): rename to Connectors, prettier tool calls, observability Zacharie Laik 2026-05-04 ↗ GitHub
commit body
Polish on top of the initial MCP support commit. Same scope (no auth/marketplace yet),
just smoothing the rough edges from a real test session.

UX
- Settings tab + chat-input button renamed to "Connectors". MCP is mentioned in
  the page description (with a link to modelcontextprotocol.io) so the protocol
  is still discoverable.
- New `Connectors` button next to Documents / Workflows in the chat input opens a
  popover with a per-server toggle switch. Hides itself when the user has no
  connectors configured.
- Tool calls in chat now render `Running <Server> · <tool>` (friendly) instead of
  the raw `mcp__<slug>__<tool>` prefix; the original name still routes correctly.
- After each MCP tool call, a result block shows ✓/✗ + first line of output, with
  a "Show details" toggle that expands pretty-printed JSON arguments and the full
  text output.
- New connectors auto-discover their tool list immediately on save (no extra Test
  click). Re-enabling a disabled connector also auto-tests.
- Settings card redesigned: status pill, header chips, expandable per-tool
  descriptions with More/Less. Sanitises Name field if it looks like a Bearer
  token was pasted into it (best-effort safety net).
- Amber "only add connectors you trust" notice at the top of the page and a
  compact restated form inside the Add panel.

Backend
- New SSE event type `mcp_tool_result` with `{ server, tool, ok, args, output }`.
  args/output capped at 4 KB each before persistence (the model still receives
  the untruncated tool output - only the user-visible preview is capped).
- `tool_call_start` now optionally carries `display_name`; the renderer
  prefers it.
52749e6e feat(mcp): OAuth 2.1 sign-in for connectors Zacharie Laik 2026-05-05 ↗ GitHub
commit body
Adds OAuth 2.1 (RFC 9728 discovery + RFC 7591 dynamic client registration +
PKCE) so spec-conformant MCP servers like https://legaldatahunter.com/mcp
work without the user pasting any token.

The MCP TypeScript SDK does almost all the heavy lifting via its `auth()`
helper - discovery, DCR, PKCE, code exchange, refresh. We only have to plug
in an OAuthClientProvider whose getters/setters read and write the row's
oauth_* columns, plus an HMAC-signed state token so the popup callback can
look the row up without a server-side session.

DB
- migration 002 + inline patch to the one-shot:
  alter table user_mcp_servers
    add auth_type ('headers'|'oauth' default 'headers'),
    add oauth_metadata jsonb,
    add oauth_tokens jsonb,
    add oauth_code_verifier text;

Backend
- New `lib/mcp/oauth.ts`:
  - `DbOAuthProvider` implements OAuthClientProvider, persists everything
    on the user_mcp_servers row.
  - "initiate" mode (used by /oauth/start) captures the authorize URL into
    a property so the route can return it for the popup; "use" mode (used
    by chat) throws ReauthRequiredError when the SDK wants the user back,
    so the caller can mark the row reauth_required.
  - signOAuthState/verifyOAuthState - HMAC over user_id+server_id (5 min
    TTL) reusing DOWNLOAD_SIGNING_SECRET. No DB round-trip on callback.
- `lib/mcp/client.ts`: accepts an optional authProvider passed through to
  StreamableHTTPClientTransport - the SDK auto-attaches Authorization
  headers and auto-refreshes on 401.
- `lib/mcp/servers.ts`: builds a DbOAuthProvider for OAuth rows that have
  tokens; rows without tokens are skipped (UI surfaces a "Sign in" button
  in settings instead).
- New `routes/mcpOauth.ts` mounted at /mcp/oauth: public callback that
  verifies state, finishes the SDK auth() flow, and returns a small HTML
  page that postMessage()s the opener and closes the popup.
- `routes/mcpServers.ts`:
  - POST /:id/oauth/start kicks off discovery + DCR via the SDK and
    returns { authorize_url } for the frontend popup.
  - POST creates honor `auth_type`; PATCH/test/list now project + return
    auth_type and a boolean oauth_authorized (the access_token itself
    never round-trips to the browser).
- `BACKEND_PUBLIC_URL` env var (defaults to http://localhost:${PORT}) used
  to build the OAuth redirect URI; documented in `.env.example`.

Frontend
- `account/mcp/page.tsx`:
  - Authentication mode radio in the Add form: "API key / headers" vs
    "OAuth (auto-discover)". Headers section hides itself in OAuth mode.
  - Save button label switches to "Save & sign in" for OAuth, which
    immediately opens the authorize popup. The page polls listMcpServers
    until oauth_authorized flips, then auto-runs tool discovery.
  - Per-card status pills: "OAuth · signed in" (blue) / "OAuth · sign-in
    required" (amber). Cards in the latter state show a "Sign in" button
    instead of "Test".
  - Simplified copy per user feedback: dropped the OAuth explainer block,
    redundant "By saving..." trust pill, and helper text under Name and
    URL inputs. Single load-bearing trust warning at top of page remains.
- `mikeApi.ts`: `startMcpOauth(id)` wrapper.

Security notes for reviewers
- access_token / refresh_token / oauth_metadata are stored at-rest in
  jsonb (RLS owner-only). Per-row encryption deferred to a separate
  hardening PR - matches existing precedent for user_profiles.{claude,
  gemini}_api_key.
- State token is HMAC-signed with DOWNLOAD_SIGNING_SECRET, 5 min TTL,
  carries user_id + server_id only. CSRF-safe across the popup hop with
  no server-side session needed.
- Public client (token_endpoint_auth_method=none, PKCE-protected) - no
  client secret needed for confidential storage.

Capture this thread into my fork

Download a single Markdown prompt that tells Claude how to port every commit above into your working tree — adapting paths and structure to match your repo. Run it via claude -p < capture-thread-308.md from inside the repo you want the changes in.

⬇ Download capture-thread-308.md