harnessmith 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- harnessmith/__init__.py +3 -0
- harnessmith/catalog/__init__.py +166 -0
- harnessmith/catalog/mcp_servers.yaml +185 -0
- harnessmith/cli.py +348 -0
- harnessmith/cli_wizard.py +174 -0
- harnessmith/debuglog.py +59 -0
- harnessmith/generator.py +507 -0
- harnessmith/node_bootstrap.py +197 -0
- harnessmith/presets/__init__.py +50 -0
- harnessmith/presets/coding-assistant/mcp_prefill.yaml +13 -0
- harnessmith/presets/coding-assistant/spec.yaml +54 -0
- harnessmith/scaffold.py +145 -0
- harnessmith/spec.py +239 -0
- harnessmith/templates/.devcontainer/devcontainer.json.j2 +12 -0
- harnessmith/templates/.dockerignore.j2 +11 -0
- harnessmith/templates/.env.example.j2 +5 -0
- harnessmith/templates/.gitignore.j2 +17 -0
- harnessmith/templates/.python-version.j2 +1 -0
- harnessmith/templates/AGENTS.md.j2 +914 -0
- harnessmith/templates/Dockerfile.j2 +30 -0
- harnessmith/templates/LICENSE.j2 +21 -0
- harnessmith/templates/README.md.j2 +325 -0
- harnessmith/templates/RULES.md.j2 +10 -0
- harnessmith/templates/__launch_name__.bat.j2 +173 -0
- harnessmith/templates/__launch_name__.sh.j2 +143 -0
- harnessmith/templates/config.yaml.j2 +270 -0
- harnessmith/templates/pyproject.toml.j2 +50 -0
- harnessmith/templates/skills/example-skill/SKILL.md.j2 +30 -0
- harnessmith/templates/src/__project_slug__/__init__.py.j2 +3 -0
- harnessmith/templates/src/__project_slug__/harness/__init__.py.j2 +17 -0
- harnessmith/templates/src/__project_slug__/harness/config.py.j2 +681 -0
- harnessmith/templates/src/__project_slug__/harness/context.py.j2 +471 -0
- harnessmith/templates/src/__project_slug__/harness/debuglog.py.j2 +72 -0
- harnessmith/templates/src/__project_slug__/harness/extensions.py.j2 +188 -0
- harnessmith/templates/src/__project_slug__/harness/hooks.py.j2 +116 -0
- harnessmith/templates/src/__project_slug__/harness/interaction.py.j2 +266 -0
- harnessmith/templates/src/__project_slug__/harness/llm.py.j2 +425 -0
- harnessmith/templates/src/__project_slug__/harness/llm_anthropic.py.j2 +422 -0
- harnessmith/templates/src/__project_slug__/harness/loop.py.j2 +85 -0
- harnessmith/templates/src/__project_slug__/harness/mcp.py.j2 +1251 -0
- harnessmith/templates/src/__project_slug__/harness/memory.py.j2 +353 -0
- harnessmith/templates/src/__project_slug__/harness/mock.py.j2 +109 -0
- harnessmith/templates/src/__project_slug__/harness/paradigms/__init__.py.j2 +359 -0
- harnessmith/templates/src/__project_slug__/harness/paradigms/agent.py.j2 +236 -0
- harnessmith/templates/src/__project_slug__/harness/paradigms/ask.py.j2 +236 -0
- harnessmith/templates/src/__project_slug__/harness/paradigms/plan.py.j2 +240 -0
- harnessmith/templates/src/__project_slug__/harness/prompts.py.j2 +153 -0
- harnessmith/templates/src/__project_slug__/harness/session.py.j2 +316 -0
- harnessmith/templates/src/__project_slug__/harness/skills.py.j2 +143 -0
- harnessmith/templates/src/__project_slug__/harness/tools.py.j2 +357 -0
- harnessmith/templates/src/__project_slug__/harness/trace.py.j2 +110 -0
- harnessmith/templates/src/__project_slug__/harness/usage.py.j2 +207 -0
- harnessmith/templates/src/__project_slug__/interfaces/__init__.py.j2 +1 -0
- harnessmith/templates/src/__project_slug__/interfaces/cli.py.j2 +1261 -0
- harnessmith/templates/src/__project_slug__/interfaces/web.py.j2 +1456 -0
- harnessmith/templates/src/__project_slug__/interfaces/web_index.html.j2 +3296 -0
- harnessmith/templates/tests/_mcp_dummy_server.py.j2 +36 -0
- harnessmith/templates/tests/test_harness.py.j2 +2539 -0
- harnessmith/templates/tests/test_llm_anthropic.py.j2 +324 -0
- harnessmith/templates/tests/test_mcp.py.j2 +1126 -0
- harnessmith/templates/tests/test_memory.py.j2 +251 -0
- harnessmith/templates/tests/test_sessions.py.j2 +364 -0
- harnessmith/templates/tests/test_skills.py.j2 +112 -0
- harnessmith/templates/tests/test_web.py.j2 +1706 -0
- harnessmith/wizard/__init__.py +11 -0
- harnessmith/wizard/app.py +682 -0
- harnessmith/wizard/static/index.html +430 -0
- harnessmith-0.1.0.dist-info/METADATA +431 -0
- harnessmith-0.1.0.dist-info/RECORD +72 -0
- harnessmith-0.1.0.dist-info/WHEEL +4 -0
- harnessmith-0.1.0.dist-info/entry_points.txt +2 -0
- harnessmith-0.1.0.dist-info/licenses/LICENSE +21 -0
harnessmith/__init__.py
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"""Static MCP server catalog — a generation-time convenience datasource (Slice 6).
|
|
2
|
+
|
|
3
|
+
Loaded by ``harnessmith new --mcp-server <name>`` and by presets to PREFILL the
|
|
4
|
+
generated repo's runtime ``config.yaml`` (``mcp.servers`` + the tool allowlist).
|
|
5
|
+
It is **not** a security gate and is **not** part of :class:`HarnessSpec` or its
|
|
6
|
+
snapshot — the real gate is the runtime allowlist + per-tool risk markers.
|
|
7
|
+
Secrets are referenced by env-var NAME only, never stored as values.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from dataclasses import dataclass, field
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
import yaml
|
|
16
|
+
|
|
17
|
+
CATALOG_PATH = Path(__file__).parent / "mcp_servers.yaml"
|
|
18
|
+
|
|
19
|
+
SAFE = "safe"
|
|
20
|
+
HIGH = "high"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class CatalogError(Exception):
|
|
24
|
+
"""Raised when the catalog file or a requested server is invalid/missing."""
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass(frozen=True)
|
|
28
|
+
class CatalogTool:
|
|
29
|
+
name: str
|
|
30
|
+
risk: str = HIGH
|
|
31
|
+
default_enabled: bool = False
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass(frozen=True)
|
|
35
|
+
class CatalogServer:
|
|
36
|
+
"""One curated MCP server entry (transport + tools + provenance)."""
|
|
37
|
+
|
|
38
|
+
name: str
|
|
39
|
+
description: str = ""
|
|
40
|
+
transport: str = "stdio" # "stdio" | "remote"
|
|
41
|
+
command: str | None = None
|
|
42
|
+
args: list[str] = field(default_factory=list)
|
|
43
|
+
env: list[str] = field(default_factory=list) # env-var NAMES (secrets, from .env)
|
|
44
|
+
env_const: dict[str, str] = field(default_factory=dict) # literal non-secret env (e.g. MODE=stdio)
|
|
45
|
+
url: str | None = None
|
|
46
|
+
auth_env: str | None = None
|
|
47
|
+
requires: str | None = None # runtime prerequisite: "uv" | "node" | None
|
|
48
|
+
source: str = ""
|
|
49
|
+
updated: str = ""
|
|
50
|
+
tools: list[CatalogTool] = field(default_factory=list)
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def safe_tools(self) -> list[str]:
|
|
54
|
+
"""Unprefixed names of read-only/low-risk tools (offered to plan/ask)."""
|
|
55
|
+
return [t.name for t in self.tools if t.risk == SAFE]
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def uvx_package(self) -> str | None:
|
|
59
|
+
"""The pip/uvx package name for a uvx-launched server (else ``None``).
|
|
60
|
+
|
|
61
|
+
Handles both ``uvx <pkg>`` and ``uvx --from <pkg> <entrypoint>`` (used when
|
|
62
|
+
the package's console-script name differs from the package name) by taking
|
|
63
|
+
the first non-flag arg — matching the runtime warm path (``_warm_argv``)."""
|
|
64
|
+
if self.command == "uvx":
|
|
65
|
+
return next((a for a in self.args if not a.startswith("-")), None)
|
|
66
|
+
return None
|
|
67
|
+
|
|
68
|
+
def server_entry(self) -> dict:
|
|
69
|
+
"""A ``config.yaml`` ``mcp.servers`` entry (env-var NAMES only)."""
|
|
70
|
+
entry: dict = {"name": self.name}
|
|
71
|
+
if self.description:
|
|
72
|
+
entry["description"] = self.description
|
|
73
|
+
if self.command:
|
|
74
|
+
entry["command"] = self.command
|
|
75
|
+
entry["args"] = list(self.args)
|
|
76
|
+
if self.env:
|
|
77
|
+
entry["env"] = list(self.env)
|
|
78
|
+
if self.env_const:
|
|
79
|
+
entry["env_const"] = dict(self.env_const)
|
|
80
|
+
else:
|
|
81
|
+
entry["url"] = self.url
|
|
82
|
+
if self.auth_env:
|
|
83
|
+
entry["auth_env"] = self.auth_env
|
|
84
|
+
if self.safe_tools:
|
|
85
|
+
entry["safe_tools"] = self.safe_tools
|
|
86
|
+
return entry
|
|
87
|
+
|
|
88
|
+
def allowlist_entries(self) -> list[dict]:
|
|
89
|
+
"""``config.yaml`` ``tools`` allowlist entry for this server.
|
|
90
|
+
|
|
91
|
+
A single ``<server>__*`` wildcard that enables EVERY tool the server
|
|
92
|
+
exposes (present and future), so the full toolset is available by default
|
|
93
|
+
without listing each tool by name. Per-tool risk still comes from
|
|
94
|
+
``safe_tools`` (read-only tools stay ``safe``; the rest are ``high``), and
|
|
95
|
+
any tool can be turned off individually later from ``config.yaml`` / the web
|
|
96
|
+
Tools panel.
|
|
97
|
+
"""
|
|
98
|
+
return [{"name": f"{self.name}__*", "enabled": True}]
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _coerce_server(name: str, data: dict) -> CatalogServer:
|
|
102
|
+
tools = [
|
|
103
|
+
CatalogTool(
|
|
104
|
+
name=t["name"],
|
|
105
|
+
risk=t.get("risk", HIGH),
|
|
106
|
+
default_enabled=bool(t.get("default_enabled", False)),
|
|
107
|
+
)
|
|
108
|
+
for t in (data.get("tools") or [])
|
|
109
|
+
]
|
|
110
|
+
return CatalogServer(
|
|
111
|
+
name=name,
|
|
112
|
+
description=data.get("description", ""),
|
|
113
|
+
transport=data.get("transport", "stdio"),
|
|
114
|
+
command=data.get("command"),
|
|
115
|
+
args=list(data.get("args") or []),
|
|
116
|
+
env=list(data.get("env") or []),
|
|
117
|
+
env_const={str(k): str(v) for k, v in (data.get("env_const") or {}).items()},
|
|
118
|
+
url=data.get("url"),
|
|
119
|
+
auth_env=data.get("auth_env"),
|
|
120
|
+
requires=data.get("requires"),
|
|
121
|
+
source=data.get("source", ""),
|
|
122
|
+
updated=str(data.get("updated", "")),
|
|
123
|
+
tools=tools,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def load_catalog(path: str | Path = CATALOG_PATH) -> dict[str, CatalogServer]:
|
|
128
|
+
"""Load the catalog into a name -> :class:`CatalogServer` mapping."""
|
|
129
|
+
path = Path(path)
|
|
130
|
+
if not path.exists():
|
|
131
|
+
raise CatalogError(f"catalog file not found: {path}")
|
|
132
|
+
data = yaml.safe_load(path.read_text(encoding="utf-8")) or {}
|
|
133
|
+
servers = data.get("servers") or {}
|
|
134
|
+
if not isinstance(servers, dict):
|
|
135
|
+
raise CatalogError("catalog 'servers' must be a mapping of name -> entry")
|
|
136
|
+
return {name: _coerce_server(name, entry) for name, entry in servers.items()}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def available_servers() -> list[str]:
|
|
140
|
+
"""Names of curated catalog servers."""
|
|
141
|
+
return sorted(load_catalog())
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def get_server(name: str) -> CatalogServer:
|
|
145
|
+
"""Resolve a catalog server by name (raises :class:`CatalogError`)."""
|
|
146
|
+
catalog = load_catalog()
|
|
147
|
+
if name not in catalog:
|
|
148
|
+
known = ", ".join(sorted(catalog)) or "(none)"
|
|
149
|
+
raise CatalogError(f"unknown MCP server {name!r}; catalog has: {known}")
|
|
150
|
+
return catalog[name]
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def resolve_servers(names: list[str]) -> list[CatalogServer]:
|
|
154
|
+
"""Resolve catalog server names, de-duplicated, preserving first-seen order."""
|
|
155
|
+
catalog = load_catalog()
|
|
156
|
+
resolved: list[CatalogServer] = []
|
|
157
|
+
seen: set[str] = set()
|
|
158
|
+
for name in names:
|
|
159
|
+
if name in seen:
|
|
160
|
+
continue
|
|
161
|
+
if name not in catalog:
|
|
162
|
+
known = ", ".join(sorted(catalog)) or "(none)"
|
|
163
|
+
raise CatalogError(f"unknown MCP server {name!r}; catalog has: {known}")
|
|
164
|
+
resolved.append(catalog[name])
|
|
165
|
+
seen.add(name)
|
|
166
|
+
return resolved
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# Curated MCP server catalog (HarnessSmith, Slice 6).
|
|
2
|
+
#
|
|
3
|
+
# A *generation-time convenience datasource* — used by `harnessmith new
|
|
4
|
+
# --mcp-server <name>` and by presets to PREFILL the generated repo's runtime
|
|
5
|
+
# config.yaml (mcp.servers + tool allowlist). It is NOT a security gate and is
|
|
6
|
+
# NOT part of HarnessSpec or its snapshot: the real gate is the runtime tool
|
|
7
|
+
# allowlist + per-tool risk markers (high-risk tools default OFF). Secrets are
|
|
8
|
+
# referenced by env-var NAME only — never values.
|
|
9
|
+
#
|
|
10
|
+
# Because the generated harness ships no built-in productivity tools, these MCP
|
|
11
|
+
# presets double as the *capability baseline*. Each prefilled server is enabled by
|
|
12
|
+
# a single `<server>__*` wildcard in config.yaml — its WHOLE toolset (read +
|
|
13
|
+
# mutating/shell) is on by default (narrow it after generation if you want).
|
|
14
|
+
# uvx-based servers (requires: uv) can be prewarmed at generation and baked into
|
|
15
|
+
# the Docker image for offline use; Node-based servers (requires: node) need
|
|
16
|
+
# Node/npx on the host.
|
|
17
|
+
#
|
|
18
|
+
# Per-tool `risk`: safe = read-only / low-impact (offered even to read-only
|
|
19
|
+
# paradigms like plan/ask); high = mutating / shell / network side effects
|
|
20
|
+
# (agent-only). `risk` feeds `safe_tools` (risk grading); the per-tool
|
|
21
|
+
# `default_enabled` flag is retained as documentation but the prefill now enables
|
|
22
|
+
# every tool via the wildcard regardless.
|
|
23
|
+
version: 1
|
|
24
|
+
|
|
25
|
+
servers:
|
|
26
|
+
fetch:
|
|
27
|
+
description: Fetch a URL from the internet and extract its content as markdown.
|
|
28
|
+
transport: stdio
|
|
29
|
+
command: uvx
|
|
30
|
+
args: [mcp-server-fetch]
|
|
31
|
+
requires: uv
|
|
32
|
+
source: https://pypi.org/project/mcp-server-fetch/
|
|
33
|
+
updated: "2026-06-04"
|
|
34
|
+
tools:
|
|
35
|
+
- {name: fetch, risk: safe, default_enabled: true}
|
|
36
|
+
|
|
37
|
+
web-search:
|
|
38
|
+
# Default web-search server: a keyless, multi-engine scraper that probes each
|
|
39
|
+
# engine for reachability and FAILS OVER between them (Bing / Baidu / DuckDuckGo
|
|
40
|
+
# / Brave / Sogou / …), so it keeps working when any single engine is slow or
|
|
41
|
+
# unreachable on a given network — much more resilient than a single-engine
|
|
42
|
+
# scraper. Node-based (npx); launched directly from a stable per-server install
|
|
43
|
+
# (see harness/mcp.py `_node_*`), never the ephemeral npx cache. `MODE=stdio`
|
|
44
|
+
# (env_const) keeps it a pure stdio MCP server — without it the default `both`
|
|
45
|
+
# mode also binds an HTTP port. Pinned (NOT @latest) so warm-on-first-run
|
|
46
|
+
# installs the exact version the later connect launches; bump it + `updated:`
|
|
47
|
+
# together when refreshing. Still an HTML scraper, so an engine layout change
|
|
48
|
+
# can degrade a single engine (the failover absorbs it).
|
|
49
|
+
description: >-
|
|
50
|
+
Multi-engine web search (Bing, Baidu, DuckDuckGo, Brave, Sogou, and more)
|
|
51
|
+
with automatic failover; keyless. Returns title, URL, and snippet per
|
|
52
|
+
result, and can fetch a result page's content. Some engines may be
|
|
53
|
+
unreachable on certain networks — it falls back across engines automatically.
|
|
54
|
+
transport: stdio
|
|
55
|
+
command: npx
|
|
56
|
+
args: ["-y", "open-websearch@2.1.11"]
|
|
57
|
+
env_const: {MODE: stdio}
|
|
58
|
+
requires: node
|
|
59
|
+
source: https://github.com/Aas-ee/open-webSearch
|
|
60
|
+
updated: "2026-06-14"
|
|
61
|
+
tools:
|
|
62
|
+
# All read-only network reads (search + fetch a page) -> safe, so the
|
|
63
|
+
# read-only plan/ask paradigms can search/read too.
|
|
64
|
+
- {name: search, risk: safe, default_enabled: true}
|
|
65
|
+
- {name: fetchWebContent, risk: safe, default_enabled: true}
|
|
66
|
+
- {name: fetchGithubReadme, risk: safe, default_enabled: true}
|
|
67
|
+
- {name: fetchCsdnArticle, risk: safe, default_enabled: false}
|
|
68
|
+
- {name: fetchLinuxDoArticle, risk: safe, default_enabled: false}
|
|
69
|
+
- {name: fetchJuejinArticle, risk: safe, default_enabled: false}
|
|
70
|
+
|
|
71
|
+
ddg-search:
|
|
72
|
+
# uvx-based (no Node) keyless fallback. DuckDuckGo is unreachable on some
|
|
73
|
+
# networks — prefer `web-search` (multi-engine) there; this stays as a
|
|
74
|
+
# lightweight uvx alternative for hosts without Node, or where DuckDuckGo is
|
|
75
|
+
# reachable. Add with `--mcp-server ddg-search`.
|
|
76
|
+
description: >-
|
|
77
|
+
Web search via DuckDuckGo (keyless) plus fetching a result page as
|
|
78
|
+
markdown. A uvx-based alternative (no Node); DuckDuckGo is unreachable on
|
|
79
|
+
some networks, where web-search is the better default.
|
|
80
|
+
transport: stdio
|
|
81
|
+
command: uvx
|
|
82
|
+
args: [duckduckgo-mcp-server]
|
|
83
|
+
requires: uv
|
|
84
|
+
source: https://github.com/nickclyde/duckduckgo-mcp-server
|
|
85
|
+
updated: "2026-06-14"
|
|
86
|
+
tools:
|
|
87
|
+
- {name: search, risk: safe, default_enabled: true}
|
|
88
|
+
- {name: fetch_content, risk: safe, default_enabled: true}
|
|
89
|
+
|
|
90
|
+
git:
|
|
91
|
+
description: Inspect and operate on local Git repositories (read tools on; write tools off).
|
|
92
|
+
transport: stdio
|
|
93
|
+
command: uvx
|
|
94
|
+
# No --repository pin on purpose: every git tool already takes a required
|
|
95
|
+
# `repo_path` arg, so pinning adds no default — it ONLY restricts which repo is
|
|
96
|
+
# reachable, AND makes mcp-server-git EXIT at startup when launched outside a
|
|
97
|
+
# git repo (it surfaces as the server going "unreachable: Connection closed").
|
|
98
|
+
# The server's health should reflect the tool, not the cwd; unpinned it stays
|
|
99
|
+
# up and the agent operates on whatever repo it points `repo_path` at.
|
|
100
|
+
args: [mcp-server-git]
|
|
101
|
+
requires: uv
|
|
102
|
+
source: https://pypi.org/project/mcp-server-git/
|
|
103
|
+
updated: "2026-06-04"
|
|
104
|
+
tools:
|
|
105
|
+
- {name: git_status, risk: safe, default_enabled: true}
|
|
106
|
+
- {name: git_diff_unstaged, risk: safe, default_enabled: true}
|
|
107
|
+
- {name: git_diff_staged, risk: safe, default_enabled: true}
|
|
108
|
+
- {name: git_diff, risk: safe, default_enabled: true}
|
|
109
|
+
- {name: git_log, risk: safe, default_enabled: true}
|
|
110
|
+
- {name: git_show, risk: safe, default_enabled: true}
|
|
111
|
+
- {name: git_branch, risk: safe, default_enabled: true}
|
|
112
|
+
- {name: git_add, risk: high, default_enabled: false}
|
|
113
|
+
- {name: git_reset, risk: high, default_enabled: false}
|
|
114
|
+
- {name: git_commit, risk: high, default_enabled: false}
|
|
115
|
+
- {name: git_create_branch, risk: high, default_enabled: false}
|
|
116
|
+
- {name: git_checkout, risk: high, default_enabled: false}
|
|
117
|
+
- {name: git_init, risk: high, default_enabled: false}
|
|
118
|
+
|
|
119
|
+
desktop-commander:
|
|
120
|
+
description: Terminal command execution + full filesystem read/write/edit (powerful; read tools safe, write/shell high-risk).
|
|
121
|
+
transport: stdio
|
|
122
|
+
command: npx
|
|
123
|
+
# `--silent` keeps npm OUT of the child's stdout. A stdio MCP child's stdout
|
|
124
|
+
# must be PURE JSON-RPC, but on first launch `npx` installs the package and
|
|
125
|
+
# (on older npm) leaks its `added N packages ...` summary to stdout — which the
|
|
126
|
+
# MCP reader then tries to parse as protocol, spamming parse tracebacks. npm
|
|
127
|
+
# logs/warnings go to stderr (captured separately), and `--silent` does NOT
|
|
128
|
+
# touch the launched server's own stdout, so the protocol stream is unaffected.
|
|
129
|
+
# Pinned (NOT @latest) on purpose: warm-on-first-run pre-fetches THIS exact
|
|
130
|
+
# version into the npx cache, and a pin is what makes the later connect a true
|
|
131
|
+
# offline cache hit — `@latest` would re-hit the registry to re-resolve and could
|
|
132
|
+
# miss the warmed copy. Bump the version + `updated:` together when refreshing.
|
|
133
|
+
args: ["--silent", "-y", "@wonderwhy-er/desktop-commander@0.2.42"]
|
|
134
|
+
requires: node
|
|
135
|
+
source: https://github.com/wonderwhy-er/DesktopCommanderMCP
|
|
136
|
+
updated: "2026-06-14"
|
|
137
|
+
# A representative subset (Desktop Commander exposes ~26 tools). The prefilled
|
|
138
|
+
# `desktop-commander__*` wildcard enables the WHOLE discovered set (needs Node);
|
|
139
|
+
# the per-tool `risk` below grades it. Read-only tools are `safe` so the
|
|
140
|
+
# read-only plan/ask paradigms can use them too (without them, plan/ask get NO
|
|
141
|
+
# filesystem access at all — see Slice 5); write/shell/config-mutating tools are
|
|
142
|
+
# `high` (agent-only, HITL-gated). Risk grading matches the discovered tools BY
|
|
143
|
+
# NAME, so naming the real read-only tools here is what lets plan/ask read files.
|
|
144
|
+
tools:
|
|
145
|
+
# Read-only (safe): also offered to the read-only plan/ask paradigms.
|
|
146
|
+
- {name: read_file, risk: safe, default_enabled: false}
|
|
147
|
+
- {name: read_multiple_files, risk: safe, default_enabled: false}
|
|
148
|
+
- {name: list_directory, risk: safe, default_enabled: false}
|
|
149
|
+
- {name: get_file_info, risk: safe, default_enabled: false}
|
|
150
|
+
- {name: start_search, risk: safe, default_enabled: false}
|
|
151
|
+
- {name: get_more_search_results, risk: safe, default_enabled: false}
|
|
152
|
+
- {name: list_searches, risk: safe, default_enabled: false}
|
|
153
|
+
# Mutating / shell / config writes (high): agent-only, off by default.
|
|
154
|
+
- {name: write_file, risk: high, default_enabled: false}
|
|
155
|
+
- {name: edit_block, risk: high, default_enabled: false}
|
|
156
|
+
- {name: create_directory, risk: high, default_enabled: false}
|
|
157
|
+
- {name: move_file, risk: high, default_enabled: false}
|
|
158
|
+
- {name: set_config_value, risk: high, default_enabled: false}
|
|
159
|
+
- {name: start_process, risk: high, default_enabled: false}
|
|
160
|
+
- {name: kill_process, risk: high, default_enabled: false}
|
|
161
|
+
|
|
162
|
+
# --- Extra candidates (not in the coding-assistant baseline). Add with
|
|
163
|
+
# `--mcp-server <name>` or paste the server block into config.yaml. ---
|
|
164
|
+
|
|
165
|
+
time:
|
|
166
|
+
description: Current time and timezone conversion utilities.
|
|
167
|
+
transport: stdio
|
|
168
|
+
command: uvx
|
|
169
|
+
args: [mcp-server-time]
|
|
170
|
+
requires: uv
|
|
171
|
+
source: https://pypi.org/project/mcp-server-time/
|
|
172
|
+
updated: "2026-06-04"
|
|
173
|
+
tools:
|
|
174
|
+
- {name: get_current_time, risk: safe, default_enabled: true}
|
|
175
|
+
- {name: convert_time, risk: safe, default_enabled: true}
|
|
176
|
+
|
|
177
|
+
github:
|
|
178
|
+
description: GitHub platform API (issues / PRs / repos). Remote MCP — needs a token.
|
|
179
|
+
transport: remote
|
|
180
|
+
url: https://api.githubcopilot.com/mcp/
|
|
181
|
+
auth_env: GITHUB_MCP_TOKEN
|
|
182
|
+
source: https://github.com/github/github-mcp-server
|
|
183
|
+
updated: "2026-06-04"
|
|
184
|
+
# Large surface (70+ tools); enable specific tools by name as needed.
|
|
185
|
+
tools: []
|