Gatherings MCP Server
by abutbul
import os
import sys
import json
import subprocess
from typing import Dict, Any, List, Optional, Union, TypedDict
print(f"Python path: {sys.path}")
print(f"Python executable: {sys.executable}")
# Import MCP SDK
from mcp.server.fastmcp import FastMCP
# Initialize FastMCP
mcp = FastMCP("Gatherings")
# Get Python script path from environment or use default
PYTHON_PATH = os.environ.get("GATHERINGS_SCRIPT", os.path.join(os.getcwd(), "gatherings.py"))
# Error handling
def error_handler(error):
print(f"[MCP Error] {error}", file=sys.stderr)
mcp.onerror = error_handler
def run_command(cmd_args):
"""Execute a command and return the result"""
try:
command = ["python", PYTHON_PATH, "--json"] + cmd_args
# Execute the command
env = os.environ.copy()
env["GATHERINGS_DB_PATH"] = os.environ.get("GATHERINGS_DB_PATH", "gatherings.db")
process = subprocess.run(
command,
env=env,
capture_output=True,
text=True
)
if process.stderr:
print(f"[Command Error] {process.stderr}", file=sys.stderr)
try:
result = json.loads(process.stdout)
return result
except json.JSONDecodeError:
# If output is not valid JSON, return it as text
return {
"success": False,
"error": "Invalid JSON response",
"output": process.stdout
}
except Exception as e:
return {
"success": False,
"error": str(e)
}
# Define create_gathering handler
@mcp.tool()
def create_gathering(gathering_id: str, members: int):
"""Create a new gathering"""
return run_command(["create", gathering_id, "--members", str(int(members))])
# Define add_expense handler
@mcp.tool()
def add_expense(gathering_id: str, member_name: str, amount: float):
"""Add an expense for a member"""
return run_command(["add-expense", gathering_id, member_name, str(amount)])
# Define calculate_reimbursements handler
@mcp.tool()
def calculate_reimbursements(gathering_id: str):
"""Calculate reimbursements for a gathering"""
return run_command(["calculate", gathering_id])
# Define record_payment handler
@mcp.tool()
def record_payment(gathering_id: str, member_name: str, amount: float):
"""Record a payment made by a member"""
return run_command(["record-payment", gathering_id, member_name, str(amount)])
# Define rename_member handler
@mcp.tool()
def rename_member(gathering_id: str, old_name: str, new_name: str):
"""Rename an unnamed member"""
return run_command(["rename-member", gathering_id, old_name, new_name])
# Define show_gathering handler
@mcp.tool()
def show_gathering(gathering_id: str):
"""Show details of a gathering"""
return run_command(["show", gathering_id])
# Define list_gatherings handler
@mcp.tool()
def list_gatherings():
"""List all gatherings"""
return run_command(["list"])
# Define close_gathering handler
@mcp.tool()
def close_gathering(gathering_id: str):
"""Close a gathering"""
return run_command(["close", gathering_id])
# Define delete_gathering handler
@mcp.tool()
def delete_gathering(gathering_id: str, force: bool = False):
"""Delete a gathering"""
cmd = ["delete", gathering_id]
if force:
cmd.append("--force")
return run_command(cmd)
# Define add_member handler
@mcp.tool()
def add_member(gathering_id: str, member_name: str):
"""Add a new member to a gathering"""
return run_command(["add-member", gathering_id, member_name])
# Define remove_member handler
@mcp.tool()
def remove_member(gathering_id: str, member_name: str):
"""Remove a member from a gathering"""
return run_command(["remove-member", gathering_id, member_name])
if __name__ == "__main__":
print("Gatherings MCP server running on stdio", file=sys.stderr)
try:
mcp.run(transport="stdio")
except KeyboardInterrupt:
print("\nShutting down server...", file=sys.stderr)