Gitian

Reference

The MCP servers, the tools grouped by job, the config file and the annotation syntax.

The MCP server

The knowledge base is a remote MCP server at one URL:

https://gitian.dev/api/mcp/kb

It speaks streamable HTTP and keeps no session: every call is a self-contained POST, so a client can reconnect at any time without resuming anything. Any MCP client that sends a bearer token and follows discovery from a 401 can connect.

Every call
POST https://gitian.dev/api/mcp/kb
Authorization: Bearer <token>
Content-Type: application/json
Accept: application/json, text/event-stream

Sign-in, discovered from the 401

A call without a token answers 401 with a WWW-Authenticate header that points at the server's own metadata. From there the client finds the authorization server, registers itself (dynamic client registration, public clients only, no client secret) and opens your browser for consent. The authorization code flow requires PKCE. Every approved connection is listed in Settings and can be revoked on its own.

The discovery chain
401  WWW-Authenticate: Bearer resource_metadata="…"
  → /.well-known/oauth-protected-resource/api/mcp/kb
  → /.well-known/oauth-authorization-server
  → /oauth/register    dynamic client registration
  → /oauth/authorize   consent, in the browser
  → /oauth/token       code + PKCE verifier

API tokens

Where no browser can open, as in CI, mint a personal access token in Settings. It starts with gkb_, is shown once, and only its SHA-256 hash is stored.

claude mcp add --transport http gitian-kb https://gitian.dev/api/mcp/kb --header "Authorization: Bearer gkb_…"

A fixed Authorization header turns the browser sign-in off, which is why the plugin ships none. The bare /api/mcp is an older address for the same server; connect new clients to /api/mcp/kb.

The repository server

Your repositories are a second, read-only server, with its own consent. A token for one server is refused by the other; when minting one for this server, choose Repositories.

claude mcp add --transport http gitian-code https://gitian.dev/api/mcp/code

Its tools are code_repos, code_overview, code_search, code_page, code_annotation, code_prs and code_pr. It reads only what you can open in Gitian, never clones a repository and never returns a whole file. The pull-request tools read a synced copy of pull-request metadata (never a body or a comment), say when it was last refreshed, and return pr_ref, the [[pr:owner/name#N]] link to paste into a knowledge-base item. A repository you cannot open answers as if it did not exist.

Tools by job

Names are stable, and the set grows, so treat the server's own tool list as the authority.

orient
search, list, neighbors, topic, file_intents, history, and changes for everything written since a time.
read
get an item, at any revision, with what it links to and from; read_resource for clients that cannot read resources.
publish
publish_doc, publish_memory, publish_entry, and batch_write for several at once.
revise
patch_doc, patch_memory, append_entry; retract_item keeps the history and can redirect; move_item carries a doc to another knowledge base.
curate
publish_topic, retract_topic, publish_category. Merging topics is done in the web app.

The server also teaches its own formats as resources: gitian-kb://format/*, one guide per kind plus shared conventions, and gitian-kb://vocab, the live topics and categories. Every response carries vocab_rev, which changes only when a topic or category does. Warnings never fail a write, and errors are typed so a client can branch on them.

.gitian/config.yaml

One optional file at the repository root. Every field is optional, and with no file at all Gitian uses its defaults with the built-in categories.

.gitian/config.yaml
annotations:
  anchor: gitian           # you write @gitian:…
  render_style: nested     # nested | separated
  detect_docs: false       # @param, @returns, @deprecated in /** */ and ///
  detect_keywords: false   # bare TODO, FIXME, HACK, …
  keywords:                # keyword → category, with detect_keywords
    FIXME: bug
  tags:                    # your own categories
    decision:
      kind: block          # marker | inline | block
      color: "#8b5cf6"     # required
      label: "Decision"
      urgency: normal      # subtle | normal | loud | critical
      groups: "architecture"
      pinned: false        # pinned categories surface on the overview
discovery:
  docs_dirs: "docs,.docs"
groups:
  auth: { color: "#10b981", label: "Auth", pinned: true }
files:
  hide_source_only: false  # hide files with no docs and no annotations
modules:                   # named areas of the repo on the overview
  payments: { label: "Payments", dir: src/payments, group: billing }
pr_analysis:               # pull request comments from the GitHub App
  alert_tags: [security, bug]
sharing: true              # shareable file links

An annotation joins a module when its file is under one of the module's dir paths, its groups include the module's group, or it carries --module=. Leave modules out to keep the plain overview.

Annotation syntax

@gitian:<category> in any line comment (//, ///, #, --, %) or block comment. Metadata follows on its own comment lines, one --key=value each; a key starts with a letter and a value is one token, so quote a title with spaces.

--id=
A stable id, for directives, api payloads and code references. Keep it unique in the repository.
--title="…"
Replaces the heading shown for the annotation.
--group=
Comma-separated groups, across files.
--urgency=
subtle, normal, loud or critical.
--module=
Binds the annotation to a module.
--pr=
The pull request behind the annotation: 123, #123, owner/name#123, a pull request URL, or a comma-separated list. Shown as a pull request chip.
--request=
api kind only: the id of the annotation whose code is the request.
--response=
api kind only: the id of the annotation whose code is the response.

Directives: {{annotation:<id>}}, {{annotation:#<group>}} and {{annotation:@<category>}}.