Tim Lingo a01236753a feat(connectors): clean-install bundling + Google OAuth foundation
Make connectors work on a clean Mac with no Node/npm installed, and lay
the foundation for one-click Google sign-in.

Clean-install bundling:
- bundle scripts: `npm run bundle` -> self-contained dist/connectd.cjs (CJS,
  no node_modules); `bundle:servers` -> pre-bundled MCP servers (fs-server.mjs
  for "Your files", runs without npx); `bundle:all`.
- runtime resolution in the bridge: a connector config can use command "@node"
  (the bundled runtime, process.execPath) and arg "@bundled/<server>" (a server
  shipped alongside the bridge), resolved at spawn time via
  NEURON_CONNECTD_BUNDLE_DIR. So remote connectors + "Your files" work offline,
  zero deps.
- graceful ENOENT -> needs_setup ("coming soon") instead of a cryptic spawn
  crash for not-yet-bundled npx connectors on a clean machine.

Google OAuth foundation (google-oauth.ts):
- desktop-style authorization-code + PKCE flow, refresh, Keychain storage,
  gated on GOOGLE_OAUTH_CLIENT_ID (honest needs_setup until configured).
- new auth mode "google" for stdio connectors + /google/oauth/start and
  /google/callback endpoints. NOTE: pending the Neuron Google OAuth client +
  Google verification; not certified end-to-end yet.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 14:27:04 -05:00

neuron-connectd

The Neuron MCP-connector bridge — the Accessor that isolates the MCP wire protocol (stdio framing, SSE, OAuth, server lifecycle) behind a flat loopback HTTP contract the El soul consumes. The soul stays El-simple; this process absorbs the ecosystem.

Spec: ../docs/research/mcp-connectors-adoption-spec.md.

Run

npm install
npm run dev          # tsx src/index.ts  (dev)
# or
npm run build && npm start

Binds loopback only: http://127.0.0.1:7771 (override with NEURON_CONNECTD_PORT).

Config

Reads ~/.neuron/connectors.json. If absent, falls back to a Phase-1 default: one zero-auth filesystem MCP server scoped to ~/neuron-connectd-sandbox.

{
  "servers": {
    "filesystem": {
      "transport": "stdio",
      "enabled": true,
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"]
    }
  }
}

Secrets never live in this file — Phase 3 puts OAuth/API tokens in the macOS Keychain (ai.neuron.connect).

HTTP contract (Axon-shaped)

Method + path Body Returns
GET /mcp/tools { tools: [{ name:"mcp__<srv>__<tool>", description, input_schema }] }
POST /mcp/call { name, input } { ok, content } or { ok:false, error }
GET /mcp/servers { servers: [{ id, status, tools }] }
GET /healthz { ok:true }

Tools are namespaced mcp__<serverId>__<toolName>; POST /mcp/call routes back to the owning server by that prefix. input_schema is translated from MCP's inputSchema into Anthropic tool format so the soul can splice it straight into its tools array.

Auth (Phase 3)

Remote (http) connectors support two auth modes:

  • auth: "token" — a static bearer token stored in the Keychain under account <serverId>. The bridge reads it and sends Authorization: Bearer …. Covers GitHub PATs and any API-key MCP server.

  • auth: "oauth" — SDK-driven PKCE. The bridge exposes:

    • POST /mcp/oauth/start {id}{ authUrl } (open in the system browser)
    • GET /mcp/oauth/callback?id=..&code=.. → completes the exchange, stores tokens in the Keychain, reconnects.

    Tokens, the dynamic-registration client info, and the in-flight PKCE verifier all live in the Keychain (<serverId>:oauth / :client / :verifier), so a sign-in survives bridge restarts.

Status

  • Phase 1 (done): stdio servers, tool merge + namespacing, call routing, graceful error paths. Proven against server-filesystem via curl.
  • Phase 2 (done): soul integration — chat.el merges + dispatches mcp__* tools; the model calls them through the approval loop. Proven on a rebuilt soul.
  • Phase 3 (done): http (Streamable HTTP) transport, Keychain-backed secrets, token auth, OAuth (PKCE) provider + endpoints. Token path proven end-to-end against a local token-gated MCP server (positive + negative); OAuth provider mechanics proven via Keychain round-trip. Note: the full live OAuth handshake (discovery → DCR → consent) is correct-by-construction on the SDK's flow but still needs a real OAuth MCP server to exercise end-to-end.
  • Phase 4 (todo): ConnectorsView.kt UI + /api/connectors/* soul routes.
  • Phase 5 (todo): server catalog, schema-hash pinning, per-connector auto-approve, config hot-reload, run neuron-connectd as a managed daemon.
S
Description
No description provided
Readme
145 KiB
Languages
TypeScript 94.6%
JavaScript 5.4%