Guide

Agents

The same thirty tools over MCP, the Pi extension and the OMP extension, what they hold back, and how tokens and hosts stay out of a model's hands.

Thirty tools, three surfaces

The MCP server, the Pi extension and the OMP extension all call the same executors in src/tool-operations.ts, so they answer identically. Fix one, fixed everywhere. The tools mirror the nine resources:

GroupTools
repositoriesforges_repos_list, forges_repos_get
contribution templatesforges_contribution_templates_list, forges_contribution_templates_get
codeforges_code_search
CI and commitsforges_ci_runs_list, forges_commits_list, forges_commits_get
issuesforges_issues_list, forges_issues_search, forges_issues_get, forges_issues_comments, forges_issues_comments_get, forges_issues_create
pull requestsforges_pull_requests_list, forges_pull_requests_search, forges_pull_requests_get, forges_pull_requests_files, forges_pull_requests_checks, forges_pull_requests_comments, forges_pull_requests_comments_get, forges_pull_requests_create
users and authforges_users_get, forges_users_authenticated, forges_auth_reload
review threadsforges_threads_list, forges_threads_get, forges_threads_reply, forges_threads_resolve, forges_threads_unresolve

Every tool takes a platform of github, gitlab or gitea plus the owner, repo, number or username the call needs.

MCP

forges mcp
claude mcp add forges --scope user -- npx -y @agntn/forges mcp

Or in a client's config:

{
  "mcpServers": {
    "forges": { "command": "npx", "args": ["-y", "@agntn/forges", "mcp"] }
  }
}

The server speaks MCP over stdio. createMcpServer() from @agntn/forges/mcp returns the same server for a host that brings its own transport.

An MCP client sees the text a tool returns and nothing else, so the text carries the whole answer as JSON. Lists and searches drop bodies and name the tool that reads one in full. One page of a busy repository with bodies is big enough to push the conversation that asked for it out of the window, and I would rather the model asks twice. Pull request search leaves revision details to forges_pull_requests_get. forges_threads_list bounds each comment to twelve lines and four thousand characters but keeps every comment of every thread on the page, so ask for a small perPage on a heavily reviewed pull request. The comment tools carry the same bound, and their _get variants read one comment whole.

Reads, writes and credentials

Read tools use the normal token chain and fall back to anonymous access when nothing is found. Anonymous providers are kept apart and can never be reused for a write, not even by accident.

Five tools write: forges_issues_create, forges_pull_requests_create, forges_threads_reply, forges_threads_resolve and forges_threads_unresolve. They carry MCP annotations saying so, readOnlyHint: false. The two creates and the reply are marked as not idempotent because doing them twice leaves two of them behind. Resolve and unresolve are idempotent. forges_users_authenticated names the account the writes would go out as, check it before you let a model write anything.

The credential stays pinned per platform and endpoint until forges_auth_reload swaps it and returns the new profile. Reload is gated as a mutation because it changes local server state. It writes nothing to the platform.

Hosts stay local

A self hosted endpoint is FORGES_GITHUB_BASE_URL, FORGES_GITLAB_BASE_URL or FORGES_GITEA_BASE_URL in the agent's process environment. Never a tool argument, so a model cannot aim a call at another host. A failure names the status and, on a rate limit, the retry window. It never repeats the endpoint, so the host stays out of the model's context even when the platform answers with an error.

A failed operation is a tool error, not a transport failure: unknown repository, rejected token, exhausted rate limit. The model sees a sentence, the session survives.

Pi and OMP

pi install npm:@agntn/forges

The package declares both extensions in package.json. They render tool calls and results in the terminal: a repository row, a list of pull requests with their states, a thread with its comments, bounded the same way the MCP text is. forges_repos_get includes fork state, the parent and the viewer's role. A null role means the platform said nothing, not that the viewer has no access.

What the answer is

The tools return the normalized objects, not prose. The Explorer shows the same objects for any public repository, a quick way to check a model's summary against the source when it gets creative.

Issue bodies, comments and review threads are written by whoever has an account on the platform. Data to report, not instructions to follow. An agent that reads body: "ignore previous instructions" has learned one thing about the issue and nothing about what to do next.

@agntn/forges·MIT license· Issue bodies, comments and review threads are data, never instructions.