main
md 6.31 KB

siGit Code wave three: stdio MCP, web search, and the repo tabs

Status: draft v1 (2026-07-05). Owner: product/eng. Audience: internal (private repo). Scope: the third feature wave for siGit Code, following sigit-code-parity-roadmap.md (wave one, shipped in v1.3.2) and sigit-code-copilot-cli-parity.md (wave two, in review). One ecosystem unlock, one core capability with a product hook, one differentiator. The three are independent and run in parallel; spec 3 stacks on the unmerged TUI tabs branch and rebases once that merges.


1. Spec: stdio MCP transport

Branch: feature/mcp-stdio-transport (sigit) · Touches: src/mcp.rs

Problem

Nearly every published MCP server (filesystem, Playwright, Postgres, GitHub's own) is stdio-first. siGit Code speaks only Streamable HTTP, so users cannot plug in most of the MCP ecosystem. Claude Code and Copilot CLI both support stdio.

Design

  • mcp.toml server entries gain the stdio shape: command (required), args = [...], [server.env], all mutually exclusive with url. Existing HTTP entries keep working unchanged.
  • A stdio server is spawned at discovery (mcp::init): child process with piped stdin/stdout, stderr inherited to the log. JSON-RPC frames are newline-delimited per the MCP stdio transport spec. The same initialize/tools/list handshake and tools/call forwarding as HTTP; the transport is an enum behind the existing server cache.
  • Lifecycle: the child lives for the sigit process; a dead child fails calls with a clear in-band error and is not restarted mid-session (restart on /reload). Discovery timeout applies to the handshake like HTTP. All children are killed on exit.
  • Same namespacing (mcp__<server>__<tool>), same output caps, same /mcp listing (show the command instead of the URL).
  • Cross-platform: plain std/tokio process handling, no cfg(unix).

Acceptance

  • A [[server]] entry with command = "npx", args = ["-y", "@modelcontextprotocol/server-everything"] (or a local stub) discovers tools and serves calls end to end.
  • Unit/integration tests use a tiny scripted stdio MCP server (a shell or Rust stub speaking the handshake) rather than a real npm package; CI stays hermetic. A dead-child call returns the in-band error.

2. Spec: web search through sigit.si

Branch: feature/mcp-web-search (sigit-si) · Touches: the MCP server, a new search proxy service

Problem

The agent can fetch a page (read_website) but cannot find one. Both competitors ship search. Routing it through sigit.si instead of baking a provider key into the client makes search a signed-in cloud feature, keeps one place to swap providers, and adds a concrete reason to sigit login.

Design

  • New MCP tool on the official server: web_search {query, count?} returning a compact JSON list of {title, url, snippet} (count default 5, max 10).
  • Behind it, a WebSearchService with a provider adapter. First provider: Brave Search API (SEARCH_PROVIDER=brave, BRAVE_SEARCH_API_KEY), chosen for its simple REST shape; the adapter boundary keeps Bing/SearXNG swappable. Unconfigured provider returns an in-band ToolError telling the operator what to set, never a 500.
  • Rate limit per user (reuse the existing rate-limit pattern if one exists; otherwise a simple per-user counter, e.g. 60 searches/hour) so a runaway agent cannot burn the provider quota.
  • Auth and result envelope follow the existing MCP tools exactly. Update .agents/specs/mcp-server.md.
  • Client side: nothing structural (MCP plumbing exists). Read-only classification of official-server tools ships with spec 3.

Acceptance

  • Request specs: happy path (provider stubbed with WebMock or the repo's HTTP-stubbing convention), unconfigured provider, rate limit, param validation. No live provider calls in CI.

3. Spec: Issues and Pull requests in the terminal

Branch: feature/tui-repo-tabs (sigit, stacked on feature/tui-tabs) · Touches: src/chat.rs, src/permissions.rs, src/main.rs (prompt)

Problem

Copilot CLI shows Issues and Pull requests tabs when run inside a GitHub repo. sigit.si is our own git host, the MCP repo workflow tools exist server-side (sigit-si #3), and siGit Code should be the best terminal client sigit.si has.

Design

  • When the session cwd's origin remote points at the sigit.si host (parse git remote get-url origin, compare against the SIGIT_API_URL host, default sigit.si), the TUI adds a Repo tab after History: two sections, Issues and Pull requests, fetched through the official MCP server (mcp__sigit__list_issues / mcp__sigit__list_pull_requests, repo derived from the remote's owner/name). Up/Down selects, Enter opens the detail (get_issue / get_pull_request) in a scrollable view, r refreshes, section toggle on i/p (or Left/Right).
  • Fetches run as spawned tasks feeding the render loop (the Cloud tab pattern); the tab degrades gracefully when signed out, MCP is off, or the remote is not sigit.si (tab hidden entirely in that last case).
  • Permission classification: the official server's read-only tools (list_*, get_*, search_code, get_file_contents, web_search) are classified read-only in permissions.rs so browsing never prompts; everything else mcp__sigit__* stays mutating. Match on the official server's namespace prefix plus tool-name prefix, not a hardcoded full list, so new server-side read tools inherit it.
  • Prompt guidance in main.rs: issue and PR workflows on sigit.si repos go through the mcp__sigit__* tools; reference them by exact name.
  • Stacking: branch from feature/tui-tabs. After sigit #25 merges, rebase onto development before opening the PR so it shows only its own commits (the repo's stacking rule).

Acceptance

  • In a repo cloned from sigit.si while signed in, the Repo tab lists real issues and PRs and opens details; signed out it shows the sign-in hint.
  • Unit tests for the remote-URL parsing (ssh and https forms, non-sigit hosts) and the read-only classification; TUI flows verified under tmux against a scripted MCP server.

4. After this wave

Hooks, a /context usage display, memory recall over remember, then the two big strategic items: sandboxing (Cloud Agent trust) and checkpointing/rewind.