Add MCP registry
Seto Elkahfi committed
Jul 22, 2026 at 22:59 UTC
674b836af43db766b20c04deeec634dcace31825
4 files changed
+181
-1
.agents/AGENTS.md
+6
-1
@@ -180,7 +180,12 @@ feeds results back. Neither the loop nor ACP/TUI surfaces depend on a concrete b
180
corresponding baked-in one. Extra servers live in `mcp.toml` (global
181
`$SIGIT_CONFIG_DIR/mcp.toml` and project-local `.sigit/mcp.toml`). The stdio path is covered by
182
`tests/mcp_stdio.rs`, driven by the test-only `src/bin/mcp_stdio_stub.rs` helper binary
183
- (excluded from the published crate via `exclude` in `Cargo.toml`).
183
+ (excluded from the published crate via `exclude` in `Cargo.toml`). The baked-in official
184
+ server is *also* listed in the public MCP Registry as `si.sigit/sigit` — a **remote**
185
+ Streamable-HTTP listing (`server.json` at the repo root, published by
186
+ `release-mcp-registry.yml`). Because it's a remote server, the registry's URL-match rule
187
+ forces a domain namespace (`si.sigit` ↔ `sigit.si`) verified by a DNS TXT record, not the
188
+ GitHub-OIDC scheme `smbcloud-cli` uses for its package listing.
189
- **`src/permissions.rs`** — tool permission policy. Every tool call passes through
190
`decision_for` before executing: read-only tools always run; mutating tools (and all
191
`mcp__*`/unknown tools) are governed by, in order: per-session plan mode (`/plan` — deny all
.github/workflows/release-mcp-registry.yml
new
+79
@@ -0,0 +1,79 @@
1
+name: MCP Registry Release
2
+
3
+on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ version:
7
+ description: "Override the version in server.json (e.g. 0.2.0); leave blank to publish as-is"
8
+ required: false
9
+
10
+# A remote server proves namespace ownership through domain (DNS) verification,
11
+# not GitHub OIDC: the registry checks a v=MCPv1 TXT record on sigit.si against
12
+# a request signed with the matching Ed25519 private key. See the MCP Registry
13
+# doc in the sigit-si repo for the one-time key/DNS setup.
14
+permissions:
15
+ contents: read
16
+
17
+jobs:
18
+ publish:
19
+ name: Publish server.json to the MCP Registry
20
+ runs-on: ubuntu-latest
21
+ steps:
22
+ - name: Checkout
23
+ uses: actions/checkout@v6
24
+
25
+ - name: Optionally override the version in server.json
26
+ shell: bash
27
+ run: |
28
+ version="${{ github.event.inputs.version }}"
29
+ if [ -n "${version}" ]; then
30
+ jq --arg v "${version}" '.version = $v' server.json > server.tmp
31
+ mv server.tmp server.json
32
+ fi
33
+ cat server.json
34
+
35
+ - name: Check the remote URL matches the namespace domain
36
+ shell: bash
37
+ run: |
38
+ # The registry rejects a remote server whose URL isn't under the
39
+ # namespace's domain. si.sigit -> sigit.si, so every listed remote
40
+ # must live on sigit.si (or a subdomain).
41
+ server_name="$(jq -r '.name' server.json)"
42
+ domain="$(echo "${server_name%%/*}" | awk -F. '{ for (i=NF; i>=1; i--) printf "%s%s", $i, (i>1 ? "." : "") }')"
43
+ echo "Server: ${server_name} Domain: ${domain}"
44
+
45
+ bad="$(jq -r --arg d "${domain}" '
46
+ .remotes // []
47
+ | map(.url | sub("^[a-z]+://"; "") | sub("/.*$"; ""))
48
+ | map(select(. != $d and (endswith("." + $d) | not)))
49
+ | .[]' server.json)"
50
+ if [ -n "${bad}" ]; then
51
+ echo "Remote URL host(s) not under ${domain}: ${bad}" >&2
52
+ exit 1
53
+ fi
54
+
55
+ - name: Install mcp-publisher
56
+ shell: bash
57
+ run: |
58
+ curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher
59
+
60
+ - name: Authenticate to the MCP Registry
61
+ shell: bash
62
+ env:
63
+ MCP_REGISTRY_DNS_PRIVATE_KEY: ${{ secrets.MCP_REGISTRY_DNS_PRIVATE_KEY }}
64
+ run: |
65
+ if [ -z "${MCP_REGISTRY_DNS_PRIVATE_KEY}" ]; then
66
+ echo "MCP_REGISTRY_DNS_PRIVATE_KEY secret is not set. See the MCP Registry doc in the sigit-si repo." >&2
67
+ exit 1
68
+ fi
69
+ ./mcp-publisher login dns --domain=sigit.si --private-key="${MCP_REGISTRY_DNS_PRIVATE_KEY}"
70
+
71
+ - name: Publish
72
+ shell: bash
73
+ run: ./mcp-publisher publish
74
+
75
+ - name: Verify the server is listed
76
+ shell: bash
77
+ run: |
78
+ server_name="$(jq -r '.name' server.json)"
79
+ curl -fsSL "https://registry.modelcontextprotocol.io/v0.1/servers?search=${server_name}" | jq .
docs/mcp.md
new
+68
@@ -0,0 +1,68 @@
1
+# The official siGit MCP server
2
+
3
+siGit Code Cloud runs a hosted [Model Context Protocol](https://modelcontextprotocol.io)
4
+server at **`https://sigit.si/api/v1/mcp`**. It's a stateless **Streamable-HTTP**
5
+server (JSON-RPC 2.0 over a single POST endpoint) that exposes your
6
+siGit-hosted git repositories — plus web search — as MCP tools, so any MCP
7
+client can browse repos, read files, search code, and open or comment on pull
8
+requests and issues on your behalf.
9
+
10
+This page documents the server from a **client's** perspective: the siGit Code
11
+CLI is its reference consumer, but the endpoint is a standard remote MCP server
12
+that works with any compliant client. The server implementation itself is
13
+closed-source (it's part of the hosted service); only this consumer-facing
14
+description is public.
15
+
16
+## Tools
17
+
18
+| Tool | What it does |
19
+| --- | --- |
20
+| `list_repositories` | List the git repositories the authenticated user can access. Use this first to discover the `owner/name` to pass to other tools. |
21
+| `get_file_contents` | Read a file's contents at a given ref (branch, tag, or commit SHA). |
22
+| `search_code` | Search file contents across a repository; returns matching files with line snippets. |
23
+| `list_issues` | List issues in a repository, optionally filtered by state or a title/body search. |
24
+| `get_issue` | Fetch one issue by number, including its body and comments. |
25
+| `create_issue` | Open a new issue in a repository. |
26
+| `list_pull_requests` | List pull requests in a repository, optionally filtered by state. |
27
+| `get_pull_request` | Fetch one pull request by number. |
28
+| `create_pull_request` | Open a pull request from a head branch into a base branch. |
29
+| `add_issue_comment` | Post a comment on an issue or pull request by its number. |
30
+| `web_search` | Search the public web; returns matching pages as title, URL, and snippet. |
31
+
32
+All repository tools take a repo in `owner/name` form and only ever see
33
+repositories the authenticated user may access.
34
+
35
+## Authentication
36
+
37
+The server is a per-user protected resource. Every `tools/call` requires an
38
+`Authorization: Bearer <token>` header carrying a siGit Code Cloud session
39
+token. Unauthenticated requests get a `401` with a `WWW-Authenticate` header
40
+advertising the OAuth protected-resource metadata, so MCP clients that support
41
+OAuth can discover the sign-in flow automatically.
42
+
43
+Being stateless, the server issues no `Mcp-Session-Id` and offers no
44
+server→client SSE stream (a `GET` to the endpoint returns `405`) — a valid,
45
+tool-only MCP transport mode.
46
+
47
+## How the siGit Code CLI uses it
48
+
49
+The CLI bakes this endpoint in as its **official** MCP server (default
50
+`https://sigit.si/api/v1/mcp`, overridable via `SIGIT_CLOUD_URL`). When you're
51
+signed in with `sigit login`, the CLI sends your cloud session token as the
52
+bearer credential; when you're not, the server simply contributes no tools.
53
+Its tools are namespaced `mcp__sigit__<tool>` inside the agent (see
54
+[`src/mcp.rs`](../src/mcp.rs)). `web_search` is additionally re-exposed as a
55
+first-class read-only tool rather than a raw `mcp__*` call.
56
+
57
+A user-defined `mcp.toml` entry named `sigit` overrides the baked-in default,
58
+so you can repoint the CLI at a different deployment without a code change.
59
+
60
+## MCP Registry listing
61
+
62
+The server is published to the
63
+[official MCP Registry](https://registry.modelcontextprotocol.io) as
64
+**`si.sigit/sigit`**, a remote Streamable-HTTP listing, so registry-aware
65
+clients can add it in one click. The registry only stores metadata; the
66
+`server.json` and publish workflow live in this repo, and namespace ownership is
67
+proven by a DNS TXT record on `sigit.si`. The internal setup and release runbook
68
+live with the server (private `sigit-si` repo).
server.json
new
+28
@@ -0,0 +1,28 @@
1
+{
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
+ "name": "si.sigit/sigit",
4
+ "title": "siGit Si",
5
+ "description": "siGit tools: browse repos, read files, search code, manage pull requests and issues, and web search.",
6
+ "version": "0.1.0",
7
+ "websiteUrl": "https://sigit.si",
8
+ "remotes": [
9
+ {
10
+ "type": "streamable-http",
11
+ "url": "https://sigit.si/api/v1/mcp"
12
+ }
13
+ ],
14
+ "_meta": {
15
+ "io.modelcontextprotocol.registry/publisher-provided": {
16
+ "categories": ["developer-tools", "version-control"],
17
+ "keywords": [
18
+ "git",
19
+ "code search",
20
+ "pull requests",
21
+ "issues",
22
+ "repositories",
23
+ "web search",
24
+ "coding agent"
25
+ ]
26
+ }
27
+ }
28
+}