Skip to main content
Glama

Zotero MCP

#!/usr/bin/env python # -*- coding: utf-8 -*- """ Setup helper for zotero-mcp. This script provides utilities to automatically configure zotero-mcp by finding the installed executable and updating Claude Desktop's config. """ import argparse import json import os import shutil import sys from pathlib import Path def find_executable(): """Find the full path to the zotero-mcp executable.""" # Try to find the executable in the PATH exe_name = "zotero-mcp" if sys.platform == "win32": exe_name += ".exe" exe_path = shutil.which(exe_name) if exe_path: print(f"Found zotero-mcp in PATH at: {exe_path}") return exe_path # If not found in PATH, try to find it in common installation directories potential_paths = [] # User site-packages import site for site_path in site.getsitepackages(): potential_paths.append(Path(site_path) / "bin" / exe_name) # User's home directory potential_paths.append(Path.home() / ".local" / "bin" / exe_name) # Virtual environment if "VIRTUAL_ENV" in os.environ: potential_paths.append(Path(os.environ["VIRTUAL_ENV"]) / "bin" / exe_name) # Additional common locations if sys.platform == "darwin": # macOS potential_paths.append(Path("/usr/local/bin") / exe_name) potential_paths.append(Path("/opt/homebrew/bin") / exe_name) for path in potential_paths: if path.exists() and os.access(path, os.X_OK): print(f"Found zotero-mcp at: {path}") return str(path) # If still not found, search in common directories print("Searching for zotero-mcp in common locations...") try: # On Unix-like systems, try using the 'find' command if sys.platform != 'win32': import subprocess result = subprocess.run( ["find", os.path.expanduser("~"), "-name", "zotero-mcp", "-type", "f", "-executable"], capture_output=True, text=True, timeout=10 ) paths = result.stdout.strip().split('\n') if paths and paths[0]: print(f"Found zotero-mcp at {paths[0]}") return paths[0] except Exception as e: print(f"Error searching for zotero-mcp: {e}") print("Warning: Could not find zotero-mcp executable.") print("Make sure zotero-mcp is installed and in your PATH.") return None def find_claude_config(): """Find Claude Desktop config file path.""" config_paths = [] # macOS if sys.platform == "darwin": # Try both old and new paths config_paths.append(Path.home() / "Library" / "Application Support" / "Claude" / "claude_desktop_config.json") config_paths.append(Path.home() / "Library" / "Application Support" / "Claude Desktop" / "claude_desktop_config.json") # Windows elif sys.platform == "win32": appdata = os.environ.get("APPDATA") if appdata: config_paths.append(Path(appdata) / "Claude" / "claude_desktop_config.json") config_paths.append(Path(appdata) / "Claude Desktop" / "claude_desktop_config.json") # Linux else: config_home = os.environ.get('XDG_CONFIG_HOME', Path.home() / '.config') config_paths.append(Path(config_home) / "Claude" / "claude_desktop_config.json") config_paths.append(Path(config_home) / "Claude Desktop" / "claude_desktop_config.json") # Check all possible locations for path in config_paths: if path.exists(): print(f"Found Claude Desktop config at: {path}") return path # Return the default path for the platform if not found # We'll use the newer "Claude Desktop" path as default if sys.platform == "darwin": # macOS default_path = Path.home() / "Library" / "Application Support" / "Claude Desktop" / "claude_desktop_config.json" elif sys.platform == "win32": # Windows appdata = os.environ.get("APPDATA", "") default_path = Path(appdata) / "Claude Desktop" / "claude_desktop_config.json" else: # Linux and others config_home = os.environ.get('XDG_CONFIG_HOME', Path.home() / '.config') default_path = Path(config_home) / "Claude Desktop" / "claude_desktop_config.json" print(f"Claude Desktop config not found. Using default path: {default_path}") return default_path def update_claude_config(config_path, zotero_mcp_path, local=True, api_key=None, library_id=None, library_type="user"): """Update Claude Desktop config to add zotero-mcp.""" # Create directory if it doesn't exist config_dir = config_path.parent config_dir.mkdir(parents=True, exist_ok=True) # Load existing config or create new one if config_path.exists(): try: with open(config_path, 'r') as f: config = json.load(f) print(f"Loaded existing config from: {config_path}") except json.JSONDecodeError: print(f"Error: Config file at {config_path} is not valid JSON. Creating new config.") config = {} else: print(f"Creating new config file at: {config_path}") config = {} # Ensure mcpServers key exists if "mcpServers" not in config: config["mcpServers"] = {} # Create environment settings based on local vs web API env_settings = { "ZOTERO_LOCAL": "true" if local else "false" } # Add API key and library settings for web API if not local: if api_key: env_settings["ZOTERO_API_KEY"] = api_key if library_id: env_settings["ZOTERO_LIBRARY_ID"] = library_id if library_type: env_settings["ZOTERO_LIBRARY_TYPE"] = library_type # Add or update zotero config config["mcpServers"]["zotero"] = { "command": zotero_mcp_path, "env": env_settings } # Write updated config try: with open(config_path, 'w') as f: json.dump(config, f, indent=2) print(f"\nSuccessfully wrote config to: {config_path}") except Exception as e: print(f"Error writing config file: {str(e)}") return False return config_path def main(cli_args=None): """Main function to run the setup helper.""" parser = argparse.ArgumentParser(description="Configure zotero-mcp for Claude Desktop") parser.add_argument("--no-local", action="store_true", help="Configure for Zotero Web API instead of local API") parser.add_argument("--api-key", help="Zotero API key (only needed with --no-local)") parser.add_argument("--library-id", help="Zotero library ID (only needed with --no-local)") parser.add_argument("--library-type", choices=["user", "group"], default="user", help="Zotero library type (only needed with --no-local)") parser.add_argument("--config-path", help="Path to Claude Desktop config file") # If this is being called from CLI with existing args if cli_args is not None and hasattr(cli_args, 'no_local'): args = cli_args print("Using arguments passed from command line") else: # Otherwise parse from command line args = parser.parse_args() print("Parsed arguments from command line") # Find zotero-mcp executable exe_path = find_executable() if not exe_path: print("Error: Could not find zotero-mcp executable.") return 1 print(f"Using zotero-mcp at: {exe_path}") # Find Claude Desktop config config_path = args.config_path if not config_path: config_path = find_claude_config() else: print(f"Using specified config path: {config_path}") config_path = Path(config_path) if not config_path: print("Error: Could not determine Claude Desktop config path.") return 1 # Update config use_local = not args.no_local api_key = args.api_key library_id = args.library_id library_type = args.library_type print(f"\nSetup with the following settings:") print(f" Local API: {use_local}") if not use_local: print(f" API Key: {api_key or 'Not provided'}") print(f" Library ID: {library_id or 'Not provided'}") print(f" Library Type: {library_type}") try: updated_config_path = update_claude_config( config_path, exe_path, local=use_local, api_key=api_key, library_id=library_id, library_type=library_type ) if updated_config_path: print("\nSetup complete!") print("To use Zotero in Claude Desktop:") print("1. Restart Claude Desktop if it's running") print("2. In Claude, type: /tools zotero") if use_local: print("\nNote: Make sure Zotero desktop is running and the local API is enabled in preferences.") else: missing = [] if not api_key: missing.append("API key") if not library_id: missing.append("Library ID") if missing: print(f"\nWarning: The following required settings for Web API were not provided: {', '.join(missing)}") print("You may need to set these as environment variables or reconfigure.") return 0 else: print("\nSetup failed. See errors above.") return 1 except Exception as e: print(f"\nSetup failed with error: {str(e)}") return 1 if __name__ == "__main__": sys.exit(main())

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/54yyyu/zotero-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server