An MCP (Model Context Protocol) server that exposes the 1Password Device Trust API (formerly Kolide K2) as tools for AI agents. Uses Streamable HTTP transport for communication.
- Full coverage of 1Password Device Trust (Kolide K2) API endpoints (57 endpoint tools + 3 composite analytical tools)
- Auto-pagination (
fetch_all) to retrieve complete datasets in a single tool call - Field projection (
fields) to return only the columns you need, reducing response size - Device owner enrichment (
enrich_device_owner) to automatically resolve device IDs to owner names/emails - Composite analytical tools for common aggregation tasks (resolution time stats, grouped counts)
- Dynamic reporting table validation — table names are fetched from the API at startup and refreshable on demand
- MCP Resources providing search syntax docs, reporting table guides, and workflow references
- Bearer token authentication on all MCP endpoints
- Structured JSON audit logging of every tool invocation
- Binds to localhost only by default; configurable CORS allowlist
- Streamable HTTP transport for easy integration with AI tools
- API key and Kolide API version (
KOLIDE_API_VERSION) read fresh on each request (supports.envupdates without restart)
The server does not load OpenAPI at runtime. Tools are defined in src/kolide_mcp/endpoints.py (ENDPOINTS), and the HTTP client sends x-kolide-api-version from get_kolide_api_version() in src/kolide_mcp/api_version.py (overridable via KOLIDE_API_VERSION in your environment or .env).
Workflow when the Kolide API changes:
-
openapi/— Treatopenapi/openapi*.jsonas the canonical REST contract snapshot. There is one file per supported version (e.g.openapi2026-04-07.json); CI checksENDPOINTSagainst all of them. -
Implementation — For any real API delta reflected in those JSON files, update
ENDPOINTS(andcomposite_tools.py/resources.pyif needed). SetKOLIDE_API_VERSIONin.envto the version line you run against. -
Verification — CI runs drift checks so
ENDPOINTSstays aligned with the pinned OpenAPI file (path templates are compared with parameter names ignored). To run the same tests locally afteruv sync:uv run python -m unittest discover -s tests -v
If the pinned OpenAPI file gains operations you do not want as MCP tools yet, add the normalized (METHOD, path) pair to OPENAPI_OPERATIONS_WITHOUT_MCP_TOOL in tests/test_openapi_drift.py and document why.
Endpoints that exist only on some API versions
Kolide may expose routes on one dated API line but not another. In EndpointSpec, set api_versions to a frozenset of version strings (must be a subset of SUPPORTED_KOLIDE_API_VERSIONS in api_version.py):
api_versions=None(default) — tool is listed and callable for every supported version, as long as that version’s OpenAPI snapshot includes the operation.api_versions=frozenset({"2026-04-07"})— tool appears inlist_toolsand works only whenKOLIDE_API_VERSIONis2026-04-07; other versions skip it in drift checks and get a clear error if invoked anyway.
After adding a new version line to the server, extend SUPPORTED_KOLIDE_API_VERSIONS, add openapi<version>.json, and adjust api_versions on affected specs.
cd /path/to/k2_api_mcp
uv synccd /path/to/k2_api_mcp
pip install -e .Copy the example and fill in your values:
cp .env.example .envRequired variables:
| Variable | Description |
|---|---|
KOLIDE_API_KEY |
Your Kolide API key (Dashboard > Settings > API Keys) |
MCP_AUTH_TOKEN |
Bearer token for MCP endpoint access. Generate one with: python -c "import secrets; print(secrets.token_hex(32))" |
Optional variables:
| Variable | Default | Description |
|---|---|---|
KOLIDE_API_URL |
https://api.kolide.com |
Kolide API base URL (unusual to override). |
KOLIDE_API_VERSION |
2026-04-07 |
Set in .env to pin the dated Kolide API line. Must be one of the values in SUPPORTED_KOLIDE_API_VERSIONS. Sent as X-Kolide-Api-Version on every upstream request. Use the older supported API version only if you depend on the older API contract. |
MCP_HOST |
127.0.0.1 |
Bind address. Only change if you need remote access. |
MCP_PORT |
8000 |
Listen port |
MCP_CORS_ALLOWED_ORIGINS |
http://localhost,http://127.0.0.1 |
Comma-separated origins for browser-based MCP clients |
MCP_MAX_ENRICH_RECORDS |
500 |
Max records enriched per enrich_device_owner call |
MCP_LOG_FILE |
(unset) | File path for structured audit logs (in addition to stdout) |
MCP_DEBUG |
false |
Starlette debug mode (development only) |
The Kolide API key and API version header are read fresh on each tool call (using your .env if present), so you can change KOLIDE_API_KEY or KOLIDE_API_VERSION without restarting the server.
uv run kolide-mcppython -m kolide_mcp.serverThe server will start and display:
Starting 1Password Device Trust MCP server on 127.0.0.1:8000
MCP endpoint: http://127.0.0.1:8000/mcp
Health check: http://127.0.0.1:8000/health
Note: The server refuses to start if
MCP_AUTH_TOKENis not set.
Tip: Drop-in example configs live in
.cursor.example/,.claude.example/, and.vscode.example/at the repo root. Copy the one you need into place (e.g.cp -r .cursor.example .cursor) instead of writing the JSON by hand, then replaceyour-mcp-auth-token-herewith yourMCP_AUTH_TOKEN.
Add to .cursor/mcp.json in your project or global config:
{
"mcpServers": {
"kolide": {
"url": "http://localhost:8000/mcp",
"headers": {
"Authorization": "Bearer YOUR_MCP_AUTH_TOKEN"
}
}
}
}Claude Desktop's claude_desktop_config.json only supports stdio (subprocess) servers — it does not connect to remote HTTP URLs configured in the JSON file. To bridge the gap, use mcp-remote, which wraps the HTTP server as a stdio process that Claude Desktop can manage.
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"kolide": {
"command": "npx",
"args": [
"-y", "mcp-remote",
"http://localhost:8000/mcp",
"--header", "Authorization: Bearer YOUR_MCP_AUTH_TOKEN"
]
}
}
}Requires VS Code 1.99+ with MCP support. Add to .vscode/mcp.json in your project, then open the Copilot Chat panel in Agent mode:
{
"servers": {
"kolide": {
"type": "http",
"url": "http://localhost:8000/mcp",
"headers": {
"Authorization": "Bearer YOUR_MCP_AUTH_TOKEN"
}
}
}
}Connect to the MCP endpoint at http://localhost:8000/mcp with an Authorization: Bearer <token> header. The server uses the Streamable HTTP transport. Clients that only support stdio can use mcp-remote as shown in the Claude Desktop example above.
Replace YOUR_MCP_AUTH_TOKEN in all examples with the same value you set in MCP_AUTH_TOKEN.
All paginated list tools support these additional parameters that significantly reduce the number of tool calls needed for analytical queries.
Automatically follow all pagination cursors and return the complete result set in a single response. Capped at 10,000 records or 50 pages.
{
"table_name": "device_chrome_extensions",
"fetch_all": true
}Return only specified fields in each record, reducing response size dramatically for tables with large payloads.
{
"table_name": "device_chrome_extensions",
"fetch_all": true,
"fields": ["device_id", "device_name", "name", "identifier"]
}Automatically resolve device_id or device_information fields to the registered owner's name and email. Injects owner_name and owner_email into each record.
{
"query": "check_id:\"27680\"",
"fetch_all": true,
"enrich_device_owner": true
}The server exposes 60 tools: 57 endpoint tools covering all API functionality, plus 3 composite/utility tools.
kolide_issue_resolution_stats- Compute resolution time statistics (avg, median, min, max, p90) for issues of a specific check. Automatically fetches all pages.kolide_count_table_records_by_field- Count records in a reporting table grouped by a field. Returns ranked results. Useful for "which device has the most extensions?" style questions.kolide_refresh_reporting_tables- Refresh the cached list of valid reporting table names from the API. Use if a table name is unexpectedly rejected.
kolide_whoami- Get organization information
kolide_list_devices- List all deviceskolide_get_device- Get device detailskolide_delete_device- Delete a devicekolide_get_device_open_issues- Get open issues for a devicekolide_update_device_authentication_mode- Update device auth modekolide_delete_device_registration- Delete device registrationkolide_create_check_refresh- Trigger check refresh on devicekolide_get_device_check_results- Get check results for device
kolide_list_device_groups- List device groupskolide_get_device_group- Get device group detailskolide_list_device_group_devices- List devices in a groupkolide_add_device_to_group- Add device to groupkolide_remove_device_from_group- Remove device from group
kolide_list_people- List all peoplekolide_get_person- Get person detailskolide_list_person_devices- List devices for a personkolide_list_person_issues- List open issues for a personkolide_list_person_groups_for_person- List groups a person belongs tokolide_list_deprovisioned_people- List deprovisioned people
kolide_list_person_groups- List person groupskolide_get_person_group- Get person group detailskolide_list_person_group_people- List people in a group
kolide_list_issues- List all issueskolide_get_issue- Get issue details
kolide_list_checks- List security checkskolide_get_check- Get check detailskolide_get_check_results- Get results for a checkkolide_get_check_configuration- Get check configurationkolide_update_check_configuration- Update check configuration
kolide_list_live_query_campaigns- List live query campaignskolide_get_live_query_campaign- Get campaign detailskolide_create_live_query_campaign- Create new osquery campaignkolide_update_live_query_campaign- Update campaignkolide_delete_live_query_campaign- Delete campaignkolide_get_live_query_results- Get campaign results
kolide_list_exemption_requests- List exemption requestskolide_get_exemption_request- Get request detailskolide_update_exemption_request- Approve/deny request
kolide_list_registration_requests- List registration requestskolide_get_registration_request- Get request detailskolide_update_registration_request- Update request
kolide_list_packages- List software packageskolide_get_package- Get package details
kolide_list_admin_users- List admin userskolide_get_admin_user- Get admin user details
kolide_list_audit_logs- List audit logskolide_get_audit_log- Get audit log details
kolide_list_auth_logs- List auth log sessionskolide_get_auth_log- Get auth log details
kolide_list_reporting_tables- List available reporting tableskolide_get_reporting_table- Get table schemakolide_get_table_records- Fetch records from a tablekolide_list_report_queries- List saved report querieskolide_get_report_query- Get query detailskolide_get_report_query_results- Execute and get query results
The server exposes three reference documentation resources that AI agents can read for context:
| Resource URI | Description |
|---|---|
kolide://docs/search-syntax |
Full search query syntax with operators, field names per endpoint, and examples |
kolide://docs/reporting-tables |
Overview of reporting tables with efficient querying tips |
kolide://docs/workflows |
Step-by-step guides for common analytical tasks |
Many list tools support a query parameter for filtering. The query syntax uses:
:for exact matches (e.g.,status:"fail")~for substring matches (e.g.,name~"MacBook")>/<for datetime comparisons (e.g.,detected_at>"2025-01-01T00:00:00Z")AND/ORto combine clauses
Each tool's description includes the searchable fields and examples for that endpoint.
List tools return paginated results. Use the cursor from the response to fetch the next page, or set fetch_all: true to retrieve all pages automatically:
{
"cursor": "next_page_cursor",
"per_page": 25
}The server provides a health endpoint at http://localhost:8000/health that returns:
{"status": "ok"}MIT