gym-mcp-client


Namegym-mcp-client JSON
Version 0.1.0 PyPI version JSON
download
home_pageNone
SummaryA unified interface for local and remote Gymnasium environments via gym-mcp-server
upload_time2025-11-01 13:54:49
maintainerNone
docs_urlNone
authorHaggai Shachar
requires_python>=3.12
licenseMIT
keywords agent environment gym gymnasium mcp reinforcement-learning
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Gym MCP Client

A unified Python interface for working with both local and remote Gymnasium environments via [gym-mcp-server](https://github.com/haggaishachar/gym-mcp-server).

**Goal**: Write code once, seamlessly switch between local development and remote execution.

## Features

- 🎮 **Unified API**: Same Gymnasium interface for both local and remote environments
- 🔄 **Seamless Switching**: Change modes with a single parameter
- 🌐 **Remote Execution**: Connect to gym-mcp-server instances over HTTP
- 🔧 **Full Compatibility**: Supports all Gymnasium environment types (Box, Discrete, MultiBinary, etc.)
- 🐍 **Modern Python**: Python 3.12+ with complete type hints
- 📦 **Easy Setup**: Managed with uv for fast dependency management
- ✅ **Well Tested**: 14 comprehensive tests, all passing

## Installation

```bash
# Clone the repository
git clone <your-repo-url>
cd gym-mcp-client

# Install with uv (recommended)
uv sync

# Or with pip
pip install -e .
```

## Quick Start

### Local Mode

```python
from gym_mcp_client import GymMCPClient

# Create a local environment
env = GymMCPClient("CartPole-v1", mode="local")

# Use standard Gymnasium API
observation, info = env.reset(seed=42)
action = env.action_space.sample()
observation, reward, terminated, truncated, info = env.step(action)

env.close()
```

### Remote Mode

First, start a gym-mcp-server:

```bash
python -m gym_mcp_server --env CartPole-v1 --transport streamable-http --port 8000
```

Then connect to it:

```python
from gym_mcp_client import GymMCPClient

# Create a remote environment
env = GymMCPClient(
    "CartPole-v1",
    mode="remote",
    gym_server_url="http://localhost:8000"
)

# Use the exact same API as local mode!
observation, info = env.reset(seed=42)
action = env.action_space.sample()
observation, reward, terminated, truncated, info = env.step(action)

env.close()
```

### Context Manager

```python
from gym_mcp_client import GymMCPClient

# Automatic cleanup
with GymMCPClient("CartPole-v1", mode="local") as env:
    observation, info = env.reset()
    action = env.action_space.sample()
    observation, reward, terminated, truncated, info = env.step(action)
    # env.close() called automatically
```

## Switching Between Modes

The main benefit: write once, run anywhere!

```python
import os
from gym_mcp_client import GymMCPClient

# Configuration from environment variables
MODE = os.getenv("GYM_MODE", "local")
SERVER_URL = os.getenv("GYM_SERVER_URL", "http://localhost:8000")

# Create environment based on mode
if MODE == "local":
    env = GymMCPClient("CartPole-v1", mode="local")
else:
    env = GymMCPClient(
        "CartPole-v1",
        mode="remote",
        gym_server_url=SERVER_URL,
        gym_server_key=os.getenv("GYM_API_KEY")
    )

# Your code works the same regardless of mode!
observation, info = env.reset()
for _ in range(1000):
    action = env.action_space.sample()
    observation, reward, terminated, truncated, info = env.step(action)
    if terminated or truncated:
        observation, info = env.reset()

env.close()
```

Switch modes via command line:

```bash
# Run locally
export GYM_MODE=local
python your_training_script.py

# Run remotely
export GYM_MODE=remote
export GYM_SERVER_URL=http://gpu-server:8000
python your_training_script.py
```

## API Reference

### `GymMCPClient`

```python
GymMCPClient(
    env_id: str,
    mode: str = "local",
    render_mode: str | None = None,
    gym_server_url: str | None = None,
    gym_server_key: str | None = None,
    **kwargs
)
```

**Parameters:**
- `env_id`: Gymnasium environment ID (e.g., "CartPole-v1")
- `mode`: Either "local" or "remote"
- `render_mode`: Render mode ("rgb_array", "human", etc.)
- `gym_server_url`: URL of gym-mcp-server (required for remote mode)
- `gym_server_key`: Optional API key for authentication
- `**kwargs`: Additional arguments passed to `gym.make()` in local mode

**Methods:**
- `reset(seed=None, options=None)` → (observation, info)
- `step(action)` → (observation, reward, terminated, truncated, info)
- `render()` → render_output
- `close()` → None

**Properties:**
- `observation_space`: The observation space
- `action_space`: The action space
- `reward_range`: The reward range
- `metadata`: Environment metadata

## Architecture

```
┌─────────────────┐
│  Your Code      │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ GymMCPClient    │
└────────┬────────┘
         │
    ┌────┴────┐
    ▼         ▼
┌────────┐ ┌──────────────┐
│ Local  │ │ Remote       │
│ Gym    │ │ HTTP Client  │
└────────┘ └──────┬───────┘
              │
              ▼
         ┌──────────────┐
         │ gym-mcp-     │
         │ server       │
         └──────┬───────┘
                │
                ▼
           ┌────────┐
           │ Gym    │
           │ Env    │
           └────────┘
```

### Supported Space Types

| Space Type | Local | Remote | Serialization |
|------------|-------|--------|---------------|
| Box | ✅ | ✅ | array ↔ list |
| Discrete | ✅ | ✅ | int ↔ int |
| MultiBinary | ✅ | ✅ | array ↔ list |
| MultiDiscrete | ✅ | ✅ | array ↔ list |
| Tuple | ✅ | ✅ | recursive |
| Dict | ✅ | ✅ | recursive |

## Examples

See the `examples/` directory:
- `local_example.py`: Local mode usage
- `remote_example.py`: Remote mode usage
- `context_manager_example.py`: Context manager pattern

Run examples:

```bash
# Local mode
uv run python examples/local_example.py

# Remote mode (start server first!)
python -m gym_mcp_server --env CartPole-v1 --transport streamable-http --port 8000
uv run python examples/remote_example.py

# Demo CLI tool
python main.py --mode local --episodes 3
```

## Development

### Setup

```bash
git clone <your-repo-url>
cd gym-mcp-client
make install
```

### Available Commands

```bash
make help       # Show all commands
make test       # Run test suite (14 tests)
make lint       # Run ruff linter
make format     # Format code with ruff
make typecheck  # Run mypy type checker
make check      # Run all checks (lint + typecheck + test)
make all        # Format, then run all checks
make demo       # Run local demo
make clean      # Clean build artifacts
```

### Running Tests

```bash
make test
# Or: uv run pytest tests/ -v
# 14 tests, all passing ✅
```

## Use Cases

1. **Development → Production**: Develop locally, deploy remotely
2. **Distributed Training**: Multiple processes connecting to remote environments
3. **Resource Management**: Run expensive simulations on dedicated servers
4. **Testing**: Test locally before remote deployment

## Performance

### Local Mode
- **Overhead**: Minimal (thin wrapper)
- **Best for**: Development, testing, lightweight environments

### Remote Mode
- **Overhead**: HTTP round-trip (1-10ms on localhost)
- **Best for**: Expensive environments, distributed training, resource sharing

## Error Handling

```python
from gym_mcp_client import GymMCPClient
import httpx

try:
    env = GymMCPClient(
        "CartPole-v1",
        mode="remote",
        gym_server_url="http://localhost:8000"
    )
    observation, info = env.reset()
    # ... your code ...
except ValueError:
    # Invalid mode, missing URL, etc.
    pass
except RuntimeError:
    # Environment initialization failed, remote call failed
    pass
except httpx.HTTPError:
    # Network error (remote mode only)
    pass
finally:
    if 'env' in locals():
        env.close()
```

## Troubleshooting

### Remote Connection Issues

1. Ensure the gym-mcp-server is running and accessible
2. Check URL is correct (including protocol: `http://` or `https://`)
3. Verify firewall/network settings
4. Check server logs for errors

### Environment Not Found

```bash
# For Atari environments
uv add "gymnasium[atari]"

# For Box2D environments
uv add "gymnasium[box2d]"

# For MuJoCo environments
uv add "gymnasium[mujoco]"
```

## Requirements

- Python 3.12+
- gymnasium >= 1.2.1
- httpx >= 0.28.1
- numpy >= 2.0.0
- gym-mcp-server (from GitHub)

## Contributing

Contributions are welcome! Please:

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Run `make check` to verify all tests pass
5. Submit a Pull Request

See `CONTRIBUTING.md` for detailed guidelines.

## License

MIT License - see LICENSE file for details.

## Related Projects

- [gym-mcp-server](https://github.com/haggaishachar/gym-mcp-server) - MCP server for Gymnasium environments
- [Gymnasium](https://gymnasium.farama.org/) - RL environment standard
- [Model Context Protocol](https://modelcontextprotocol.io/) - Tool integration protocol

## Support

- **Issues**: Open a GitHub issue
- **Questions**: Start a GitHub discussion
- **Documentation**: See examples/ directory

---

**Status**: ✅ Production Ready | **Version**: 0.1.0 | **Python**: 3.12+

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "gym-mcp-client",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.12",
    "maintainer_email": null,
    "keywords": "agent, environment, gym, gymnasium, mcp, reinforcement-learning",
    "author": "Haggai Shachar",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/a8/2e/3b366894d7a082f36f31828c0992ae2a5087b25cb20f8d4afe6aff5bb76c/gym_mcp_client-0.1.0.tar.gz",
    "platform": null,
    "description": "# Gym MCP Client\n\nA unified Python interface for working with both local and remote Gymnasium environments via [gym-mcp-server](https://github.com/haggaishachar/gym-mcp-server).\n\n**Goal**: Write code once, seamlessly switch between local development and remote execution.\n\n## Features\n\n- \ud83c\udfae **Unified API**: Same Gymnasium interface for both local and remote environments\n- \ud83d\udd04 **Seamless Switching**: Change modes with a single parameter\n- \ud83c\udf10 **Remote Execution**: Connect to gym-mcp-server instances over HTTP\n- \ud83d\udd27 **Full Compatibility**: Supports all Gymnasium environment types (Box, Discrete, MultiBinary, etc.)\n- \ud83d\udc0d **Modern Python**: Python 3.12+ with complete type hints\n- \ud83d\udce6 **Easy Setup**: Managed with uv for fast dependency management\n- \u2705 **Well Tested**: 14 comprehensive tests, all passing\n\n## Installation\n\n```bash\n# Clone the repository\ngit clone <your-repo-url>\ncd gym-mcp-client\n\n# Install with uv (recommended)\nuv sync\n\n# Or with pip\npip install -e .\n```\n\n## Quick Start\n\n### Local Mode\n\n```python\nfrom gym_mcp_client import GymMCPClient\n\n# Create a local environment\nenv = GymMCPClient(\"CartPole-v1\", mode=\"local\")\n\n# Use standard Gymnasium API\nobservation, info = env.reset(seed=42)\naction = env.action_space.sample()\nobservation, reward, terminated, truncated, info = env.step(action)\n\nenv.close()\n```\n\n### Remote Mode\n\nFirst, start a gym-mcp-server:\n\n```bash\npython -m gym_mcp_server --env CartPole-v1 --transport streamable-http --port 8000\n```\n\nThen connect to it:\n\n```python\nfrom gym_mcp_client import GymMCPClient\n\n# Create a remote environment\nenv = GymMCPClient(\n    \"CartPole-v1\",\n    mode=\"remote\",\n    gym_server_url=\"http://localhost:8000\"\n)\n\n# Use the exact same API as local mode!\nobservation, info = env.reset(seed=42)\naction = env.action_space.sample()\nobservation, reward, terminated, truncated, info = env.step(action)\n\nenv.close()\n```\n\n### Context Manager\n\n```python\nfrom gym_mcp_client import GymMCPClient\n\n# Automatic cleanup\nwith GymMCPClient(\"CartPole-v1\", mode=\"local\") as env:\n    observation, info = env.reset()\n    action = env.action_space.sample()\n    observation, reward, terminated, truncated, info = env.step(action)\n    # env.close() called automatically\n```\n\n## Switching Between Modes\n\nThe main benefit: write once, run anywhere!\n\n```python\nimport os\nfrom gym_mcp_client import GymMCPClient\n\n# Configuration from environment variables\nMODE = os.getenv(\"GYM_MODE\", \"local\")\nSERVER_URL = os.getenv(\"GYM_SERVER_URL\", \"http://localhost:8000\")\n\n# Create environment based on mode\nif MODE == \"local\":\n    env = GymMCPClient(\"CartPole-v1\", mode=\"local\")\nelse:\n    env = GymMCPClient(\n        \"CartPole-v1\",\n        mode=\"remote\",\n        gym_server_url=SERVER_URL,\n        gym_server_key=os.getenv(\"GYM_API_KEY\")\n    )\n\n# Your code works the same regardless of mode!\nobservation, info = env.reset()\nfor _ in range(1000):\n    action = env.action_space.sample()\n    observation, reward, terminated, truncated, info = env.step(action)\n    if terminated or truncated:\n        observation, info = env.reset()\n\nenv.close()\n```\n\nSwitch modes via command line:\n\n```bash\n# Run locally\nexport GYM_MODE=local\npython your_training_script.py\n\n# Run remotely\nexport GYM_MODE=remote\nexport GYM_SERVER_URL=http://gpu-server:8000\npython your_training_script.py\n```\n\n## API Reference\n\n### `GymMCPClient`\n\n```python\nGymMCPClient(\n    env_id: str,\n    mode: str = \"local\",\n    render_mode: str | None = None,\n    gym_server_url: str | None = None,\n    gym_server_key: str | None = None,\n    **kwargs\n)\n```\n\n**Parameters:**\n- `env_id`: Gymnasium environment ID (e.g., \"CartPole-v1\")\n- `mode`: Either \"local\" or \"remote\"\n- `render_mode`: Render mode (\"rgb_array\", \"human\", etc.)\n- `gym_server_url`: URL of gym-mcp-server (required for remote mode)\n- `gym_server_key`: Optional API key for authentication\n- `**kwargs`: Additional arguments passed to `gym.make()` in local mode\n\n**Methods:**\n- `reset(seed=None, options=None)` \u2192 (observation, info)\n- `step(action)` \u2192 (observation, reward, terminated, truncated, info)\n- `render()` \u2192 render_output\n- `close()` \u2192 None\n\n**Properties:**\n- `observation_space`: The observation space\n- `action_space`: The action space\n- `reward_range`: The reward range\n- `metadata`: Environment metadata\n\n## Architecture\n\n```\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  Your Code      \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n         \u2502\n         \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 GymMCPClient    \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n         \u2502\n    \u250c\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2510\n    \u25bc         \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Local  \u2502 \u2502 Remote       \u2502\n\u2502 Gym    \u2502 \u2502 HTTP Client  \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n              \u2502\n              \u25bc\n         \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n         \u2502 gym-mcp-     \u2502\n         \u2502 server       \u2502\n         \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                \u2502\n                \u25bc\n           \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n           \u2502 Gym    \u2502\n           \u2502 Env    \u2502\n           \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n```\n\n### Supported Space Types\n\n| Space Type | Local | Remote | Serialization |\n|------------|-------|--------|---------------|\n| Box | \u2705 | \u2705 | array \u2194 list |\n| Discrete | \u2705 | \u2705 | int \u2194 int |\n| MultiBinary | \u2705 | \u2705 | array \u2194 list |\n| MultiDiscrete | \u2705 | \u2705 | array \u2194 list |\n| Tuple | \u2705 | \u2705 | recursive |\n| Dict | \u2705 | \u2705 | recursive |\n\n## Examples\n\nSee the `examples/` directory:\n- `local_example.py`: Local mode usage\n- `remote_example.py`: Remote mode usage\n- `context_manager_example.py`: Context manager pattern\n\nRun examples:\n\n```bash\n# Local mode\nuv run python examples/local_example.py\n\n# Remote mode (start server first!)\npython -m gym_mcp_server --env CartPole-v1 --transport streamable-http --port 8000\nuv run python examples/remote_example.py\n\n# Demo CLI tool\npython main.py --mode local --episodes 3\n```\n\n## Development\n\n### Setup\n\n```bash\ngit clone <your-repo-url>\ncd gym-mcp-client\nmake install\n```\n\n### Available Commands\n\n```bash\nmake help       # Show all commands\nmake test       # Run test suite (14 tests)\nmake lint       # Run ruff linter\nmake format     # Format code with ruff\nmake typecheck  # Run mypy type checker\nmake check      # Run all checks (lint + typecheck + test)\nmake all        # Format, then run all checks\nmake demo       # Run local demo\nmake clean      # Clean build artifacts\n```\n\n### Running Tests\n\n```bash\nmake test\n# Or: uv run pytest tests/ -v\n# 14 tests, all passing \u2705\n```\n\n## Use Cases\n\n1. **Development \u2192 Production**: Develop locally, deploy remotely\n2. **Distributed Training**: Multiple processes connecting to remote environments\n3. **Resource Management**: Run expensive simulations on dedicated servers\n4. **Testing**: Test locally before remote deployment\n\n## Performance\n\n### Local Mode\n- **Overhead**: Minimal (thin wrapper)\n- **Best for**: Development, testing, lightweight environments\n\n### Remote Mode\n- **Overhead**: HTTP round-trip (1-10ms on localhost)\n- **Best for**: Expensive environments, distributed training, resource sharing\n\n## Error Handling\n\n```python\nfrom gym_mcp_client import GymMCPClient\nimport httpx\n\ntry:\n    env = GymMCPClient(\n        \"CartPole-v1\",\n        mode=\"remote\",\n        gym_server_url=\"http://localhost:8000\"\n    )\n    observation, info = env.reset()\n    # ... your code ...\nexcept ValueError:\n    # Invalid mode, missing URL, etc.\n    pass\nexcept RuntimeError:\n    # Environment initialization failed, remote call failed\n    pass\nexcept httpx.HTTPError:\n    # Network error (remote mode only)\n    pass\nfinally:\n    if 'env' in locals():\n        env.close()\n```\n\n## Troubleshooting\n\n### Remote Connection Issues\n\n1. Ensure the gym-mcp-server is running and accessible\n2. Check URL is correct (including protocol: `http://` or `https://`)\n3. Verify firewall/network settings\n4. Check server logs for errors\n\n### Environment Not Found\n\n```bash\n# For Atari environments\nuv add \"gymnasium[atari]\"\n\n# For Box2D environments\nuv add \"gymnasium[box2d]\"\n\n# For MuJoCo environments\nuv add \"gymnasium[mujoco]\"\n```\n\n## Requirements\n\n- Python 3.12+\n- gymnasium >= 1.2.1\n- httpx >= 0.28.1\n- numpy >= 2.0.0\n- gym-mcp-server (from GitHub)\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch\n3. Make your changes\n4. Run `make check` to verify all tests pass\n5. Submit a Pull Request\n\nSee `CONTRIBUTING.md` for detailed guidelines.\n\n## License\n\nMIT License - see LICENSE file for details.\n\n## Related Projects\n\n- [gym-mcp-server](https://github.com/haggaishachar/gym-mcp-server) - MCP server for Gymnasium environments\n- [Gymnasium](https://gymnasium.farama.org/) - RL environment standard\n- [Model Context Protocol](https://modelcontextprotocol.io/) - Tool integration protocol\n\n## Support\n\n- **Issues**: Open a GitHub issue\n- **Questions**: Start a GitHub discussion\n- **Documentation**: See examples/ directory\n\n---\n\n**Status**: \u2705 Production Ready | **Version**: 0.1.0 | **Python**: 3.12+\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A unified interface for local and remote Gymnasium environments via gym-mcp-server",
    "version": "0.1.0",
    "project_urls": {
        "Author LinkedIn": "https://www.linkedin.com/in/haggaishachar/",
        "Documentation": "https://agentring.ai",
        "Homepage": "https://agentring.ai",
        "Issues": "https://github.com/Agent-Ring/gym-mcp-client/issues",
        "Repository": "https://github.com/Agent-Ring/gym-mcp-client"
    },
    "split_keywords": [
        "agent",
        " environment",
        " gym",
        " gymnasium",
        " mcp",
        " reinforcement-learning"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "45ae0fdecda9f88359cd8ecd60c71549116e30a063102a04fc50d7b3460a3995",
                "md5": "c772dd79455e654a415bd05179b12651",
                "sha256": "2c1fb0e89af4aa05b74f1c6e800db1084459e54aadc9dbff13bf69d0e361453b"
            },
            "downloads": -1,
            "filename": "gym_mcp_client-0.1.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "c772dd79455e654a415bd05179b12651",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.12",
            "size": 9620,
            "upload_time": "2025-11-01T13:54:48",
            "upload_time_iso_8601": "2025-11-01T13:54:48.072548Z",
            "url": "https://files.pythonhosted.org/packages/45/ae/0fdecda9f88359cd8ecd60c71549116e30a063102a04fc50d7b3460a3995/gym_mcp_client-0.1.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "a82e3b366894d7a082f36f31828c0992ae2a5087b25cb20f8d4afe6aff5bb76c",
                "md5": "b4c43d25b1cd05484e6cf02bafcdcde6",
                "sha256": "f432bafcd227da9f627f66d8e8cc6bd14f8fe3b8df451e600f52cb0d3791f17c"
            },
            "downloads": -1,
            "filename": "gym_mcp_client-0.1.0.tar.gz",
            "has_sig": false,
            "md5_digest": "b4c43d25b1cd05484e6cf02bafcdcde6",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.12",
            "size": 12069,
            "upload_time": "2025-11-01T13:54:49",
            "upload_time_iso_8601": "2025-11-01T13:54:49.607127Z",
            "url": "https://files.pythonhosted.org/packages/a8/2e/3b366894d7a082f36f31828c0992ae2a5087b25cb20f8d4afe6aff5bb76c/gym_mcp_client-0.1.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-11-01 13:54:49",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "Agent-Ring",
    "github_project": "gym-mcp-client",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "gym-mcp-client"
}
        
Elapsed time: 2.00446s