# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

MCP server for querying network devices: Palo Alto firewalls and Cisco IOS via SSH (netmiko), F5 BIG-IP via iControl REST API (requests). Uses FastMCP (official Python SDK). Read-only tools for Claude Desktop integration.

## Commands

```bash
# Install (development mode)
pip install -e ".[dev]"

# Run tests
pytest

# Run single test file
pytest tests/unit/test_models.py

# Run single test
pytest tests/unit/test_models.py::TestQueryRequest::test_valid_request

# Lint
ruff check .

# Fix lint issues
ruff check . --fix
```

## Architecture

```
src/mcp_network_jcd/
├── server.py          # FastMCP entry point, registers all tools
├── models/
│   ├── paloalto.py    # Pydantic models (QueryRequest, QueryResponse, CommandResult, ErrorInfo)
│   ├── cisco.py       # CiscoCredentials (reuses shared models from paloalto)
│   └── f5.py          # F5Credentials, F5Response, F5_OBJECT_TYPES, F5_SUBCOLLECTIONS
└── tools/
    ├── paloalto.py    # paloalto_query() - SSH via netmiko
    ├── cisco.py       # cisco_ios_query() - SSH via netmiko
    └── f5.py          # f5_list(), f5_stats() - HTTPS via requests
```

**Data Flow (SSH tools)**: `server.py` → `tools/{paloalto,cisco}.py` → netmiko SSH → device
**Data Flow (F5 tools)**: `server.py` → `tools/f5.py` → requests HTTPS → iControl REST API → F5 BIG-IP

**Credentials**: Loaded from environment variables via `from_env()` classmethods. Never passed as tool parameters.
- Palo Alto: `PALOALTO_USERNAME`, `PALOALTO_PASSWORD`
- Cisco: `CISCO_USERNAME`, `CISCO_PASSWORD`, `CISCO_ENABLE_PASSWORD` (optional)
- F5: `F5_USERNAME`, `F5_PASSWORD`

## Test Organization

- `tests/unit/` - Pydantic model validation
- `tests/contract/` - Tool API contracts, error codes, partial failure handling
- `tests/integration/` - netmiko SSH mocking (PA/Cisco), requests mocking (F5)

## Key Patterns

- **Error Codes (SSH)**: CONFIG_ERROR, AUTH_FAILED, CONNECTION_TIMEOUT, CONNECTION_REFUSED, UNKNOWN_ERROR
- **Error Codes (F5 REST)**: CONFIG_ERROR, AUTH_FAILED, CONNECTION_TIMEOUT, CONNECTION_REFUSED, HTTP_ERROR, VALIDATION_ERROR, UNKNOWN_ERROR
- **Partial Failure**: If SSH drops mid-batch, returns partial results (success=True with failed commands)
- **Validation Limits (SSH)**: 1-10 commands per request, port 1-65535, timeout 1-300s
- **F5 Object Types**: virtual, pool, irule, profile
- **F5 Sub-Collections**: pool→members, virtual→policies/profiles (via `sub_collection` param on `f5_list`)
- **F5 Auth**: Token-based (POST /mgmt/shared/authn/login → X-F5-Auth-Token header). Always direct access (no proxy).

## Active Technologies
- Python 3.12 + FastMCP (mcp>=1.0.0), netmiko>=4.0.0, pydantic>=2.0.0, requests>=2.31.0
