dsh-web-search-ddg
aooyoo
Zero-token DuckDuckGo search provider for the DeepSeek Harness (DSH) web seam — local headless browser, no API key, no m…
PROJECT TOPICS
PROJECT README
repogate is a GitHub workbench for coding agents: it wraps the GitHub REST API into a set of MCP (Model Context Protocol) tools, letting agents perform repo queries, issue management, PR creation and merging, code review, search, and other common operations directly in a conversation.
fetch, node:test); no packages need to be installed to run;cordis.patch.yml + a self-developed bridge plugin), connected with dsh plugin add in one step — tools appear automatically in the model's tool list (mcp__repogate__*);# requires Node.js ≥ 18.17
REPOGATE_TOKEN=ghp_yourtoken node src/entry.js
Example config line using the official dsh bridge (also works in Claude Code / Codex MCP configs):
# dsh: insert into $DSH_HOME/profiles/<profile>/cordis.patch.yml
- insert:
- id: mcp-repogate
name: '@deepseek-ai/dsh-mcp-client'
config:
serverName: repogate
transport: stdio
command: node
args: ['/absolute/path/to/src/entry.js']
env:
REPOGATE_TOKEN: !!js process.env.REPOGATE_TOKEN ?? ''
After connecting, the model sees 23 tools such as gh_issue_fetch and gh_pr_merge
(generic MCP clients see bare names; under dsh they carry the mcp__repogate__ prefix, see below).
This plugin is declared as a dsh bundle (the dsh.bundle field in package.json). In the plugin checkout directory run:
dsh plugin --profile web add .
web profile automatically and adds this package to dsh.profile.bundles;repogate/bridge plugin defined in the package's cordis.patch.yml launches this MCP server directly inside the dsh process, and after the handshake registers all tools into ctx.tools — no manual config changes needed;REPOGATE_TOKEN or GITHUB_TOKEN);dsh plugin --profile web remove repogate.After installing, restart dsh and simply say in a session:
"Look at the open issues of the octo/hello repo, close #12, then comment 'fixed, waiting for verification' on #12."
The corresponding tool call chain: mcp__repogate__gh_issue_browse → mcp__repogate__gh_issue_fetch →
mcp__repogate__gh_issue_edit → mcp__repogate__gh_issue_respond.
Note: dsh does not enable any MCP server by default (each server command is trusted code executed outside the sandbox); this plugin's bundle line is the "enable" action itself; only install trusted plugins.
dsh plugin --profile demo add github:JohnXu22786/github-mcp
A single command installs this plugin into the dsh demo profile from the GitHub repository. Integration, auth, and lifecycle details follow in the "dsh integration" section below.
dsh uses the Cordis plugin framework; the unit of composition is a bundle: an npm package + a patch layer. The loading chain is as follows:
package.json (dsh.bundle.patch → ./cordis.patch.yml)
└─ a line in cordis.patch.yml: name: 'repogate/bridge'
└─ src/bridge/plugin.js (Cordis plugin, inject: ['tools'])
├─ spawns src/entry.js (the MCP server child process, stdio) using Node itself
├─ completes the initialize / tools/list handshake
└─ registers each tool as mcp__repogate__<tool name> into ctx.tools
mcp__<serverName>__<original tool name>, serverName defaults to repogate;ctx.tools tool interface;apply; on unload it kills the child process and unregisters all tools automatically
(cleanup registered via ctx.effect, so hot reloads/unloads leave no residue);repogate/bridge (zero dependencies, works out of the box) and
the official dsh @deepseek-ai/dsh-mcp-client config line (see examples/overlay-for-dsh.yml.example);
the tools are named and behave identically — pick either one, do not enable both;env config; the built-in bridge's child process inherits the host environment, so REPOGATE_TOKEN is passed through automatically.| Symptom | Treatment |
|---|---|
| Tools don't appear in the list | Check whether the cordis.patch.yml line took effect (dsh --profile <name> --dump-config to inspect layers), confirm no errors in the startup log |
| 401 invalid token | Check the env.REPOGATE_TOKEN config; or ask the model to call mcp__repogate__gh_auth_login in the session to use OAuth |
| Want read-only | Configure args: ['--read-only'] on the bridge line, or append --read-only to the official line's args |
| pnpm ≥10 rejects prepare scripts on git installs | This plugin is pure JS with no build script, so it's not affected; install from checkout or tarball |
| Domain | Tool | Purpose | Write op |
|---|---|---|---|
| Repo | gh_repo_fetch |
Repo details: default branch, stars, language, visibility | |
| Repo | gh_repo_browse |
List user/org/own repos (paginated) | |
| Issue | gh_issue_open |
Create an issue (title required, optional labels/assignee) | ✔ |
| Issue | gh_issue_fetch |
View full issue info | |
| Issue | gh_issue_browse |
Filter by state/labels/assignee/author (pages may exclude PRs) | |
| Issue | gh_issue_edit |
Edit title/body/state/assignee/labels | ✔ |
| Issue | gh_issue_respond |
Post a comment (works in PR threads too) | ✔ |
| PR | gh_pr_open |
Create a pull request (head/base/draft) | ✔ |
| PR | gh_pr_fetch |
PR details: mergeability, changed stats, review count | |
| PR | gh_pr_browse |
Filter by state/branch, sort, paginate | |
| PR | gh_pr_edit |
Edit title/body/state/draft/base branch | ✔ |
| PR | gh_pr_merge |
Merge (method/commit message/delete source branch) | ✔ |
| Review | gh_review_submit |
Submit a full review: approve / request_changes / comment | ✔ |
| Review | gh_review_comment |
Line-level diff comments (including range comments) | ✔ |
| Review | gh_review_fetch |
List all line-level comments | |
| Review | gh_review_browse |
List submitted full reviews | |
| Search | gh_search_repos |
Search repos with GitHub search syntax | |
| Search | gh_search_issues |
Search issues/PRs (type:pr distinguishes) |
|
| Search | gh_search_code |
Search code (requires token, returns file hits) | |
| Account | gh_whoami |
Current identity, token source, read-only mode, API quota | |
| Auth | gh_auth_login |
Start OAuth device authorization (requires configured clientId) | |
| Auth | gh_auth_check |
Poll authorization result once | |
| Auth | gh_auth_logout |
Clear the local token cache |
All tools take JSON Schema inputs (name/description/inputSchema) that models can discover on their own;
write tools are intercepted with a clear message in read-only mode.
Priority: CLI flags > environment variables > config file > defaults. The config file is JSON, its path given by --config
or REPOGATE_CONFIG; see examples/repogate.config.json.example.
| Config item | Environment variable | Default |
|---|---|---|
| Access token | REPOGATE_TOKEN (also accepts GITHUB_TOKEN / GH_TOKEN) |
none |
| API base URL (enterprise instances) | REPOGATE_BASE_URL |
https://api.github.com |
| Read-only mode | REPOGATE_READ_ONLY (1/true/yes/on) |
false |
| Per-request timeout (ms) | REPOGATE_TIMEOUT_MS |
30000 |
| OAuth Client ID | REPOGATE_OAUTH_CLIENT_ID |
none |
| OAuth token cache file | REPOGATE_TOKEN_FILE |
~/.repogate/token.json when oauth.clientId is configured |
| Config file path | REPOGATE_CONFIG |
none |
| Debug logging (stderr) | REPOGATE_DEBUG |
false |
CLI flags: --config --token --read-only --base-url --timeout-ms
--oauth-client-id --token-file --debug --version --help.
Generate one in GitHub's Developer settings (check the repo permissions needed on a fine-grained token), then choose any of:
REPOGATE_TOKEN=ghp_xxx node src/entry.js # environment variable
node src/entry.js --token ghp_xxx # CLI flag
node src/entry.js --config repogate.config.json # config file (token field)
Token resolution order: --token > REPOGATE_TOKEN > GITHUB_TOKEN > GH_TOKEN > config file > cache file.
For those who'd rather not assemble a token by hand. You first need a GitHub App's Client ID (the device flow only requires a public client_id):
oauth.clientId (config file or REPOGATE_OAUTH_CLIENT_ID);gh_auth_login → returns an authorization URL and a one-time code;gh_auth_check (may be called multiple times; each call checks once) → once granted, the token is written to the cache file,
and all tools become available; the cached token survives process restarts;gh_auth_logout clears the cache.Note: the device authorization endpoint always uses github.com; for enterprise instances (custom
baseUrl) use a PAT. The token cache file is written with 0600 permissions; do not commit the cache file to version control.
node src/entry.js --read-only # or REPOGATE_READ_ONLY=1
When enabled, the 8 write tools (gh_issue_open / gh_issue_edit / gh_issue_respond /
gh_pr_open / gh_pr_edit / gh_pr_merge / gh_review_submit / gh_review_comment)
are intercepted after argument validation and return a [readonly] error explaining how to turn it off; query, search, and auth tools are unaffected.
All failures are returned as structured errors (MCP isError: true + structuredContent.error) in the form
[error code] reason. Common error codes and typical scenarios:
| Error code | Scenario | Guide |
|---|---|---|
auth |
Token missing/invalid (401) | Configure a token or use OAuth device authorization |
ratelimit |
Quota exhausted (403/429) | Report reset time or Retry-After seconds |
http |
404/403/422/409 etc. | Explain the specific cause (not found/no permission/params rejected/conflict) |
validation |
Argument validation failed | Point out which argument is invalid |
readonly |
Read-only mode blocks a write | Explain how to disable |
timeout |
Request timeout | Suggest increasing timeoutMs |
network |
Network-layer failure | Check the network and baseUrl |
The gateway automatically retries once on 502/503/504 and network jitter (idempotent read requests only; writes are not retried to avoid duplicate side effects);
if a 5xx still fails after retry, it returns an http error instead of failing silently.
src/
├── entry.js entry: config parsing → assembly → start the stdio session
├── protocol/ protocol layer (MCP over stdio, line-delimited JSON-RPC 2.0)
│ ├── jsonrpc.js message encoding/decoding and classification
│ ├── transport.js stdin/stdout read/write loop (logs go to stderr only)
│ └── engine.js session engine: initialize / ping / tools/list / tools/call
├── core/ core layer
│ ├── config.js layered config merge (flag > env > config file > defaults)
│ ├── auth.js credential hub: token resolution + OAuth device auth state machine + cache
│ ├── gateway.js REST gateway: request assembly/retry/timeout/status-code mapping
│ └── errors.js unified error model with actionable hints
├── tools/ tool layer
│ ├── registry.js registry: argument validation (JSON Schema subset) + read-only gate + dispatch
│ ├── repo.js / issue.js / pull.js / review.js / search.js / account.js
│ └── index.js assembles the 23 tools
├── bridge/ dsh integration
│ ├── client.js MCP stdio client (initialize/list/call, cancellation and timeout)
│ └── plugin.js Cordis plugin: spawns the server and registers tools into ctx.tools
└── util/format.js output shaping: entity summaries, pagination detection, URL building
test/ tests (node:test, zero dependencies)
├── helpers/ fake fetch and a local mock API service
└── *.test.js protocol/gateway/config/auth/registry/tool/end-to-end (121 test cases)
Design highlights:
bridge/client.js and the server share the same JSON-RPC vocabulary, so handshake and call logic are consistent.node --test # run all 121 tests (including real child-process end-to-end)
node src/entry.js --help
Test coverage: protocol handshake and error paths (including interception of uninitialized sessions), gateway retry (idempotent methods only) and status-code mapping, the full OAuth state machine (including expiry), config priority, argument validation, the read-only gate, request construction and output shaping for all 23 tools, and an end-to-end chain of "real child process + local mock API".
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。