# Development Guide
This guide covers local development setup and workflow for the Darwin Standards MCP Server.
## Prerequisites
- Python 3.11 or 3.12
- Docker (optional, for container builds)
- Git
## Setup
### 1. Clone the Repository
```bash
git clone https://github.com/fgarcia/darwin-standards-mcp.git
cd darwin-standards-mcp
```
### 2. Create Virtual Environment
```bash
# Using make (recommended)
make install
# Or manually
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
```
### 3. Configure Standards Path
The server needs access to standards documentation. Set the path:
```bash
export STANDARDS_PATH=/path/to/docs/standards
export REFERENCE_IMPLEMENTATIONS_PATH=/path/to/reference-implementations
```
## Running Locally
### stdio Mode (for Claude Code)
```bash
make run-local
```
### HTTP Mode (for testing)
```bash
make run-http
```
The server will be available at `http://localhost:8080`.
## Testing
### Run All Tests
```bash
make test
```
### Run with Coverage
```bash
make test-cov
```
Coverage report will be available in `htmlcov/index.html`.
### Run Specific Tests
```bash
# Run a specific test file
.venv/bin/pytest tests/tools/test_validation.py -v
# Run a specific test
.venv/bin/pytest tests/tools/test_validation.py::TestValidateAzureResourceName::test_valid_resource_group_name -v
```
## Code Quality
### Linting
```bash
# Check for issues
make lint
# Auto-fix issues
make format
```
### Type Checking
```bash
make typecheck
```
## Project Structure
```
darwin-standards-mcp/
├── src/standards_mcp_server/
│ ├── __init__.py # Package initialization, version
│ ├── server.py # Main MCP server entry point
│ ├── config.py # Pydantic configuration
│ ├── observability.py # OpenTelemetry setup
│ ├── resources/
│ │ ├── __init__.py
│ │ ├── standards.py # Standards document resources
│ │ └── implementations.py # Template/implementation resources
│ └── tools/
│ ├── __init__.py
│ ├── validation.py # Validation tools
│ └── search.py # Search tools
├── tests/
│ ├── __init__.py
│ ├── conftest.py # Pytest fixtures
│ └── tools/
│ ├── __init__.py
│ ├── test_validation.py
│ └── test_search.py
└── ...
```
## Adding New Features
### Adding a New MCP Tool
1. Create or update a file in `src/standards_mcp_server/tools/`:
```python
from fastmcp import FastMCP, Context
from ..observability import get_tracer
router = FastMCP("my-tools")
tracer = get_tracer(__name__)
@router.tool()
async def my_new_tool(
param1: str,
param2: int,
ctx: Context
) -> dict:
"""Brief description of what the tool does.
Longer description with more details.
Args:
param1: Description of param1
param2: Description of param2
ctx: MCP context
Returns:
Dictionary with results.
Example:
>>> result = await my_new_tool("value", 42)
>>> print(result["status"])
"success"
"""
with tracer.start_as_current_span("tool.my_new_tool") as span:
span.set_attribute("param1", param1)
await ctx.info(f"Processing with param1={param1}")
# Implementation here
return {"status": "success"}
```
2. Register the router in `src/standards_mcp_server/tools/__init__.py`:
```python
from .my_tools import router as my_tools_router
```
3. Mount in `src/standards_mcp_server/server.py`:
```python
from .tools import validation_router, search_router, my_tools_router
mcp.mount(my_tools_router)
```
4. Add tests in `tests/tools/test_my_tools.py`.
### Adding a New MCP Resource
1. Create or update a file in `src/standards_mcp_server/resources/`:
```python
from fastmcp import FastMCP
from fastmcp.exceptions import NotFoundError
from ..config import get_config
from ..observability import get_tracer
router = FastMCP("my-resources")
tracer = get_tracer(__name__)
config = get_config()
@router.resource("myscheme://category/item")
async def my_resource() -> str:
"""Description of the resource.
Detailed documentation.
Cache: Long-lived (24 hours)
"""
with tracer.start_as_current_span("resource.my_resource"):
return await _load_content("path/to/content.md")
async def _load_content(path: str) -> str:
# Implementation
pass
```
2. Register and mount similar to tools.
## Configuration
### Environment Variables
Create a `.env` file for local development:
```env
MCP_SERVER_NAME=standards-mcp-server
MCP_TRANSPORT=stdio
MCP_PORT=8080
MCP_LOG_LEVEL=DEBUG
STANDARDS_PATH=/path/to/standards
REFERENCE_IMPLEMENTATIONS_PATH=/path/to/implementations
OTEL_ENABLED=false
```
### Pydantic Settings
Configuration is managed via `src/standards_mcp_server/config.py` using Pydantic Settings:
```python
from standards_mcp_server.config import get_config
config = get_config()
print(config.server_name)
print(config.get_standards_root())
```
## Debugging
### VS Code Configuration
Create `.vscode/launch.json`:
```json
{
"version": "0.2.0",
"configurations": [
{
"name": "Standards MCP Server",
"type": "python",
"request": "launch",
"module": "standards_mcp_server.server",
"env": {
"MCP_TRANSPORT": "http",
"MCP_LOG_LEVEL": "DEBUG",
"STANDARDS_PATH": "${workspaceFolder}/standards"
}
},
{
"name": "Pytest",
"type": "python",
"request": "launch",
"module": "pytest",
"args": ["-v", "tests/"]
}
]
}
```
### Logging
The server uses structured logging via `structlog`. Enable debug logging:
```bash
MCP_LOG_LEVEL=DEBUG make run-local
```
### Tracing
Enable OpenTelemetry tracing for detailed request tracing:
```bash
OTEL_ENABLED=true OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 make run-http
```
## Contributing
1. Create a feature branch: `git checkout -b feature/DARWIN-123-my-feature`
2. Make changes following the coding standards
3. Add tests with >80% coverage
4. Run linting and tests: `make lint && make test`
5. Commit with conventional commits: `git commit -m "feat(tools): add new validation tool"`
6. Create a pull request
### Commit Message Format
```
<type>(<scope>): <description>
[optional body]
[optional footer]
```
Types: `feat`, `fix`, `docs`, `refactor`, `test`, `chore`
Scopes: `tools`, `resources`, `config`, `ci`, `deps`