sym-mcp 0.0.0.post1.dev3__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.
- sym_mcp-0.0.0.post1.dev3/.github/workflows/pypi-publish.yml +59 -0
- sym_mcp-0.0.0.post1.dev3/.gitignore +58 -0
- sym_mcp-0.0.0.post1.dev3/LICENSE +21 -0
- sym_mcp-0.0.0.post1.dev3/PKG-INFO +269 -0
- sym_mcp-0.0.0.post1.dev3/PUBLISHING.md +87 -0
- sym_mcp-0.0.0.post1.dev3/README.md +242 -0
- sym_mcp-0.0.0.post1.dev3/README.zh.md +242 -0
- sym_mcp-0.0.0.post1.dev3/pyproject.toml +56 -0
- sym_mcp-0.0.0.post1.dev3/scripts/benchmark.py +90 -0
- sym_mcp-0.0.0.post1.dev3/setup.cfg +4 -0
- sym_mcp-0.0.0.post1.dev3/src/sym_mcp/__init__.py +2 -0
- sym_mcp-0.0.0.post1.dev3/src/sym_mcp/__main__.py +6 -0
- sym_mcp-0.0.0.post1.dev3/src/sym_mcp/config.py +27 -0
- sym_mcp-0.0.0.post1.dev3/src/sym_mcp/errors/__init__.py +2 -0
- sym_mcp-0.0.0.post1.dev3/src/sym_mcp/errors/parser.py +114 -0
- sym_mcp-0.0.0.post1.dev3/src/sym_mcp/executor/__init__.py +2 -0
- sym_mcp-0.0.0.post1.dev3/src/sym_mcp/executor/pool.py +182 -0
- sym_mcp-0.0.0.post1.dev3/src/sym_mcp/executor/sandbox.py +82 -0
- sym_mcp-0.0.0.post1.dev3/src/sym_mcp/executor/worker_main.py +65 -0
- sym_mcp-0.0.0.post1.dev3/src/sym_mcp/schemas.py +8 -0
- sym_mcp-0.0.0.post1.dev3/src/sym_mcp/security/__init__.py +2 -0
- sym_mcp-0.0.0.post1.dev3/src/sym_mcp/security/ast_guard.py +190 -0
- sym_mcp-0.0.0.post1.dev3/src/sym_mcp/server.py +153 -0
- sym_mcp-0.0.0.post1.dev3/src/sym_mcp.egg-info/PKG-INFO +269 -0
- sym_mcp-0.0.0.post1.dev3/src/sym_mcp.egg-info/SOURCES.txt +34 -0
- sym_mcp-0.0.0.post1.dev3/src/sym_mcp.egg-info/dependency_links.txt +1 -0
- sym_mcp-0.0.0.post1.dev3/src/sym_mcp.egg-info/entry_points.txt +2 -0
- sym_mcp-0.0.0.post1.dev3/src/sym_mcp.egg-info/requires.txt +7 -0
- sym_mcp-0.0.0.post1.dev3/src/sym_mcp.egg-info/top_level.txt +1 -0
- sym_mcp-0.0.0.post1.dev3/tests/test_ast_guard.py +47 -0
- sym_mcp-0.0.0.post1.dev3/tests/test_error_parser.py +55 -0
- sym_mcp-0.0.0.post1.dev3/tests/test_math_correctness.py +38 -0
- sym_mcp-0.0.0.post1.dev3/tests/test_perf_guardrails.py +64 -0
- sym_mcp-0.0.0.post1.dev3/tests/test_pool.py +66 -0
- sym_mcp-0.0.0.post1.dev3/tests/test_security_adversarial.py +40 -0
- sym_mcp-0.0.0.post1.dev3/tests/test_server_integration.py +104 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- name: Checkout
|
|
14
|
+
uses: actions/checkout@v4
|
|
15
|
+
with:
|
|
16
|
+
fetch-depth: 0
|
|
17
|
+
|
|
18
|
+
- name: Set up Python
|
|
19
|
+
uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.11"
|
|
22
|
+
|
|
23
|
+
- name: Install build tools
|
|
24
|
+
run: |
|
|
25
|
+
python -m pip install --upgrade pip
|
|
26
|
+
python -m pip install build twine
|
|
27
|
+
|
|
28
|
+
- name: Clean dist directory
|
|
29
|
+
run: rm -rf dist
|
|
30
|
+
|
|
31
|
+
- name: Build distributions
|
|
32
|
+
run: python -m build
|
|
33
|
+
|
|
34
|
+
- name: Check distributions
|
|
35
|
+
run: twine check dist/*
|
|
36
|
+
|
|
37
|
+
- name: Upload artifacts
|
|
38
|
+
uses: actions/upload-artifact@v4
|
|
39
|
+
with:
|
|
40
|
+
name: dist
|
|
41
|
+
path: dist/
|
|
42
|
+
|
|
43
|
+
publish:
|
|
44
|
+
needs: build
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
permissions:
|
|
47
|
+
id-token: write
|
|
48
|
+
environment:
|
|
49
|
+
name: pypi
|
|
50
|
+
url: https://pypi.org/p/sym-mcp
|
|
51
|
+
steps:
|
|
52
|
+
- name: Download artifacts
|
|
53
|
+
uses: actions/download-artifact@v4
|
|
54
|
+
with:
|
|
55
|
+
name: dist
|
|
56
|
+
path: dist/
|
|
57
|
+
|
|
58
|
+
- name: Publish to PyPI (Trusted Publisher)
|
|
59
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# =========================
|
|
2
|
+
# Python cache / bytecode
|
|
3
|
+
# =========================
|
|
4
|
+
__pycache__/
|
|
5
|
+
*.py[cod]
|
|
6
|
+
*$py.class
|
|
7
|
+
|
|
8
|
+
# =========================
|
|
9
|
+
# Build / packaging outputs
|
|
10
|
+
# =========================
|
|
11
|
+
build/
|
|
12
|
+
dist/
|
|
13
|
+
*.egg-info/
|
|
14
|
+
.eggs/
|
|
15
|
+
*.egg
|
|
16
|
+
pip-wheel-metadata/
|
|
17
|
+
|
|
18
|
+
# =========================
|
|
19
|
+
# Test / coverage / typecheck caches
|
|
20
|
+
# =========================
|
|
21
|
+
.pytest_cache/
|
|
22
|
+
.coverage
|
|
23
|
+
.coverage.*
|
|
24
|
+
htmlcov/
|
|
25
|
+
.mypy_cache/
|
|
26
|
+
.pyre/
|
|
27
|
+
.ruff_cache/
|
|
28
|
+
.hypothesis/
|
|
29
|
+
.tox/
|
|
30
|
+
.nox/
|
|
31
|
+
|
|
32
|
+
# =========================
|
|
33
|
+
# Virtual environments
|
|
34
|
+
# =========================
|
|
35
|
+
.venv/
|
|
36
|
+
venv/
|
|
37
|
+
env/
|
|
38
|
+
|
|
39
|
+
# =========================
|
|
40
|
+
# Local env / secrets
|
|
41
|
+
# =========================
|
|
42
|
+
.env
|
|
43
|
+
.env.*
|
|
44
|
+
*.local
|
|
45
|
+
|
|
46
|
+
# =========================
|
|
47
|
+
# Editor / OS files
|
|
48
|
+
# =========================
|
|
49
|
+
.vscode/
|
|
50
|
+
.idea/
|
|
51
|
+
.DS_Store
|
|
52
|
+
Thumbs.db
|
|
53
|
+
|
|
54
|
+
# =========================
|
|
55
|
+
# Project-specific local docs (non-core)
|
|
56
|
+
# =========================
|
|
57
|
+
PRD.txt
|
|
58
|
+
TEST_PLAN.md
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 tyy
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sym-mcp
|
|
3
|
+
Version: 0.0.0.post1.dev3
|
|
4
|
+
Summary: SymPy sandbox MCP server based on FastMCP
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/Eis4TY/Sym-MCP
|
|
7
|
+
Project-URL: Repository, https://github.com/Eis4TY/Sym-MCP
|
|
8
|
+
Project-URL: Issues, https://github.com/Eis4TY/Sym-MCP/issues
|
|
9
|
+
Keywords: mcp,sympy,sandbox,agent,llm,math
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
|
+
Requires-Python: >=3.11
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: fastmcp>=3.0.0
|
|
21
|
+
Requires-Dist: sympy>=1.13.0
|
|
22
|
+
Requires-Dist: pydantic>=2.8.0
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
25
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# SymPy Sandbox MCP
|
|
29
|
+
|
|
30
|
+
English | [中文版](README.zh.md)
|
|
31
|
+
|
|
32
|
+
A production-focused MCP service that lets agents/LLMs run SymPy safely and efficiently.
|
|
33
|
+
It combines AST policy checks, runtime resource limits, and prewarmed workers to deliver low-noise, parse-friendly results.
|
|
34
|
+
|
|
35
|
+
## Features
|
|
36
|
+
|
|
37
|
+
- Single tool: `sympy` (input only requires `code`)
|
|
38
|
+
- Prewarmed worker pool to avoid repeated `import sympy`
|
|
39
|
+
- Two-layer safety: AST guard + runtime resource limits
|
|
40
|
+
- Compact structured JSON output for low token overhead
|
|
41
|
+
- Standardized error codes for reliable auto-retry workflows
|
|
42
|
+
|
|
43
|
+
## Typical Use Cases
|
|
44
|
+
|
|
45
|
+
- Symbolic algebra, differentiation, integration, equation solving
|
|
46
|
+
- MCP tool integration for Codex / Cursor / Claude Desktop / custom MCP clients
|
|
47
|
+
- Agent workflows that need controllable failures and clean error signals
|
|
48
|
+
|
|
49
|
+
## Recommended Integration (MCP client via stdio)
|
|
50
|
+
|
|
51
|
+
Call example:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
fastmcp call \
|
|
55
|
+
--command 'python -m sym_mcp.server' \
|
|
56
|
+
--target sympy \
|
|
57
|
+
--input-json '{"code":"import sympy as sp\\nx=sp.Symbol(\"x\")\\nprint(sp.factor(x**2-1))"}'
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Client config (`python -m`, recommended):
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"mcpServers": {
|
|
65
|
+
"sympy-sandbox": {
|
|
66
|
+
"command": "python",
|
|
67
|
+
"args": ["-m", "sym_mcp.server"]
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Client config (installed as `sym-mcp`):
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"mcpServers": {
|
|
78
|
+
"sympy-sandbox": {
|
|
79
|
+
"command": "sym-mcp",
|
|
80
|
+
"args": []
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Client config (`uvx`):
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"mcpServers": {
|
|
91
|
+
"sympy-sandbox": {
|
|
92
|
+
"command": "uvx",
|
|
93
|
+
"args": ["sym-mcp"]
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Quick Start
|
|
100
|
+
|
|
101
|
+
### 1) Requirements
|
|
102
|
+
|
|
103
|
+
- Python 3.11+
|
|
104
|
+
- Linux / macOS (Linux recommended for production)
|
|
105
|
+
|
|
106
|
+
### 2) Install (Tsinghua mirror first)
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -e .
|
|
110
|
+
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -e ".[dev]"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 3) Run server (stdio)
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
python -m sym_mcp.server
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### 4) Verify tool
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
fastmcp list --command 'python -m sym_mcp.server'
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Tool Contract
|
|
126
|
+
|
|
127
|
+
### Tool name
|
|
128
|
+
|
|
129
|
+
- `sympy`
|
|
130
|
+
|
|
131
|
+
### Input
|
|
132
|
+
|
|
133
|
+
- `code: str`
|
|
134
|
+
|
|
135
|
+
Notes:
|
|
136
|
+
- You must `print()` final outputs.
|
|
137
|
+
- If nothing is printed, `out` may be empty.
|
|
138
|
+
|
|
139
|
+
### Output (always compact JSON string)
|
|
140
|
+
|
|
141
|
+
Success:
|
|
142
|
+
|
|
143
|
+
```json
|
|
144
|
+
{"out":"x**2/2"}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Failure:
|
|
148
|
+
|
|
149
|
+
```json
|
|
150
|
+
{"code":"E_RUNTIME","line":3,"err":"ZeroDivisionError: division by zero","hint":"Runtime error. Check variable types, division-by-zero, or undefined names near the reported line."}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Field definitions:
|
|
154
|
+
|
|
155
|
+
- `out`: stdout text on success
|
|
156
|
+
- `code`: error code
|
|
157
|
+
- `line`: user code error line, or `null`
|
|
158
|
+
- `err`: compact error message (traceback noise removed)
|
|
159
|
+
- `hint`: fix hint (based on configured hint level)
|
|
160
|
+
- If `out` / `err` / `hint` is too long, it will be truncated with `...[truncated]`
|
|
161
|
+
|
|
162
|
+
## Error Codes
|
|
163
|
+
|
|
164
|
+
- `E_AST_BLOCK`: blocked by AST safety policy
|
|
165
|
+
- `E_SYNTAX`: syntax error
|
|
166
|
+
- `E_TIMEOUT`: timeout
|
|
167
|
+
- `E_MEMORY`: memory limit triggered
|
|
168
|
+
- `E_RUNTIME`: general runtime error
|
|
169
|
+
- `E_WORKER`: worker communication/state failure
|
|
170
|
+
- `E_INTERNAL`: internal server error
|
|
171
|
+
|
|
172
|
+
## Recommended Agent Prompt Rules
|
|
173
|
+
|
|
174
|
+
1. Use math-only Python code.
|
|
175
|
+
2. Only import `sympy` or `math`.
|
|
176
|
+
3. Always `print()` final answers.
|
|
177
|
+
4. For multiple outputs, use multiple `print()` lines.
|
|
178
|
+
5. On failure, patch minimally near `line` and retry.
|
|
179
|
+
6. For `E_TIMEOUT`, reduce scale first; for `E_MEMORY`, reduce object size/dimension; for `E_AST_BLOCK`, remove unsafe statements.
|
|
180
|
+
|
|
181
|
+
Example:
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
import sympy as sp
|
|
185
|
+
x = sp.Symbol("x")
|
|
186
|
+
expr = (x + 1)**5
|
|
187
|
+
print(sp.expand(expr))
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Security Model
|
|
191
|
+
|
|
192
|
+
### Before execution (AST policy)
|
|
193
|
+
|
|
194
|
+
- Only `sympy` / `math` imports are allowed
|
|
195
|
+
- Dangerous capabilities are blocked (`eval`, `exec`, `open`, `__import__`, etc.)
|
|
196
|
+
- Dunder attribute traversal is blocked (e.g. `__class__`)
|
|
197
|
+
|
|
198
|
+
### During execution (OS resource limits)
|
|
199
|
+
|
|
200
|
+
- Per-task CPU time limit + timeout kill
|
|
201
|
+
- Per-worker memory limit via `setrlimit`
|
|
202
|
+
- Worker auto-rebuild on failure to keep server healthy
|
|
203
|
+
|
|
204
|
+
## Architecture
|
|
205
|
+
|
|
206
|
+
- `src/sym_mcp/server.py`: MCP entrypoint and tool registration
|
|
207
|
+
- `src/sym_mcp/security/ast_guard.py`: AST validation
|
|
208
|
+
- `src/sym_mcp/executor/worker_main.py`: worker loop
|
|
209
|
+
- `src/sym_mcp/executor/pool.py`: async prewarmed process pool
|
|
210
|
+
- `src/sym_mcp/executor/sandbox.py`: restricted execution and stdout capture
|
|
211
|
+
- `src/sym_mcp/errors/parser.py`: error normalization and code mapping
|
|
212
|
+
- `src/sym_mcp/config.py`: runtime configuration
|
|
213
|
+
|
|
214
|
+
## Configuration (Environment Variables)
|
|
215
|
+
|
|
216
|
+
- `SYMMCP_POOL_SIZE`: worker pool size, default `10`
|
|
217
|
+
- `SYMMCP_EXEC_TIMEOUT_SEC`: per execution timeout (sec), default `3`
|
|
218
|
+
- `SYMMCP_MEMORY_LIMIT_MB`: memory cap per worker (MB), default `150`
|
|
219
|
+
- `SYMMCP_QUEUE_WAIT_SEC`: queue wait timeout (sec), default `2`
|
|
220
|
+
- `SYMMCP_LOG_LEVEL`: log level, default `INFO`
|
|
221
|
+
- `SYMMCP_MAX_OUTPUT_CHARS`: output truncation threshold, default `1200`
|
|
222
|
+
- `SYMMCP_HINT_LEVEL`: hint level (`none/short/medium`), default `medium`
|
|
223
|
+
|
|
224
|
+
## FAQ
|
|
225
|
+
|
|
226
|
+
### Why is `out` empty?
|
|
227
|
+
|
|
228
|
+
Most likely the code does not `print()` the final result.
|
|
229
|
+
|
|
230
|
+
### Why return compact JSON string?
|
|
231
|
+
|
|
232
|
+
It is easier for agents to parse reliably and reduces token cost.
|
|
233
|
+
|
|
234
|
+
### Is memory limiting always stable on macOS?
|
|
235
|
+
|
|
236
|
+
`setrlimit` behavior differs by OS. Linux is preferred for production.
|
|
237
|
+
|
|
238
|
+
### Does it support HTTP/SSE?
|
|
239
|
+
|
|
240
|
+
Current primary delivery is `stdio`. HTTP/SSE can be added later via FastMCP transport extensions.
|
|
241
|
+
|
|
242
|
+
## Known Limits
|
|
243
|
+
|
|
244
|
+
- This is restricted Python execution, not VM/container-grade isolation
|
|
245
|
+
- Memory limit behavior is OS-dependent
|
|
246
|
+
- Output is truncated at threshold, with `...[truncated]` suffix
|
|
247
|
+
|
|
248
|
+
## Development
|
|
249
|
+
|
|
250
|
+
### Run tests
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
PYTHONPATH=src pytest -q
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Benchmark
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
PYTHONPATH=src python scripts/benchmark.py --concurrency 100 --total 500
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## Contributing
|
|
263
|
+
|
|
264
|
+
- Run `PYTHONPATH=src pytest -q` before submitting PRs
|
|
265
|
+
- When adding new capabilities, update:
|
|
266
|
+
- error code docs
|
|
267
|
+
- README examples
|
|
268
|
+
- related unit/integration tests
|
|
269
|
+
- Publishing process: [PUBLISHING.md](./PUBLISHING.md)
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Publishing Guide (PyPI)
|
|
2
|
+
|
|
3
|
+
本文档描述如何将 `sym-mcp` 发布到 PyPI。
|
|
4
|
+
|
|
5
|
+
## 0. 发布前检查
|
|
6
|
+
|
|
7
|
+
1. 确认包名可用:
|
|
8
|
+
```bash
|
|
9
|
+
pip index versions sym-mcp
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
2. 版本号由 Git Tag 自动生成(`setuptools-scm`),不再手改 `pyproject.toml`。
|
|
13
|
+
- 例如:`v0.1.1` -> 发布版本 `0.1.1`
|
|
14
|
+
- 非 tag 构建会得到开发版号(仅用于本地/CI)
|
|
15
|
+
|
|
16
|
+
3. 执行测试:
|
|
17
|
+
```bash
|
|
18
|
+
PYTHONPATH=src pytest -q
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## 1. 构建分发包
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
python -m pip install -U build
|
|
25
|
+
python -m build
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
产物在 `dist/` 目录下(`.whl` + `.tar.gz`)。
|
|
29
|
+
|
|
30
|
+
## 2. 校验元数据
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
python -m pip install -U twine
|
|
34
|
+
twine check dist/*
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## 3. 上传到 TestPyPI(推荐先试)
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
twine upload --repository testpypi dist/*
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## 4. 上传到 PyPI
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
twine upload dist/*
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## 5. 安装与回归验证
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install -U sym-mcp
|
|
53
|
+
sym-mcp
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
另开终端验证工具:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
fastmcp list --command "sym-mcp"
|
|
60
|
+
fastmcp call --command "sym-mcp" --target sympy --input-json '{"code":"import sympy as sp\nx=sp.Symbol(\"x\")\nprint(sp.factor(x**2-1))"}'
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## 使用 GitHub Trusted Publisher(推荐)
|
|
64
|
+
|
|
65
|
+
仓库已包含工作流:
|
|
66
|
+
|
|
67
|
+
- `.github/workflows/pypi-publish.yml`
|
|
68
|
+
|
|
69
|
+
发布方式:
|
|
70
|
+
|
|
71
|
+
1. 在 PyPI 项目中创建 Trusted Publisher,填写:
|
|
72
|
+
- Owner: `Eis4TY`
|
|
73
|
+
- Repository: `Sym-MCP`
|
|
74
|
+
- Workflow: `pypi-publish.yml`
|
|
75
|
+
- Environment: `pypi`
|
|
76
|
+
|
|
77
|
+
2. 推送版本标签触发发布(版本自动从 tag 推导):
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
git tag v0.1.1
|
|
81
|
+
git push origin v0.1.1
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
3. GitHub Actions 会自动完成:
|
|
85
|
+
- 构建
|
|
86
|
+
- `twine check`
|
|
87
|
+
- OIDC 发布到 PyPI
|