Skip to main content
Glama
syndr

Ara Records MCP Server

by syndr

Ara Records MCP Server

CI

A custom Model Context Protocol (MCP) server for integrating with the Ara Records API, enabling Ansible playbook execution monitoring through Claude Code.

Overview

This MCP server provides programmatic access to Ara Records (Ansible Run Analysis) API endpoints, allowing Claude Code to query and analyze Ansible playbook execution data.

Related MCP server: MCP Ansible Server

Setup

Prerequisites

  • Node.js >= 18.0.0

  • Ara API running locally (default: http://localhost:8000)

Installation

The easiest way to install is using claude mcp add with npx:

# Local installation (project-specific, default)
claude mcp add ara-api -- npx -y @ultroncore/ara-records-mcp

# User installation (available globally for your user)
claude mcp add --scope user ara-api -- npx -y @ultroncore/ara-records-mcp

With custom ARA server:

claude mcp add --scope user ara-api -- npx -y @ultroncore/ara-records-mcp --api-server http://ara.example.com:8080

With authentication:

claude mcp add --scope user ara-api -- npx -y @ultroncore/ara-records-mcp --api-server https://ara.example.com --username admin --password secret

Scope options:

  • local (default): Project-specific installation

  • user: Available globally for your user account

  • project: Project-specific (same as local)

You can also run it directly without installation:

npx @ultroncore/ara-records-mcp --help

Install Globally via npm

For global installation (allows running ara-records-mcp from anywhere):

npm install -g @ultroncore/ara-records-mcp

Then run directly:

ara-records-mcp --help
ara-records-mcp --api-server http://localhost:8000

Install from GitHub

Install directly from the GitHub repository:

npm install git+https://github.com/syndr/ara-records-mcp.git

This will automatically:

  • Clone the repository

  • Install the @modelcontextprotocol/sdk dependency

  • Make the MCP server ready to use

Install from Local Clone

If you've cloned the repository locally:

# Quick setup (recommended)
./setup.sh

# Manual setup
npm install

The setup script will:

  • Verify Node.js >= 18.0.0 is installed

  • Install @modelcontextprotocol/sdk and dependencies

  • Validate the installation was successful

Common Setup Scenarios

  • Initial repository clone

  • Merging feature branches

  • Switching between worktrees

  • After running git clean -fdx

Features

Resources (Read-Only Access)

The server exposes the following resources via the ara:// URI scheme:

  • ara://playbooks - List of recorded Ansible playbooks

  • ara://plays - List of recorded Ansible plays

  • ara://tasks - List of recorded Ansible tasks

  • ara://hosts - List of recorded Ansible hosts

  • ara://results - List of recorded task results

  • ara://latesthosts - Latest playbook result for each host

  • ara://running - Currently executing Ansible playbooks (for real-time monitoring)

Tools

  • ara_query - Query arbitrary Ara API endpoints with GET/POST support and automatic pagination

  • watch_playbook - Monitor a specific playbook execution with detailed progress tracking, task completion status, and execution timeline

  • get_playbook_status - Get a quick summary of playbook execution status without detailed task information

  • delete_playbook - Delete a single playbook record and all associated plays, tasks, and results

  • delete_playbooks_bulk - Delete multiple playbook records concurrently with configurable concurrency limit

Technical Details

Project Structure

ara-records-mcp/
├── ara-server.js    # Main MCP server implementation
├── package.json     # Node.js dependencies
├── package-lock.json # Locked dependency versions
├── setup.sh         # Automated setup script
├── .gitignore       # Git ignore rules
└── README.md        # This documentation

Configuration

Configure the server in your Claude Code .mcp.json file:

After Installing from GitHub

{
  "mcpServers": {
    "ara-api": {
      "command": "node",
      "args": ["node_modules/ara-records-mcp/ara-server.js"],
      "env": {
        "ARA_API_SERVER": "http://localhost:8000"
      }
    }
  }
}

After Local Clone/Development

{
  "mcpServers": {
    "ara-api": {
      "command": "node",
      "args": ["ara-server.js"],
      "env": {
        "ARA_API_SERVER": "http://localhost:8000"
      }
    }
  }
}

Environment Variables and CLI Arguments

Configuration can be provided via environment variables or CLI arguments. CLI arguments take precedence over environment variables.

CLI Argument

Environment Variable

Description

Default

Required

--api-server <url>

ARA_API_SERVER

Base URL of the Ara API server

http://localhost:8000

No

--username <user>

ARA_USERNAME

Username for HTTP Basic Authentication

None

No

--password <pass>

ARA_PASSWORD

Password for HTTP Basic Authentication

None

No

--concurrency <num>

ARA_CONCURRENCY

Max concurrent requests for bulk operations

5

No

Priority: CLI arguments > Environment variables > Defaults

Authentication Support

The server currently supports HTTP Basic Authentication for scenarios where the Ara API is behind a reverse proxy (nginx, Apache, etc.) that implements authentication.

Additional authentication methods (API tokens, OAuth, etc.) may be added in future releases.

Example with Basic Auth (Environment Variables):

{
  "mcpServers": {
    "ara-api": {
      "command": "node",
      "args": ["node_modules/ara-records-mcp/ara-server.js"],
      "env": {
        "ARA_API_SERVER": "https://ara.example.com",
        "ARA_USERNAME": "your-username",
        "ARA_PASSWORD": "your-password"
      }
    }
  }
}

Example with Custom Concurrency for Bulk Operations:

{
  "mcpServers": {
    "ara-api": {
      "command": "node",
      "args": ["node_modules/ara-records-mcp/ara-server.js"],
      "env": {
        "ARA_API_SERVER": "http://localhost:8000",
        "ARA_CONCURRENCY": "10"
      }
    }
  }
}

Example with Basic Auth (CLI Arguments via npx):

claude mcp add ara-api -- npx -y @ultroncore/ara-records-mcp --api-server https://ara.example.com --username your-username --password your-password

Note: Both ARA_USERNAME and ARA_PASSWORD (or --username and --password) must be set for authentication to be enabled. If only one is provided, no authentication will be used.

API Endpoints

The server connects to Ara's REST API v1 endpoints:

  • Base URL: http://localhost:8000 (configurable via ARA_API_SERVER environment variable or --api-server CLI argument)

  • API Path: /api/v1 (hardcoded for consistency)

  • Full endpoints: /api/v1/playbooks, /api/v1/plays, etc.

Automatic Pagination

All requests include automatic pagination to prevent token overflow:

  • Default Limit: 10 results per request (if not specified)

  • Smart Ordering: Automatically applies order=-started to chronological endpoints (playbooks, plays, tasks, results)

  • Token Efficiency: Prevents MCP tool responses from exceeding token limits

  • Backward Compatibility: Respects explicit query parameters when provided

Requirements

  • Ara API must be running and accessible (default: http://localhost:8000)

  • Claude Code restart required after installation to load the MCP server

  • Supports GET/POST operations only

Development

Running Tests

The project includes a comprehensive test suite using Node.js built-in test runner (no dependencies required).

Run all tests:

npm test

Run tests in watch mode (Node 19+):

node --test --watch

Test Coverage

Tests cover:

  • CLI Argument Parsing: Validates --api-server, --username, --password flags and defaults

  • Authentication Headers: Tests Basic auth header generation and base64 encoding

  • Pagination Logic: Validates automatic limit/order defaults and parameter preservation

  • MCP Schema Validation: Tests resources, tools, URI mappings, and response formats

Publishing Releases

The project uses automated GitHub Actions workflows for releases:

Setup npm Token (One-time)

  1. Create an npm access token at https://www.npmjs.com/settings/your-username/tokens

  2. Add the token as a GitHub repository secret:

    • Go to repository Settings → Secrets and variables → Actions

    • Click "New repository secret"

    • Name: NPM_TOKEN

    • Value: Your npm token

Releasing a New Version

  1. Update version in package.json (following semver):

    # For bug fixes
    npm version patch
    
    # For new features (backward compatible)
    npm version minor
    
    # For breaking changes
    npm version major
  2. Commit and push to main branch:

    git add package.json
    git commit -m "Bump version to X.Y.Z"
    git push origin main
  3. The Release workflow automatically:

    • Detects version change

    • Creates git tag (e.g., v1.1.0)

    • Creates GitHub release with auto-generated notes

    • Publishes package to npm

You can also trigger releases manually via workflow_dispatch in the GitHub Actions tab.

Testing the MCP Server

Verify Ara API is Running

curl -s http://localhost:8000/api/v1/ | jq

Test MCP Server Startup

timeout 2 node ara-server.js 2>&1

Expected output: *whirring* Ara MCP server activated. Testing chamber operational.

Verification Steps

  1. Ara API Check: Ensure Ara is running and responding at http://localhost:8000/api/v1/

  2. MCP Server Test: Run the server directly to confirm no startup errors

  3. Claude Code Integration: Restart Claude Code and verify MCP resources are available

  4. Resource Access: Test accessing ara://playbooks and other resources

Usage Examples

Default Query with Automatic Pagination

mcp__ara-api__ara_query({ endpoint: "/api/v1/playbooks" })
// Automatically applies: limit=10&order=-started

Explicit Pagination

mcp__ara-api__ara_query({ endpoint: "/api/v1/playbooks?limit=10&offset=20" })
// Respects user-provided parameters

Specific Resource Lookup

mcp__ara-api__ara_query({ endpoint: "/api/v1/playbooks/2273" })
// No pagination applied for specific resource IDs

Real-Time Playbook Monitoring

Monitor a playbook execution as it runs:

// Get detailed progress with task information
mcp__ara-api__watch_playbook({
  playbook_id: 2510,
  include_tasks: true,
  include_results: false
})

// Returns:
// - Execution status (running, completed, failed)
// - Progress percentage (tasks completed / total tasks)
// - Task list with status, timing, and action details
// - Host and play counts

Quick Status Check

Check playbook status without verbose task details:

mcp__ara-api__get_playbook_status({ playbook_id: 2510 })

// Returns:
// - Current status
// - Progress percentage
// - Start/end times and duration
// - Playbook path

Delete a Single Playbook

Permanently remove a playbook and all associated data:

mcp__ara-api__delete_playbook({ playbook_id: 2510 })

// Returns:
// { "success": true, "message": "Playbook 2510 deleted successfully" }

Bulk Delete Playbooks

Delete multiple playbooks concurrently:

mcp__ara-api__delete_playbooks_bulk({ playbook_ids: [2510, 2511, 2512, 2513] })

// Returns:
// {
//   "total": 4,
//   "deleted": [2510, 2511, 2512, 2513],
//   "failed": [],
//   "summary": "Deleted 4/4 playbooks"
// }

The bulk delete operation processes requests concurrently using a configurable concurrency limit (default: 5). Configure via --concurrency CLI argument or ARA_CONCURRENCY environment variable to balance performance with API server load.

Monitor Running Playbooks

List all currently executing playbooks:

// Using resource
ReadMcpResourceTool({ server: "ara-api", uri: "ara://running" })

// Or using ara_query
mcp__ara-api__ara_query({ endpoint: "/api/v1/playbooks?status=running" })

Implementation Notes

Architecture

  • Uses schema-based request handlers (ListResourcesRequestSchema, ReadResourceRequestSchema, CallToolRequestSchema)

  • Implements MCP SDK v1.0.0+ standards

  • Provides both resource exposure and tool functionality for comprehensive API access

  • Automatic pagination and ordering to prevent token overflow in large result sets

Real-Time Monitoring

While Ara doesn't natively support WebSockets, the MCP server provides polling-based monitoring that Claude can use to watch playbook execution:

  • Polling Pattern: Tools return current state that can be called repeatedly

  • Progress Tracking: Calculates completion percentage based on tasks completed vs total tasks

  • Resource Filtering: The ara://running resource filters for in-progress playbooks only

  • Structured Data: Returns normalized JSON with status, timing, and progress information

How to Use for Monitoring:

  1. Get list of running playbooks from ara://running resource

  2. Use get_playbook_status() tool to check progress periodically

  3. Use watch_playbook() tool for detailed task-level monitoring

  4. Call tools repeatedly (every few seconds) to track execution progress

Error Handling

The server implements basic error handling for:

  • Invalid resource URIs

  • HTTP errors from Ara API

  • Network connectivity issues

  • Missing or invalid playbook IDs

Future Enhancements

  • Basic Authentication: HTTP Basic Auth support via environment variables (completed)

  • Additional Authentication Methods: Support for API tokens, OAuth, JWT, or other auth mechanisms

  • Pagination: Implement proper pagination handling for large result sets (completed)

  • Advanced Filtering: Add more sophisticated query parameter support for resource endpoints

  • Enhanced Error Handling: Improve error messages and recovery strategies

  • Real-Time Monitoring: Polling-based playbook execution monitoring with progress tracking (completed - note: WebSocket not supported by Ara API, implemented polling-based solution instead)

  • Automated Deployment: Ansible playbook for updating and deploying the MCP server

Version History

v1.0.0 (2025-10-20) - Initial Release

  • Basic Authentication Support: HTTP Basic Authentication for reverse proxy scenarios

    • Environment variables ARA_USERNAME and ARA_PASSWORD for credentials

    • Automatic Authorization header generation with base64 encoding

    • Future-ready for additional authentication methods

  • Real-Time Monitoring: Polling-based playbook execution monitoring

    • New ara://running resource for listing active playbooks

    • watch_playbook tool for detailed progress tracking with task information

    • get_playbook_status tool for quick status checks

    • Progress calculation (percentage, task counts, timing information)

  • Pagination Support: Automatic pagination with configurable limits and smart ordering

  • MCP SDK Integration: Schema-based request handlers using MCP SDK v1.0.0+

  • Token Optimization: Safeguards to prevent token overflow in responses

  • GitHub Installation: Proper package.json metadata for direct git installation

License

MIT

Support

For issues or questions, please refer to the main project documentation or submit an issue to the repository.

Available Tools

3 tools
ara_queryA

Query Ara API endpoints with automatic pagination defaults (limit=3, order=-started)

ParametersJSON Schema
NameRequiredDescriptionDefault
bodyNoRequest body for POST requests
endpointYesAPI endpoint path (e.g., /api/v1/playbooks, /api/v1/plays/1). Supports query parameters like ?limit=10&offset=20&order=-started. If no limit is specified, defaults to 3 results.
methodNoGET

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It adds useful context about automatic pagination defaults (limit=3, order=-started), which isn't in the schema. However, it doesn't cover other behavioral aspects like error handling, authentication needs, rate limits, or what the response looks like (no output schema). The description provides some value but leaves significant gaps for a mutation-capable tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is highly concise and front-loaded in a single sentence, with no wasted words. It efficiently communicates the core functionality and key behavioral trait (pagination defaults), earning its place without redundancy or fluff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (3 parameters, no annotations, no output schema, supports POST/PUT mutations), the description is incomplete. It covers pagination defaults but misses critical details like mutation implications, response format, error handling, and when to use POST vs. GET. For a general-purpose API query tool with mutation capability, this leaves too many gaps for safe and effective use.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description adds meaningful semantics beyond the schema: it explains the automatic pagination defaults (limit=3, order=-started) for the 'endpoint' parameter, which the schema only partially covers with its example. With 67% schema description coverage, the description compensates well by clarifying default behavior, though it doesn't detail all parameters (e.g., 'body' or 'method' beyond the default).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Query Ara API endpoints' with the specific behavior of 'automatic pagination defaults (limit=3, order=-started)'. It distinguishes itself from siblings like 'get_playbook_status' and 'watch_playbook' by being a general-purpose query tool rather than focused on specific operations. However, it doesn't explicitly contrast with siblings beyond its general nature.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage by mentioning 'automatic pagination defaults', suggesting it's for querying endpoints with pagination support. However, it doesn't explicitly state when to use this tool versus alternatives like 'get_playbook_status' or 'watch_playbook', nor does it provide exclusions or prerequisites. The guidance is limited to implied context without clear alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_playbook_statusA

Get a quick summary of playbook execution status without detailed task information. Useful for checking if a playbook is complete or monitoring multiple playbooks.

ParametersJSON Schema
NameRequiredDescriptionDefault
playbook_idYesThe ID of the playbook to check

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It discloses that this is a read operation ('Get') and specifies the output scope ('quick summary' vs 'detailed task information'), but doesn't mention behavioral aspects like error handling, performance characteristics, or what 'quick summary' entails. It adds some context but lacks comprehensive behavioral disclosure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is perfectly concise with two sentences that each serve a distinct purpose: the first states the tool's function and scope, the second provides usage scenarios. There's zero wasted language, and it's front-loaded with the core purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter read tool with no annotations and no output schema, the description provides adequate context about what the tool does and when to use it. However, it doesn't describe what the 'quick summary' output contains or how it differs from what sibling tools might provide, leaving some gaps in completeness.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents the single parameter 'playbook_id' with its description. The description doesn't add any parameter-specific information beyond what's in the schema, maintaining the baseline score of 3 when schema coverage is high.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Get a quick summary of playbook execution status without detailed task information.' It specifies the verb ('Get'), resource ('playbook execution status'), and scope ('quick summary' vs 'detailed task information'), but doesn't explicitly differentiate from sibling tools like 'ara_query' or 'watch_playbook'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use this tool: 'Useful for checking if a playbook is complete or monitoring multiple playbooks.' This gives practical scenarios, though it doesn't explicitly state when NOT to use it or name alternatives among the sibling tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

watch_playbookA

Monitor a playbook execution in real-time. Returns detailed progress including task completion, current status, and execution timeline. Call repeatedly to track progress.

ParametersJSON Schema
NameRequiredDescriptionDefault
include_resultsNoInclude task result details (default: false, can be verbose)
include_tasksNoInclude detailed task information (default: true)
playbook_idYesThe ID of the playbook to monitor

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It discloses key behavioral traits: real-time monitoring, repeated calling requirement, and that it returns progress details. However, it doesn't mention potential side effects, authentication needs, rate limits, or error conditions that would be important for a monitoring tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is perfectly concise with three sentences that each earn their place: states the purpose, describes the return value, and provides crucial usage guidance. It's front-loaded with the core functionality and wastes no words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a monitoring tool with no annotations and no output schema, the description provides adequate basic information about what the tool does and how to use it. However, it lacks details about the return format structure, error handling, and the implications of 'real-time' monitoring that would be needed for full contextual understanding.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema description coverage, the schema already documents all three parameters thoroughly. The description doesn't add any parameter-specific information beyond what's in the schema, so it meets the baseline for high schema coverage without compensating with additional semantic context.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose with specific verbs ('Monitor', 'Returns', 'Call repeatedly') and identifies the resource ('playbook execution'). It distinguishes from siblings by focusing on real-time monitoring rather than querying (ara_query) or getting a single status snapshot (get_playbook_status).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for usage ('Call repeatedly to track progress'), indicating this is for ongoing monitoring rather than one-time status checks. However, it doesn't explicitly state when NOT to use this tool or directly compare it to the sibling tools (ara_query, get_playbook_status).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv1.0.0
    • First observedara_query
    • First observedget_playbook_status
    • First observedwatch_playbook

TDQS

A3.7/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: ara_query is for general API queries, get_playbook_status provides summary status, and watch_playbook offers real-time monitoring with detailed progress. There is no overlap in functionality, making tool selection straightforward for an agent.

Naming Consistency4/5

The naming is mostly consistent with a verb_noun pattern (e.g., get_playbook_status, watch_playbook), but ara_query uses a different prefix (ara_) which deviates slightly. Overall, the names are readable and follow a logical structure, with only minor inconsistency.

Tool Count3/5

With only 3 tools, the count feels thin for a records or monitoring server, potentially limiting coverage of the domain. While the tools cover key functions, more operations might be expected for comprehensive interaction with Ara records or playbooks.

Completeness3/5

The tools cover querying, status checking, and monitoring, but there are notable gaps such as creating, updating, or deleting records or playbooks. This may cause agents to hit dead ends when full lifecycle management is needed, though core monitoring workflows are supported.

Maintenance

ActivityInactive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    C
    quality
    F
    maintenance
    This Model Context Protocol server enables AI assistants to interact directly with Ansible, allowing them to execute playbooks, manage inventory, check syntax, and perform other Ansible operations.
    18
    26
    MIT
  • F
    license
    Not graded
    quality
    F
    maintenance
    Enables comprehensive Ansible automation management through natural language, including playbook creation and execution, inventory management, role scaffolding, and project workflows. Supports both local inventories and full project lifecycle management with syntax validation and idempotency testing.
    30
    -
  • F
    license
    C
    quality
    D
    maintenance
    Enables comprehensive management of Ansible Automation Platform Controller and Gateway through 17 specialized tools covering job execution, inventory management, workflows, credentials, user administration, and system monitoring.
    18
    -