mcp-browser/setup.py

228 lines
7.8 KiB
Python

"""
Setup script for MCP Browser.
This package is developed exclusively by AI assistants.
"""
from setuptools import setup, find_packages, Command
import os
import sys
import subprocess
from pathlib import Path
import asyncio
class GenerateAIDocs(Command):
"""Generate AI-friendly documentation."""
description = 'Generate documentation for AI navigation'
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
"""Run all AI documentation generators."""
print("Generating AI-friendly documentation...")
# 1. Generate API documentation
try:
subprocess.run([sys.executable, '-m', 'pydoc', '-w', '.'],
cwd='mcp_browser', check=True)
print("✓ Generated pydoc API documentation")
except Exception as e:
print(f"⚠ pydoc generation failed: {e}")
# 2. Generate ctags for code navigation
try:
subprocess.run(['ctags', '-R', '--languages=Python',
'--python-kinds=-i', '-f', '.tags'], check=True)
print("✓ Generated ctags file")
except FileNotFoundError:
print("⚠ ctags not installed (install with: apt-get install universal-ctags)")
except Exception as e:
print(f"⚠ ctags generation failed: {e}")
# 3. Generate structure documentation
self.generate_structure_doc()
# 4. Generate API summary
self.generate_api_summary()
print("\nAI documentation generation complete!")
print("Files created:")
print(" - docs/STRUCTURE.md - Project structure overview")
print(" - docs/API_SUMMARY.md - API quick reference")
print(" - .tags - ctags for code navigation")
print(" - *.html - pydoc HTML documentation")
def generate_structure_doc(self):
"""Generate project structure documentation."""
structure = []
for root, dirs, files in os.walk('.'):
# Skip hidden directories and __pycache__
dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__']
level = root.replace('.', '').count(os.sep)
indent = ' ' * level
structure.append(f"{indent}{os.path.basename(root)}/")
subindent = ' ' * (level + 1)
for file in sorted(files):
if file.endswith('.py'):
structure.append(f"{subindent}{file}")
os.makedirs('docs', exist_ok=True)
with open('docs/STRUCTURE.md', 'w') as f:
f.write("# Project Structure\n\n")
f.write("```\n")
f.write('\n'.join(structure))
f.write("\n```\n")
def generate_api_summary(self):
"""Generate API summary for quick reference."""
api_summary = []
api_summary.append("# MCP Browser API Summary\n")
api_summary.append("## Main Classes\n")
# Extract main classes and methods
main_files = [
('mcp_browser/proxy.py', 'MCPBrowser'),
('mcp_browser/registry.py', 'ToolRegistry'),
('mcp_browser/server.py', 'MCPServer'),
('mcp_browser/multi_server.py', 'MultiServerManager'),
]
for file_path, class_name in main_files:
if os.path.exists(file_path):
api_summary.append(f"\n### {class_name} ({file_path})\n")
# Simple method extraction (could be enhanced)
try:
with open(file_path, 'r') as f:
content = f.read()
lines = content.split('\n')
for i, line in enumerate(lines):
if line.strip().startswith('def ') and not line.strip().startswith('def _'):
method = line.strip()[4:].split('(')[0]
api_summary.append(f"- `{method}()`")
except Exception:
pass
os.makedirs('docs', exist_ok=True)
with open('docs/API_SUMMARY.md', 'w') as f:
f.write('\n'.join(api_summary))
class TestCommand(Command):
"""Run all tests including integration tests."""
description = 'Run unit and integration tests'
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
"""Run all tests."""
print("Running MCP Browser Tests")
print("=" * 50)
# Run pytest for unit tests
print("\nRunning unit tests with pytest...")
try:
subprocess.run([sys.executable, '-m', 'pytest', 'tests/', '-v',
'--ignore=tests/test_integration.py'], check=True)
print("✓ Unit tests passed")
except subprocess.CalledProcessError:
print("✗ Unit tests failed")
sys.exit(1)
except FileNotFoundError:
print("⚠ pytest not installed. Run: pip install -e .[dev]")
sys.exit(1)
# Run integration tests
print("\nRunning integration tests...")
try:
# Run integration test directly
subprocess.run([sys.executable, 'tests/test_integration.py'], check=True)
print("✓ Integration tests passed")
except subprocess.CalledProcessError:
print("✗ Integration tests failed")
sys.exit(1)
print("\n" + "=" * 50)
print("✅ All tests passed!")
# Read long description
with open("README.md", "r", encoding="utf-8") as fh:
long_description = fh.read()
setup(
name="mcp-browser",
version="0.1.0",
description="A generic MCP browser with context optimization for AI systems",
long_description=long_description,
long_description_content_type="text/markdown",
author="Claude4Ξlope",
author_email="xilope@esus.name",
url="https://github.com/Xilope0/mcp-browser",
packages=find_packages(include=['mcp_browser*', 'mcp_servers*']),
package_data={
'mcp_browser': ['py.typed'],
'mcp_servers': ['**/*.py'],
'mcp_servers.screen': ['*.py'],
'mcp_servers.memory': ['*.py'],
'mcp_servers.pattern_manager': ['*.py'],
'mcp_servers.onboarding': ['*.py'],
},
include_package_data=True,
install_requires=[
"aiofiles>=23.0.0",
"jsonpath-ng>=1.6.0",
"pyyaml>=6.0",
"typing-extensions>=4.0.0;python_version<'3.11'",
],
extras_require={
'dev': [
'pytest>=7.0.0',
'pytest-asyncio>=0.21.0',
'black>=23.0.0',
'mypy>=1.0.0',
'ruff>=0.1.0',
],
'docs': [
'sphinx>=6.0.0',
'sphinx-rtd-theme>=1.3.0',
'myst-parser>=2.0.0',
],
},
python_requires=">=3.8",
entry_points={
"console_scripts": [
"mcp-browser=mcp_browser.__main__:main",
],
},
cmdclass={
'aidocs': GenerateAIDocs,
'test': TestCommand,
},
classifiers=[
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Topic :: Software Development :: Libraries :: Application Frameworks",
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
],
keywords="mcp model-context-protocol ai llm tools json-rpc",
)