ninja_query_software
Query software inventory across managed devices with filters for name or device type. Supports pagination to retrieve results.
Instructions
Query software inventory across all managed devices.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| df | No | Device filter expression | |
| pageSize | No | Max results to return | |
| cursor | No | Pagination cursor from previous response | |
| name | No | Filter by software name (partial match) |
Implementation Reference
- src/tools/queries.ts:11-27 (handler)The queryTool function on line 11 creates a ToolDef with a handler that calls NinjaOneClient.get(path, clean(args)). For 'ninja_query_software', the handler is an async closure that makes a GET request to '/queries/software' with cleaned query parameters (df, pageSize, cursor, name).
function queryTool( name: string, description: string, path: string, extraProps: Record<string, unknown> = {}, ): ToolDef { return { tool: { name, description, inputSchema: { type: 'object', properties: { ...basePaginationProps, ...extraProps }, }, }, handler: async (args, client: NinjaOneClient) => client.get(path, clean(args)), }; - src/tools/queries.ts:89-96 (schema)The schema (inputSchema) for 'ninja_query_software' includes base pagination props (df, pageSize, cursor) plus an extra optional string parameter 'name' for filtering by software name. The schema is defined inline within the queryTool call on line 89-96.
queryTool( 'ninja_query_software', 'Query software inventory across all managed devices.', '/queries/software', { name: { type: 'string', description: 'Filter by software name (partial match)' }, }, ), - src/tools/index.ts:13-24 (registration)The tool is registered as part of the ALL_TOOLS array in src/tools/index.ts by spreading queryTools (which includes 'ninja_query_software') into the list. The registration occurs at src/tools/index.ts:13-24.
export const ALL_TOOLS = [ ...deviceTools, ...organizationTools, ...alertTools, ...activityTools, ...ticketingTools, ...queryTools, ...policyTools, ...userTools, ...backupTools, ...systemTools, ]; - src/index.ts:23-60 (registration)In src/index.ts, ALL_TOOLS is loaded and a toolMap is built by mapping each ToolDef's tool.name to its handler. On ListToolsRequestSchema, all tool definitions are returned. On CallToolRequestSchema, the handler is looked up by name and invoked with the NinjaOneClient. Lines 24, 31-33, 35-44 show this runtime registration and dispatch.
const ninjaClient = new NinjaOneClient(NINJA_BASE_URL, NINJA_CLIENT_ID, NINJA_CLIENT_SECRET); const toolMap = new Map(ALL_TOOLS.map((def) => [def.tool.name, def.handler])); const server = new Server( { name: 'ninjaone-mcp', version: '1.0.0' }, { capabilities: { tools: {} } }, ); server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: ALL_TOOLS.map((def) => def.tool), })); server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; const handler = toolMap.get(name); if (!handler) { return { content: [{ type: 'text', text: `Unknown tool: ${name}` }], isError: true, }; } try { const result = await handler( (args ?? {}) as Record<string, unknown>, ninjaClient, ); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], }; } catch (err) { return { content: [{ type: 'text', text: err instanceof Error ? err.message : String(err) }], isError: true, }; } }); - src/utils.ts:1-6 (helper)The 'clean' utility function is used by the handler to strip null/empty values from the arguments object before passing them as query parameters to the API call.
// eslint-disable-next-line @typescript-eslint/no-explicit-any export function clean(args: Record<string, any>): Record<string, unknown> { return Object.fromEntries( Object.entries(args).filter(([, v]) => v != null && v !== ''), ); }