@yottameta/yotta-dev-mcp-plugin 0.2.1 → 0.2.2
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.
- package/.agents/plugins/marketplace.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/skills/yotta-dev-mcp/SKILL.md +13 -1
- package/skills/yotta-dev-mcp/scripts/dev_engine.py +1 -1
- package/skills/yotta-dev-mcp/scripts/dev_selftest.py +5 -4
- package/skills/yotta-dev-mcp/scripts/yotta_dev_mcp.py +86 -6
- package/skills/yotta-dev-mcp/server.json +2 -2
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"authentication": "ON_INSTALL"
|
|
13
13
|
},
|
|
14
14
|
"category": "Developer Tools",
|
|
15
|
-
"version": "0.2.
|
|
15
|
+
"version": "0.2.2",
|
|
16
16
|
"description": "YuanKai (yotta-dev-mcp) - deterministic local development tools exposed over stdio MCP: repo_map, system_model, architecture_review, impact_analysis, verify_change, self_test, run_adapter, find_code, compress_output, review_code, review_diff, mcp_doctor, scan_secrets, scan_dependencies, check_publish_readiness, run_checks, scaffold_skill and workflow_state. Reads an optional .yotta/architecture.json contract plus .yotta/verification.json policy for architecture reviews, change impact cones and the L0-L5 evidence ledger. Optional explicit adapters integrate import-linter, dependency-cruiser and Repomix without auto-install or network access. Python 3.8+ standard library, offline by default; writes and command execution require explicit flags.",
|
|
17
17
|
"interface": {
|
|
18
18
|
"displayName": "元开 yotta-dev-mcp",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"authentication": "ON_INSTALL"
|
|
13
13
|
},
|
|
14
14
|
"category": "Developer Tools",
|
|
15
|
-
"version": "0.2.
|
|
15
|
+
"version": "0.2.2",
|
|
16
16
|
"description": "YuanKai (yotta-dev-mcp) - deterministic local development tools exposed over stdio MCP: repo_map, system_model, architecture_review, impact_analysis, verify_change, self_test, run_adapter, find_code, compress_output, review_code, review_diff, mcp_doctor, scan_secrets, scan_dependencies, check_publish_readiness, run_checks, scaffold_skill and workflow_state. Reads an optional .yotta/architecture.json contract plus .yotta/verification.json policy for architecture reviews, change impact cones and the L0-L5 evidence ledger. Optional explicit adapters integrate import-linter, dependency-cruiser and Repomix without auto-install or network access. Python 3.8+ standard library, offline by default; writes and command execution require explicit flags.",
|
|
17
17
|
"interface": {
|
|
18
18
|
"displayName": "元开 yotta-dev-mcp",
|
package/package.json
CHANGED
package/plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
3
3
|
"name": "yotta-dev-mcp",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.2",
|
|
5
5
|
"description": "YuanKai (yotta-dev-mcp) - deterministic local development tools exposed over stdio MCP: repo_map, system_model, architecture_review, impact_analysis, verify_change, self_test, run_adapter, find_code, compress_output, review_code, review_diff, mcp_doctor, scan_secrets, scan_dependencies, check_publish_readiness, run_checks, scaffold_skill and workflow_state. Reads an optional .yotta/architecture.json contract plus .yotta/verification.json policy for architecture reviews, change impact cones and the L0-L5 evidence ledger. Optional explicit adapters integrate import-linter, dependency-cruiser and Repomix without auto-install or network access. Python 3.8+ standard library, offline by default; writes and command execution require explicit flags.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "YottaMeta",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: yotta-dev-mcp
|
|
3
3
|
description: 元开(yotta-dev-mcp)—— 本地、确定性的开发工具 MCP,把只读默认的开发能力暴露为 stdio MCP server:repo_map / system_model / architecture_review / impact_analysis / verify_change / self_test / run_adapter / find_code / compress_output / review_code / review_diff / mcp_doctor / scan_secrets / scan_dependencies / check_publish_readiness / run_checks / scaffold_skill / workflow_state。触发:让 AI 在陌生项目里先做结构盘点、构建系统模型或架构契约(.yotta/architecture.json)、按契约评审架构、分析改动影响锥与回归面、按验证阶梯产出证据账本、对元开自身做完整性 / 反证自测、探测或显式运行 import-linter / dependency-cruiser / Repomix 可选适配器、定位代码、评审改动、扫描密钥/依赖、检查发布就绪、运行白名单检查、生成脚手架或读取 .workflow 状态时;或用户说 元开 / 开发能力 MCP / yotta-dev-mcp / 代码库地图 / 系统模型 / 架构契约 / 架构评审 / 影响分析 / 验证账本 / 反证自测 / 代码评审 MCP / 适配器 等。边界:Python 3.8+ 标准库、离线默认;除 run_checks(显式 allow_execute)、verify_change 的 L2-L4 策略检查(显式 allow_execute)与 self_test 的测试子集(显式 allow_execute)、run_adapter 的 action=run(显式 allow_execute)、scaffold_skill / workflow_state 的显式 apply 外均为只读;不上传源码、不自动修改、不提交、不联网查询包是否存在、不自动安装或下载适配器。
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.2
|
|
5
5
|
license: MIT
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -37,6 +37,18 @@ npx -y @yottameta/yotta-dev-mcp
|
|
|
37
37
|
python scripts/yotta_dev_mcp.py
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
+
工具分组(`--tools`,与元忆同口径):
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
python scripts/yotta_dev_mcp.py --tools core # 5 工具:repo_map / find_code / review_code / review_diff / verify_change
|
|
44
|
+
python scripts/yotta_dev_mcp.py --tools full # 18 工具(默认)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`core` 给「需要把工具表常驻在上下文里」的宿主用:schema 体积约为 `full` 的 29%
|
|
48
|
+
(5 工具 3,883 字符 vs 18 工具 13,230 字符,紧凑 JSON 口径),适合默认启用;
|
|
49
|
+
`full` 暴露全部工具,适合按需调用、不常驻的场景。`core` 模式下调用 full 专属工具会返回
|
|
50
|
+
明确提示(提示用 `--tools full` 重启)。
|
|
51
|
+
|
|
40
52
|
自动接入说明:AI 首次协助配置时,必须先展示目标配置文件、完整配置片段和影响,
|
|
41
53
|
并获得用户明确同意后再写入 `mcpServers`。用户拒绝时不要写文件,直接提供上面的启动命令
|
|
42
54
|
让用户手动接入。
|
|
@@ -52,22 +52,23 @@ def _protocol_tool_contracts(source_text):
|
|
|
52
52
|
tree = ast.parse(source_text)
|
|
53
53
|
function = None
|
|
54
54
|
for node in tree.body:
|
|
55
|
-
|
|
55
|
+
# v0.2.2 起工具清单字面量在 _all_tools();mcp_tools(profile) 只做分档过滤。
|
|
56
|
+
if isinstance(node, ast.FunctionDef) and node.name in ("_all_tools", "mcp_tools"):
|
|
56
57
|
function = node
|
|
57
58
|
break
|
|
58
59
|
if function is None:
|
|
59
|
-
raise ValueError("
|
|
60
|
+
raise ValueError("tool list function not found")
|
|
60
61
|
list_node = None
|
|
61
62
|
for node in ast.walk(function):
|
|
62
63
|
if isinstance(node, ast.Return) and isinstance(node.value, ast.List):
|
|
63
64
|
list_node = node.value
|
|
64
65
|
break
|
|
65
66
|
if list_node is None:
|
|
66
|
-
raise ValueError("
|
|
67
|
+
raise ValueError("tool list function does not return a literal tool list")
|
|
67
68
|
contracts = []
|
|
68
69
|
for element in list_node.elts:
|
|
69
70
|
if not isinstance(element, ast.Dict):
|
|
70
|
-
raise ValueError("
|
|
71
|
+
raise ValueError("tool list contains a non-literal tool entry")
|
|
71
72
|
values = {}
|
|
72
73
|
for key, value in zip(element.keys, element.values):
|
|
73
74
|
if _string_constant(key):
|
|
@@ -25,6 +25,25 @@ MCP_PROTOCOL_MODERN = "2026-07-28"
|
|
|
25
25
|
MCP_PROTOCOL_LEGACY = "2025-11-25"
|
|
26
26
|
SERVER_INFO = {"name": TOOL_NAME, "version": VERSION}
|
|
27
27
|
|
|
28
|
+
# 工具分组(v0.2.2):与元忆 `--tools core|full` 同口径。core 是给「需要在上下文里
|
|
29
|
+
# 常驻工具表」的宿主用小档(5 工具,schema 远低于 8000 字符硬上限);full 保持 18 工具。
|
|
30
|
+
CORE_TOOL_NAMES = (
|
|
31
|
+
"repo_map",
|
|
32
|
+
"find_code",
|
|
33
|
+
"review_code",
|
|
34
|
+
"review_diff",
|
|
35
|
+
"verify_change",
|
|
36
|
+
)
|
|
37
|
+
TOOL_PROFILES = ("core", "full")
|
|
38
|
+
DEFAULT_TOOL_PROFILE = "full"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def normalize_tool_profile(value):
|
|
42
|
+
profile = str(value or "").strip().lower() or DEFAULT_TOOL_PROFILE
|
|
43
|
+
if profile not in TOOL_PROFILES:
|
|
44
|
+
raise ValueError("未知工具分组: %s(可用: core / full)" % value)
|
|
45
|
+
return profile
|
|
46
|
+
|
|
28
47
|
|
|
29
48
|
def _text_result(payload):
|
|
30
49
|
return {
|
|
@@ -63,7 +82,7 @@ TOOL_HANDLERS = {
|
|
|
63
82
|
}
|
|
64
83
|
|
|
65
84
|
|
|
66
|
-
def
|
|
85
|
+
def _all_tools():
|
|
67
86
|
return [
|
|
68
87
|
{
|
|
69
88
|
"name": "repo_map",
|
|
@@ -521,6 +540,15 @@ def mcp_tools():
|
|
|
521
540
|
]
|
|
522
541
|
|
|
523
542
|
|
|
543
|
+
def mcp_tools(profile=None):
|
|
544
|
+
"""按工具分档返回 tools/list 内容(core 5 个 / full 18 个)。"""
|
|
545
|
+
tools = _all_tools()
|
|
546
|
+
if normalize_tool_profile(profile) == "core":
|
|
547
|
+
by_name = {tool["name"]: tool for tool in tools}
|
|
548
|
+
return [by_name[name] for name in CORE_TOOL_NAMES]
|
|
549
|
+
return tools
|
|
550
|
+
|
|
551
|
+
|
|
524
552
|
def _req_version(params):
|
|
525
553
|
meta = (params or {}).get("_meta") or {}
|
|
526
554
|
return meta.get("io.modelcontextprotocol/protocolVersion")
|
|
@@ -548,7 +576,7 @@ def _unsupported_version(rid, protocol_version):
|
|
|
548
576
|
}
|
|
549
577
|
|
|
550
578
|
|
|
551
|
-
def handle_message(msg):
|
|
579
|
+
def handle_message(msg, tool_profile=None):
|
|
552
580
|
if not isinstance(msg, dict) or msg.get("jsonrpc") != "2.0":
|
|
553
581
|
rid = msg.get("id") if isinstance(msg, dict) else None
|
|
554
582
|
return {"jsonrpc": "2.0", "id": rid,
|
|
@@ -578,7 +606,9 @@ def handle_message(msg):
|
|
|
578
606
|
"verify_change for change-centered evidence, self_test for integrity "
|
|
579
607
|
"checks, and run_adapter to probe or explicitly run optional local "
|
|
580
608
|
"architecture adapters. Tools are offline and read-only unless an "
|
|
581
|
-
"explicit write or execute flag is set."
|
|
609
|
+
"explicit write or execute flag is set. Current tool profile: "
|
|
610
|
+
+ normalize_tool_profile(tool_profile)
|
|
611
|
+
+ " (start with --tools core|full)."
|
|
582
612
|
),
|
|
583
613
|
}, (3600000, "public")),
|
|
584
614
|
}
|
|
@@ -588,11 +618,20 @@ def handle_message(msg):
|
|
|
588
618
|
return {
|
|
589
619
|
"jsonrpc": "2.0",
|
|
590
620
|
"id": rid,
|
|
591
|
-
"result": _modern_ok({"tools": mcp_tools()}, (300000, "public")),
|
|
621
|
+
"result": _modern_ok({"tools": mcp_tools(tool_profile)}, (300000, "public")),
|
|
592
622
|
}
|
|
593
623
|
if method == "tools/call":
|
|
594
624
|
name = params.get("name")
|
|
595
625
|
arguments = params.get("arguments") or {}
|
|
626
|
+
if (normalize_tool_profile(tool_profile) == "core"
|
|
627
|
+
and name not in CORE_TOOL_NAMES):
|
|
628
|
+
return {
|
|
629
|
+
"jsonrpc": "2.0",
|
|
630
|
+
"id": rid,
|
|
631
|
+
"result": _modern_ok(_tool_error(
|
|
632
|
+
"工具 %s 属于 full 分组,当前以 --tools core 启动。"
|
|
633
|
+
"需要完整工具集时请用 --tools full 重新启动。" % name)),
|
|
634
|
+
}
|
|
596
635
|
handler = TOOL_HANDLERS.get(name)
|
|
597
636
|
if not handler:
|
|
598
637
|
return {
|
|
@@ -626,10 +665,16 @@ def handle_message(msg):
|
|
|
626
665
|
if method == "ping":
|
|
627
666
|
return {"jsonrpc": "2.0", "id": rid, "result": {}}
|
|
628
667
|
if method == "tools/list":
|
|
629
|
-
return {"jsonrpc": "2.0", "id": rid,
|
|
668
|
+
return {"jsonrpc": "2.0", "id": rid,
|
|
669
|
+
"result": {"tools": mcp_tools(tool_profile)}}
|
|
630
670
|
if method == "tools/call":
|
|
631
671
|
name = params.get("name")
|
|
632
672
|
arguments = params.get("arguments") or {}
|
|
673
|
+
if (normalize_tool_profile(tool_profile) == "core"
|
|
674
|
+
and name not in CORE_TOOL_NAMES):
|
|
675
|
+
return {"jsonrpc": "2.0", "id": rid, "result": _tool_error(
|
|
676
|
+
"工具 %s 属于 full 分组,当前以 --tools core 启动。"
|
|
677
|
+
"需要完整工具集时请用 --tools full 重新启动。" % name)}
|
|
633
678
|
handler = TOOL_HANDLERS.get(name)
|
|
634
679
|
if not handler:
|
|
635
680
|
return {
|
|
@@ -642,7 +687,42 @@ def handle_message(msg):
|
|
|
642
687
|
"error": {"code": -32601, "message": "Method not found: " + str(method)}}
|
|
643
688
|
|
|
644
689
|
|
|
690
|
+
def parse_args(argv):
|
|
691
|
+
"""解析启动参数:`--tools core|full`(默认 full)、`--version`、`--help`。"""
|
|
692
|
+
profile = DEFAULT_TOOL_PROFILE
|
|
693
|
+
index = 0
|
|
694
|
+
while index < len(argv):
|
|
695
|
+
arg = argv[index]
|
|
696
|
+
if arg == "--tools":
|
|
697
|
+
index += 1
|
|
698
|
+
if index >= len(argv):
|
|
699
|
+
sys.stderr.write("用法错误: --tools 需要一个值(core / full)\n")
|
|
700
|
+
raise SystemExit(2)
|
|
701
|
+
raw = argv[index]
|
|
702
|
+
elif arg.startswith("--tools="):
|
|
703
|
+
raw = arg.split("=", 1)[1]
|
|
704
|
+
elif arg in ("--version", "-v"):
|
|
705
|
+
print("%s %s" % (TOOL_NAME, VERSION))
|
|
706
|
+
raise SystemExit(0)
|
|
707
|
+
elif arg in ("--help", "-h"):
|
|
708
|
+
print("用法: yotta-dev-mcp [--tools core|full]")
|
|
709
|
+
print(" core: 5 工具(%s)" % " / ".join(CORE_TOOL_NAMES))
|
|
710
|
+
print(" full: 18 工具(默认)")
|
|
711
|
+
raise SystemExit(0)
|
|
712
|
+
else:
|
|
713
|
+
sys.stderr.write("用法错误: 未知参数 %s\n" % arg)
|
|
714
|
+
raise SystemExit(2)
|
|
715
|
+
try:
|
|
716
|
+
profile = normalize_tool_profile(raw)
|
|
717
|
+
except ValueError as exc:
|
|
718
|
+
sys.stderr.write("用法错误: %s\n" % exc)
|
|
719
|
+
raise SystemExit(2)
|
|
720
|
+
index += 1
|
|
721
|
+
return profile
|
|
722
|
+
|
|
723
|
+
|
|
645
724
|
def main():
|
|
725
|
+
tool_profile = parse_args(sys.argv[1:])
|
|
646
726
|
try:
|
|
647
727
|
sys.stdin.reconfigure(encoding="utf-8")
|
|
648
728
|
sys.stdout.reconfigure(encoding="utf-8")
|
|
@@ -659,7 +739,7 @@ def main():
|
|
|
659
739
|
response = {"jsonrpc": "2.0", "id": None,
|
|
660
740
|
"error": {"code": -32700, "message": "parse error"}}
|
|
661
741
|
else:
|
|
662
|
-
response = handle_message(message)
|
|
742
|
+
response = handle_message(message, tool_profile)
|
|
663
743
|
if response is not None:
|
|
664
744
|
sys.stdout.write(json.dumps(response, ensure_ascii=False) + "\n")
|
|
665
745
|
sys.stdout.flush()
|
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/YottaMeta/yotta-dev-mcp",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "0.2.
|
|
9
|
+
"version": "0.2.2",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "@yottameta/yotta-dev-mcp",
|
|
14
|
-
"version": "0.2.
|
|
14
|
+
"version": "0.2.2",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
}
|