answer42 0.2.7__tar.gz → 0.2.9__tar.gz
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.
- {answer42-0.2.7 → answer42-0.2.9}/PKG-INFO +1 -1
- {answer42-0.2.7 → answer42-0.2.9}/pyproject.toml +1 -1
- answer42-0.2.9/src/mcp_1c/__init__.py +22 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/mcp_1c/server.py +38 -9
- answer42-0.2.7/src/mcp_1c/__init__.py +0 -4
- {answer42-0.2.7 → answer42-0.2.9}/.gitignore +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/LICENSE +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/README.md +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/credentials.example.json +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/docs/agent-installation.md +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/docs/architecture.md +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/docs/assets/answer42-logo.png +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/docs/assets/platform42-logo.svg +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/docs/installation.md +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/scripts/build_cf.py +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/scripts/build_pages.py +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/scripts/e2e_stable.py +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/scripts/openclaw_mcp_autoreload.py +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/scripts/rag_cli.py +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/cf/ConfigDumpInfo.xml +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/cf/Configuration.xml +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/cf/DataProcessors/MCPTestManager/Ext/ObjectModule.bsl +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/cf/DataProcessors/MCPTestManager/Forms//320/244/320/276/321/200/320/274/320/260/Ext/Form/Module.bsl" +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/cf/DataProcessors/MCPTestManager/Forms//320/244/320/276/321/200/320/274/320/260/Ext/Form.xml" +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/cf/DataProcessors/MCPTestManager/Forms//320/244/320/276/321/200/320/274/320/260.xml" +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/cf/DataProcessors/MCPTestManager.xml +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/cf/Ext/ManagedApplicationModule.bsl +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/cf/Languages//320/240/321/203/321/201/321/201/320/272/320/270/320/271.xml" +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/client_cf/Catalogs//320/237/320/241_/320/222/320/273/320/260/320/264/320/265/320/273/320/265/321/206.xml" +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/client_cf/Catalogs//320/237/320/241_/320/241/320/277/321/200/320/260/320/262/320/276/321/207/320/275/320/270/320/2721.xml" +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/client_cf/ConfigDumpInfo.xml +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/client_cf/Configuration.xml +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/client_cf/Languages//320/240/321/203/321/201/321/201/320/272/320/270/320/271.xml" +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/client_cf/Reports//320/237/320/241_/320/241/320/277/320/270/321/201/320/276/320/272/320/255/320/273/320/265/320/274/320/265/320/275/321/202/320/276/320/262/Ext/ManagerModule.bsl" +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/client_cf/Reports//320/237/320/241_/320/241/320/277/320/270/321/201/320/276/320/272/320/255/320/273/320/265/320/274/320/265/320/275/321/202/320/276/320/262/Ext/ObjectModule.bsl" +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/client_cf/Reports//320/237/320/241_/320/241/320/277/320/270/321/201/320/276/320/272/320/255/320/273/320/265/320/274/320/265/320/275/321/202/320/276/320/262/Templates//320/236/321/201/320/275/320/276/320/262/320/275/320/260/321/217/320/241/321/205/320/265/320/274/320/260/320/232/320/276/320/274/320/277/320/276/320/275/320/276/320/262/320/272/320/270/320/224/320/260/320/275/320/275/321/213/321/205/Ext/Template.xml" +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/client_cf/Reports//320/237/320/241_/320/241/320/277/320/270/321/201/320/276/320/272/320/255/320/273/320/265/320/274/320/265/320/275/321/202/320/276/320/262/Templates//320/236/321/201/320/275/320/276/320/262/320/275/320/260/321/217/320/241/321/205/320/265/320/274/320/260/320/232/320/276/320/274/320/277/320/276/320/275/320/276/320/262/320/272/320/270/320/224/320/260/320/275/320/275/321/213/321/205.xml" +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/client_cf/Reports//320/237/320/241_/320/241/320/277/320/270/321/201/320/276/320/272/320/255/320/273/320/265/320/274/320/265/320/275/321/202/320/276/320/262.xml" +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/mcp_1c/assets/MCPTestClient.cf +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/mcp_1c/assets/MCPTestManager.cf +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/mcp_1c/assets/__init__.py +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/mcp_1c/assets/skills/answer42/SKILL.md +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/mcp_1c/assets/skills/answer42-rag/SKILL.md +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/mcp_1c/bridge.py +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/mcp_1c/credentials.py +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/mcp_1c/os_support.py +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/mcp_1c/platform.py +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/mcp_1c/protocol.py +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/mcp_1c/rag/__init__.py +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/mcp_1c/rag/detect.py +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/mcp_1c/rag/model.py +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/mcp_1c/rag/parsers.py +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/mcp_1c/rag/service.py +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/mcp_1c/rag/store.py +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/mcp_1c/recorder.py +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/mcp_1c/release_helper.py +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/mcp_1c/runtime.py +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/mcp_1c/skill_installer.py +0 -0
- {answer42-0.2.7 → answer42-0.2.9}/src/mcp_1c/window_control.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: answer42
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.9
|
|
4
4
|
Summary: Answer42 — The Answer to Life, Universe, and 1C — UI Driver. MCP-powered 1C:Enterprise UI automation: click, fill, navigate, test, and introspect managed forms through the test-client API
|
|
5
5
|
Author: Marvin (AI Assistant), 42Clouds, and contributors
|
|
6
6
|
Author-email: "Kosolapov Stanislav (proDOOMman)" <prodoomman@gmail.com>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "answer42"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.9"
|
|
4
4
|
description = "Answer42 — The Answer to Life, Universe, and 1C — UI Driver. MCP-powered 1C:Enterprise UI automation: click, fill, navigate, test, and introspect managed forms through the test-client API"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""MCP server for 1C:Enterprise test manager automation."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
import tomllib
|
|
6
|
+
|
|
7
|
+
__all__ = ["__version__"]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _version_from_pyproject() -> str:
|
|
11
|
+
pyproject = Path(__file__).resolve().parents[2] / "pyproject.toml"
|
|
12
|
+
try:
|
|
13
|
+
data = tomllib.loads(pyproject.read_text(encoding="utf-8"))
|
|
14
|
+
return str(data.get("project", {}).get("version") or "0+unknown")
|
|
15
|
+
except Exception:
|
|
16
|
+
return "0+unknown"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
__version__ = version("answer42")
|
|
21
|
+
except PackageNotFoundError:
|
|
22
|
+
__version__ = _version_from_pyproject()
|
|
@@ -25,6 +25,7 @@ from typing import Annotated, Any
|
|
|
25
25
|
|
|
26
26
|
from mcp.server.fastmcp import FastMCP
|
|
27
27
|
|
|
28
|
+
from . import __version__
|
|
28
29
|
from . import os_support
|
|
29
30
|
from . import platform as _platform
|
|
30
31
|
from . import runtime
|
|
@@ -40,6 +41,7 @@ from .recorder import RecordingSession
|
|
|
40
41
|
mcp = FastMCP("Answer42")
|
|
41
42
|
_RAG = RagService()
|
|
42
43
|
_RAG_ENABLED = os.getenv("ONEC_MCP_DISABLE_RAG", "").strip().lower() not in {"1", "true", "yes", "on"}
|
|
44
|
+
_CREDENTIAL_STORE_ENABLED = os.getenv("ONEC_MCP_DISABLE_CREDENTIAL_STORE", "").strip().lower() not in {"1", "true", "yes", "on"}
|
|
43
45
|
DEFAULT_SESSION = "default"
|
|
44
46
|
STATE_FILE = os_support.runtime_path("ONEC_MCP_SESSION_STATE", "sessions.json")
|
|
45
47
|
AUTORELOAD_PID_FILE = os_support.runtime_path("ONEC_MCP_AUTORELOAD_PID_FILE", "answer42-autoreload.pid")
|
|
@@ -2023,9 +2025,21 @@ def export_eventlog(
|
|
|
2023
2025
|
return {"path": str(exported), "format": fmt, "eventlog_dir": str(eventlog_path)}
|
|
2024
2026
|
|
|
2025
2027
|
|
|
2028
|
+
def _credential_store_disabled_error() -> RuntimeError:
|
|
2029
|
+
return RuntimeError("Credential store is disabled by --disable-credential-store or ONEC_MCP_DISABLE_CREDENTIAL_STORE.")
|
|
2030
|
+
|
|
2031
|
+
|
|
2032
|
+
def _lookup_credentials(base_url: str) -> dict[str, str] | None:
|
|
2033
|
+
if not _CREDENTIAL_STORE_ENABLED:
|
|
2034
|
+
return None
|
|
2035
|
+
return _credentials_store().lookup(base_url)
|
|
2036
|
+
|
|
2037
|
+
|
|
2026
2038
|
@mcp.tool()
|
|
2027
2039
|
def credentials_check(base_url: str) -> dict[str, object]:
|
|
2028
2040
|
"""Check whether credentials exist for a base URL without returning secrets."""
|
|
2041
|
+
if not _CREDENTIAL_STORE_ENABLED:
|
|
2042
|
+
return {"base_url": base_url, "found": False, "disabled": True}
|
|
2029
2043
|
credentials = _credentials_store().lookup(base_url)
|
|
2030
2044
|
if credentials is None:
|
|
2031
2045
|
return {"base_url": base_url, "found": False}
|
|
@@ -2047,6 +2061,8 @@ def credentials_save(
|
|
|
2047
2061
|
login/password pairs so that ``start_session`` can pick them up automatically
|
|
2048
2062
|
without exposing secrets in MCP tool-call arguments.
|
|
2049
2063
|
"""
|
|
2064
|
+
if not _CREDENTIAL_STORE_ENABLED:
|
|
2065
|
+
raise _credential_store_disabled_error()
|
|
2050
2066
|
updated = _credentials_store().upsert(url, username, password)
|
|
2051
2067
|
return {
|
|
2052
2068
|
"url": url,
|
|
@@ -2060,6 +2076,8 @@ def credentials_remove(
|
|
|
2060
2076
|
url: Annotated[str, "Exact URL pattern to remove from the credentials store"],
|
|
2061
2077
|
) -> dict[str, object]:
|
|
2062
2078
|
"""Remove a credential entry from the local store by exact URL match."""
|
|
2079
|
+
if not _CREDENTIAL_STORE_ENABLED:
|
|
2080
|
+
raise _credential_store_disabled_error()
|
|
2063
2081
|
removed = _credentials_store().remove(url)
|
|
2064
2082
|
return {"url": url, "removed": removed}
|
|
2065
2083
|
|
|
@@ -2067,6 +2085,8 @@ def credentials_remove(
|
|
|
2067
2085
|
@mcp.tool()
|
|
2068
2086
|
def credentials_list() -> list[dict[str, str]]:
|
|
2069
2087
|
"""List configured credential URL patterns (no usernames or passwords)."""
|
|
2088
|
+
if not _CREDENTIAL_STORE_ENABLED:
|
|
2089
|
+
return []
|
|
2070
2090
|
return _credentials_store().list_entries()
|
|
2071
2091
|
|
|
2072
2092
|
|
|
@@ -2332,7 +2352,7 @@ async def _connect_test_client_impl(
|
|
|
2332
2352
|
raise ValueError("base_url or connection_value is required")
|
|
2333
2353
|
r_base = r_value
|
|
2334
2354
|
if not r_user and not r_pass:
|
|
2335
|
-
credentials =
|
|
2355
|
+
credentials = _lookup_credentials(r_base)
|
|
2336
2356
|
if credentials:
|
|
2337
2357
|
r_user = credentials["username"]
|
|
2338
2358
|
r_pass = credentials["password"]
|
|
@@ -2398,7 +2418,7 @@ async def _connect_test_client_impl(
|
|
|
2398
2418
|
target_connection_mode = mode
|
|
2399
2419
|
|
|
2400
2420
|
if not r_user and not r_pass and r_base:
|
|
2401
|
-
credentials =
|
|
2421
|
+
credentials = _lookup_credentials(r_base)
|
|
2402
2422
|
if credentials:
|
|
2403
2423
|
r_user = credentials["username"]
|
|
2404
2424
|
r_pass = credentials["password"]
|
|
@@ -4063,15 +4083,17 @@ async def _run() -> None:
|
|
|
4063
4083
|
_SESSIONS.clear()
|
|
4064
4084
|
|
|
4065
4085
|
|
|
4066
|
-
def main() -> None:
|
|
4067
|
-
global _RAG_ENABLED
|
|
4086
|
+
def main(argv: list[str] | None = None) -> None:
|
|
4087
|
+
global _RAG_ENABLED, _CREDENTIAL_STORE_ENABLED
|
|
4068
4088
|
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4089
|
+
argv = list(sys.argv[1:] if argv is None else argv)
|
|
4090
|
+
if argv and argv[0] in {"install-skills", "skills-install"}:
|
|
4091
|
+
raise SystemExit(skill_installer.main(argv[1:]))
|
|
4092
|
+
if argv and argv[0] in {"release", "release-pypi"}:
|
|
4093
|
+
raise SystemExit(release_helper.main(argv[1:]))
|
|
4073
4094
|
|
|
4074
4095
|
parser = argparse.ArgumentParser(description="MCP server for 1C:Enterprise test manager")
|
|
4096
|
+
parser.add_argument("--version", action="version", version=f"answer42 {__version__}")
|
|
4075
4097
|
parser.add_argument("--log-level", default=os.getenv("ONEC_MCP_LOG_LEVEL", "INFO"))
|
|
4076
4098
|
parser.add_argument(
|
|
4077
4099
|
"--disable-rag",
|
|
@@ -4079,6 +4101,12 @@ def main() -> None:
|
|
|
4079
4101
|
default=os.getenv("ONEC_MCP_DISABLE_RAG", "").strip().lower() in {"1", "true", "yes", "on"},
|
|
4080
4102
|
help="disable built-in Answer42 RAG tools and RAG enrichment",
|
|
4081
4103
|
)
|
|
4104
|
+
parser.add_argument(
|
|
4105
|
+
"--disable-credential-store",
|
|
4106
|
+
action="store_true",
|
|
4107
|
+
default=os.getenv("ONEC_MCP_DISABLE_CREDENTIAL_STORE", "").strip().lower() in {"1", "true", "yes", "on"},
|
|
4108
|
+
help="disable loading, saving and automatic lookup of credentials from the local credential store",
|
|
4109
|
+
)
|
|
4082
4110
|
parser.add_argument(
|
|
4083
4111
|
"--rag-source-dir",
|
|
4084
4112
|
action="append",
|
|
@@ -4114,9 +4142,10 @@ def main() -> None:
|
|
|
4114
4142
|
default=float(os.getenv("ONEC_MCP_DEV_RESTART_TIMEOUT", "30")),
|
|
4115
4143
|
help="seconds of no file changes before the OpenClaw MCP autoreload watchdog triggers reload",
|
|
4116
4144
|
)
|
|
4117
|
-
args = parser.parse_args()
|
|
4145
|
+
args = parser.parse_args(argv)
|
|
4118
4146
|
|
|
4119
4147
|
_RAG_ENABLED = not args.disable_rag
|
|
4148
|
+
_CREDENTIAL_STORE_ENABLED = not args.disable_credential_store
|
|
4120
4149
|
logging.basicConfig(level=getattr(logging, args.log_level.upper(), logging.INFO))
|
|
4121
4150
|
if _RAG_ENABLED:
|
|
4122
4151
|
_register_startup_rag_source_dirs(args.rag_source_dir or [], args.rag_source_prefix, not args.rag_source_no_recursive, args.rag_source_max_depth)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|