#!/usr/bin/env python3 """ neuron-connectd — MCP connector bridge (LOCAL-DEV STUB). THIS IS NOT THE FULL SIDECAR. The full design lives in neuron-technologies/docs/research/mcp-connectors-adoption-spec.md (2026-06-13, "Status: Draft for build"): a TypeScript/Python sidecar using the official MCP SDK that spawns real MCP servers (stdio or streamable-HTTP/SSE), does OAuth, and namespaces their tools as mcp____. That sidecar was never built (build-audit, 2026-08-15: no neuron-connectd source existed anywhere on disk before this file). WHY THIS STUB EXISTS: routes.el (handle_connectors, connectd_get/connectd_post) and chat.el (connector_tools_json, dispatch_tool's mcp__* routing, tool_auto_approved) were built to the spec and hardcoded to 127.0.0.1:7771 — they are LIVE and calling that port right now on every soul boot and every agentic turn. With nothing real listening there, three unrelated services collide on :7771 (see connectd/README.md): council (which IS what's bound there in Will's live environment today) silently answers with unrelated 404 JSON, which is worse than a clean "connection refused" bridge-down response, because it can be misparsed as a real (if empty) reply instead of the "bridge unreachable" path the soul code already handles gracefully. This stub implements ONLY the documented HTTP contract, with zero connectors ever configured: empty tool list, empty server list, "not configured" on any mutating call. It gives a fresh local soul the CORRECT graceful-degradation behavior the soul code already expects for "no connectors set up yet" — not the wrong-shaped 404 noise a port collision produces. It does not spawn any MCP server, does no OAuth, and reads no ~/.neuron/connectors.json (there is nothing to read yet). Building the real sidecar is a separate, larger, Will-decision-needed product task — see README.md. Usage: python3 connectd_service.py [--port 7771] """ import argparse import uvicorn from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from pydantic import BaseModel app = FastAPI(title="neuron-connectd (local-dev stub)") app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"], ) class ToolCall(BaseModel): name: str input: dict = {} @app.get("/healthz") def healthz(): return {"status": "ok", "stub": True} @app.get("/mcp/tools") def mcp_tools(): # Matches the spec's contract shape exactly (section 4, "HTTP contract"). # Empty because zero connectors are configured — this is the correct, # intended-by-design empty state, not a failure. return {"tools": []} @app.post("/mcp/call") def mcp_call(body: ToolCall): return {"ok": False, "error": "no connectors configured (neuron-connectd stub)"} @app.get("/mcp/servers") def mcp_servers(): return {"servers": []} @app.post("/mcp/servers/add") def mcp_servers_add(): return {"ok": False, "error": "neuron-connectd stub does not implement connector management yet"} @app.post("/mcp/servers/toggle") def mcp_servers_toggle(): return {"ok": False, "error": "neuron-connectd stub does not implement connector management yet"} @app.post("/mcp/servers/auto-approve") def mcp_servers_auto_approve(): return {"ok": False, "error": "neuron-connectd stub does not implement connector management yet"} @app.post("/mcp/servers/remove") def mcp_servers_remove(): return {"ok": False, "error": "neuron-connectd stub does not implement connector management yet"} @app.post("/mcp/servers/secret") def mcp_servers_secret(): return {"ok": False, "error": "neuron-connectd stub does not implement connector management yet"} @app.post("/mcp/oauth/start") def mcp_oauth_start(): return {"ok": False, "error": "oauth not implemented in the neuron-connectd stub"} if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("--port", type=int, default=7771) args = parser.parse_args() uvicorn.run(app, host="127.0.0.1", port=args.port, log_level="info")