# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## User Preferences
I prefer uv
I prefer python
I prefer streamlit
I prefer openai, anthropic or gemini models
## Project Overview
This is an MCP (Model Context Protocol) server built in Python that wraps the Oracle Fusion Cloud Accounts Receivable REST API. It provides secure, multi-tenant access for AI agents to query AR invoice data through credential-per-request authentication.
## Commands
### Development
```bash
# Install dependencies with uv (preferred)
uv pip install -e ".[dev]"
# Run the server
uv run python -m src.server
# Run in development mode
python -m src.server
```
### Testing
```bash
# Run all tests
uv run pytest
# Run tests with coverage
uv run pytest --cov=src
# Run specific test file
uv run pytest tests/test_formatter.py
# Run tests in watch mode
uv run pytest-watch
```
### Code Quality
```bash
# Format code with Black
uv run black src tests
# Lint with Ruff
uv run ruff check src tests
# Fix linting issues
uv run ruff check --fix src tests
# Type check with mypy
uv run mypy src
```
### MCP Testing
```bash
# Test with MCP Inspector
npx @modelcontextprotocol/inspector uv run python -m src.server
```
## Architecture
### Core Components
1. **src/server.py** - Main MCP server entry point
- Sets up MCP server with Python SDK
- Registers three MCP tools
- Handles tool calls and routing
- Uses stdio transport for Claude Desktop integration
2. **src/tools.py** - MCP tool implementations
- `list_invoices()` - List and filter invoices
- `get_invoice_details()` - Get specific invoice details
- `search_invoices()` - Advanced search with filters
- Each tool validates input, calls Oracle API, formats response
3. **src/oracle_client.py** - Oracle Fusion API client
- `OracleClient` class with async methods
- Handles Basic Auth with per-request credentials
- Builds Oracle REST query filters
- Makes HTTP requests using httpx
- No credential storage - stateless design
4. **src/formatter.py** - Response formatting
- Formats data as both Markdown (human-readable) and JSON (structured)
- Calculates totals and statistics
- Handles empty results and pagination info
- Currency and date formatting utilities
5. **src/errors.py** - Error handling
- Maps httpx exceptions to OracleApiError
- Provides actionable error messages for different HTTP status codes
- Sanitizes logs to remove credentials
- Custom error classes for validation
6. **src/models.py** - Pydantic data models
- OracleInvoice, OracleApiResponse, InvoiceSummary
- Tool parameter models with validation
- Type-safe data structures throughout
7. **src/config.py** - Configuration management
- Pydantic Settings for environment variables
- Oracle API URL construction
- Default values and limits
### Data Flow
```
MCP Client (Claude) → MCP Server → Oracle Client → Oracle Fusion API
↓ ↓ ↓
Input Validation HTTP Request JSON Response
↓ ↓ ↓
Tool Handler Authentication Raw Invoice Data
↓ ↓ ↓
Formatted Response ← Markdown + JSON ← Summary Creation
```
### Transport Mode
- **stdio**: For local development and Claude Desktop integration (current)
- **HTTP/SSE**: Can be added for remote deployment
## Oracle Fusion API Details
### Base Configuration
- Default URL: `https://fa-euth-dev46-saasfademo1.ds-fa.oraclepdemos.com`
- API Path: `/fscmRestApi/resources/11.13.18.05/receivablesInvoices`
- Authentication: Basic Auth (per-request, no storage)
### Query Building
Oracle REST API uses semicolon-separated conditions in the `q` parameter:
```
q=CustomerName LIKE '%Acme%';InvoiceDate>='2024-01-01';InvoiceStatus='Open'
```
### Pagination
- `limit`: Results per page (1-100, default: 20)
- `offset`: Skip N results for pagination
## Key Design Principles
1. **Security First**
- Never log or store credentials
- Sanitize all error logs
- Validate all inputs with Pydantic
- Basic Auth over HTTPS
2. **Stateless Design**
- No session state
- Credentials passed per-request
- Enables horizontal scaling
- Each request is independent
3. **Async/Await**
- All API calls use async/await
- Uses httpx for async HTTP
- Non-blocking I/O operations
4. **Dual Format Responses**
- Markdown for human readability (shown first)
- JSON for programmatic access (included at end)
- Both formats in single response
5. **Type Safety**
- Full Pydantic coverage
- Runtime validation
- Type hints throughout
- mypy strict mode
## Common Development Patterns
### Adding a New Tool
1. Define parameter model in `src/models.py`:
```python
class NewToolParams(BaseModel):
username: str = Field(min_length=1)
password: str = Field(min_length=1)
# ... other fields
```
2. Implement tool in `src/tools.py`:
```python
async def new_tool(arguments: dict[str, Any]) -> list[dict[str, Any]]:
params = NewToolParams(**arguments)
result = await oracle_client.new_method(...)
markdown = format_new_tool_markdown(result)
json_data = result.model_dump_json(indent=2)
return [
{"type": "text", "text": markdown},
{"type": "text", "text": f"\\n\\n---\\n\\n**Raw JSON:**\\n```json\\n{json_data}\\n```"},
]
```
3. Register in `src/server.py`:
```python
# Add to TOOLS list
Tool(
name="oracle_ar_new_tool",
description="...",
inputSchema={...},
)
# Add handler in call_tool()
elif name == "oracle_ar_new_tool":
results = await new_tool(arguments)
return [TextContent(type="text", text=item["text"]) for item in results]
```
### Adding Oracle API Methods
Add to `src/oracle_client.py`:
```python
async def new_method(
self,
username: str,
password: str,
**options
) -> OracleApiResponse:
try:
async with httpx.AsyncClient(timeout=self.timeout) as client:
response = await client.get(
self.base_url,
params=options,
headers={
"Authorization": self._create_auth_header(username, password),
"Accept": "application/json",
},
)
response.raise_for_status()
return OracleApiResponse(**response.json())
except Exception as e:
handle_oracle_api_error(e)
raise
```
## Testing Strategy
1. **Unit Tests**: Test formatters, models, validation in isolation
2. **Integration Tests**: Test actual Oracle API calls with test credentials (if available)
3. **MCP Inspector**: Interactive testing of tools via CLI
4. **Manual Testing**: Test with Claude Desktop integration
## Package Management with uv
uv is a fast, reliable Python package manager:
```bash
# Install packages
uv pip install package-name
# Install from pyproject.toml
uv pip install -e ".[dev]"
# Run commands in virtual environment
uv run python script.py
uv run pytest
# Update dependencies
uv pip compile pyproject.toml
```
## Claude Desktop Integration
Add to `claude_desktop_config.json`:
```json
{
"mcpServers": {
"oracle-ar": {
"command": "uv",
"args": [
"--directory",
"C:\\KumR\\Knowledge\\Claude\\23jan2026",
"run",
"python",
"-m",
"src.server"
]
}
}
}
```
## Troubleshooting
### Import Errors
- Ensure virtual environment is activated
- Run `uv pip install -e ".[dev]"`
- Check Python version >= 3.10
### MCP Connection Issues
- Check command and args in Claude Desktop config
- Verify server starts without errors: `uv run python -m src.server`
- Check logs in Claude Desktop
### Oracle API Errors
- Verify credentials are correct
- Check Oracle API endpoint is accessible
- Review error messages in logs (credentials are sanitized)
### Type Errors
- Run mypy: `uv run mypy src`
- Check Pydantic model definitions
- Ensure all functions have type hints