This change implements a Model Context Protocol (MCP) server that enables AI assistants to manage society members through natural language interactions. Changes: - Add MCP server implementation (src/mcp_server.py) - Implement 4 core tools: * list_members - Query all members * get_member - Get specific member by ID * create_member - Create new member * update_member - Update member information - Add mcp and httpx dependencies to pyproject.toml - Update README with comprehensive MCP server documentation - Create OpenSpec proposal in openspec/changes/add-mcp-server/ The MCP server connects to the GraphQL API via HTTP and provides structured tools that abstract away GraphQL complexity. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
362 lines
8.4 KiB
Markdown
362 lines
8.4 KiB
Markdown
# Clubber
|
|
|
|
A toolset for managing members of non-profit societies (Vereine) with AI-powered administration.
|
|
|
|
## Overview
|
|
|
|
Clubber provides a GraphQL API for member management combined with an MCP (Model Context Protocol) server that enables AI assistants to help with society administration tasks.
|
|
|
|
**Current Status**: Early development - OpenSpec documentation and project structure in place.
|
|
|
|
## Architecture
|
|
|
|
The system consists of two main components:
|
|
|
|
1. **GraphQL API** - Core backend for member data management
|
|
- Built with FastAPI and Strawberry GraphQL
|
|
- Database-agnostic design (SQLite for development, PostgreSQL for production)
|
|
- SQLAlchemy 2.0 ORM with async support
|
|
|
|
2. **MCP Server** - AI assistant integration layer
|
|
- Connects to the GraphQL API
|
|
- Provides tools for AI agents to manage society operations
|
|
- Service account authentication
|
|
|
|
## Tech Stack
|
|
|
|
- **Python 3.11+** - Primary language
|
|
- **uv** - Fast package and project manager
|
|
- **FastAPI** - Async web framework
|
|
- **Strawberry GraphQL** - Type-safe GraphQL with Python type hints
|
|
- **SQLAlchemy 2.0** - Database ORM
|
|
- **Alembic** - Database migrations
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
clubber/
|
|
├── openspec/ # Specification-driven development
|
|
│ ├── project.md # Project conventions and context
|
|
│ ├── specs/ # Current specifications
|
|
│ └── changes/ # Change proposals
|
|
├── CLAUDE.md # AI assistant instructions
|
|
└── README.md # This file
|
|
```
|
|
|
|
## Getting Started
|
|
|
|
### Prerequisites
|
|
|
|
- Python 3.11 or higher
|
|
- [uv](https://github.com/astral-sh/uv) package manager
|
|
|
|
### Setup
|
|
|
|
```bash
|
|
# Clone the repository
|
|
git clone ssh://git@codeberg.org/gurix/clubber.git
|
|
cd clubber
|
|
|
|
# Install uv if not already installed
|
|
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
|
|
# Install dependencies
|
|
uv sync
|
|
|
|
# Run database migrations
|
|
uv run alembic upgrade head
|
|
|
|
# (Optional) Seed the database with sample data
|
|
PYTHONPATH=. uv run python scripts/seed.py
|
|
```
|
|
|
|
### Running the Server
|
|
|
|
Start the development server:
|
|
|
|
```bash
|
|
uv run uvicorn src.main:app --host 127.0.0.1 --port 8000 --reload
|
|
```
|
|
|
|
The `--reload` flag enables auto-restart when code changes are detected.
|
|
|
|
Access the API:
|
|
- **GraphQL Playground**: http://127.0.0.1:8000/graphql
|
|
- **API Documentation**: http://127.0.0.1:8000/docs
|
|
- **Root Endpoint**: http://127.0.0.1:8000/
|
|
|
|
## API Usage Examples
|
|
|
|
### Member Data Model
|
|
|
|
Members have the following fields:
|
|
- `firstName` (required) - Member's first name
|
|
- `lastName` (optional) - Member's last name
|
|
- `street` (optional) - Street address
|
|
- `apartmentNumber` (optional) - Apartment or unit number
|
|
- `zip` (optional) - Postal code
|
|
- `city` (optional) - City
|
|
- `country` (optional) - Country
|
|
- `email` (optional) - Email address (validated when provided)
|
|
- `phone` (optional) - Phone number in E.164 format (validated when provided)
|
|
|
|
**Key Feature**: Only `firstName` is required. All other fields are optional and can be populated later. Email and phone are validated only when provided (not when null/empty).
|
|
|
|
### GraphQL Queries
|
|
|
|
List all members:
|
|
```graphql
|
|
{
|
|
members {
|
|
id
|
|
firstName
|
|
lastName
|
|
email
|
|
phone
|
|
city
|
|
}
|
|
}
|
|
```
|
|
|
|
Get a single member:
|
|
```graphql
|
|
{
|
|
member(id: 1) {
|
|
id
|
|
firstName
|
|
lastName
|
|
email
|
|
street
|
|
city
|
|
country
|
|
}
|
|
}
|
|
```
|
|
|
|
### GraphQL Mutations
|
|
|
|
Create a member (minimal - only firstName):
|
|
```graphql
|
|
mutation {
|
|
createMember(input: {
|
|
firstName: "Alice"
|
|
}) {
|
|
id
|
|
firstName
|
|
email
|
|
}
|
|
}
|
|
```
|
|
|
|
Create a member with all fields:
|
|
```graphql
|
|
mutation {
|
|
createMember(input: {
|
|
firstName: "Bob"
|
|
lastName: "Johnson"
|
|
street: "123 Main St"
|
|
apartmentNumber: "4B"
|
|
zip: "12345"
|
|
city: "Springfield"
|
|
country: "USA"
|
|
email: "bob.johnson@example.com"
|
|
phone: "+14155551234"
|
|
}) {
|
|
id
|
|
firstName
|
|
lastName
|
|
email
|
|
phone
|
|
}
|
|
}
|
|
```
|
|
|
|
Update a member:
|
|
```graphql
|
|
mutation {
|
|
updateMember(input: {
|
|
id: 1
|
|
email: "updated@example.com"
|
|
phone: "+14155559999"
|
|
}) {
|
|
id
|
|
firstName
|
|
email
|
|
phone
|
|
}
|
|
}
|
|
```
|
|
|
|
Delete a member:
|
|
```graphql
|
|
mutation {
|
|
deleteMember(id: 2)
|
|
}
|
|
```
|
|
|
|
### Using curl
|
|
|
|
Query members:
|
|
```bash
|
|
curl -X POST http://127.0.0.1:8000/graphql \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"query": "{ members { id firstName lastName email } }"}'
|
|
```
|
|
|
|
Create a member:
|
|
```bash
|
|
curl -X POST http://127.0.0.1:8000/graphql \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"query": "mutation { createMember(input: { firstName: \"Charlie\" }) { id firstName } }"}'
|
|
```
|
|
|
|
## MCP Server
|
|
|
|
The MCP (Model Context Protocol) server enables AI assistants like Claude to manage society members through natural language interactions.
|
|
|
|
### What is MCP?
|
|
|
|
The Model Context Protocol (MCP) is a standard protocol that allows AI assistants to use tools and access external systems. The Clubber MCP server provides 4 tools that connect to the GraphQL API:
|
|
|
|
- **list_members** - List all members with their complete information
|
|
- **get_member** - Get detailed information about a specific member by ID
|
|
- **create_member** - Create a new member (only firstName required)
|
|
- **update_member** - Update an existing member's information
|
|
|
|
### Running the MCP Server
|
|
|
|
The MCP server requires the GraphQL API to be running first:
|
|
|
|
```bash
|
|
# Terminal 1: Start the GraphQL API
|
|
uv run uvicorn src.main:app --host 127.0.0.1 --port 8000
|
|
|
|
# Terminal 2: Run the MCP server
|
|
python -m src.mcp_server
|
|
```
|
|
|
|
### Configuration
|
|
|
|
The MCP server can be configured via environment variables:
|
|
|
|
```bash
|
|
# Use a custom API URL (default: http://127.0.0.1:8000/graphql)
|
|
export CLUBBER_API_URL="http://localhost:3000/graphql"
|
|
python -m src.mcp_server
|
|
```
|
|
|
|
### Integrating with Claude Code
|
|
|
|
To use the MCP server with Claude Code, add it to your MCP configuration:
|
|
|
|
**For macOS/Linux** (`~/Library/Application Support/Claude/claude_desktop_config.json` or `~/.config/claude/config.json`):
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"clubber": {
|
|
"command": "python",
|
|
"args": ["-m", "src.mcp_server"],
|
|
"cwd": "/absolute/path/to/clubber",
|
|
"env": {
|
|
"CLUBBER_API_URL": "http://127.0.0.1:8000/graphql"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
After adding the configuration, restart Claude Code. You can then use natural language to manage members:
|
|
|
|
- "List all members in the society"
|
|
- "Create a new member named Alice"
|
|
- "Update member 5's email to alice@example.com"
|
|
- "Show me details for member 3"
|
|
|
|
### MCP Server Usage Examples
|
|
|
|
Once configured, you can interact with the MCP server through Claude Code:
|
|
|
|
**Example 1: Create a member**
|
|
```
|
|
User: Create a new member named Bob Smith with email bob@example.com
|
|
|
|
Claude uses create_member tool:
|
|
- firstName: "Bob"
|
|
- lastName: "Smith"
|
|
- email: "bob@example.com"
|
|
|
|
Result: Member created with ID 1
|
|
```
|
|
|
|
**Example 2: Update member information**
|
|
```
|
|
User: Update member 1's phone number to +41791234567
|
|
|
|
Claude uses update_member tool:
|
|
- id: 1
|
|
- phone: "+41791234567"
|
|
|
|
Result: Member updated successfully
|
|
```
|
|
|
|
**Example 3: List all members**
|
|
```
|
|
User: Show me all members in the society
|
|
|
|
Claude uses list_members tool and displays formatted results:
|
|
- Bob Smith (bob@example.com, +41791234567)
|
|
- Alice Johnson (alice@example.com)
|
|
...
|
|
```
|
|
|
|
## Development Workflow
|
|
|
|
This project uses [OpenSpec](https://openspec.dev) for specification-driven development:
|
|
|
|
1. **Review existing specs** in `openspec/specs/`
|
|
2. **Create change proposals** in `openspec/changes/` before implementing features
|
|
3. **Validate proposals** with `openspec validate --strict`
|
|
4. **Implement changes** following the proposal
|
|
5. **Archive completed changes** after deployment
|
|
|
|
See `openspec/AGENTS.md` for detailed workflow instructions.
|
|
|
|
### Working with Git Worktrees
|
|
|
|
We use git worktrees for parallel development:
|
|
|
|
```bash
|
|
# Create a worktree for a feature branch
|
|
git worktree add ../clubber-feature-name feature/feature-name
|
|
|
|
# Work in the worktree
|
|
cd ../clubber-feature-name
|
|
|
|
# Remove worktree after merge
|
|
git worktree remove ../clubber-feature-name
|
|
```
|
|
|
|
## Contributing
|
|
|
|
1. Read `openspec/project.md` for project conventions
|
|
2. For new features, create an OpenSpec proposal first
|
|
3. Follow the coding style (Black, isort, ruff)
|
|
4. Write tests for new functionality
|
|
5. Use conventional commits (`feat:`, `fix:`, `docs:`, etc.)
|
|
|
|
## License
|
|
|
|
The MIT License
|
|
|
|
## Contact
|
|
|
|
Markus Graf - [info@markusgraf.ch](mailto:info@markusgraf.ch)
|
|
|
|
## Acknowledgments
|
|
|
|
Built with support from:
|
|
- [Strawberry GraphQL](https://strawberry.rocks)
|
|
- [FastAPI](https://fastapi.tiangolo.com)
|
|
- [OpenSpec](https://openspec.dev)
|