Skip to content

add exa and parallel, and move custom mcp servers onto built-in integrations - #116

Open
hkonsti wants to merge 9 commits into
mainfrom
hkonsti/parallelai-vs-exa
Open

hkonsti wants to merge 9 commits into
mainfrom
hkonsti/parallelai-vs-exa

Conversation

@hkonsti

@hkonsti hkonsti commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

Adds Exa and Parallel as built-in integrations: people sign in through each provider's MCP server or paste an API key, and agents get Search the web and Read web pages. Every integration built on an MCP server (Granola, Notion, Linear, Exa, Parallel) now declares itself once in BUILT_IN_MCP, and that list drives its sign-in routes, its key route where its server takes a key (Exa, Parallel and Linear, which lists the key beside its plus in the catalog and under a connection's permissions), and the takeover of custom connections. A key is checked with the server before the connection is made and sent as the bearer token, never refreshed. Exa and Parallel say nothing of who signed in, so each of their sign-ins or keys is a connection of its own, renewed only from its page; Linear names the account, so a key for a workspace renews that workspace's connection, as signing in again does. Entering one of those servers on the custom MCP form starts the built-in sign-in, or connects the integration with the token typed in as its key, and on every start the api moves existing custom connections to those servers over to the built-in integration. Settings are mapped so nothing gains access, tool runs in the activity log become the integration's requests, an OAuth sign-in or a typed-in token carries over, while connections set up with no credential wait for a sign-in. The first deploy converts production data and can't be rolled back by reverting the code, so take a database backup first; there's no schema migration and no new environment variables.


Open workspace in Conductor

…tions built on them

Connect Exa and Parallel by signing in to their MCP servers, as Granola, Notion and Linear are.
Agents search the web and read pages through either, each a command that only runs: Parallel's
results are written out as Exa's are, and a page is cut at 100,000 characters.

Every integration built on its provider's MCP server now declares itself once (BuiltInMcp, listed
in BUILT_IN_MCP): its server, how a sign-in names its account, its defaults, and what each of the
server's tools becomes. From that:

- the custom MCP form signs in to the integration instead when given its server's address, the
  connection under the name typed there;
- on every start, the api moves custom connections to those servers over to the integration,
  keeping their id, name and activity. An action is on only where every tool of it was, its tool
  runs become the integration's requests, and a sign-in to the server carries over, for the
  account it is for. One with a token typed in, or none, waits to be signed in to;
- signing in again from a connection renews that connection, whatever account it showed.

A connection without a credential now needs a sign-in: every action is unavailable, the
connection's page says so, and agents are told to sign in.
…tions built on mcp servers

The api registers every integration in BUILT_IN_MCP's start and callback routes from its
declaration, so each route.ts only declares its integration. The catalog marks the integrations
connected by signing in (`signIn`), which the web app reads for where a sign-in starts instead of
a list of its own; a test holds the marks to Google and BUILT_IN_MCP.
An integration's logo is public/integrations/<id>.svg unless LOGOS says otherwise: the icons for
Information and Email, our mark for custom MCP servers, Granola's png, and the logos that fill
their tile. PostgreSQL's file is renamed to its id. A test holds every integration in the catalog
to having its file.
…allel sign-in or key a connection of its own

The catalog's apiKey flag adds a key beside an integration's plus, which takes the key in a
dialog, and the connection page offers a new key beside signing in again. A key is checked with
the server and sent as the bearer token, never refreshed. Exa and Parallel say nothing of who
signed in, so each of their sign-ins or keys is a connection of its own, renewed only from its
page; Linear names the account, so a key for a workspace renews its connection. A custom
connection with a token typed in moves over as the integration's key. The count on a catalog
row sits beside the name as a badge.
… apart, and move custom connections over without losing what worked

- a sign-in or key that names its account renews that account's connection, never the one the sign-in began from; `?connection=` renews only an exa or parallel connection, or one moved over that was never signed in to
- the catalog marks exa and parallel `anonymous`, and only their connection pages always offer signing in again
- moving a custom connection over: keyless servers stay custom, an exa key in the address carries over, an unreadable credential is left for the next start, and a sign-in is refreshed before asking for its account, workspace and all, under a row lock so two servers starting at once refresh it once
- the custom form connects exa with a key in its address, and turns down a token for granola or notion rather than dropping it
- the exa key check fails only on a key exa turns down
- connection access keeps its latest settings in a layout effect, before a queued save runs
- drop the unused `name` of connecting with a key, and the `unknown`s of tool params and web tool args
…-exa

# Conflicts:
#	packages/api/src/connections/connect-flow.ts
#	packages/db/src/audit.ts
#	packages/web/src/lib/integrations.ts
…-exa

# Conflicts:
#	packages/api/src/mcp/route.test.ts
…le moving a connection over, and space enable all from the edge above

- notion's refresh answers no workspace_name, so a moved notion connection's account came out without its workspace; notion-get-self names both, as the first sign-in did, so the token responses no longer carry a workspace
- moving a connection over refreshes its tokens only when they ran out or are turned down, and keeps the new ones on the custom connection at once, since notion replaces the refresh token on every refresh
- enable all sits as far from the edge above as the rows are from the side, in the welcome step's card
…ough --bleed

- a container's padding is the text line: the shells' main, the agent footer and the welcome frame use page-column, a Card its own padding, a widget frame its own; --bleed says how far a row may reach past it
- rows, their headers and the catalog, audit, access, settings and widget rows reach into it with bleed; nothing else indents itself, so the 48 hand-copied md:px-3 and the spacing-only className props are gone
- Card in @proxy/ui for the hand-written cards and the welcome step's permissions, which sit even on every side
- spacing between things is the gap of what holds them: main is a column with a gap, and the outer margins became gaps or padding
- the access list spaces its rows with a gap, its own-setting stripe an inset shadow, and its checkbox centered on the label's line
- the welcome steps' rows now line up with the text above them, and the forms, the delete-account box and the added banner start on the text line
- layout-rules.test.ts fails on an outer margin or a hand-copied responsive inset

This branch has not been deployed

No deployments
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