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>
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:
-
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
-
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 package manager
Setup
# 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:
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 namelastName(optional) - Member's last namestreet(optional) - Street addressapartmentNumber(optional) - Apartment or unit numberzip(optional) - Postal codecity(optional) - Citycountry(optional) - Countryemail(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:
{
members {
id
firstName
lastName
email
phone
city
}
}
Get a single member:
{
member(id: 1) {
id
firstName
lastName
email
street
city
country
}
}
GraphQL Mutations
Create a member (minimal - only firstName):
mutation {
createMember(input: {
firstName: "Alice"
}) {
id
firstName
email
}
}
Create a member with all fields:
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:
mutation {
updateMember(input: {
id: 1
email: "updated@example.com"
phone: "+14155559999"
}) {
id
firstName
email
phone
}
}
Delete a member:
mutation {
deleteMember(id: 2)
}
Using curl
Query members:
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:
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:
# 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:
# 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):
{
"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 for specification-driven development:
- Review existing specs in
openspec/specs/ - Create change proposals in
openspec/changes/before implementing features - Validate proposals with
openspec validate --strict - Implement changes following the proposal
- Archive completed changes after deployment
See openspec/AGENTS.md for detailed workflow instructions.
Working with Git Worktrees
We use git worktrees for parallel development:
# 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
- Read
openspec/project.mdfor project conventions - For new features, create an OpenSpec proposal first
- Follow the coding style (Black, isort, ruff)
- Write tests for new functionality
- Use conventional commits (
feat:,fix:,docs:, etc.)
License
The MIT License
Contact
Markus Graf - info@markusgraf.ch
Acknowledgments
Built with support from: