A GraphQL API wrapper for SOTI MobiControl REST API, built with Strawberry GraphQL and FastAPI. Types and endpoints are based on the official MobiControl Swagger specification.
- GraphQL API - Query MobiControl resources using GraphQL
- Type-safe - Built with Strawberry GraphQL for full type safety
- Async - Fully async implementation for optimal performance
- Paginated - Built-in pagination support for all list queries
- GraphiQL - Interactive GraphQL playground in development mode
- Swagger-based - Types match the official SOTI MobiControl API specification
- Secure - Production-hardened with query limits, input validation, and error masking
- Devices - Query device information based on
DeviceBaseschema - Device Groups - Query device group hierarchy (regular and virtual groups)
- Profiles - Query configuration profiles (
ProfileSummaryschema) - Packages - Query managed packages and versions
- Python 3.11+
- uv package manager
- SOTI MobiControl server with API access
# Clone the repository
git clone <repository-url>
cd soti-mobicontrol-graphql-wrapper
# Install dependencies
uv sync
# Copy environment template
cp .env.example .env
# Edit .env with your MobiControl credentialsEdit .env with your SOTI MobiControl settings:
ENVIRONMENT=dev
MOBICONTROL_BASE_URL=https://your-mobicontrol-server/MobiControl
MOBICONTROL_CLIENT_ID=your_client_id
MOBICONTROL_CLIENT_SECRET=your_client_secretSee Environment Modes for details on
devvsprodbehavior.
# Development mode (with auto-reload)
uv run uvicorn app.main:app --reload
# Or run directly
uv run python -m app.mainThe server will start at http://localhost:8000:
- GraphQL endpoint:
http://localhost:8000/graphql - GraphiQL playground:
http://localhost:8000/graphql(in dev mode) - API docs:
http://localhost:8000/docs
query {
devices(take: 10) {
items {
deviceId
deviceName
platform
isAgentOnline
}
hasMore
totalCount
}
}query {
device(deviceId: "abc-123-def") {
deviceId
deviceName
manufacturer
model
osVersion
customAttributes {
name
value
}
}
}query {
deviceBySerialNumber(serialNumber: "ABC12345DE") {
deviceId
deviceName
hardwareSerialNumber
model
}
}query {
deviceGroups(path: "\\Root") {
items {
name
path
kind
}
hasMore
}
}query {
profiles(forFamilies: "AndroidPlus", withStatuses: "Active") {
items {
name
referenceId
deviceFamily
status
}
hasMore
}
}query {
packages(deviceFamilies: "AndroidPlus") {
items {
name
referenceId
deviceFamily
totalVersions
}
hasMore
}
}For more examples, see Full Documentation.
uv run pytestsoti-mobicontrol-graphql-wrapper/
├── app/
│ ├── main.py # FastAPI app entry point
│ ├── config.py # Environment configuration
│ ├── client/
│ │ ├── auth.py # OAuth2 token management
│ │ └── mobicontrol.py # REST API client
│ ├── schema/
│ │ ├── types/ # GraphQL types (Device, DeviceGroup, Profile, Package)
│ │ └── queries.py # Root Query definition
│ └── resolvers/ # Query resolvers
├── docs/ # Documentation
│ ├── DOCS.md # Full API documentation
│ └── SECURITY.md # Security documentation
├── tests/ # Test suite
└── soti-mobicontrol-swagger.json # API specification
Core device properties including:
- Identifiers:
deviceId,deviceName,hostName - Classification:
kind,family,platform,mode - Hardware:
manufacturer,model,osVersion - Network:
macAddress,wifiMac,bluetoothMac,vpnIp - Status:
isAgentOnline,complianceStatus,compliancePolicyStatus - Enrollment:
enrollmentType,enrollmentTime - Azure:
azureDeviceId,azureRegistrationStatus,azureComplianceStatus - Custom:
customAttributes,complianceItems
name,path,referenceIdicon(Yellow, Red, Green, Blue, Purple, Cyan, None)kind(Regular, Virtual)- Virtual groups include
filterexpression
name,referenceId,descriptiondeviceFamily,status- Version info:
activeVersionNumber,draftVersionNumber - Audit:
createdDate,lastModified,lastModifiedBy
name,referenceId,deviceFamilytotalVersions,lastVersion(with version details)- Audit:
createdDate,createdBy
The wrapper uses OAuth2 client credentials flow to authenticate with the SOTI MobiControl REST API. You need to:
- Generate an API client in SOTI MobiControl
- Set the client ID and secret in your
.envfile
The token is automatically refreshed when it expires.
This wrapper includes production-grade security features:
- Query Depth Limiting - Prevents deeply nested queries (max 6 levels)
- Query Cost Analysis - Rejects expensive queries that could cause DoS
- Introspection Control - Disabled in production to prevent schema reconnaissance
- Input Validation - All inputs validated with Pydantic
- Injection Prevention - URL-encoded path parameters
- Error Masking - Internal errors hidden in production
- Security Headers - HSTS, CSP, X-Frame-Options, etc.
For detailed security documentation, see SECURITY.md.
MIT