Jamf Platform Server
БесплатноНе проверенMCP server giving AI assistants read-only access to a Jamf fleet via the Jamf Platform API Gateway using OAuth2 client credentials, with tools for fleet overvie
Описание
MCP server giving AI assistants read-only access to a Jamf fleet via the Jamf Platform API Gateway using OAuth2 client credentials, with tools for fleet overview, device queries, group membership, automation auditing, and passthrough requests.
README
An MCP server that gives AI assistants read access to a Jamf fleet through the
Jamf Platform API Gateway, authenticating with OAuth 2.0 client credentials
rather than user-account tokens. That choice is the point of the project: scoped
machine credentials mean the permission boundary is enforced by Jamf, so a
read-only integration cannot mutate a fleet no matter what this code does. See
JPM-0001.
Canonical location: github.com/jackvaughanjr/jamf-platform-mcp-server.
Tier: Prototype — no production dependants, upstream API in public beta, minor versions may break.
The upstream API is a public beta. The Platform API Gateway has no published breaking-change protocol and no announced GA date. Pin dependencies and expect churn. One documented API group (Compliance Benchmarks) currently returns a gateway-side 500 (JPM-0006).
Provenance
This is an independent project, not a fork or a derivative. No shared git history, no upstream remote, and no copied code.
It is worth naming an influence, though: evaluating dbankscard/jamf-mcp-server (MIT) is what surfaced the compound-tool idea used here: answering a whole fleet question in one call rather than making a model loop over per-device requests. That is a design idea, freely reusable and not subject to any licence term, so this credit is courtesy rather than obligation and carries no requirement onward to anyone using this project. Reasoning: JPM-0002.
Related work worth knowing about:
- Jamf-Concepts/mcp-hub — Jamf's own open-source MCP server (Python, Beta) for Jamf Pro, Protect and Security Cloud
- developer.jamf.com/mcp — Jamf-hosted MCP server for documentation search, not tenant management
Structure
src/
index.ts MCP server: tool registration, stdio transport
platform-client.ts every gateway concern — auth, token cache, URL shapes, paging
config.ts environment validation (zod)
fleet.ts pure fleet aggregation — no client, no clock, no I/O
automations.ts script/policy auditing, criteria projection, inventory cost
declaration-scope.ts pure DDM rollup: one declaration across many devices
references.ts pure reference analysis + smart-group dependency graph
*.test.ts unit tests (vitest)
decisions/ architectural decision records, JPM- prefix, immutable
docs/
capabilities.md what the server can answer, by question rather than endpoint
gateway-reference.md observed gateway behaviour: paths, status semantics, paging
endpoint-inventory.md documented endpoint surface, compiled from Jamf's llms.txt
fixtures/
shapes/ type-only response schemas — committed
raw/ captured responses — GITIGNORED, live fleet data
discovery-report.md empirical record of what resolves
scripts/
discover-gateway.sh resolves service segments, enumerates hosting, derives shapes
fetch-blueprints.sh standalone Blueprints smoke test
jamf cwd-independent wrapper: scripts/jamf <tool> ['<json>']
call-tool.mjs calls one MCP tool live; inherits env so `op run` works
check-adr-immutability.sh
.githooks/pre-commit rejects force-added ignored files; enforces ADR immutability
Current state (as of 2026-08-06)
Working and confirmed against a live tenant:
| segment | style | resource | notes |
|---|---|---|---|
blueprints |
tenant | blueprints |
totalCount-only envelope |
blueprints |
tenant | blueprint-components |
records keyed identifier, not id |
devices |
tenant | devices |
full paging envelope; spans macOS and iOS |
device-groups |
tenant | device-groups |
full envelope; exposes memberCount |
pro |
tenant | 300+ resources | the Jamf Pro API in full |
proclassic |
classic | /tenant/{t}/{resource} |
Jamf Pro Classic — no version segment |
ddm/report |
tenant | devices/{id}/channels |
Declaration Reporting |
ddm/report |
tenant | devices/{id}/declarations |
per-device declaration state; filter required |
ddm/report |
tenant | declarations/{id}/devices |
the same state per declaration, across devices |
Compliance Benchmarks has a correct, documented path but returns 500
{"error":"Upstream host lookup failed"}. The gateway routes it and cannot reach
its own backend. A fault on Jamf's side, not something a client can work around.
An earlier revision of this file claimed Classic, Declaration Reporting and Compliance Benchmarks were simply not exposed. That was wrong; see JPM-0006, which supersedes JPM-0005 and explains how the error happened.
Tools: getFleetOverview, findDevices, findOutdatedDevices, findDeviceGroups,
getDeviceGroupMembers, findExpensiveAutomations, getInventoryCollectionSettings
and findCriteriaReferences (compound), listBlueprints and
getDeviceDeclarationState, getDeclarationScope, findObjectReferences and
findGroupDependencies and getComputerGroup (typed), and
platformRequest (authenticated GET-only passthrough to any gateway route). Tool
count stays deliberately small
(JPM-0003).
Pagination is confirmed live: a real page-1 request returned different records with
hasPrevious: true and totalPages: 13, so page is 0-based as assumed and query
parameters survive the passthrough.
device-actions remains unverified, because every route in it is a write and no
write scopes have been granted.
Setup
npm install # also points core.hooksPath at .githooks
cp .env.op.example .env.op # edit to match your 1Password vault/item
npm run build
Create an integration in Jamf Account → Integrations. A read-only integration is sufficient and strongly preferred. The client secret is shown exactly once.
| Variable | Required | Notes |
|---|---|---|
JAMF_CLIENT_ID |
yes | from the integration |
JAMF_CLIENT_SECRET |
yes | shown once at creation |
JAMF_TENANT_ID |
yes | appears in every gateway path |
JAMF_GATEWAY_BASE_URL |
no | defaults to https://us.apigw.jamf.com |
JAMF_TOKEN_URL |
no | defaults to <base>/auth/token |
JAMF_READ_ONLY |
no | defaults to true; a backstop, not the guarantee |
Write posture
A read-only integration (above) is this project's supported configuration, not a starter mode to graduate from (JPM-0007). Scopes that can erase or unmanage a device are never granted to this server — not gated, not granted, in any configuration. That work belongs in Jamf Pro's own interface, where it is attributed to a named person and lands in Jamf's audit log.
JAMF_READ_ONLY above is a backstop, not the guarantee: it is on unless the value
is the literal string false, so a typo fails closed. The real boundary is what
the credential's scopes permit, which Jamf enforces, not this code. A fork that
grants write scopes is making that decision, and owns what follows from it.
platformRequest offers no method or body parameter, so the passthrough cannot
express a mutation at all, not even with write scopes granted. A passthrough write
is unreviewable in a way a typed tool's write is not, since method, path and body
would all be caller-composed with no schema constraining any of them. Any future
write is a named tool with a narrow schema, so the set of possible mutations stays
enumerable by reading src/index.ts.
Credentials are injected at runtime so the secret never lands on disk:
op run --env-file=.env.op -- npm run dev
Register with Claude Code
claude mcp add jamf-platform -- node /absolute/path/to/dist/index.js
Conventions
- ISO dates (
YYYY-MM-DD) everywhere, including in dated snapshots above. - ADRs are immutable once committed. Correct one by superseding it, never by
editing. Enforced by
scripts/check-adr-immutability.shvia the pre-commit hook;ADR_ALLOW_EDIT=1covers the sanctioned exceptions. Prefix:JPM-. - Decisions vs findings.
decisions/holds decisions and is immutable.docs/gateway-reference.mdholds observations about a beta API and is expected to change. Do not mix them. - Never
git add -f. The ignore list is a data-handling boundary guarding the client secret and captured fleet data; a pre-commit hook enforces it. - Never commit a captured API response. Only type-only shapes (JPM-0004).
- Confirm routes empirically. A Jamf docs section is not evidence a route exists. The documentation has been wrong about this gateway four times, each retraction recorded in docs/gateway-reference.md.
- Commit messages explain why, and state explicitly when they retract an earlier conclusion. Descriptive imperative subjects; not Conventional Commits, which is why there is no badge claiming otherwise.
Versioning
SemVer 2.0.0. package.json is the single
source of the version. Changes are recorded in
CHANGELOG.md per Keep a Changelog.
Releases are tagged vX.Y.Z.
While the gateway remains in public beta, minor versions may carry breaking changes, because the upstream contract offers no stability guarantee, so strict SemVer against it would be a false promise.
Testing
npm test # vitest, 270 tests
npm run typecheck
DRY_RUN=1 ./scripts/discover-gateway.sh # probe matrix, no credentials needed
To exercise a tool against a live tenant, from any directory:
scripts/jamf tools/list
scripts/jamf getFleetOverview
scripts/jamf findDevices '{"query":"MacBook"}'
scripts/jamf wraps op run with an absolute --env-file path, because op
resolves that against the caller's cwd and fails with a bare "open .env.op: no such
file or directory" otherwise. It also unsets OP_SERVICE_ACCOUNT_TOKEN, which the
committed .envrc handles inside the repo but cannot outside it, and resolves
symlinks so it can be linked onto PATH for a shorter handle:
ln -s "$PWD/scripts/jamf" ~/.local/bin/jamf-mcp
jamf-mcp getFleetOverview
Not npm run inspector under op run. The MCP Inspector spawns the server as
a child process without forwarding the parent environment, so injected credentials
never reach it and the server exits on config validation. Its -e flag would work
but puts the client secret on a command line where ps can read it.
scripts/call-tool.mjs spawns the server with the environment inherited, so
credentials go straight to the process that needs them. Its output can contain live
fleet data, so redirect to a gitignored path if you keep it.
Tests never reach the gateway: fetch is stubbed per test and credentials are
fixtures. The suite is mutation-checked rather than assumed useful: each of these
deliberate breakages causes failures: removing the totalCount pagination
fallback, making paging 1-based, disabling the read-only guard, misclassifying
iPads as Macs, treating an unparseable timestamp as a recent check-in, letting an
empty search query match every device, and counting an absent managed flag as
unmanaged.
The contribution contract
CONTRIBUTING.md is written as a contract, separating what a guard will stop you doing from what a human reviews. Three rules are mechanically enforced by a pre-commit hook and by CI:
| Rule | Enforced by |
|---|---|
| No live identifiers in tracked files — including test fixtures | scripts/check-no-identifiers.sh |
No captured API responses committed; never git add -f |
.githooks/pre-commit |
| Committed ADRs are immutable — supersede, never edit | scripts/check-adr-immutability.sh + CI base-branch diff |
src/conventions.test.ts additionally asserts the conventions that drifted during
early development: the test-count badge matches reality, ADR numbering is sequential
and fully indexed, every superseded record names its successor, and the README does
not cite a superseded ADR as guidance.
Test UUIDs use the reserved deadbeef- prefix, so an identifier copied out of live
output is visible rather than plausible. That rule exists because a real device id
reached a test file exactly that way.
Pull request and review policy
Single maintainer at present, so changes land directly on main. On a second
contributor: branch protection on main, one non-author approval, and
decisions/ changes reviewed by someone other than the author.
Every change should pass npm test, npm run typecheck, and npm run build.
Anything touching src/platform-client.ts should also be exercised against a live
tenant, since no test can confirm the gateway's actual behaviour.
Cross-reference
- CONTRIBUTING.md — setup, enforced rules, how to add an endpoint
- CLAUDE.md — working rules for AI assistants in this repo
- decisions/ — why the project is built this way
- docs/gateway-reference.md — observed gateway behaviour
- docs/capabilities.md — what the server can answer, and what it cannot
- docs/endpoint-inventory.md — documented endpoint surface
- fixtures/discovery-report.md — empirical results
License
MIT — see LICENSE.
Установка Jamf Platform Server
У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.
▸ github.com/jackvaughanjr/jamf-platform-mcp-serverFAQ
Jamf Platform Server MCP бесплатный?
Да, Jamf Platform Server MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для Jamf Platform Server?
Нет, Jamf Platform Server работает без API-ключей и переменных окружения.
Jamf Platform Server — hosted или self-hosted?
Доступен hosted-вариант: Unyly запускает сервер в облаке, локальная установка не обязательна.
Как установить Jamf Platform Server в Claude Desktop, Claude Code или Cursor?
Открой Jamf Platform Server на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
Fetch
Web content fetching and conversion for efficient LLM usage.
AWS KB Retrieval
Retrieval from AWS Knowledge Base using Bedrock Agent Runtime.
автор: modelcontextprotocolSpring AI MCP Server
Provides auto-configuration for setting up an MCP server in Spring Boot applications.
llm-analysis-assistant
A very streamlined mcp client that supports calling and monitoring stdio/sse/streamableHttp, and can also view request responses through the /logs page. It also
автор: xuzexin-hzCompare Jamf Platform Server with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории ai
