Metadata-Version: 2.4
Name: gopher-mcp-python
Version: 0.1.40.2
Summary: Python SDK for Gopher MCP - AI Agent orchestration framework with native performance
Author-email: Gopher Security <dev@gophersecurity.com>
License: Apache-2.0
Project-URL: Homepage, https://github.com/GopherSecurity/gopher-mcp-python
Project-URL: Repository, https://github.com/GopherSecurity/gopher-mcp-python.git
Project-URL: Issues, https://github.com/GopherSecurity/gopher-mcp-python/issues
Keywords: gopher,mcp,ai,agent,orchestration,llm,ffi
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
Requires-Dist: mypy>=1.0.0; extra == "dev"
Requires-Dist: black>=24.0.0; extra == "dev"
Requires-Dist: ruff>=0.3.0; extra == "dev"
Provides-Extra: darwin-arm64
Requires-Dist: gopher-mcp-python-native-darwin-arm64>=0.1.0; extra == "darwin-arm64"
Provides-Extra: darwin-x64
Requires-Dist: gopher-mcp-python-native-darwin-x64>=0.1.0; extra == "darwin-x64"
Provides-Extra: linux-arm64
Requires-Dist: gopher-mcp-python-native-linux-arm64>=0.1.0; extra == "linux-arm64"
Provides-Extra: linux-x64
Requires-Dist: gopher-mcp-python-native-linux-x64>=0.1.0; extra == "linux-x64"
Provides-Extra: win32-arm64
Requires-Dist: gopher-mcp-python-native-win32-arm64>=0.1.0; extra == "win32-arm64"
Provides-Extra: win32-x64
Requires-Dist: gopher-mcp-python-native-win32-x64>=0.1.0; extra == "win32-x64"
Dynamic: license-file

# gopher-mcp-python Python SDK

Python SDK for gopher-mcp-python, providing AI agent orchestration with native C++ performance through ctypes FFI bindings.

## Features

- Python 3.8+ compatibility
- pip/setuptools build system
- ctypes FFI bindings to native library
- GopherAgent class with builder pattern configuration
- Context manager support for automatic resource cleanup
- Typed errors (AgentError, ApiKeyError, ConnectionError, TimeoutError)
- Comprehensive test suite with pytest

## Requirements

- Python 3.8 or higher
- `venv` and `pip` for PyPI installation, examples, and development workflows
- Native gopher-mcp-python library (built from source)
- On Linux, system OpenSSL runtime libraries (`libssl` / `libcrypto`) from
  your distribution. Native wheels do not bundle OpenSSL, so OS security
  updates remain effective.

On Debian/Ubuntu, install the Python venv and pip packages before using the
PyPI install path, running examples, or setting up development dependencies:

```bash
sudo apt-get install python3 python3-venv python3-pip
```

## Installation

### From Source

1. Clone the repository:
```bash
git clone https://github.com/GopherSecurity/gopher-mcp-python.git
cd gopher-mcp-python
```

2. Build the native library:
```bash
./build.sh
```

3. Install the Python package:
```bash
python3 -m pip install -e .
```

## Quick Start

### Using API Key

```python
from gopher_mcp_python import GopherAgent, GopherAgentConfig

# Create configuration with API key
config = (GopherAgentConfig.builder()
    .provider("AnthropicProvider")
    .model("claude-3-haiku-20240307")
    .api_key("your-api-key")
    .build())

# Create and use agent with context manager
with GopherAgent.create(config) as agent:
    response = agent.run("What time is it in Tokyo?")
    print(response)
```

### Using JSON Server Configuration

```python
from gopher_mcp_python import GopherAgent, GopherAgentConfig

# Create configuration with server config
config = (GopherAgentConfig.builder()
    .provider("AnthropicProvider")
    .model("claude-3-haiku-20240307")
    .server_config('{"mcpServers": [...]}')
    .build())

# Create agent
agent = GopherAgent.create(config)
try:
    response = agent.run("What is the weather?")
    print(response)
finally:
    agent.dispose()
```

### Using Convenience Methods

```python
from gopher_mcp_python import GopherAgent

# Create with API key (shorthand)
agent = GopherAgent.create_with_api_key(
    provider="AnthropicProvider",
    model="claude-3-haiku-20240307",
    api_key="your-api-key"
)

# Or with server config
agent = GopherAgent.create_with_server_config(
    provider="AnthropicProvider",
    model="claude-3-haiku-20240307",
    server_config='{"mcpServers": [...]}'
)
```

### Getting Detailed Results

```python
from gopher_mcp_python import GopherAgent

with GopherAgent.create(config) as agent:
    result = agent.run_detailed("What time is it?")

    if result.is_success():
        print(f"Response: {result.response}")
        print(f"Iterations: {result.iteration_count}")
        print(f"Tokens used: {result.tokens_used}")
    elif result.is_timeout():
        print(f"Request timed out: {result.error_message}")
    else:
        print(f"Error: {result.error_message}")
```

## API Reference

### GopherAgent

Main class for interacting with the gopher-mcp-python native library.

#### Static Methods

- `GopherAgent.init()` - Initialize the library (called automatically)
- `GopherAgent.shutdown()` - Shutdown the library
- `GopherAgent.is_initialized()` - Check if library is initialized
- `GopherAgent.create(config)` - Create an agent with configuration
- `GopherAgent.create_with_api_key(provider, model, api_key)` - Convenience method
- `GopherAgent.create_with_server_config(provider, model, server_config)` - Convenience method

#### Instance Methods

- `agent.run(query, timeout_ms=60000)` - Run a query and get response string
- `agent.run_detailed(query, timeout_ms=60000)` - Run a query and get AgentResult
- `agent.dispose()` - Release resources
- `agent.is_disposed()` - Check if agent is disposed

### GopherAgentConfig

Configuration class with builder pattern.

```python
config = (GopherAgentConfig.builder()
    .provider("AnthropicProvider")  # Required
    .model("claude-3-haiku-20240307")  # Required
    .api_key("key")  # Either api_key or server_config required
    .server_config("{...}")  # Either api_key or server_config required
    .build())
```

### AgentResult

Result class with status and metadata.

- `result.response` - Response text
- `result.status` - AgentResultStatus enum
- `result.iteration_count` - Number of iterations
- `result.tokens_used` - Tokens consumed
- `result.error_message` - Error message (if applicable)
- `result.is_success()` - Check if successful
- `result.is_error()` - Check if error
- `result.is_timeout()` - Check if timeout

### Provider OAuth Elicitation

Provider OAuth requested during a tool call is handled automatically by default.
For URL-mode elicitation, the SDK opens the authorization URL when possible,
prints it as a fallback, waits for the user to finish the browser flow, and then
lets the native agent retry the tool call.

No example-level elicitation configuration is required:

```python
agent = GopherAgent.create_with_url(provider, model, mcp_url)
```

Use `GopherAgentCreateOptions` only when you need a custom synchronous handler
or want to disable browser opening while still printing the URL:

```python
from gopher_mcp_python import GopherAgentCreateOptions

agent = GopherAgent.create_with_url(
    provider,
    model,
    mcp_url,
    GopherAgentCreateOptions(
        elicitation={
            "open_browser": False,
            "handler": lambda request: "accept",
        },
    ),
)
```

First-step MCP server OAuth is controlled separately by the `oauth` create
option. Setting `oauth={"mode": "disabled"}` skips SDK OAuth discovery for the
MCP endpoint but still leaves provider elicitation enabled.

### Exceptions

- `AgentError` - Base exception for agent errors
- `ApiKeyError` - Invalid API key
- `ConnectionError` - Connection failed
- `TimeoutError` - Operation timed out

## Development

### Running Tests

```bash
pytest
```

For deterministic OAuth auto verification with a local custom IdP and local MCP
server/gateway endpoints, see
[`docs/oauth-auto-custom-idp.md`](docs/oauth-auto-custom-idp.md).

### Code Formatting

This project uses Black for code formatting and Ruff for linting.

Format code:
```bash
black .
```

Check formatting without modifying:
```bash
black --check .
```

Run linter:
```bash
ruff check .
```

Fix linting issues:
```bash
ruff check --fix .
```

### Building the Native Library

```bash
./build.sh
```

### Clean Build

```bash
./build.sh --clean
```

## OAuth scope selection

Automatic OAuth uses the challenge's `scope` when present, otherwise explicit
`oauth.scopes`, then the protected resource's `scopes_supported`. If none are
available, the request omits `scope`. The authorization server's realm-wide scope
list is never used as a default. An explicit empty list means omit `scope`.

Web applications managing their own redirects can reuse the same policy:

```python
from gopher_mcp_python import select_oauth_scopes

scopes = select_oauth_scopes(
    challenge_scopes=challenge_scopes,  # None if absent; [] if explicitly empty
    resource_scopes=resource_scopes,
)
```

Use this result for both client registration and the authorization request,
omitting the scope field when the result is empty. This helper performs no
network requests or browser operations.

Automatic OAuth preserves the protected-resource metadata's `resource` identifier
through authorization, code exchange, and token refresh. It can differ from the
MCP connection URL. Applications using `exchange_oauth_code_for_token` or
`refresh_oauth_token` directly can pass it with the `resource` keyword argument.

Applications with a guarded or asynchronous HTTP client can prepare the same
code-exchange request without letting the SDK send it:

```python
from gopher_mcp_python.oauth_token_exchange import build_oauth_code_exchange_request

request = build_oauth_code_exchange_request(
    code=code,
    redirect_uri=redirect_uri,
    code_verifier=code_verifier,
    token_endpoint=token_endpoint,
    client_id=client_id,
    resource=resource,
    client_secret=client_secret,
    token_endpoint_auth_method=token_endpoint_auth_method,
)
# Send request.data as form data to request.token_endpoint, with request.headers,
# using your application's HTTP client and URL validation.
```

The built-in exchange helper uses this builder too. Public clients and
`client_secret_post`/`client_secret_basic` authentication are supported.

## Environment Variables

- `GOPHER_MCP_PYTHON_LIBRARY_PATH` - Custom path to native library
- `DEBUG` - Enable debug output for library loading

## License

See LICENSE file for details.
