Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 182 additions & 0 deletions docs/operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,181 @@ Open `htmlcov/index.html` in your browser to view the detailed coverage report.
uv run pytest tests/test_prompts.py -v
```

## Observability and Monitoring

### Health Endpoints

The SDD MCP server provides health check endpoints for monitoring:

#### `/health` - Basic Health Check

Simple health check endpoint that returns `OK` when the server is running.

```bash
curl http://localhost:8000/health
```

Response: `OK`

#### `/mcp/health` - Detailed Readiness Check

Comprehensive health check with detailed status information about server components.

```bash
curl http://localhost:8000/mcp/health
```

Example healthy response:

```json
{
"status": "healthy",
"timestamp": "2025-11-11T18:10:21.614Z",
"uptime_seconds": 123.45,
"checks": {
"workspace": {
"status": "healthy",
"path": "/workspace",
"exists": true,
"writable": true
},
"prompts": {
"status": "healthy",
"path": "/path/to/prompts",
"exists": true,
"readable": true
}
}
}
```

Example degraded response (HTTP 503):

```json
{
"status": "degraded",
"timestamp": "2025-11-11T18:10:21.614Z",
"uptime_seconds": 123.45,
"checks": {
"workspace": {
"status": "unhealthy",
"path": "/workspace",
"exists": false,
"writable": false
},
"prompts": {
"status": "healthy",
"path": "/path/to/prompts",
"exists": true,
"readable": true
}
}
}
```

### Structured Logging

The server uses structured logging to provide detailed operational insights. Logs can be configured via environment variables:

- `SDD_LOG_LEVEL`: Set log level (DEBUG, INFO, WARNING, ERROR)
- `SDD_LOG_FORMAT`: Choose output format (json or text)

#### JSON Format (Default)

```json
{
"timestamp": "2025-11-11T18:10:21.614Z",
"level": "INFO",
"logger": "sdd-mcp",
"message": "MCP server initialized successfully",
"module": "__init__",
"function": "create_app",
"line": 95,
"version": "1.8.0"
}
```

#### Text Format

```
2025-11-11 18:10:21,614 - sdd-mcp - INFO - MCP server initialized successfully
```

### Helper Tools

The server exposes the following helper tools for workspace management:

#### `list-artifacts`

List workspace artifacts (specs, tasks, or all).

Parameters:
- `artifact_type`: Type of artifacts to list ("specs", "tasks", or "all")

Example output:
```
Specs (2):
- 0001-spec-user-auth.md
- 0002-spec-api-gateway.md
Tasks (1):
- tasks-0001-spec-user-auth.md
```

#### `create-spec-stub`

Create a new spec stub file in the workspace.

Parameters:
- `feature_name`: Name of the feature (used in filename)
- `spec_number`: Optional spec number (auto-incremented if not provided)

Example output:
```
/workspace/specs/0003-spec-new-feature.md
```

#### `summarize-diff`

Summarize differences between two versions of a file.

Parameters:
- `file_path`: Path to the file being compared
- `base_content`: Original content
- `modified_content`: Modified content

Example output:
```
File: test.txt
Lines added: 2
Characters: 100 → 150 (+50)
Line 1:
- original line
+ modified line
```

### Notifications

The server broadcasts notifications when workspace artifacts change:

- `notify_spec_created`: Emitted when a new spec is created
- `notify_spec_modified`: Emitted when a spec is modified
- `notify_spec_deleted`: Emitted when a spec is deleted
- `notify_task_created`: Emitted when a new task is created
- `notify_task_modified`: Emitted when a task is modified
- `notify_task_deleted`: Emitted when a task is deleted

All notifications trigger a `resource_list_changed` event to notify MCP clients that the resource list should be refreshed.

### Sampling

The server supports MCP sampling protocol for requesting client-generated summaries and analysis:

- `request_summary`: Request a summary of content from the client
- `request_analysis`: Request an analysis (general, technical, requirements, risks)
- `request_comparison`: Request a comparison of two pieces of content

These sampling capabilities enable the server to leverage client AI capabilities for advanced content processing.

## Troubleshooting

### Server Won't Start
Expand All @@ -175,3 +350,10 @@ uv run pytest tests/test_prompts.py -v
1. Ensure all dependencies are installed: `uv sync`
2. Run tests with verbose output: `uv run pytest -v`
3. Check for environment variable conflicts

### Health Check Issues

1. Check `/mcp/health` endpoint for detailed status
2. Verify workspace directory exists and is writable
3. Verify prompts directory exists and is readable
4. Review structured logs for error details
62 changes: 54 additions & 8 deletions mcp_server/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
spec-driven development workflows.
"""

from fastmcp import FastMCP
from fastmcp import Context, FastMCP
from starlette.requests import Request
from starlette.responses import PlainTextResponse
from starlette.responses import JSONResponse, PlainTextResponse

try:
from __version__ import __version__
Expand All @@ -17,7 +17,9 @@
__version__ = version("spec-driven-development-mcp")

from .config import config
from .logging import health_checker, logger
from .prompts_loader import register_prompts
from .tools import create_spec_stub, list_artifacts, summarize_diff


def create_app() -> FastMCP:
Expand All @@ -29,23 +31,67 @@ def create_app() -> FastMCP:
# Initialize FastMCP server
mcp = FastMCP(name="spec-driven-development-mcp")

logger.info("Initializing Spec-Driven Development MCP server", version=__version__)

@mcp.custom_route("/health", methods=["GET"])
async def health_check(request: Request) -> PlainTextResponse:
return PlainTextResponse("OK")

@mcp.custom_route("/mcp/health", methods=["GET"])
async def mcp_health_check(request: Request) -> JSONResponse:
"""Detailed health check endpoint with readiness information."""
health_status = health_checker.check_health()
status_code = 200 if health_status["status"] == "healthy" else 503
return JSONResponse(health_status, status_code=status_code)

# Load prompts from the prompts directory and register them
register_prompts(mcp, config.prompts_dir)

@mcp.tool(name="basic-example", description="Return a static message for testing.")
def basic_example_tool() -> str:
"""Basic example tool used to verify MCP tool registration."""

return "Basic example tool invoked successfully."

# TODO: Register resources (Task 2.1)
# TODO: Register tools (Task 5.1)
# TODO: Setup notifications (Task 5.2)
# TODO: Setup sampling (Task 5.3)
# TODO: Setup logging (Task 5.4)
# Register helper tools
@mcp.tool(
name="list-artifacts",
description="List workspace artifacts (specs, tasks, or all)",
)
def list_artifacts_tool(
ctx: Context,
artifact_type: str = "all",
) -> str:
"""List artifacts in the workspace."""
logger.info("Listing artifacts", artifact_type=artifact_type)
return list_artifacts(ctx, artifact_type) # type: ignore

@mcp.tool(
name="create-spec-stub",
description="Create a new spec stub file in the workspace",
)
def create_spec_stub_tool(
ctx: Context,
feature_name: str,
spec_number: int | None = None,
) -> str:
"""Create a spec stub file."""
logger.info("Creating spec stub", feature_name=feature_name, spec_number=spec_number)
return create_spec_stub(ctx, feature_name, spec_number)

@mcp.tool(
name="summarize-diff",
description="Summarize differences between two versions of a file",
)
def summarize_diff_tool(
ctx: Context,
file_path: str,
base_content: str,
modified_content: str,
) -> str:
"""Summarize file differences."""
logger.info("Summarizing diff", file_path=file_path)
return summarize_diff(ctx, file_path, base_content, modified_content)

logger.info("MCP server initialized successfully")

return mcp
Loading