From bbaa0daa7b176d0bf2d3070a3958357cdad13ce1 Mon Sep 17 00:00:00 2001 From: david Date: Sat, 3 Jan 2026 14:06:04 -0500 Subject: [PATCH] added new gemini creations --- .../check_db.py | 0 .../comics_organizesteps.py | 0 .../fixed_comics_manager.py | 0 gemini_projects/mcp/.env | 1 + gemini_projects/mcp/README.md | 47 ++++++++ gemini_projects/mcp/gemini_client.py | 62 ++++++++++ gemini_projects/mcp/requirements.txt | 3 + gemini_projects/mcp/setup.sh | 48 ++++++++ gemini_projects/mcp/simple_server.py | 20 ++++ .../truenas_storagetracker/.env.template | 2 + .../truenas_storagetracker/README.md | 83 +++++++++++++ .../truenas_storagetracker/requirements.txt | 3 + .../truenas_storagetracker/src/__init__.py | 0 .../src/__pycache__/tracker.cpython-313.pyc | Bin 0 -> 5118 bytes .../truenas_storagetracker/src/tracker.py | 109 ++++++++++++++++++ .../truenas_storagetracker/tests/__init__.py | 0 .../__pycache__/test_tracker.cpython-313.pyc | Bin 0 -> 3711 bytes .../tests/test_tracker.py | 71 ++++++++++++ 18 files changed, 449 insertions(+) rename check_db.py => ServerManagerWebApp/check_db.py (100%) rename comics_organizesteps.py => ServerManagerWebApp/comics_organizesteps.py (100%) rename fixed_comics_manager.py => ServerManagerWebApp/fixed_comics_manager.py (100%) create mode 100644 gemini_projects/mcp/.env create mode 100644 gemini_projects/mcp/README.md create mode 100644 gemini_projects/mcp/gemini_client.py create mode 100644 gemini_projects/mcp/requirements.txt create mode 100755 gemini_projects/mcp/setup.sh create mode 100644 gemini_projects/mcp/simple_server.py create mode 100644 gemini_projects/truenas_storagetracker/.env.template create mode 100644 gemini_projects/truenas_storagetracker/README.md create mode 100644 gemini_projects/truenas_storagetracker/requirements.txt create mode 100644 gemini_projects/truenas_storagetracker/src/__init__.py create mode 100644 gemini_projects/truenas_storagetracker/src/__pycache__/tracker.cpython-313.pyc create mode 100644 gemini_projects/truenas_storagetracker/src/tracker.py create mode 100644 gemini_projects/truenas_storagetracker/tests/__init__.py create mode 100644 gemini_projects/truenas_storagetracker/tests/__pycache__/test_tracker.cpython-313.pyc create mode 100644 gemini_projects/truenas_storagetracker/tests/test_tracker.py diff --git a/check_db.py b/ServerManagerWebApp/check_db.py similarity index 100% rename from check_db.py rename to ServerManagerWebApp/check_db.py diff --git a/comics_organizesteps.py b/ServerManagerWebApp/comics_organizesteps.py similarity index 100% rename from comics_organizesteps.py rename to ServerManagerWebApp/comics_organizesteps.py diff --git a/fixed_comics_manager.py b/ServerManagerWebApp/fixed_comics_manager.py similarity index 100% rename from fixed_comics_manager.py rename to ServerManagerWebApp/fixed_comics_manager.py diff --git a/gemini_projects/mcp/.env b/gemini_projects/mcp/.env new file mode 100644 index 0000000..a16f944 --- /dev/null +++ b/gemini_projects/mcp/.env @@ -0,0 +1 @@ +GOOGLE_API_KEY= diff --git a/gemini_projects/mcp/README.md b/gemini_projects/mcp/README.md new file mode 100644 index 0000000..c3d332b --- /dev/null +++ b/gemini_projects/mcp/README.md @@ -0,0 +1,47 @@ +# Gemini MCP Integration + +This directory contains a boilerplate setup for integrating Google Gemini with the Model Context Protocol (MCP). + +## Structure + +- **`simple_server.py`**: A simple MCP server using `FastMCP` that exposes two tools (`add_numbers`, `get_current_time`). +- **`gemini_client.py`**: A Python script that acts as an MCP client. It connects to `simple_server.py`, lists the available tools, and provides guidance on integrating them with the `google-genai` SDK. +- **`setup.sh`**: A provision script that sets up the Python virtual environment and installs dependencies. +- **`requirements.txt`**: List of Python dependencies. + +## Prerequisites + +- Python 3 +- Node.js & npm (for MCP Inspector) + +## Setup + +1. Run the setup script: + ```bash + ./setup.sh + ``` +2. Activate the virtual environment: + ```bash + source venv/bin/activate + ``` +3. Set your Google API Key in `.env`: + ```bash + # Edit .env file + GOOGLE_API_KEY=your_api_key_here + ``` + +## Running the Example + +Run the client script to see the connection to the server and the list of tools: + +```bash +python gemini_client.py +``` + +## Using MCP Inspector + +You can use the official MCP Inspector to interact with the `simple_server.py` visually. + +```bash +npx @modelcontextprotocol/inspector python simple_server.py +``` diff --git a/gemini_projects/mcp/gemini_client.py b/gemini_projects/mcp/gemini_client.py new file mode 100644 index 0000000..1ac42f6 --- /dev/null +++ b/gemini_projects/mcp/gemini_client.py @@ -0,0 +1,62 @@ +import asyncio +import os +import sys +from mcp import ClientSession, StdioServerParameters +from mcp.client.stdio import stdio_client +from google import genai +from dotenv import load_dotenv + +# Load environment variables +load_dotenv() + +async def main(): + print("Starting MCP Client...") + + # Check for API Key + api_key = os.getenv("GOOGLE_API_KEY") + if not api_key: + print("Warning: GOOGLE_API_KEY is not set in .env. Gemini calls will fail.") + else: + print("GOOGLE_API_KEY found.") + + # Define the server parameters + # We run the simple_server.py we created earlier + server_script = os.path.join(os.path.dirname(__file__), "simple_server.py") + + server_params = StdioServerParameters( + command=sys.executable, # Use the current python interpreter + args=[server_script], + env=None + ) + + print(f"Connecting to MCP server at: {server_script}") + + try: + async with stdio_client(server_params) as (read, write): + async with ClientSession(read, write) as session: + # Initialize the session + await session.initialize() + + # List available tools + result = await session.list_tools() + tools = result.tools + + print(f"\nSuccessfully connected! Found {len(tools)} tools:") + for tool in tools: + print(f" - {tool.name}: {tool.description}") + print(f" Schema: {tool.inputSchema}") + + print("\n--- Integration with Gemini (google-genai) ---") + print("To integrate these tools with Gemini using the new SDK, you would:") + print("1. Convert the MCP tool schemas to Gemini tool definitions.") + print("2. Initialize the Gemini client:") + print(" from google import genai") + print(" client = genai.Client(api_key=api_key)") + print("3. Pass the tools to the generate_content call.") + print("4. Handle the tool calls returned by the model.") + + except Exception as e: + print(f"Error connecting to MCP server: {e}") + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/gemini_projects/mcp/requirements.txt b/gemini_projects/mcp/requirements.txt new file mode 100644 index 0000000..a9cd9b3 --- /dev/null +++ b/gemini_projects/mcp/requirements.txt @@ -0,0 +1,3 @@ +mcp +google-genai +python-dotenv diff --git a/gemini_projects/mcp/setup.sh b/gemini_projects/mcp/setup.sh new file mode 100755 index 0000000..9d3c384 --- /dev/null +++ b/gemini_projects/mcp/setup.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +# Exit on error +set -e + +echo "Provisioning MCP environment..." + +# Check for Python 3 +if ! command -v python3 &> /dev/null; then + echo "Python 3 could not be found. Please install Python 3." + exit 1 +fi + +# Create Virtual Environment +if [ ! -d "venv" ]; then + echo "Creating virtual environment..." + python3 -m venv venv +else + echo "Virtual environment already exists." +fi + +# Activate venv +source venv/bin/activate + +# Upgrade pip +echo "Upgrading pip..." +pip install --upgrade pip + +# Install dependencies +if [ -f "requirements.txt" ]; then + echo "Installing dependencies from requirements.txt..." + pip install -r requirements.txt +else + echo "requirements.txt not found!" + exit 1 +fi + +# Create .env from template if it doesn't exist +if [ ! -f ".env" ]; then + echo "Creating .env file..." + touch .env + echo "GOOGLE_API_KEY=" >> .env + echo "Please add your GOOGLE_API_KEY to mcp/.env" +fi + +echo "Setup complete! To start working:" +echo "cd mcp" +echo "source venv/bin/activate" diff --git a/gemini_projects/mcp/simple_server.py b/gemini_projects/mcp/simple_server.py new file mode 100644 index 0000000..08f5bfa --- /dev/null +++ b/gemini_projects/mcp/simple_server.py @@ -0,0 +1,20 @@ +from mcp.server.fastmcp import FastMCP +import asyncio + +# Initialize FastMCP server +mcp = FastMCP("Simple Demo Server") + +@mcp.tool() +def add_numbers(a: int, b: int) -> int: + """Add two numbers together.""" + return a + b + +@mcp.tool() +def get_current_time() -> str: + """Get the current local time.""" + from datetime import datetime + return datetime.now().isoformat() + +if __name__ == "__main__": + # Run the server over stdio + mcp.run() diff --git a/gemini_projects/truenas_storagetracker/.env.template b/gemini_projects/truenas_storagetracker/.env.template new file mode 100644 index 0000000..dd84a09 --- /dev/null +++ b/gemini_projects/truenas_storagetracker/.env.template @@ -0,0 +1,2 @@ +TRUENAS_API_URL=http://your-truenas-ip/api/v2.0 +TRUENAS_API_KEY=your-api-key-here diff --git a/gemini_projects/truenas_storagetracker/README.md b/gemini_projects/truenas_storagetracker/README.md new file mode 100644 index 0000000..7017cb0 --- /dev/null +++ b/gemini_projects/truenas_storagetracker/README.md @@ -0,0 +1,83 @@ +# TrueNAS Scale Storage Tracker + +A CLI tool to list storage usage for each data pool in TrueNAS SCALE using the TrueNAS API. + +## Features + +- Lists all data pools with total size, used size, free size, and percentage used. +- Supports output in Text (default), JSON, and CSV formats. +- Configurable via `.env` file. +- Robust error handling. + +## Prerequisites + +- Python 3.x +- `requests` +- `python-dotenv` + +## Installation + +1. Clone the repository or navigate to the project directory. +2. Install dependencies: + ```bash + pip install -r requirements.txt + ``` + +## Configuration + +1. Copy the `.env.template` to `.env`: + ```bash + cp .env.template .env + ``` +2. Edit `.env` and provide your TrueNAS Scale credentials: + ```ini + TRUENAS_API_URL=http://your-truenas-ip/api/v2.0 + TRUENAS_API_KEY=your-api-key-here + ``` + + * **TRUENAS_API_URL**: The URL to your TrueNAS API (e.g., `http://192.168.1.100/api/v2.0`). + * **TRUENAS_API_KEY**: An API Key generated from the TrueNAS web interface (Settings -> API Keys). + +## Usage + +Run the tool from the command line: + +```bash +python3 src/tracker.py +``` + +### Options + +* `--format`: Specify the output format (`text`, `json`, `csv`). Default is `text`. + +### Examples + +**Default Text Output:** +```bash +python3 src/tracker.py +``` + +**JSON Output:** +```bash +python3 src/tracker.py --format json +``` + +**CSV Output:** +```bash +python3 src/tracker.py --format csv +``` + +## Testing + +Run the unit tests: + +```bash +python3 -m unittest discover tests +``` + +## Project Structure + +* `src/tracker.py`: Main application logic. +* `tests/test_tracker.py`: Unit tests. +* `.env.template`: Template for environment variables. +* `requirements.txt`: Python dependencies. diff --git a/gemini_projects/truenas_storagetracker/requirements.txt b/gemini_projects/truenas_storagetracker/requirements.txt new file mode 100644 index 0000000..3d7b914 --- /dev/null +++ b/gemini_projects/truenas_storagetracker/requirements.txt @@ -0,0 +1,3 @@ +requests +python-dotenv +argparse diff --git a/gemini_projects/truenas_storagetracker/src/__init__.py b/gemini_projects/truenas_storagetracker/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gemini_projects/truenas_storagetracker/src/__pycache__/tracker.cpython-313.pyc b/gemini_projects/truenas_storagetracker/src/__pycache__/tracker.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b0a0634a40e623d36caa833e067fd0b87ad63ff3 GIT binary patch literal 5118 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 0: + percent_used = (used_size / total_size) * 100 + else: + percent_used = 0.0 + + processed_data.append({ + "pool_name": name, + "total_size_bytes": total_size, + "used_size_bytes": used_size, + "free_size_bytes": free_size, + "percent_used": round(percent_used, 2) + }) + return processed_data + +def format_output(data, output_format): + if output_format == 'json': + print(json.dumps(data, indent=4)) + elif output_format == 'csv': + writer = csv.DictWriter(sys.stdout, fieldnames=["pool_name", "total_size_bytes", "used_size_bytes", "free_size_bytes", "percent_used"]) + writer.writeheader() + writer.writerows(data) + else: + # Default text/human-readable + print(f"{'Pool Name':<20} {'Total Size':<15} {'Used Size':<15} {'Free Size':<15} {'% Used':<10}") + print("-" * 75) + for item in data: + print(f"{item['pool_name']:<20} {item['total_size_bytes']:<15} {item['used_size_bytes']:<15} {item['free_size_bytes']:<15} {item['percent_used']:<10}%") + +def main(): + parser = argparse.ArgumentParser(description="TrueNAS Scale Storage Tracker") + parser.add_argument("--format", choices=['json', 'csv', 'text'], default='text', help="Output format (json, csv, text)") + args = parser.parse_args() + + try: + raw_data = fetch_pool_data() + processed_data = process_pool_data(raw_data) + format_output(processed_data, args.format) + except ValueError as e: + print(f"Configuration Error: {e}", file=sys.stderr) + sys.exit(1) + except Exception as e: + print(f"An unexpected error occurred: {e}", file=sys.stderr) + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/gemini_projects/truenas_storagetracker/tests/__init__.py b/gemini_projects/truenas_storagetracker/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gemini_projects/truenas_storagetracker/tests/__pycache__/test_tracker.cpython-313.pyc b/gemini_projects/truenas_storagetracker/tests/__pycache__/test_tracker.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3dcd4da357afb074a42d0d47ae9ed8c7912920a7 GIT binary patch literal 3711 zcmbVP&2JmW6`%bgmtUe3$%&*`A}!gBs92<}LT>HIg49GsVpnRwH5(feuvn8rYAtG) znOzF7PD+8+Dtc*v2CiK~Fy9k1#E|WXAy-An3tB5J-`M06F!|eu$JJH%901 z_RY-i&Ca~}z4vzaVzDrSHd4B#|3^mX8`kk#&{OtKa|nHa6r^yM5n)gMGIxn5{3U@1 zNq1Z%qBAcMX<5ug{UzGZT)eIO+Ol*cvd5oqKc9i@Z6kbbIXnfsWla$jaY}G?f6Uu$ zghcw$2vVd$qy&~xuHQvm)ig%uiF(8_vY!7Qw9@RENC_^Qn5rZ{xNjjH0_D1X;wU=zfFCIJQXjz=BwG2 zf1uAe+O-CbRvB6?YPOcv}Q!hFPesVZ*kv>sG-m;%pTY z%QQ5w#Ot_XR@r2>jMsESSF6OlfeV1O!B>W6sg~<3+jUmf1~s;>OZv`l44yuU1;EBtN&zcXbhw~6ptmsTjC@6 zto%MkJ? z=hKzF*K2tp$Eb0rRrZkz0)&%m4no?9tCMYgX+MMHx(?!5uN`lO2)j8VUtFC%YL8RA zyH*nA`P>n?!#^WLF-r4`2YAmM!AuVDKEvlaW5Zn?<&htmCsA5l+=#E(cJ)Fw%UC&4 zBb5!=(N^(IND%QWx%@oDojUjSTWUV{+k*p_=dS^K1-MA|01KDHqz_(2<>`vHcD<<0 z&^MpWEr*RI3`wXR5UN!x6tHDwrdgC#tQk<;l}^CA))0tI)JmLbCDOZ+kPZJ3K#{IL zk8TzIGPV;Gvc2RbKtSGzSb7nwxKx6mAnc|Iq)0@?8xTP>O0ZochPtj*YM6EtO}DUG zG6@8YX4fnl^oU90hjvFJnq^^P&%ayKD)a@nqryHbxTu;&0jDLxZh}UfFbCfNsj1^r z6*@HL3=?csO~ZnW!cu@GfkBcr*LBDLms{w$|IeMwZG|ab$PHMztTE)f%Q^#In|JV(MnD<b)=KXJh4#TC8-^p`6;T5hU#*VbgL&0F%Qv^qf&yANHeBin9K?g5C2R_uX zpYU_z-Ss1FJmie%;uGdz!UPRD1&CEO!tx&NwoM!A3M+8x^_xII!ip=6Ld7XSkx^?F zE|y^g+FP?vnDa?D2yf{8EYSWW^l1;2Ar`&ucy_{$q}ZfT!A6>Q<0Iq&anWKM^11(_ z!~LHuLeKmR>wjXwik0;_h)wiW-^asy=Z3{!Bx@bZF+TQ6HH4!fwdZ z&sgnpL!Ld_=8-(@hD&E4?0?hz9S*}jbURBRkbl1j!nD_xSh{nXPkkOG(b9ei%)!U> z;npr&&SxmRr;|J<&}lU0nH1snOMDU~U`980Pe4ga3y z*m*)s;!uQ~0*uE3!qz-+|HqvBU(+p1H_9sHPDs(jqS>Fh{=){dY~3>;HqqCkudrN~ zY{hz-vEh1b_~VU7vGK2>z0K(8!{}%udg=!Ob-mh*jsG(?{-ee6#wRaM3txuk!a>5S z_aYP%SyfrAs45Ms>Y7=sRhS-CRaOSPnYgN!bYj^R-N1&as^l0L6Lvl1G!wsMVj2WJ zraE;-FQ}Sr6a9J(4y~%6A?Na)8bDY|a|8=RYZ1hs(D!1O6y8muK;%K>#I`i@FDd*W zGQ2G%cKIGDwI`rJl8MnB5xU=}qSD3P;||!x2tI}f&3zSn3p?AIrW>l7?xu3h&~0`F zH0Em=Rmul$F>_k$ls-;dtTefrLwcRp3`sQ0dJ51qR&-pAYBZ#2;SH>m5Wc%Dn$m7B@4 l_2k*72s%6K91^2j8{5J_ON`!H_`|{