SuccessFactors-MCP
SAP SuccessFactors Model Context Protocol Server
Installation ·
Quick Start ·
62 Tools ·
Deployment ·
API Reference
A production-grade Model Context Protocol server that connects Claude (or any MCP client) to SAP SuccessFactors via OData APIs. Query employee data, manage permissions, run compliance reports, and administer HR operations — all through natural language.
You: "Who on the Engineering team has a work anniversary this month?"
Claude: [calls get_anniversary_employees] Found 3 upcoming anniversaries...
- Jane Smith (5 years - milestone!) - March 12
- Bob Johnson (2 years) - March 18
- Alice Chen (10 years - milestone!) - March 25
Why SF-MCP?
| Challenge | SF-MCP Solution |
|---|
| SAP SuccessFactors APIs are complex and verbose | 62 purpose-built tools with clean interfaces |
| Building OData queries requires deep SF knowledge | Natural language — ask Claude in plain English |
| Security concerns with API access | Per-request auth, input validation, audit logging |
| Managing multiple SF instances | 21 data centers supported, cross-instance comparison |
| API rate limits and performance | Connection pooling, response caching, rate limiting |
Tools
62 tools organized across 16 categories:
Configuration & Discovery (3 tools)
| Tool | Description |
|---|
get_configuration | Retrieve OData metadata for any entity |
list_entities | Discover all available OData entities |
compare_configurations | Compare entity config between two instances |
RBP Security (7 tools)
| Tool | Description |
|---|
get_rbp_roles | List all Role-Based Permission roles |
get_role_permissions | Get permissions for specific roles |
get_user_permissions | Get all permissions for a user |
get_user_roles | Get roles assigned to a user |
get_permission_metadata | Map UI labels to permission types |
check_user_permission | Check if user has specific permission |
get_dynamic_groups | List permission groups (dynamic groups) |
Security & Audit (6 tools)
| Tool | Description |
|---|
get_role_history | View modification history for roles |
get_role_assignment_history | View history of role assignments |
get_login_audit_log | Login events — who logged in, when, from where |
get_admin_audit_log | Admin-level config/data change history |
get_sod_violations | Detect segregation-of-duty conflicts in RBP assignments |
get_dormant_users | Active accounts with no recent login activity |
Data Query (2 tools)
| Tool | Description |
|---|
query_odata | Flexible OData queries with filtering, pagination |
get_picklist_values | Get dropdown/picklist options |
Employee Lookup (4 tools)
| Tool | Description |
|---|
get_employee_profile | Complete profile with job info, manager, optional compensation |
search_employees | Find by name, department, location, or manager |
get_employee_history | Job history — promotions, transfers, title changes |
get_team_roster | Manager's team with direct/indirect reports |
Time Off (3 tools)
| Tool | Description |
|---|
get_time_off_balances | Vacation, PTO, sick leave balances |
get_upcoming_time_off | Team absence calendar for a date range |
get_time_off_requests | Pending/approved time-off requests |
Hiring & Onboarding (3 tools)
| Tool | Description |
|---|
get_open_requisitions | Job requisitions with status and hiring manager |
get_candidate_pipeline | Candidates by stage for a requisition |
get_new_hires | Recent/upcoming hires for onboarding |
Compliance & Reporting (3 tools)
| Tool | Description |
|---|
get_terminations | Terminated employees for exit processing |
get_employees_missing_data | Incomplete profiles for compliance audits |
get_anniversary_employees | Upcoming work anniversaries for recognition |
Performance & Compensation (5 tools)
| Tool | Description |
|---|
get_performance_review_status | Review form completion across the org |
get_compensation_details | Pay breakdown with recurring/non-recurring components |
get_compensation_history | Full compensation change history (not just latest) |
get_compensation_review_status | Comp planning worksheet completion by manager/department |
get_salary_range_analysis | Compa-ratio: pay vs. grade midpoint |
Performance & Talent (4 tools)
| Tool | Description |
|---|
get_goal_summary | Employee goals — category, weight, completion |
get_development_plans | Development goals and learning activities |
get_talent_flags | Potential, flight risk, impact of loss, key position |
get_succession_nominees | Talent pool nominees for key positions |
Position Management (3 tools)
| Tool | Description |
|---|
get_position_details | Position with incumbent, department, FTE |
get_vacant_positions | Open positions for headcount planning |
get_org_chart | Org hierarchy from any position (up or down) |
MDF Objects (3 tools)
| Tool | Description |
|---|
get_mdf_object_definitions | List custom MDF objects and their fields |
query_mdf_object | Query any MDF/generic object (cust_*) |
get_foundation_objects | Query foundation objects (departments, cost centers, etc.) |
Workflow (2 tools)
| Tool | Description |
|---|
get_pending_approvals | Pending workflow items for a user or globally |
get_workflow_history | Audit trail of approval steps |
Monitoring & Admin (6 tools)
| Tool | Description |
|---|
get_alert_notifications | System alerts and notifications |
get_scheduled_job_status | Scheduled job run status |
get_integration_center_jobs | Integration Center job status |
get_api_quota_status | Rate limit usage per instance |
get_cache_status | Cache hit rates and entry counts |
clear_cache | Clear cached responses |
Employee Central (5 tools)
| Tool | Description |
|---|
get_global_assignments | International assignments — home/host details |
get_employee_documents | Documents attached to an employee's record |
get_pay_component_groups | Recurring pay elements (allowances, bonuses) |
get_work_permit_expiry | Work permits/visas expiring soon |
get_probation_end_dates | Employees approaching end of probation |
Data Management (3 tools)
| Tool | Description |
|---|
bulk_export_employees | Paginated full export of active employees |
get_picklist_usage | Which picklists are used on which entity fields |
get_country_specific_fields | Field population rates for a given country |
Installation
Prerequisites
- Python 3.10+
- uv package manager
- SAP SuccessFactors account with API access
Setup
git clone https://github.com/aiadiguru2025/sf-mcp.git
cd sf-mcp
uv sync
Quick Start
Development mode (MCP Inspector):
uv run mcp dev main.py
Stdio mode (Claude Desktop):
uv run main.py
HTTP mode (Cloud Run / remote):
PORT=8080 uv run main.py
Claude Desktop Integration
Step 1 — Find the path to uv
# macOS / Linux
which uv
# Windows (PowerShell)
Get-Command uv | Select-Object -ExpandProperty Source
Step 2 — Edit your Claude Desktop config
| OS | Config path |
|---|
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
Add the sf-mcp server:
{
"mcpServers": {
"sf-mcp": {
"command": "/path/to/uv",
"args": ["--directory", "/path/to/sf-mcp", "run", "main.py"]
}
}
}
Step 3 — Restart Claude Desktop
The MCP tools icon (hammer) will appear in the input area with all 62 tools available.
Note: Credentials (auth_user_id and auth_password) are provided on each tool call — nothing is stored in the config.
Deployment
Google Cloud Run
# Build and deploy
export PROJECT_ID=your-gcp-project-id
gcloud builds submit --tag gcr.io/$PROJECT_ID/sf-mcp
gcloud run deploy sf-mcp \
--image gcr.io/$PROJECT_ID/sf-mcp \
--platform managed \
--region us-central1
Then point Claude Desktop to the remote URL:
{
"mcpServers": {
"sf-mcp": {
"url": "https://sf-mcp-xxxxx-uc.a.run.app/mcp"
}
}
}
Docker (local)
docker build -t sf-mcp .
docker run -p 8080:8080 sf-mcp
API Key Protection (optional)
Set MCP_API_KEY to require authentication on the HTTP endpoint:
MCP_API_KEY=your-secret-key PORT=8080 uv run main.py
Clients must then include X-API-Key: your-secret-key in requests.
Configuration
All tool parameters (data_center, environment, auth_user_id, auth_password) are provided per-request. Server-side environment variables are optional:
Rate Limiting
| Variable | Default | Description |
|---|
SF_RATE_LIMIT | 100 | Max requests per window per instance |
SF_RATE_LIMIT_WINDOW | 60 | Window duration in seconds |
SF_RATE_LIMIT_WARN_THRESHOLD | 0.8 | Log warning at 80% usage |
SF_RATE_LIMIT_RETRY_AFTER | 5 | Seconds to wait on 429 retry |
SF_RATE_LIMIT_MAX_RETRIES | 3 | Max 429 retry attempts |
Response Caching
| Variable | Default | Description |
|---|
SF_CACHE_TTL_METADATA | 3600 | Metadata cache TTL (1 hour) |
SF_CACHE_TTL_SERVICE_DOC | 3600 | Service doc cache TTL (1 hour) |
SF_CACHE_TTL_PICKLIST | 1800 | Picklist cache TTL (30 min) |
SF_CACHE_TTL_PERMISSIONS | 3600 | Permission cache TTL (1 hour) |
SF_CACHE_TTL_DEFAULT | 0 | Default TTL (0 = disabled) |
SF_CACHE_MAX_ENTRIES | 1000 | Max cache entries before eviction |
Endpoint Protection
| Variable | Default | Description |
|---|
MCP_API_KEY | (none) | API key for HTTP endpoint auth |
Copy .env.example to .env to customize:
cp .env.example .env
Supported Data Centers
21 data centers across 6 continents with alias support:
| Data Center | Alias | Location | Environments |
|---|
| DC2 | DC57 | Netherlands | preview, production, sales_demo |
| DC4 | DC68 | Virginia, US | preview, production, sales_demo |
| DC8 | DC70 | Ashburn, Virginia, US | preview, production, sales_demo |
| DC10 | DC66 | Sydney, Australia | preview, production |
| DC12 | DC33 | Germany | preview, production |
| DC15 | DC30 | Shanghai, China | preview, production |
| DC17 | DC60 | Toronto, Canada | preview, production |
| DC19 | DC62 | Sao Paulo, Brazil | preview, production |
| DC22 | — | Dubai, UAE | preview, production |
| DC23 | DC84 | Riyadh, Saudi Arabia | preview, production |
| DC40 | — | — | sales_demo |
| DC41 | — | Virginia, US | preview, production |
| DC44 | DC52 | Singapore | preview, production |
| DC47 | — | Canada Central | preview, production |
| DC50 | — | Tokyo, Japan | preview, production |
| DC55 | — | Frankfurt, Germany | preview, production |
| DC74 | — | Zurich, Switzerland | preview, production |
| DC80 | — | Mumbai, India | preview, production |
| DC82 | — | Riyadh, Saudi Arabia | preview, production |
Architecture
sf-mcp/
├── main.py # Entry point (stdio + HTTP modes)
├── sf_mcp/
│ ├── server.py # FastMCP instance
│ ├── config.py # DC mappings, constants, env vars
│ ├── auth.py # Credential resolution, API key middleware
│ ├── client.py # HTTP client (OData, metadata, service doc, pagination)
│ ├── cache.py # TTL-based response cache with deep-copy safety
│ ├── rate_limiter.py # Sliding-window rate limiter (per-instance)
│ ├── validation.py # 10 input validators with registry pattern
│ ├── decorators.py # sf_tool decorator (cross-cutting concerns)
│ ├── dependencies.py # FastMCP DI for schema exclusion
│ ├── logging_config.py # Cloud Logging JSON formatter, audit_log()
│ ├── xml_utils.py # Safe XML parsing (defusedxml), SAP date parsing
│ └── tools/ # 62 tools across 16 modules
│ ├── configuration.py # get_configuration, compare_configurations, list_entities
│ ├── permissions.py # 7 RBP security tools
│ ├── audit.py # Role history, role assignment history
│ ├── query.py # query_odata, get_picklist_values
│ ├── employee.py # Profile, search, history, team roster
│ ├── time_off.py # Balances, upcoming absences, requests
│ ├── recruiting.py # Requisitions, pipeline, new hires
│ ├── compliance.py # Terminations, missing data, anniversaries, reviews, comp
│ ├── position.py # Position details, vacancies, org chart
│ ├── workflow.py # Pending approvals, workflow history
│ ├── mdf.py # MDF object definitions, queries, foundation objects
│ ├── monitoring.py # Alerts, scheduled jobs, integration jobs
│ ├── admin.py # Rate limit quota, cache status, cache clear
│ └── utils.py # Shared utilities (display_name)
├── tests/ # 110 tests
├── Dockerfile # Cloud Run container
├── .env.example # Configuration template
└── pyproject.toml # Project metadata, dependencies, linter config
Design Principles
Zero boilerplate — The sf_tool decorator handles request ID generation, timing, audit logging, input validation, credential checking, error handling, and $top clamping. Tool functions contain only business logic.
Secure by default — 10 input validators (regex allowlists), OData injection prevention, XXE-safe XML parsing (defusedxml), timing-safe API key comparison (hmac.compare_digest), and automatic credential masking in logs.
Production-ready — Connection pooling (requests.Session), mutation-safe response caching (deep-copy on put/get), sliding-window rate limiting with automatic 429 retry, and Cloud Logging-compatible JSON audit trail.
Schema-clean — Internal parameters (request_id, start_time, api_host) are hidden from the MCP tool schema via FastMCP's Dependency injection, keeping tool interfaces clean for LLM consumers.
Security
| Layer | Mechanism |
|---|
| Input validation | 10 regex-based validators; OData filter blocklist checks raw + URL-decoded + double-decoded input |
| Injection prevention | Entity paths, orderby, expand all validated; control characters rejected |
| Authentication | Per-request credentials (never stored); timing-safe API key comparison via hmac.compare_digest |
| XML safety | defusedxml prevents XXE, entity expansion, and DTD attacks |
| Audit logging | Every tool call logged with structured JSON; passwords automatically masked |
| Cache safety | Deep-copied on store and retrieval to prevent mutation bugs |
| Date handling | All SAP timestamp parsing uses explicit UTC to prevent timezone inconsistencies |
Testing
# Run all 110 tests
uv run pytest tests/ -v
# Run with coverage
uv run pytest tests/ --cov=sf_mcp
# Lint
uv run ruff check .
# Type check
uv run mypy sf_mcp/
Test coverage includes:
- Config — DC mapping resolution, case insensitivity, aliases, error cases
- Validation — All 10 validators with valid/invalid inputs, injection prevention
- Client — Mocked HTTP responses (200, 401, 500, empty, connection error)
- Rate limiter — Limit enforcement, sliding window, per-instance isolation, thread safety
- Cache — Put/get, TTL expiry, category TTLs, invalidation, eviction, deep-copy safety
- Pagination — Single/multi page, max_pages limit, error handling, $skip increments
- Decorators — Value injection, validation errors, max_top clamping, exception handling
API Reference
Every tool accepts these common parameters:
| Parameter | Type | Required | Description |
|---|
instance | string | Yes | SuccessFactors company ID |
data_center | string | Yes | SAP data center code (e.g., DC55, DC10) |
environment | string | Yes | preview, production, or sales_demo |
auth_user_id | string | Yes | SuccessFactors user ID (without @instance) |
auth_password | string | Yes | SuccessFactors password |
Configuration Tools
get_configuration
Retrieve OData metadata for a SuccessFactors entity.
| Parameter | Type | Required | Description |
|---|
entity | string | Yes | OData entity name (e.g., User, Position) |
list_entities
Discover all available OData entities in an instance.
| Parameter | Type | Required | Description |
|---|
category | string | No | foundation, employee, talent, platform, or all |
compare_configurations
Compare entity config between two instances (e.g., dev vs prod).
| Parameter | Type | Required | Description |
|---|
instance1 | string | Yes | First instance |
instance2 | string | Yes | Second instance |
entity | string | Yes | Entity to compare |
data_center1 | string | Yes | Data center for instance1 |
environment1 | string | Yes | Environment for instance1 |
data_center2 | string | Yes | Data center for instance2 |
environment2 | string | Yes | Environment for instance2 |
RBP Security Tools
get_rbp_roles
| Parameter | Type | Required | Description |
|---|
include_description | boolean | No | Include role descriptions (default: false) |
get_role_permissions
| Parameter | Type | Required | Description |
|---|
role_ids | string | Yes | Single or comma-separated: 10 or 10,20,30 |
locale | string | No | Locale for labels (default: en-US) |
get_user_permissions
| Parameter | Type | Required | Description |
|---|
user_ids | string | Yes | Single or comma-separated: admin or admin,user2 |
locale | string | No | Locale for labels (default: en-US) |
get_user_roles
| Parameter | Type | Required | Description |
|---|
user_id | string | Yes | User ID to look up roles for |
include_permissions | boolean | No | Also fetch permissions per role (default: false) |
get_permission_metadata
| Parameter | Type | Required | Description |
|---|
locale | string | No | Locale for labels (default: en-US) |
check_user_permission
| Parameter | Type | Required | Description |
|---|
access_user_id | string | Yes | User whose permission to check |
target_user_id | string | Yes | Target user of the permission |
perm_type | string | Yes | Permission type from metadata |
perm_string_value | string | Yes | Permission string value |
perm_long_value | string | No | Permission long value (default: -1L) |
get_dynamic_groups
| Parameter | Type | Required | Description |
|---|
group_type | string | No | Filter by group type |
Security & Audit Tools
get_role_history
| Parameter | Type | Required | Description |
|---|
role_id | string | No | Filter by role ID |
role_name | string | No | Filter by role name |
from_date | string | No | Start date (YYYY-MM-DD) |
to_date | string | No | End date (YYYY-MM-DD) |
top | integer | No | Max records (default: 100, max: 500) |
get_role_assignment_history
| Parameter | Type | Required | Description |
|---|
role_id | string | No | Filter by role ID |
user_id | string | No | Filter by user ID |
from_date | string | No | Start date (YYYY-MM-DD) |
to_date | string | No | End date (YYYY-MM-DD) |
top | integer | No | Max records (default: 100, max: 500) |
At least one of role_id or user_id is required.
get_login_audit_log
| Parameter | Type | Required | Description |
|---|
user_id | string | No | Filter to a single user's login history |
from_date | string | No | Start date (YYYY-MM-DD) |
to_date | string | No | End date (YYYY-MM-DD) |
top | integer | No | Max records (default: 100, max: 500) |
Requires the instance's Audit Trail / Login Tracking feature to be provisioned.
get_admin_audit_log
| Parameter | Type | Required | Description |
|---|
entity_name | string | No | Filter by entity/object name (e.g., RBPRole, User) |
changed_by | string | No | Filter by the admin who made the change |
from_date | string | No | Start date (YYYY-MM-DD) |
to_date | string | No | End date (YYYY-MM-DD) |
top | integer | No | Max records (default: 100, max: 500) |
Requires the instance's Audit Trail feature to be provisioned.
get_sod_violations
| Parameter | Type | Required | Description |
|---|
user_ids | string | Yes | Employee user ID(s), comma-separated (max 20) |
permission_pairs | string | No | Custom conflict pairs: "PermA|PermB,PermC|PermD". Defaults to a built-in list of common RBP conflicts |
get_dormant_users
| Parameter | Type | Required | Description |
|---|
dormant_days | integer | No | Flag users with no login in this many days (default: 90) |
department | string | No | Filter by department |
top | integer | No | Max records (default: 100, max: 500) |
Data Query Tools
query_odata
| Parameter | Type | Required | Description |
|---|
entity | string | Yes | Entity name or key: User or User('admin') |
select | string | No | Fields: userId,firstName,lastName |
filter | string | No | OData filter: status eq 'active' |
expand | string | No | Nav properties: empInfo,jobInfoNav |
top | integer | No | Max records (default: 100, max: 1000) |
skip | integer | No | Records to skip |
orderby | string | No | Sort: lastName asc |
paginate | boolean | No | Auto-fetch all pages (default: false) |
max_pages | integer | No | Max pages when paginating (default: 10, max: 50) |
get_picklist_values
| Parameter | Type | Required | Description |
|---|
picklist_id | string | Yes | Picklist ID: ecJobFunction, nationality |
locale | string | No | Locale for labels (default: en-US) |
include_inactive | boolean | No | Include inactive values (default: false) |
Employee Lookup Tools
get_employee_profile
| Parameter | Type | Required | Description |
|---|
user_id | string | Yes | Employee user ID |
include_compensation | boolean | No | Include compensation (default: false) |
search_employees
| Parameter | Type | Required | Description |
|---|
search_text | string | No | Partial name search |
department | string | No | Filter by department |
location | string | No | Filter by location |
manager_id | string | No | Filter to manager's reports |
status | string | No | active, inactive, or all (default: active) |
top | integer | No | Max results (default: 50, max: 200) |
get_employee_history
| Parameter | Type | Required | Description |
|---|
user_id | string | Yes | Employee user ID |
include_compensation_changes | boolean | No | Include salary history (default: false) |
get_team_roster
| Parameter | Type | Required | Description |
|---|
manager_id | string | Yes | Manager's user ID |
include_indirect_reports | boolean | No | Include reports-of-reports (default: false) |
top | integer | No | Max direct reports (default: 100, max: 200) |
Time Off Tools
get_time_off_balances
| Parameter | Type | Required | Description |
|---|
user_ids | string | Yes | Comma-separated user IDs (max 50) |
as_of_date | string | No | Balance as of date (YYYY-MM-DD) |
get_upcoming_time_off
| Parameter | Type | Required | Description |
|---|
start_date | string | Yes | Range start (YYYY-MM-DD) |
end_date | string | Yes | Range end (YYYY-MM-DD) |
department | string | No | Filter by department |
manager_id | string | No | Filter to manager's team |
status | string | No | approved, pending, or all (default: approved) |
top | integer | No | Max results (default: 200, max: 500) |
get_time_off_requests
| Parameter | Type | Required | Description |
|---|
user_id | string | No | Filter to employee |
status | string | No | pending, approved, rejected, cancelled, or all (default: pending) |
from_date | string | No | Submitted after date (YYYY-MM-DD) |
top | integer | No | Max results (default: 50, max: 200) |
Hiring & Onboarding Tools
get_open_requisitions
| Parameter | Type | Required | Description |
|---|
department | string | No | Filter by department |
hiring_manager_id | string | No | Filter by hiring manager |
location | string | No | Filter by location |
status | string | No | open, filled, closed, or all (default: open) |
top | integer | No | Max results (default: 100, max: 500) |
get_candidate_pipeline
| Parameter | Type | Required | Description |
|---|
requisition_id | string | Yes | Job requisition ID |
include_rejected | boolean | No | Include rejected candidates (default: false) |
top | integer | No | Max results (default: 100, max: 500) |
get_new_hires
| Parameter | Type | Required | Description |
|---|
start_date_from | string | Yes | Hires on/after date (YYYY-MM-DD) |
start_date_to | string | Yes | Hires on/before date (YYYY-MM-DD) |
department | string | No | Filter by department |
top | integer | No | Max results (default: 100, max: 500) |
Compliance & Reporting Tools
get_terminations
| Parameter | Type | Required | Description |
|---|
from_date | string | Yes | Range start (YYYY-MM-DD) |
to_date | string | Yes | Range end (YYYY-MM-DD) |
department | string | No | Filter by department |
top | integer | No | Max results (default: 100, max: 500) |
get_employees_missing_data
| Parameter | Type | Required | Description |
|---|
check_fields | string | Yes | Comma-separated: email, phone, address, emergency_contact |
department | string | No | Filter by department |
top | integer | No | Max results (default: 100, max: 500) |
get_anniversary_employees
| Parameter | Type | Required | Description |
|---|
from_date | string | Yes | Range start (YYYY-MM-DD) |
to_date | string | Yes | Range end (YYYY-MM-DD) |
milestone_years_only | boolean | No | Only 1, 5, 10, 15, 20, 25+ years (default: false) |
department | string | No | Filter by department |
top | integer | No | Max results (default: 100, max: 500) |
Performance & Compensation Tools
get_performance_review_status
| Parameter | Type | Required | Description |
|---|
form_template_id | string | No | Filter by form template |
department | string | No | Filter by department |
manager_id | string | No | Filter by manager |
status | string | No | not_started, in_progress, completed, or "" for all |
top | integer | No | Max results (default: 100, max: 500) |
get_compensation_details
| Parameter | Type | Required | Description |
|---|
user_ids | string | Yes | Comma-separated user IDs (max 20) |
effective_date | string | No | Compensation as of date (YYYY-MM-DD) |
get_compensation_history
| Parameter | Type | Required | Description |
|---|
user_id | string | Yes | The employee's user ID |
top | integer | No | Max history records (default: 50, max: 200) |
get_compensation_review_status
| Parameter | Type | Required | Description |
|---|
form_template_id | string | Yes | The compensation worksheet's form template ID |
department | string | No | Filter by department |
manager_id | string | No | Filter by manager |
status | string | No | not_started, in_progress, completed, or "" for all |
top | integer | No | Max results (default: 100, max: 500) |
get_salary_range_analysis
| Parameter | Type | Required | Description |
|---|
user_ids | string | Yes | Comma-separated user IDs (max 20) |
Returns compa-ratio (current salary ÷ grade midpoint × 100) per employee.
Performance & Talent Tools
get_goal_summary
| Parameter | Type | Required | Description |
|---|
user_id | string | Yes | The employee's user ID |
status | string | No | not_started, in_progress, completed, or "" for all |
top | integer | No | Max results (default: 100, max: 200) |
get_development_plans
| Parameter | Type | Required | Description |
|---|
user_id | string | Yes | The employee's user ID |
status | string | No | not_started, in_progress, completed, or "" for all |
top | integer | No | Max results (default: 100, max: 200) |
get_talent_flags
| Parameter | Type | Required | Description |
|---|
user_ids | string | Yes | Comma-separated user IDs (max 20) |
Field availability depends on the instance's Succession Data Model configuration.
get_succession_nominees
| Parameter | Type | Required | Description |
|---|
pool_id | string | No | Filter to nominees for a specific talent pool |
user_id | string | No | Filter to pools an employee is nominated to |
top | integer | No | Max results (default: 100, max: 200) |
Position Management Tools
get_position_details
| Parameter | Type | Required | Description |
|---|
position_id | string | Yes | Position ID |
get_vacant_positions
| Parameter | Type | Required | Description |
|---|
department | string | No | Filter by department |
location | string | No | Filter by location |
top | integer | No | Max results (default: 100, max: 500) |
get_org_chart
| Parameter | Type | Required | Description |
|---|
position_id | string | Yes | Starting position ID |
direction | string | No | down or up (default: down) |
levels | integer | No | Levels to traverse (default: 2, max: 5) |
MDF Object Tools
get_mdf_object_definitions
| Parameter | Type | Required | Description |
|---|
object_name | string | No | Specific MDF object (e.g., cust_myObject). Empty = list all. |
query_mdf_object
| Parameter | Type | Required | Description |
|---|
object_name | string | Yes | MDF object name (e.g., cust_myObject) |
select | string | No | Comma-separated fields |
filter | string | No | OData filter |
top | integer | No | Max results (default: 100, max: 500) |
skip | integer | No | Pagination offset |
orderby | string | No | Sort order |
effective_date | string | No | Effective date filter (YYYY-MM-DD) |
get_foundation_objects
| Parameter | Type | Required | Description |
|---|
object_type | string | Yes | company, department, division, location, cost_center, job_code, job_function, pay_grade, pay_group, business_unit, event_reason, legal_entity |
filter | string | No | Additional OData filter |
top | integer | No | Max results (default: 100, max: 500) |
include_inactive | boolean | No | Include end-dated records (default: false) |
Workflow Tools
get_pending_approvals
| Parameter | Type | Required | Description |
|---|
user_id | string | No | Filter to specific approver |
wf_request_id | string | No | Filter to specific workflow request |
top | integer | No | Max results (default: 100, max: 500) |
get_workflow_history
| Parameter | Type | Required | Description |
|---|
wf_request_id | string | Yes | Workflow request ID |
top | integer | No | Max results (default: 100, max: 500) |
Monitoring & Admin Tools
get_alert_notifications
| Parameter | Type | Required | Description |
|---|
from_date | string | No | Start date (YYYY-MM-DD) |
to_date | string | No | End date (YYYY-MM-DD) |
top | integer | No | Max results (default: 100, max: 500) |
get_scheduled_job_status
| Parameter | Type | Required | Description |
|---|
job_name | string | No | Filter by job name |
top | integer | No | Max results (default: 50, max: 500) |
get_integration_center_jobs
| Parameter | Type | Required | Description |
|---|
job_name | string | No | Filter by job name |
status | string | No | Filter by status |
top | integer | No | Max results (default: 50, max: 500) |
get_api_quota_status
Returns current rate limit usage for the specified instance.
get_cache_status
Returns cache hit rates, entry counts by category, and memory usage.
clear_cache
| Parameter | Type | Required | Description |
|---|
target_instance | string | No | Clear specific instance. Empty = clear all. |
Employee Central Tools
get_global_assignments
| Parameter | Type | Required | Description |
|---|
user_id | string | No | Filter to a single employee's assignment history |
active_only | boolean | No | Only currently active assignments (default: true) |
top | integer | No | Max results (default: 100, max: 200) |
get_employee_documents
| Parameter | Type | Required | Description |
|---|
user_id | string | Yes | The employee's user ID |
document_type | string | No | Filter by document type |
top | integer | No | Max results (default: 50, max: 100) |
get_pay_component_groups
| Parameter | Type | Required | Description |
|---|
user_id | string | Yes | The employee's user ID |
effective_date | string | No | Components as of date (YYYY-MM-DD) |
get_work_permit_expiry
| Parameter | Type | Required | Description |
|---|
within_days | integer | No | Flag permits/visas expiring within N days (default: 90) |
country | string | No | Filter by ISO country code |
top | integer | No | Max results (default: 100, max: 500) |
get_probation_end_dates
| Parameter | Type | Required | Description |
|---|
within_days | integer | No | Flag probation periods ending within N days (default: 30) |
department | string | No | Filter by department |
top | integer | No | Max results (default: 100, max: 500) |
Data Management Tools
bulk_export_employees
| Parameter | Type | Required | Description |
|---|
select | string | No | Comma-separated fields. Defaults to a standard field set |
department | string | No | Filter by department |
status | string | No | active, inactive, or all (default: active) |
top | integer | No | Records per page (default: 500, max: 1000) |
max_pages | integer | No | Max pages to fetch (default: 10, max: 50) |
get_picklist_usage
| Parameter | Type | Required | Description |
|---|
entities | string | No | Comma-separated entity names to scan. Defaults to a common set |
get_country_specific_fields
| Parameter | Type | Required | Description |
|---|
entity | string | Yes | OData entity to analyze (e.g., PerPersonal, PerNationalId) |
country | string | Yes | ISO country code to filter the sample |
sample_size | integer | No | Records to sample for population rates (default: 50, max: 200) |
Example Queries
Ask Claude in natural language:
| Query | Tool Used |
|---|
| "Show me all users in the Sales department" | search_employees |
| "What permissions does jsmith have?" | get_user_permissions |
| "Compare User config between dev and prod" | compare_configurations |
| "Who's on vacation next week?" | get_upcoming_time_off |
| "List all open job requisitions for Engineering" | get_open_requisitions |
| "How much PTO does jdoe have left?" | get_time_off_balances |
| "Show me all new hires starting in March" | get_new_hires |
| "Who has a 10-year anniversary this month?" | get_anniversary_employees |
| "What are the status of performance reviews for my team?" | get_performance_review_status |
| "Show John's complete job history" | get_employee_history |
| "What custom MDF objects exist in our instance?" | get_mdf_object_definitions |
| "List all departments with their cost centers" | get_foundation_objects |
| "Are there any pending workflow approvals?" | get_pending_approvals |
| "Check the status of our integration jobs" | get_integration_center_jobs |
Common SuccessFactors Entities
| Category | Entities |
|---|
| Employee | User, EmpEmployment, EmpJob, PerPersonal, PerPhone, PerEmail |
| Foundation | FOCompany, FODepartment, FOJobCode, FOLocation, FOPayGrade |
| Position | Position, PositionEntity, PositionMatrixRelationship |
| Talent | Goal, GoalPlan, PerformanceReview, Competency |
| Recruiting | JobRequisition, Candidate, JobApplication |
Use list_entities to discover all available entities in your instance.
Troubleshooting
Authentication Errors (HTTP 401)
- Verify credential format: user ID without
@instance
- Confirm the password is correct
- Ensure the API user has proper permissions in SuccessFactors Admin Center
Validation Errors
All inputs are validated to prevent injection attacks:
| Parameter | Rules |
|---|
instance | Alphanumeric, underscores, hyphens only |
entity | Valid OData entity name pattern |
filter | No blocked keywords ($batch, $metadata, <script>, etc.) |
locale | Format like en-US or de |
select / orderby | Valid field name patterns |
Server Disconnected (Claude Desktop)
- Verify
uv path in config is correct: which uv
- Check logs:
tail -f ~/Library/Logs/Claude/mcp*.log
- Test manually:
uv run mcp dev main.py
- Ensure Python 3.10+ is installed:
python3 --version
Rate Limit Errors
- The server auto-retries HTTP 429 responses (up to 3 times)
- Use
get_api_quota_status to check current usage
- Increase limits via
SF_RATE_LIMIT environment variable
- Cache responses with
SF_CACHE_TTL_DEFAULT to reduce API calls
Dependencies
| Package | Version | Purpose |
|---|
| fastmcp | >=2.0.0 | Model Context Protocol SDK |
| requests | >=2.31.0 | HTTP client with connection pooling |
| defusedxml | >=0.7.0 | XXE-safe XML parsing |
| python-dotenv | >=1.0.0 | Environment variable loading |
| uvicorn | >=0.30.0 | ASGI server for HTTP transport |
Dev dependencies: pytest, ruff, mypy
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature
- Run tests:
uv run pytest tests/ -v
- Run linting:
uv run ruff check .
- Commit your changes
- Open a Pull Request
Changelog
See CHANGELOG.md for release history.
License
This project is licensed under the MIT License — see the LICENSE file for details.
Built with FastMCP ·
Powered by Model Context Protocol