From 155302f918f962191bc50ca1062f241b325fe6ac Mon Sep 17 00:00:00 2001 From: Stephan Eberle Date: Mon, 15 Sep 2025 16:04:50 +0200 Subject: [PATCH 1/2] Add example for how to build an MCP Bundle for a Python package --- .gitignore | 13 ++- README.md | 15 ++++ .../file-manager-python-package/.mcpbignore | 6 ++ .../file-manager-python-package/manifest.json | 69 ++++++++++++++ .../mcp_server_file_manager/__init__.py | 1 + .../mcp_server_file_manager/__main__.py | 26 ++++++ .../mcp_server_file_manager/server.py | 90 +++++++++++++++++++ .../pyproject.toml | 31 +++++++ 8 files changed, 250 insertions(+), 1 deletion(-) create mode 100644 examples/file-manager-python-package/.mcpbignore create mode 100644 examples/file-manager-python-package/manifest.json create mode 100644 examples/file-manager-python-package/mcp_server_file_manager/__init__.py create mode 100644 examples/file-manager-python-package/mcp_server_file_manager/__main__.py create mode 100644 examples/file-manager-python-package/mcp_server_file_manager/server.py create mode 100644 examples/file-manager-python-package/pyproject.toml diff --git a/.gitignore b/.gitignore index bc63d59..5082005 100644 --- a/.gitignore +++ b/.gitignore @@ -105,4 +105,15 @@ self-signed-cert.pem self-signed-key.pem *.mcpb invalid-json.json -**/server/lib/** \ No newline at end of file +**/*/lib/** + +# Python +__pycache__/ +*.py[cod] +*.egg-info + +# Python virtual environments +.venv/ + +# VS Code +.vscode/PythonImportHelper-v2-Completion.json \ No newline at end of file diff --git a/README.md b/README.md index 1d768f2..f2fa49a 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,21 @@ bundle.mcpb (ZIP file) └── icon.png # Optional: Bundle icon ``` +### Example: Python Package Bundle + +``` +bundle.mcpb (ZIP file) +├── manifest.json # Required: Bundle metadata and configuration +├── server_package/ # Server files +│ ├── __init__.py # Package initializer +│ ├── __main__.py # Main entry point +│ ├── server.py # MCP server +│ └── utils.py # Additional modules +├── lib/ # Bundled Python packages (must server_package) +├── pyproject.toml # Optional: Python configuration +└── icon.png # Optional: Bundle icon +``` + ### Example: Binary Bundle ``` diff --git a/examples/file-manager-python-package/.mcpbignore b/examples/file-manager-python-package/.mcpbignore new file mode 100644 index 0000000..78dd316 --- /dev/null +++ b/examples/file-manager-python-package/.mcpbignore @@ -0,0 +1,6 @@ +.venv/ +*.egg-info/ +*.toml +build/ +dist/ +mcp_server_file_manager/__pycache__/ \ No newline at end of file diff --git a/examples/file-manager-python-package/manifest.json b/examples/file-manager-python-package/manifest.json new file mode 100644 index 0000000..e008e8a --- /dev/null +++ b/examples/file-manager-python-package/manifest.json @@ -0,0 +1,69 @@ +{ + "$schema": "../../dist/mcpb-manifest.schema.json", + "dxt_version": "0.1", + "name": "file-manager-python-package", + "display_name": "Python Package File Manager MCP", + "version": "0.1.0", + "description": "A Python Package MCP server for file operations", + "long_description": "This extension provides file management capabilities through a Python Package MCP server. It demonstrates Python package-based MCP Bundle development, including file operations, directory management, and proper MCP protocol implementation.", + "author": { + "name": "Anthropic", + "email": "support@anthropic.com", + "url": "https://github.com/anthropics" + }, + "server": { + "type": "python", + "entry_point": "mcp_server_file_manager/__main__.py", + "mcp_config": { + "command": "python", + "args": [ + "-m", + "mcp_server_file_manager", + "--workspace=${user_config.workspace_directory}" + ], + "env": { + "DEBUG": "${user_config.debug_mode}", + "PYTHONPATH": "${__dirname}/mcp_server_file_manager/lib" + } + } + }, + "tools": [ + { + "name": "list_files", + "description": "List files in a directory" + }, + { + "name": "read_file", + "description": "Read file contents" + }, + { + "name": "get_file_info", + "description": "Get information about a file" + } + ], + "keywords": ["file", "directory", "python", "management", "filesystem"], + "license": "MIT", + "user_config": { + "workspace_directory": { + "type": "directory", + "title": "Workspace Directory", + "description": "Directory to use as workspace", + "default": "${HOME}/Documents", + "required": false + }, + "debug_mode": { + "type": "boolean", + "title": "Debug Mode", + "description": "Enable debug output", + "default": false, + "required": false + } + }, + "compatibility": { + "claude_desktop": ">=0.10.0", + "platforms": ["darwin", "win32", "linux"], + "runtimes": { + "python": ">=3.8.0 <4" + } + } +} diff --git a/examples/file-manager-python-package/mcp_server_file_manager/__init__.py b/examples/file-manager-python-package/mcp_server_file_manager/__init__.py new file mode 100644 index 0000000..3bd0a8c --- /dev/null +++ b/examples/file-manager-python-package/mcp_server_file_manager/__init__.py @@ -0,0 +1 @@ +"""File Manager MCP server.""" \ No newline at end of file diff --git a/examples/file-manager-python-package/mcp_server_file_manager/__main__.py b/examples/file-manager-python-package/mcp_server_file_manager/__main__.py new file mode 100644 index 0000000..8b6c242 --- /dev/null +++ b/examples/file-manager-python-package/mcp_server_file_manager/__main__.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 + +import os +import sys +import argparse + +def main(): + # Parse command line arguments + parser = argparse.ArgumentParser(description="File Manager MCP Server") + parser.add_argument( + "--workspace", default=os.path.expanduser("~/Documents"), help="Workspace directory" + ) + parser.add_argument("--debug", action="store_true", help="Enable debug mode") + args = parser.parse_args() + + # Debug output if enabled + if args.debug: + print("Starting File Manager MCP Server...", file=sys.stderr) + print(f"Workspace: {args.workspace}", file=sys.stderr) + + # Import and run the server + from .server import mcp + mcp.run() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/examples/file-manager-python-package/mcp_server_file_manager/server.py b/examples/file-manager-python-package/mcp_server_file_manager/server.py new file mode 100644 index 0000000..9e2adb7 --- /dev/null +++ b/examples/file-manager-python-package/mcp_server_file_manager/server.py @@ -0,0 +1,90 @@ +from pathlib import Path +from mcp.server.fastmcp import FastMCP + +# Initialize server +mcp = FastMCP("file-manager-python") + + +@mcp.tool() +def list_files(path: str) -> str: + """List files in a directory""" + path_obj = Path(path) + + if not path_obj.exists(): + return f"Directory not found: {path}" + + if not path_obj.is_dir(): + return f"Path is not a directory: {path}" + + try: + files = [] + for item in path_obj.iterdir(): + file_type = "directory" if item.is_dir() else "file" + files.append(f"{item.name} ({file_type})") + + if not files: + return f"Directory is empty: {path}" + + file_list = "\n".join(files) + return f"Files in {path}:\n{file_list}" + + except PermissionError: + return f"Permission denied accessing: {path}" + except Exception as e: + return f"Error listing directory: {str(e)}" + + +@mcp.tool() +def read_file(path: str) -> str: + """Read file contents""" + path_obj = Path(path) + + if not path_obj.exists(): + return f"File not found: {path}" + + if not path_obj.is_file(): + return f"Path is not a file: {path}" + + try: + with path_obj.open("r", encoding="utf-8") as f: + content = f.read() + + return f"Contents of {path}:\n{content}" + + except UnicodeDecodeError: + return f"File is not text or uses unsupported encoding: {path}" + except PermissionError: + return f"Permission denied reading: {path}" + except Exception as e: + return f"Error reading file: {str(e)}" + + +@mcp.tool() +def get_file_info(path: str) -> str: + """Get information about a file""" + path_obj = Path(path) + + if not path_obj.exists(): + return f"Path not found: {path}" + + try: + stat_info = path_obj.stat() + file_type = "directory" if path_obj.is_dir() else "file" + + info = [ + f"Path: {path}", + f"Type: {file_type}", + f"Size: {stat_info.st_size} bytes", + f"Modified: {stat_info.st_mtime}", + f"Created: {stat_info.st_ctime}", + ] + + info_text = "\n".join(info) + return f"File Info:\n{info_text}" + + except PermissionError: + return f"Permission denied accessing: {path}" + except Exception as e: + return f"Error getting file info: {str(e)}" + + diff --git a/examples/file-manager-python-package/pyproject.toml b/examples/file-manager-python-package/pyproject.toml new file mode 100644 index 0000000..a2fdc95 --- /dev/null +++ b/examples/file-manager-python-package/pyproject.toml @@ -0,0 +1,31 @@ +[build-system] +requires = ["setuptools>=42", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "file-manager-python-package" +version = "0.1.0" +description = "A Python Package MCP server for file operations" +authors = [ + {name = "Anthropic", email = "support@anthropic.com"} +] +license = {text = "MIT"} +classifiers = [ + "Private :: Do Not Upload" # Prevents accidental uploads to PyPI +] +dependencies = [ + "mcp>=1.0.0", + "trio>=0.22.0" +] + +[tool.setuptools] +packages = ["mcp_server_file_manager"] + +[project.scripts] +mcp-server-file-manager = "mcp_server_file_manager.__main__:main" + +# Custom scripts section for MCPB development +[tool.mcpb] +bundle = "pip install . --target mcp_server_file_manager/lib --upgrade" +test = "python -m mcp_server_file_manager --help" +pack = "npx @anthropic-ai/mcpb pack . dist\file-manager.mcpb" \ No newline at end of file From a1b5ec384ff95d49030eaef3a4438d6ac8f44984 Mon Sep 17 00:00:00 2001 From: Stephan Eberle Date: Mon, 15 Sep 2025 16:55:43 +0200 Subject: [PATCH 2/2] Update examples README.md --- examples/README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/README.md b/examples/README.md index 24480ed..fe9a919 100644 --- a/examples/README.md +++ b/examples/README.md @@ -14,11 +14,12 @@ But, the MCP servers themselves are not robust secure production ready servers a ## Examples Included -| Example | Type | Demonstrates | -| --------------------- | ------- | ---------------------------------------- | -| `hello-world-node` | Node.js | Basic MCP server with simple time tool | -| `chrome-applescript` | Node.js | Browser automation via AppleScript | -| `file-manager-python` | Python | File system operations and path handling | +| Example | Type | Demonstrates | +| ----------------------------- | ------- | ---------------------------------------- | +| `hello-world-node` | Node.js | Basic MCP server with simple time tool | +| `chrome-applescript` | Node.js | Browser automation via AppleScript | +| `file-manager-python` | Python | File system operations and path handling | +| `file-manager-python-package` | Python | Same as above but shipping as Python package and featuring an MCPB manifest using module invocation instead of direct script execution | ## Usage