3cfd374160
- Add PyInstaller spec files (onefile and onedir modes) - Add build scripts for executable creation - Add MCP hooks for PyInstaller compatibility - Add test script for MCP server validation - Add Windsurf integration setup guide - Update main.py with better error reporting - Successfully tested MCP server works with ONEDIR build (45MB) Features: - Single executable deployment without Python dependency - ONEDIR mode preserves stdio communication for MCP - Build scripts with deployment instructions - Windsurf config integration guide Files added: - mt5-quant.spec (PyInstaller spec) - mt5-quant-onedir.spec (directory mode) - scripts/build-executable.sh (onefile) - scripts/build-executable-onedir.sh (directory) - hooks/hook-mcp.py (PyInstaller hook) - test_mcp.py (validation script) - WINDSURF_SETUP.md (integration guide)
162 lines
3.6 KiB
RPMSpec
162 lines
3.6 KiB
RPMSpec
# -*- mode: python ; coding: utf-8 -*-
|
|
"""
|
|
PyInstaller spec file for MT5-Quant MCP Server
|
|
|
|
Build:
|
|
pyinstaller mt5-quant.spec
|
|
|
|
Output:
|
|
dist/mt5-quant (single executable)
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
from PyInstaller.utils.hooks import collect_all
|
|
|
|
block_cipher = None
|
|
|
|
# Project root - the build script runs from project root, so use cwd
|
|
root = Path(os.getcwd()).resolve()
|
|
|
|
# Collect entire mcp package (datas, binaries, hiddenimports)
|
|
mcp_datas, mcp_binaries, mcp_hiddenimports = collect_all('mcp')
|
|
|
|
# Data files to include
|
|
# Format: (source_path, dest_dir_in_bundle)
|
|
datas = [
|
|
# Include scripts directory (bash pipeline scripts)
|
|
(str(root / 'scripts'), 'scripts'),
|
|
# Include docs if needed
|
|
(str(root / 'docs'), 'docs'),
|
|
] + mcp_datas
|
|
|
|
# Hidden imports (modules that are imported dynamically or might be missed)
|
|
# Note: mcp_hiddenimports already includes all mcp submodules from collect_all()
|
|
hiddenimports = mcp_hiddenimports + [
|
|
# MCP package - all submodules
|
|
'mcp',
|
|
'mcp.types',
|
|
'mcp.server',
|
|
'mcp.server.stdio',
|
|
'mcp.server.models',
|
|
'mcp.server.session',
|
|
'mcp.shared',
|
|
'mcp.shared.memory',
|
|
'mcp.shared.session',
|
|
'mcp.shared.exceptions',
|
|
'mcp.shared.context',
|
|
'mcp.shared.progress',
|
|
'mcp.shared.version',
|
|
'mcp.client',
|
|
'mcp.cli',
|
|
# Analytics modules (local project modules)
|
|
'analytics',
|
|
'analytics.extract',
|
|
'analytics.analyze',
|
|
'analytics.optimize_parser',
|
|
# Other dependencies
|
|
'pydantic',
|
|
'pydantic.v1',
|
|
'pydantic.v1.fields',
|
|
'pydantic.v1.main',
|
|
'pydantic_core',
|
|
'yaml',
|
|
'_yaml',
|
|
'yaml.constructor',
|
|
'yaml.representer',
|
|
'yaml.cyaml',
|
|
'anyio',
|
|
'anyio.streams',
|
|
'anyio.streams.memory',
|
|
'anyio.streams.text',
|
|
'anyio._backends',
|
|
'anyio._backends._asyncio',
|
|
# Other stdlib that might be dynamically imported
|
|
'xml.etree.ElementTree',
|
|
'html.parser',
|
|
'select',
|
|
'ssl',
|
|
'_ssl',
|
|
'certifi',
|
|
'email',
|
|
'email.parser',
|
|
'email.message',
|
|
'importlib.metadata',
|
|
]
|
|
|
|
a = Analysis(
|
|
['server/main.py'],
|
|
pathex=[str(root), str(root / 'server'), str(root / 'analytics')],
|
|
binaries=mcp_binaries,
|
|
datas=datas,
|
|
hiddenimports=hiddenimports,
|
|
hookspath=[str(root / 'hooks')],
|
|
hooksconfig={
|
|
'mcp': {
|
|
'include_all': True,
|
|
}
|
|
},
|
|
runtime_hooks=[],
|
|
excludes=[
|
|
# Exclude unnecessary packages to reduce binary size
|
|
'matplotlib',
|
|
'PIL',
|
|
'numpy',
|
|
'pandas',
|
|
'scipy',
|
|
'tkinter',
|
|
'PyQt5',
|
|
'PyQt6',
|
|
'wx',
|
|
'test',
|
|
'unittest',
|
|
'pydoc',
|
|
'doctest',
|
|
# 'email', # Required by pydantic -> mcp
|
|
# 'http.server',
|
|
# 'ftplib',
|
|
# 'telnetlib',
|
|
# 'ssl', # Required by anyio -> mcp
|
|
'sqlite3',
|
|
],
|
|
win_no_prefer_redirects=False,
|
|
win_private_assemblies=False,
|
|
cipher=block_cipher,
|
|
noarchive=False,
|
|
)
|
|
|
|
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
|
|
|
|
# Create the EXE without including binaries/datas (onedir mode)
|
|
exe = EXE(
|
|
pyz,
|
|
a.scripts,
|
|
[],
|
|
exclude_binaries=True,
|
|
name='mt5-quant',
|
|
debug=False,
|
|
bootloader_ignore_signals=False,
|
|
strip=False,
|
|
upx=False,
|
|
upx_exclude=[],
|
|
runtime_tmpdir=None,
|
|
console=True,
|
|
disable_windowed_traceback=False,
|
|
target_arch=None,
|
|
codesign_identity=None,
|
|
entitlements_file=None,
|
|
)
|
|
|
|
# Collect all files into directory (onedir mode)
|
|
coll = COLLECT(
|
|
exe,
|
|
a.binaries,
|
|
a.zipfiles,
|
|
a.datas,
|
|
strip=False,
|
|
upx=False,
|
|
upx_exclude=[],
|
|
name='mt5-quant'
|
|
)
|