# Story 4.1: Implement `fabric_list_models` MCP Tool

**Epic:** 4 (Fabric Environment & Configuration Insights)

**Status:** Draft

## Story

As an MCP Client Developer, I want to use the `fabric_list_models` tool to retrieve a list of all AI models configured and available in the connected Fabric instance (potentially categorized by vendor), so that I can inform users or make programmatic choices about model selection for pattern execution.

## Acceptance Criteria (ACs)

1. Tool implemented in `src/fabric_mcp/core.py`.
2. Registered and advertised via `list_tools()` (no params, returns object) per `design.md`.
3. Uses `FabricApiClient` for GET to Fabric API `/models/names`.
4. Parses JSON response from Fabric API (expected: list of all models, map of models by vendor).
5. MCP success response contains structured JSON (e.g., `{"models": [...], "vendors": {...}}`). Empty lists/objects if none.
6. Returns structured MCP error for Fabric API errors or connection failures.
7. Unit tests: mock `FabricApiClient` for success (models/vendors, empty), API errors.
8. Integration tests: (vs. live local `fabric --serve`) verify response reflects local Fabric model config; test with no models if possible.

## Tasks / Subtasks

- [ ] Task 1: Implement `fabric_list_models` MCP Tool (AC: 1, 2)
  - [ ] 1.1: Add `fabric_list_models` method to `FabricMCP` class in `src/fabric_mcp/core.py`
  - [ ] 1.2: Register tool in `__init__` method alongside existing tools
  - [ ] 1.3: Define tool with no parameters and appropriate return type annotations

- [ ] Task 2: Implement Fabric API Integration (AC: 3, 4)
  - [ ] 2.1: Use `_make_fabric_api_request` helper method for GET `/models/names`
  - [ ] 2.2: Implement JSON response parsing for models/vendors structure
  - [ ] 2.3: Handle empty response gracefully (empty lists/objects)

- [ ] Task 3: Implement Response Validation and Formatting (AC: 5)
  - [ ] 3.1: Validate response structure matches expected schema
  - [ ] 3.2: Type-check models list and vendors dict structure
  - [ ] 3.3: Format response as structured JSON with models array and vendors object

- [ ] Task 4: Implement Error Handling (AC: 6)
  - [ ] 4.1: Handle Fabric API connection errors using existing error patterns
  - [ ] 4.2: Handle HTTP status errors (404, 500, etc.)
  - [ ] 4.3: Return structured MCP errors with appropriate error codes

- [ ] Task 5: Unit Testing (AC: 7)
  - [ ] 5.1: Mock `_make_fabric_api_request` for successful response with models/vendors
  - [ ] 5.2: Mock `_make_fabric_api_request` for empty models list
  - [ ] 5.3: Test error handling for Fabric API connection failures
  - [ ] 5.4: Test error handling for malformed JSON responses
  - [ ] 5.5: Test response validation and type checking

- [ ] Task 6: Integration Testing (AC: 8)
  - [ ] 6.1: Test against live `fabric --serve` instance with configured models
  - [ ] 6.2: Verify response structure matches Fabric configuration
  - [ ] 6.3: Test with minimal/no model configuration if possible
  - [ ] 6.4: Verify tool appears in MCP tool list

## Dev Technical Guidance

### Previous Story Implementation Context

From Story 3.5 (projected completion):

- Extended parameter support for `fabric_run_pattern` with variables and attachments
- Robust parameter validation framework established
- Comprehensive error handling patterns for Fabric API integration
- Testing framework covers unit and integration scenarios

Key technical insight: **Established patterns for new tool implementation** - Story 4.1 follows the same implementation pattern as previous tools with API integration.

[Source: Expected completion of docs/stories/3.5.story.md]

### Fabric API Specifications

**Models Endpoint** [Source: architecture/api-reference.md#fabric-rest-api]:

- **Endpoint**: `GET /models/names`
- **Description**: Retrieves configured Fabric models categorized by vendor
- **Request Parameters**: None
- **Success Response Schema** (Code: `200 OK`):

```json
{
  "models": ["string"],           // All available model names
  "vendors": {                    // Models grouped by vendor
    "vendor_name": ["string"]     // Array of models for each vendor
  }
}
```

**Example Response**:

```json
{
  "models": ["gpt-4o", "gpt-3.5-turbo", "claude-3-opus", "llama2"],
  "vendors": {
    "openai": ["gpt-4o", "gpt-3.5-turbo"],
    "anthropic": ["claude-3-opus"],
    "ollama": ["llama2"]
  }
}
```

**Error Response Schema**: Standard HTTP errors (404, 500, etc.)

[Source: architecture/api-reference.md#external-apis-consumed]

### MCP Tool Implementation Pattern

**Tool Registration** [Source: architecture/api-reference.md#internal-apis-provided]:

Following established pattern from existing tools:

```python
def fabric_list_models(self) -> dict[Any, Any]:
    """Retrieve configured Fabric models by vendor."""
    # Implementation follows existing _make_fabric_api_request pattern
```

**Tool Registration in `__init__`**:

```python
for fn in (
    self.fabric_list_patterns,
    self.fabric_get_pattern_details,
    self.fabric_run_pattern,
    self.fabric_list_models,          # NEW - Story 4.1
    self.fabric_list_strategies,
    self.fabric_get_configuration,
):
    self.tool(fn)
```

### Component Specifications

**File Locations** [Source: architecture/project-structure.md]:

- Core implementation: `src/fabric_mcp/core.py` - add `fabric_list_models()` method
- Unit tests: `tests/unit/test_core.py` - add models listing test cases
- Integration tests: `tests/integration/test_mcp_integration.py` - add live API tests

**Implementation Location**: Insert new method after `fabric_run_pattern` and before `fabric_list_strategies` to maintain logical grouping.

### Error Handling Implementation

**Using Existing Error Patterns** [Source: architecture/error-handling-strategy.md]:

Following established `_make_fabric_api_request` pattern:

```python
def fabric_list_models(self) -> dict[Any, Any]:
    """Retrieve configured Fabric models by vendor."""
    response_data = self._make_fabric_api_request(
        "/models/names", operation="retrieving models"
    )

    # Validate and format response
    # Return structured data
```

**Error Code Mapping**:

- Connection errors: `-32603` (Internal error)
- Invalid response format: `-32603` (Internal error)
- HTTP status errors: `-32603` (Internal error)

### Response Validation Requirements

**Type Validation** [Source: architecture/coding-standards.md#python-specifics]:

```python
# Validate response structure
if not isinstance(response_data, dict):
    raise McpError(ErrorData(
        code=-32603,
        message="Invalid response from Fabric API: expected dict for models"
    ))

# Validate models field
models = response_data.get("models", [])
if not isinstance(models, list):
    raise McpError(ErrorData(
        code=-32603,
        message="Invalid models field: expected list"
    ))

# Validate vendors field
vendors = response_data.get("vendors", {})
if not isinstance(vendors, dict):
    raise McpError(ErrorData(
        code=-32603,
        message="Invalid vendors field: expected dict"
    ))
```

### Testing Requirements

**Unit Testing Strategy** [Source: architecture/overall-testing-strategy.md]:

- Mock `_make_fabric_api_request` for various response scenarios
- Test response validation and error handling
- Test empty models/vendors handling
- Verify proper error code returns
- Minimum 90% code coverage requirement

**Integration Testing Requirements**:

- Test against live `fabric --serve` with various model configurations
- Verify response accuracy against known Fabric setup
- Test tool registration and availability in MCP tool list
- Test error scenarios with unreachable Fabric instance

**Test Data Examples**:

```python
# Full response test data
full_models_response = {
    "models": ["gpt-4o", "gpt-3.5-turbo", "claude-3-opus"],
    "vendors": {
        "openai": ["gpt-4o", "gpt-3.5-turbo"],
        "anthropic": ["claude-3-opus"]
    }
}

# Empty response test data
empty_models_response = {
    "models": [],
    "vendors": {}
}
```

### Technical Constraints

**Fabric API Compatibility**:

- No authentication required for `/models/names` endpoint (inherits from base API configuration)
- Response format determined by Fabric instance configuration
- Empty models list is valid response (no models configured)

**Performance Considerations**:

- Models list relatively static, could be cached in future enhancement
- Lightweight operation, no streaming required
- Fast response expected from Fabric API

### Testing

Dev Note: Story Requires the following tests:

- [x] Pytest Unit Tests: (nextToFile: true), coverage requirement: 90%
- [x] Pytest Integration Tests (Test Location): location: `tests/integration/test_mcp_integration.py`
- [ ] Manual E2E: location: N/A

Manual Test Steps:

- Test against live `fabric --serve` instance with known model configuration
- Verify MCP tool registration by checking tool list output
- Test error handling by stopping Fabric instance and calling tool
- Validate response format matches expected JSON structure

## Dev Agent Record

### Agent Model Used: {{Agent Model Name/Version}}

### Debug Log References

[[LLM: (SM Agent) When Drafting Story, leave next prompt in place for dev agent to remove and update]]
[[LLM: (Dev Agent) If the debug is logged to during the current story progress, create a table with the debug log and the specific task section in the debug log - do not repeat all the details in the story]]

### Completion Notes List

[[LLM: (SM Agent) When Drafting Story, leave next prompt in place for dev agent to remove and update - remove this line to the SM]]
[[LLM: (Dev Agent) Anything the SM needs to know that deviated from the story that might impact drafting the next story.]]

### Change Log

[[LLM: (SM Agent) When Drafting Story, leave next prompt in place for dev agent to remove and update- remove this line to the SM]]
[[LLM: (Dev Agent) Track document versions and changes during development that deviate from story dev start]]

| Date | Version | Description | Author |
| :--- | :------ | :---------- | :----- |
