leanback 0.1.2__tar.gz → 0.1.3__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: leanback
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: MCP server for Lean 4 theorem proving — check, prove, goals, eval, search
5
5
  Author: Stefan Szeider
6
6
  License: Apache-2.0
@@ -13,7 +13,7 @@ Classifier: Programming Language :: Python :: 3.12
13
13
  Classifier: Programming Language :: Python :: 3.13
14
14
  Classifier: Topic :: Scientific/Engineering :: Mathematics
15
15
  Requires-Python: >=3.11
16
- Requires-Dist: mcp>=1.9.4
16
+ Requires-Dist: mcp>=1.26.0
17
17
  Requires-Dist: rich>=14.0.0
18
18
  Description-Content-Type: text/markdown
19
19
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "leanback"
7
- version = "0.1.2"
7
+ version = "0.1.3"
8
8
  description = "MCP server for Lean 4 theorem proving — check, prove, goals, eval, search"
9
9
  readme = "README.md"
10
10
  license = { text = "Apache-2.0" }
@@ -21,15 +21,15 @@ classifiers = [
21
21
  ]
22
22
  dependencies = [
23
23
  "rich>=14.0.0",
24
- "mcp>=1.9.4",
24
+ "mcp>=1.26.0",
25
25
  ]
26
26
 
27
27
  [dependency-groups]
28
28
  dev = [
29
- "pytest>=8.4.0",
30
- "ruff>=0.11.0",
31
- "mypy>=1.16.0",
32
- "coverage>=7.8.0",
29
+ "pytest>=9.0.0",
30
+ "ruff>=0.15.0",
31
+ "mypy>=1.19.0",
32
+ "coverage>=7.13.0",
33
33
  ]
34
34
 
35
35
  [tool.ruff]
@@ -47,6 +47,9 @@ line-length = 88
47
47
  # Auto-fix issues
48
48
  fix = true
49
49
 
50
+ # Exclude non-Python project directories
51
+ exclude = ["projects/"]
52
+
50
53
  [tool.ruff.format]
51
54
  # Black-compatible formatting
52
55
  quote-style = "double"
@@ -87,7 +90,7 @@ lines-after-imports = 2
87
90
 
88
91
  [tool.ruff.lint.per-file-ignores]
89
92
  # Tests can use assert and have unused imports
90
- "tests/*" = ["S101", "F401", "F841"]
93
+ "tests/*" = ["S101", "F401", "F841", "RUF059"]
91
94
  "__init__.py" = ["F401"]
92
95
 
93
96
  [tool.mypy]
@@ -6,9 +6,29 @@ This module provides functionality for executing Lean commands in the correct en
6
6
 
7
7
  import os
8
8
  import subprocess
9
+ import sys
9
10
  from pathlib import Path
10
11
 
11
12
 
13
+ def _find_native_dynlibs(project_path: Path) -> list[Path]:
14
+ """Discover native shared libraries in Lake packages.
15
+
16
+ Scans .lake/packages/*/.lake/build/lib/ for .so (Linux) or .dylib (macOS)
17
+ files that need --load-dynlib for the Lean interpreter.
18
+ """
19
+ packages_dir = project_path / ".lake" / "packages"
20
+ if not packages_dir.is_dir():
21
+ return []
22
+
23
+ if sys.platform == "darwin":
24
+ ext = "dylib"
25
+ elif sys.platform == "win32":
26
+ ext = "dll"
27
+ else:
28
+ ext = "so"
29
+ return sorted(packages_dir.glob(f"*/.lake/build/lib/lib*.{ext}"))
30
+
31
+
12
32
  class LeanRunner:
13
33
  """
14
34
  Utility for running Lean commands in the appropriate environment.
@@ -53,6 +73,11 @@ class LeanRunner:
53
73
 
54
74
  # Always use lake env lean for projects - this ensures proper dependency management
55
75
  command = ["lake", "env", "lean"]
76
+
77
+ # Load native shared libraries for FFI-dependent packages (e.g., cvc5)
78
+ for lib in _find_native_dynlibs(project_path):
79
+ command.append(f"--load-dynlib={lib}")
80
+
56
81
  if capture_json:
57
82
  command.append("--json")
58
83
  command.append(str(abs_file_path))
@@ -14,6 +14,8 @@ import time
14
14
  from pathlib import Path
15
15
 
16
16
  from mcp.server.fastmcp import FastMCP
17
+ from mcp.server.fastmcp.exceptions import ToolError
18
+ from mcp.server.fastmcp.tools.tool_manager import ToolManager
17
19
 
18
20
 
19
21
  def _json(obj: object) -> str:
@@ -87,6 +89,25 @@ modify files. Use your own file tools to create/edit .lean files, then use LeanB
87
89
  )
88
90
 
89
91
 
92
+ class _StrictToolManager(ToolManager):
93
+ """Rejects unknown parameters instead of silently dropping them."""
94
+
95
+ async def call_tool(self, name, arguments, context=None, **kwargs):
96
+ tool = self.get_tool(name)
97
+ if tool and arguments:
98
+ known = set(tool.parameters.get("properties", {}).keys())
99
+ unknown = set(arguments.keys()) - known
100
+ if unknown:
101
+ raise ToolError(
102
+ f"Unknown parameter(s) for '{name}': {', '.join(sorted(unknown))}. "
103
+ f"Valid parameters: {', '.join(sorted(known))}"
104
+ )
105
+ return await super().call_tool(name, arguments, context, **kwargs)
106
+
107
+
108
+ mcp._tool_manager = _StrictToolManager()
109
+
110
+
90
111
  def _resolve_project(project: str) -> Path | None:
91
112
  """Resolve and validate a project path. Returns Path or None."""
92
113
  p = Path(project)
@@ -612,6 +633,9 @@ def check(
612
633
  "total_info": info_count,
613
634
  "files_with_errors": len(files_with_errors),
614
635
  },
636
+ "hint": "This checked the entire project via 'lake build'. "
637
+ "To check specific code, use expr=. "
638
+ "To execute code, use the eval tool.",
615
639
  }
616
640
  return _json(result)
617
641
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes