Skip to content

Connect Jamf to AI Agents: Automate Device and User Lifecycles

Learn how to connect Jamf to AI agents using Truto's tools endpoint. Automate MDM workflows, handle Jamf API quirks, and bind tools to LLMs natively.

Uday Gajavalli Uday Gajavalli · · 10 min read
Connect Jamf to AI Agents: Automate Device and User Lifecycles

If your team uses ChatGPT in their daily operations, check out our guide on connecting Jamf to ChatGPT. For teams orchestrating specialized device compliance audits with Anthropic's models, read our guide on connecting Jamf to Claude. For developers building custom autonomous workflows across their infrastructure, you need a programmatic way to fetch AI-ready Jamf tools and bind them to your agent framework.

IT automation is shifting from deterministic bash scripts to agentic AI. You no longer want to just trigger a script when a user is deactivated in your HRIS; you want an autonomous system that can read the context of an offboarding ticket, query Jamf for the user's assigned devices, check the status of those devices, orchestrate a remote lock, and log the asset recovery status back to your helpdesk.

Giving a Large Language Model (LLM) read and write access to your Jamf instance is a serious engineering undertaking. You either spend weeks building, hosting, and maintaining a custom Mobile Device Management (MDM) connector, or you rely on an integration infrastructure layer that abstracts the boilerplate.

This guide breaks down exactly how to use Truto's /tools endpoint to generate AI-ready tools for Jamf, bind them natively to your LLM using frameworks like LangChain, LangGraph, or Vercel AI SDK, and execute complex device and user lifecycle workflows autonomously. For more context on this architectural approach, review our essay on architecting AI agents and the SaaS integration bottleneck.

The Engineering Reality of the Jamf API

Building AI agents is the easy part. Connecting them to external enterprise APIs is where the architecture breaks down. Giving an LLM access to external MDM data sounds simple in a local prototype: you write a Node.js function that makes a fetch request to Jamf and wrap it in an @tool decorator. In production, this approach collapses entirely.

If you decide to build a custom integration for Jamf, you own the entire API lifecycle. You have to handle legacy authentication methods. You have to write and maintain massive JSON schemas for every endpoint you want the LLM to access.

The Jamf API introduces several specific integration challenges that make it uniquely hostile to standard LLM tool calling:

The Pro API vs. Classic API Split

Jamf actually operates two parallel APIs. The legacy Classic API (which heavily utilized XML and basic authentication before transitioning to Bearer tokens) and the newer Jamf Pro API (which uses standard JSON and OAuth-style Bearer tokens). Depending on what you are trying to automate - for example, querying mobile device extension attributes vs. issuing an MDM command - you may need to cross the streams between these two APIs. Standard LLMs do not understand this historical context. If you expose raw Jamf documentation to an LLM, it will frequently hallucinate XML payloads for JSON endpoints, causing silent failures in your automation pipeline.

Complex Extension Attributes

Jamf relies heavily on Extension Attributes to store custom data about computers and mobile devices. These are not flat key-value pairs appended to a JSON object. They are deeply nested arrays of objects containing specific IDs, names, and character-entity encoded values. When an AI agent needs to update a mobile device's configuration preferences, it must pass these preferences using exact character entities. LLMs are notoriously bad at adhering to deeply nested, non-standard schema structures unless the tool definition strictly enforces it.

Strict Rate Limits and 429 Errors

Jamf enforces aggressive rate limits to protect tenant performance. If your AI agent gets stuck in a loop attempting to audit 5,000 computer inventory records, Jamf will quickly return an HTTP 429 Too Many Requests error. For more on managing this, see our guide on how to handle third-party API rate limits when an AI agent is scraping data.

Crucial Architectural Note: Truto does not magically retry, throttle, or apply backoff on rate limit errors. When the upstream Jamf API returns an HTTP 429, Truto passes that error directly to the caller. However, Truto normalizes the upstream rate limit information into standardized headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset) per the IETF specification. The caller - meaning your agent's execution loop - is strictly responsible for implementing exponential backoff and retry logic based on these standardized headers.

How Truto Maps Jamf to AI Tools

Every integration on Truto operates as a comprehensive JSON object representing the underlying product's API behavior. Truto utilizes the concept of Resources, mapping directly to endpoints on the underlying Jamf API (e.g., a mobile-devices resource maps to the corresponding Jamf endpoint).

These resources have Methods defined on them - standard CRUD operations (List, Get, Create, Update, Delete) and custom operations. These methods act as Proxy APIs. Truto handles the authentication handshake, query parameter processing, and pagination normalization, returning data in a predictable format. This zero-data-retention pass-through architecture ensures your data is never stored locally by the integration layer.

Truto provides these Proxy APIs directly to your LLM frameworks by dynamically generating descriptions and schemas for all methods defined on a Jamf integration. By calling the /integrated-account/:id/tools endpoint, you retrieve an array of formatted tools that frameworks like LangChain can consume immediately. This eliminates the need to manually write Zod schemas for Jamf's massive computer inventory objects. You can also use this data to build MCP servers for your AI agents.

Fetching Jamf Tools for Your AI Agent

To connect Jamf to your agent, you first need to authenticate a Jamf tenant via Truto and obtain an integrated account ID. Once connected, you can fetch the available tools dynamically.

Here is how you fetch and format these tools using standard TypeScript:

import { ChatOpenAI } from "@langchain/openai";
import { HumanMessage } from "@langchain/core/messages";
 
// 1. Fetch the tools from Truto's endpoint
async function getJamfTools(integratedAccountId: string, trutoApiKey: string) {
  const response = await fetch(
    `https://api.truto.one/integrated-account/${integratedAccountId}/tools?methods[0]=read&methods[1]=write`,
    {
      headers: {
        Authorization: `Bearer ${trutoApiKey}`,
      },
    }
  );
 
  if (!response.ok) {
    throw new Error(`Failed to fetch tools: ${response.statusText}`);
  }
 
  return response.json();
}
 
async function runAgent() {
  // Initialize your LLM
  const llm = new ChatOpenAI({ modelName: "gpt-4-turbo", temperature: 0 });
  
  // Retrieve the dynamically generated Jamf tools
  const rawTools = await getJamfTools("jamf-account-id-123", process.env.TRUTO_API_KEY);
  
  // In a production environment using the Truto SDK, you would use TrutoToolManager
  // to map these raw JSON definitions into executable LangChain DynamicStructuredTools.
  const jamfTools = mapToLangchainTools(rawTools);
 
  // Bind the tools to the LLM
  const agentWithTools = llm.bindTools(jamfTools);
 
  // Execute a prompt
  const response = await agentWithTools.invoke([
    new HumanMessage("Find the computer inventory record for device UDID 8A94B-2938 and tell me its OS version."),
  ]);
 
  console.log(response.tool_calls);
}

Hero Tools for Jamf Agentic Workflows

Instead of exposing hundreds of raw endpoints to your LLM, Truto provides highly optimized proxy methods tailored for agentic execution. Here are the highest-leverage tools available for orchestrating Jamf workflows.

List All Computer Inventory (list_all_jamf_computer_inventory)

Agents frequently need to audit device fleets to ensure compliance. This tool lists paginated computer inventory records in Jamf, returning critical nested fields such as general.name, general.platform, hardware.model, and the device udid.

"Audit the entire computer inventory and flag any devices that are not currently running macOS Sonoma. Generate a CSV report of the non-compliant devices."

Get Single Jamf User By ID (get_single_jamf_user_by_id)

When cross-referencing an HR ticket with Jamf, the agent needs precise user data. This tool retrieves a specific user, returning their full_name, email, ldap_server, and any associated extension_attributes. It also provides links to the hardware assets assigned to that user.

"Look up the Jamf user record for employee ID 9482. Identify which LDAP server they are authenticated against and list all extension attributes associated with their profile."

Update A Jamf User By ID (update_a_jamf_user_by_id)

During role transitions or department changes, agents can autonomously update user metadata. This tool allows the agent to mutate fields like name, full_name, email, and phone_number. Note: This operation specifically mutates user data, not hardware assignments.

"The user Sarah Connor has moved to the engineering department. Update her Jamf user profile to reflect her new position title and her updated secondary phone number."

List All Mobile Device Applications (list_all_jamf_mobile_device_applications)

Software vulnerability management requires constant auditing of installed applications across the fleet. This tool lists all mobile device applications, returning the bundle_id, version, and identifying whether the application is an internal_app.

"Pull a list of all mobile device applications deployed across the fleet. Identify any instances of the Slack application that are running a version older than 24.10.10."

Update A Mobile Device By ID (update_a_jamf_mobile_device_by_id)

Agents can execute configuration changes on specific devices. This tool updates existing mobile device details, including location data, purchasing data, and extension attributes.

"Update the mobile device with ID 402. Change its asset tag to 'ENG-MOBILE-99' and update the purchasing data to reflect that its warranty expires next month."

Delete A Jamf Account By ID (delete_a_jamf_account_by_id)

Crucial for offboarding automation, this tool handles the secure deletion of an administrator or user account within the Jamf system, returning a 200 OK upon successful removal.

"We are offboarding IT administrator David. Revoke his access by permanently deleting his Jamf admin account using his account ID."

For the complete tool inventory and schema details, visit the Jamf integration page.

Workflows in Action

AI agents provide the most value when executing multi-step workflows that span across multiple entities in the Jamf database. Here are two real-world examples of how an agent utilizes these tools.

Workflow 1: Zero-Touch Employee Offboarding

When an employee leaves, IT must reclaim their licenses, lock their devices, and remove their system access. An agent can automate this end-to-end.

"Initiate the offboarding sequence for user ID 1042. Identify their assigned computer, document its serial number for the hardware recovery team, and then delete the user's Jamf account."

Execution Steps:

  1. The agent calls get_single_jamf_user_by_id passing 1042 to retrieve the user's details and associated hardware links.
  2. The agent parses the response to find the linked computer ID.
  3. The agent calls list_all_jamf_computer_inventory (filtered by the retrieved ID) to capture the device serial_number and hardware.model.
  4. The agent formulates a message summarizing the hardware to be recovered.
  5. Finally, the agent calls delete_a_jamf_user_by_id to scrub the user from the system.

Result: The IT team receives an automated ticket containing the exact hardware specifications needed for physical recovery, and the user's MDM profile is safely purged - requiring zero human clicks.

Workflow 2: Fleet-Wide Vulnerability Audit

Security teams frequently need to identify shadow IT or outdated software on corporate mobile devices.

"Audit our mobile device fleet for the Zoom application. Find all devices that have it installed, check the version, and compile a list of devices running any version below 6.0."

Execution Steps:

  1. The agent calls list_all_jamf_mobile_device_applications to retrieve the global catalog of deployed apps.
  2. The agent filters the results in its context window to isolate the bundle_id for Zoom.
  3. The agent cross-references this with list_all_jamf_mobile_devices to map the application versions to specific device udids and user names.
  4. It compiles the non-compliant devices into a structured list.

Result: The security team gets a highly targeted list of specific users and devices that require an MDM push to update their software, bypassing the need to manually export and cross-reference multiple CSVs from the Jamf admin console.

Building Multi-Step Workflows

To safely deploy AI agents that interact with enterprise infrastructure, you must architect a resilient execution loop. Agents do not execute linearly; they evaluate the results of a tool call and decide what to do next.

Because Truto acts as a pass-through layer, your agent loop must be capable of catching API errors - specifically rate limits - and adjusting its behavior. If Jamf returns a 429 error, Truto passes the ratelimit-reset header back to your application. Your agent loop must interpret this header and pause execution.

Here is a conceptual example of a resilient agent execution loop using LangChain:

import { AIMessage } from "@langchain/core/messages";
 
async function executeAgentLoop(agent, initialPrompt: string) {
  let messages = [{ role: "user", content: initialPrompt }];
  let isComplete = false;
 
  while (!isComplete) {
    try {
      // The LLM decides whether to respond to the user or call a tool
      const response = await agent.invoke(messages);
      messages.push(response);
 
      if (response.tool_calls && response.tool_calls.length > 0) {
        // The LLM wants to call one or more Jamf tools
        for (const toolCall of response.tool_calls) {
          console.log(`Executing tool: ${toolCall.name}`);
          
          // Execute the tool (this hits the Truto Proxy API)
          const toolResult = await executeTool(toolCall.name, toolCall.args);
          
          // Feed the result back into the context window
          messages.push({
            role: "tool",
            tool_call_id: toolCall.id,
            content: JSON.stringify(toolResult)
          });
        }
      } else {
        // The LLM has gathered enough information to finalize the response
        console.log("Final Result:", response.content);
        isComplete = true;
      }
    } catch (error) {
      // Handle Truto pass-through errors (e.g., Jamf 429 Rate Limit)
      if (error.status === 429) {
        const resetTime = error.headers.get('ratelimit-reset');
        const waitMs = (parseInt(resetTime) * 1000) - Date.now();
        console.warn(`Rate limit hit. Agent backing off for ${waitMs}ms...`);
        await new Promise(resolve => setTimeout(resolve, waitMs));
        // Loop will continue and retry the last operation
      } else {
        console.error("Fatal error in agent execution:", error);
        throw error;
      }
    }
  }
}

This framework-agnostic approach works identically whether you are using LangGraph to map complex state machines or CrewAI to delegate tasks between an "Auditor" agent and a "Remediation" agent. The integration layer remains standardized.

Moving from Scripts to Agents

Connecting an AI agent to Jamf transforms MDM from a reactive database into a proactive IT teammate. However, the true cost of agentic workflows is the integration maintenance. Maintaining dual authentication flows, handling nested XML-to-JSON data structures, and monitoring API schema drift across the Classic and Pro APIs will consume your engineering team's bandwidth.

By leveraging an integration infrastructure layer that standardizes endpoints into LLM-ready tools, you decouple your AI logic from the underlying vendor API quirks. You build the automation logic once, and let the infrastructure handle the translation.

FAQ

How does Truto handle Jamf API rate limits for AI agents?
Truto does not retry, throttle, or apply backoff automatically. When Jamf returns an HTTP 429 error, Truto passes the error to the caller, while normalizing the rate limit information into standardized headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset). The caller is responsible for implementing retry and backoff logic.
Does Truto support both the Jamf Classic and Jamf Pro APIs?
Yes. Truto's integration architecture maps underlying endpoints from both APIs into standardized resources and methods, abstracting the authentication and data structure differences so your AI agent only interacts with clean JSON tools.
Can I use these Jamf tools with Vercel AI SDK or CrewAI?
Yes. The tools generated by Truto's /tools endpoint follow standard JSON schema descriptions. While this guide shows examples using LangChain, the schemas are completely framework-agnostic and can be bound to any modern agent framework.
How do AI agents handle Jamf's custom extension attributes?
Truto standardizes Jamf's extension attributes within the tool schema definitions. The LLM receives strict instructions on how to format these arrays (including required character entities) ensuring the generated API payload matches Jamf's required format.

More from our Blog