feat: add MCP function to list_user

This commit is contained in:
insleker 2026-01-19 13:52:05 +08:00
parent 501b9f5ddd
commit 6d1af46ce6
4 changed files with 400 additions and 2 deletions

View File

@ -28,6 +28,8 @@ Use this skill when:
- **User Validation**: Check if users exist and identify missing entries - **User Validation**: Check if users exist and identify missing entries
- **Filtering**: Query users by team or department - **Filtering**: Query users by team or department
- **Reloadable**: Update mappings without restarting the application - **Reloadable**: Update mappings without restarting the application
- **MCP Integration**: Share user data with other AI systems via Model Context Protocol
- **Multi-Interface**: Access as Python library OR via MCP server
## File Structure ## File Structure
@ -301,8 +303,75 @@ except ValueError:
print("User mapping file has invalid JSON!") print("User mapping file has invalid JSON!")
``` ```
## MCP Server Integration
### Overview
The skill includes an MCP (Model Context Protocol) server that exposes user management functionality to other AI systems. This allows seamless sharing of user data across multiple Claude instances and AI tools.
### Quick Start
```bash
# Install MCP SDK
pip install mcp
# or
uv add mcp
# Run the MCP server
python mcp_server.py
```
### Configure for Claude Desktop
Add to `~/.claude/claude.json`:
```json
{
"mcpServers": {
"user-manager": {
"command": "python",
"args": ["/absolute/path/to/.claude/skills/list_user/mcp_server.py"],
"type": "stdio"
}
}
}
```
### MCP Tools Available
The server exposes 7 tools:
1. **`get_formal_name`** - Map a single nickname to formal name
2. **`map_names`** - Map multiple nicknames in batch
3. **`get_user_info`** - Get complete user record
4. **`get_users_by_team`** - Find all users in a team
5. **`get_users_by_department`** - Find all users in a department
6. **`validate_users`** - Check if users exist
7. **`list_all_users`** - Get all users in system
### Example MCP Usage
Once configured, other AI systems can use the tools:
```
You: "What's the formal name for ben sung and get their team info?"
AI: [Uses get_user_info tool via MCP]
AI: "Ben sung's formal name is 宋柏昆 and they are in the 智能控制組 team."
```
### Full Documentation
See [MCP_README.md](MCP_README.md) for:
- Detailed tool specifications
- Response formats
- Configuration options
- Integration examples
- Troubleshooting
## Testing ## Testing
### Test the Python Module
Run the module directly to test basic functionality: Run the module directly to test basic functionality:
```bash ```bash
@ -315,6 +384,16 @@ This will display:
- User information retrieval - User information retrieval
- Team filtering - Team filtering
### Test the MCP Server
```bash
# Run the server (will wait for client connections)
python mcp_server.py
# In another terminal, test with curl or MCP client
# The server communicates via stdio transport
```
## Future Enhancements ## Future Enhancements
Potential improvements: Potential improvements:
@ -325,6 +404,8 @@ Potential improvements:
- User status tracking (active, inactive, etc.) - User status tracking (active, inactive, etc.)
- Export/import utilities for user data - Export/import utilities for user data
- Audit logging for user lookup operations - Audit logging for user lookup operations
- HTTP REST API wrapper for web integration
- User management tools (add, update, delete) in MCP server
## License ## License

View File

@ -0,0 +1,244 @@
"""
MCP Server for User Manager
Exposes user management and name mapping functionality via Model Context Protocol.
Allows other AI systems to query and manage user information.
Usage:
python mcp_server.py
Environment:
Communicates via stdio transport.
"""
import sys
from typing import Any
# Try importing from the installed MCP SDK
try:
from mcp.server import Server
from mcp.server.stdio import stdio_server
MCP_AVAILABLE = True
except ImportError as e:
MCP_AVAILABLE = False
MCP_ERROR = str(e)
from user_manager import UserManager
def create_mcp_server() -> Any:
"""
Create and configure the MCP server with user management tools.
Returns:
Server instance if available, otherwise None
"""
if not MCP_AVAILABLE:
return None
# Initialize MCP server
server = Server(name="user-manager")
# Initialize user manager
try:
user_manager = UserManager()
except Exception as e:
print(f"Error initializing UserManager: {e}", file=sys.stderr)
raise
# ============================================================================
# Tool 1: Get Formal Name
# ============================================================================
@server.call_tool()
def get_formal_name(nickname: str, fallback: str = "keep_original") -> dict:
"""Get the formal name for a given nickname."""
try:
formal_name = user_manager.get_formal_name(nickname, fallback=fallback)
return {
"success": True,
"nickname": nickname,
"formal_name": formal_name,
"message": f"Successfully mapped '{nickname}' to '{formal_name}'"
}
except ValueError as e:
return {
"success": False,
"nickname": nickname,
"error": str(e),
"message": f"Failed to map nickname: {e}"
}
# ============================================================================
# Tool 2: Map Multiple Names
# ============================================================================
@server.call_tool()
def map_names(nicknames: list, fallback: str = "keep_original") -> dict:
"""Map multiple nicknames to their formal names."""
try:
mapped = user_manager.map_names(nicknames, fallback=fallback)
return {
"success": True,
"input_count": len(nicknames),
"mappings": [
{"nickname": nick, "formal_name": formal}
for nick, formal in zip(nicknames, mapped)
],
"message": f"Successfully mapped {len(nicknames)} nickname(s)"
}
except Exception as e:
return {
"success": False,
"error": str(e),
"message": f"Failed to map names: {e}"
}
# ============================================================================
# Tool 3: Get User Information
# ============================================================================
@server.call_tool()
def get_user_info(nickname: str) -> dict:
"""Get complete user information."""
user_info = user_manager.get_user_info(nickname)
if user_info:
return {
"success": True,
"user": user_info,
"message": f"Found user: {user_info.get('formal_name', 'Unknown')}"
}
else:
return {
"success": False,
"nickname": nickname,
"error": f"User not found: {nickname}",
"message": f"No user found with nickname '{nickname}'"
}
# ============================================================================
# Tool 4: Get Users by Team
# ============================================================================
@server.call_tool()
def get_users_by_team(team: str) -> dict:
"""Get all users in a specific team."""
try:
users = user_manager.get_users_by_team(team)
return {
"success": True,
"team": team,
"user_count": len(users),
"users": users,
"message": f"Found {len(users)} user(s) in team '{team}'"
}
except Exception as e:
return {
"success": False,
"team": team,
"error": str(e),
"message": f"Failed to retrieve team members: {e}"
}
# ============================================================================
# Tool 5: Get Users by Department
# ============================================================================
@server.call_tool()
def get_users_by_department(department: str) -> dict:
"""Get all users in a specific department."""
try:
users = user_manager.get_users_by_department(department)
return {
"success": True,
"department": department,
"user_count": len(users),
"users": users,
"message": f"Found {len(users)} user(s) in department '{department}'"
}
except Exception as e:
return {
"success": False,
"department": department,
"error": str(e),
"message": f"Failed to retrieve department users: {e}"
}
# ============================================================================
# Tool 6: Validate Users
# ============================================================================
@server.call_tool()
def validate_users(nicknames: list) -> dict:
"""Validate that nicknames exist in the user mapping."""
try:
found, missing = user_manager.validate_users(nicknames)
return {
"success": True,
"total": len(nicknames),
"found_count": len(found),
"missing_count": len(missing),
"found": found,
"missing": missing,
"message": f"Validation complete: {len(found)} found, {len(missing)} missing"
}
except Exception as e:
return {
"success": False,
"error": str(e),
"message": f"Validation failed: {e}"
}
# ============================================================================
# Tool 7: List All Users
# ============================================================================
@server.call_tool()
def list_all_users() -> dict:
"""Get all users in the system."""
try:
users = user_manager.get_all_users()
return {
"success": True,
"user_count": len(users),
"users": users,
"message": f"Retrieved {len(users)} user(s) from the system"
}
except Exception as e:
return {
"success": False,
"error": str(e),
"message": f"Failed to retrieve user list: {e}"
}
return server
def main():
"""Run the MCP server."""
if not MCP_AVAILABLE:
print(
"ERROR: MCP SDK is not installed. Install with:\n"
" pip install mcp\n"
"or\n"
" uv add mcp",
file=sys.stderr
)
print(f"Installation error: {MCP_ERROR}", file=sys.stderr)
sys.exit(1)
try:
server = create_mcp_server()
if server:
print("Starting User Manager MCP Server...", file=sys.stderr)
with stdio_server(server) as session:
session.wait()
else:
print("Failed to create MCP server", file=sys.stderr)
sys.exit(1)
except KeyboardInterrupt:
print("\nServer stopped", file=sys.stderr)
sys.exit(0)
except Exception as e:
print(f"Server error: {e}", file=sys.stderr)
import traceback
traceback.print_exc()
sys.exit(1)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,68 @@
#!/usr/bin/env python
"""
Quick test to verify MCP server initialization
"""
import sys
import os
# Add list_user to path
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
try:
from mcp_server import create_mcp_server
from user_manager import UserManager
print("✓ Successfully imported MCP server and UserManager")
print()
# Test UserManager
print("Testing UserManager:")
print("-" * 60)
manager = UserManager()
print(f"✓ UserManager initialized with {len(manager.users)} users")
# Test name mapping
test_name = "ben sung"
formal = manager.get_formal_name(test_name)
print(f"✓ Name mapping: '{test_name}''{formal}'")
print()
# Test MCP server creation
print("Testing MCP Server:")
print("-" * 60)
try:
server = create_mcp_server()
if server:
print("✓ MCP server created successfully")
print("✓ Server is ready to accept connections on stdio transport")
print()
print("Available Tools:")
# List tools by checking method names
tool_methods = ['get_formal_name', 'map_names', 'get_user_info',
'get_users_by_team', 'get_users_by_department',
'validate_users', 'list_all_users']
for tool in tool_methods:
print(f" - {tool}")
else:
print("✗ Failed to create MCP server - returned None")
sys.exit(1)
except Exception as mcp_error:
print(f"✗ MCP server creation error: {mcp_error}")
import traceback
traceback.print_exc()
sys.exit(1)
print()
print("=" * 60)
print("✓ All tests passed!")
print("=" * 60)
print()
print("To run the MCP server:")
print(" python mcp_server.py")
except Exception as e:
print(f"✗ Error: {e}")
import traceback
traceback.print_exc()
sys.exit(1)

View File

@ -4,10 +4,15 @@
license = { text = "MIT" } license = { text = "MIT" }
name = "report-skill-expm" name = "report-skill-expm"
readme = "README.md" readme = "README.md"
requires-python = ">=3.9" requires-python = ">=3.10"
version = "1.0.0" version = "1.0.0"
dependencies = ["openpyxl>=3.1.0", "pandas>=2.0.0", "xlrd>=2.0.0"] dependencies = [
"openpyxl>=3.1.0",
"pandas>=2.0.0",
"xlrd>=2.0.0",
"mcp>=0.1.0",
]
[project.optional-dependencies] [project.optional-dependencies]
dev = ["pytest>=7.0.0", "black>=23.0.0", "flake8>=6.0.0"] dev = ["pytest>=7.0.0", "black>=23.0.0", "flake8>=6.0.0"]