# Query Analytics (OData) — Azure DevOps

> Run an OData query against the Azure DevOps Analytics service, which holds the historical and aggregated data the work item APIs do not expose. Returns the matching rows plus the @odata.context describing them. Use this for trend questions…

- Key: `azure_devops-query-analytics`
- Type: Action (Read-only)
- Version: 0.0.2
- App: Azure DevOps (`azure_devops`) — https://pipedream.com/apps/azure-devops.md
- This page (HTML): https://pipedream.com/apps/azure-devops/actions/query-analytics
- Hints: read-only · open-world
- Source: https://github.com/PipedreamHQ/pipedream/blob/master/components/azure_devops/actions/query-analytics/query-analytics.mjs

## Description

Run an OData query against the Azure DevOps Analytics service, which holds the historical and aggregated data the work item APIs do not expose. Returns the matching rows plus the `@odata.context` describing them. Use this for trend questions - how many bugs were open each day, how much work each iteration completed - and use **Query Work Items (WIQL)** instead for the current state of individual items. Set **Apply** to aggregate rather than pulling raw rows back. Example: entity set `WorkItems`, filter `State eq 'Closed'`. [See the documentation](https://learn.microsoft.com/en-us/azure/devops/report/analytics/analytics-query-parts?view=azure-devops)

## Props

| Prop | Type | Required | Description |
|---|---|---|---|
| `organization` | `string` | Yes | Name of the organization Options are loaded from the connected account. |
| `project` | `string` | No | Project ID or project name to scope the query to. Run the List Projects action first to obtain valid values. Omit to query across the whole organization. |
| `entitySet` | `string` | Yes | Analytics entity set to query. Common values: WorkItems (current state of each item), WorkItemSnapshot (one row per item per day, the basis of burndown and trend charts), WorkItemRevisions, Iterations, Areas, Teams, PipelineRuns, TestRuns. |
| `filter` | `string` | No | OData $filter expression, e.g. StateCategory eq 'Completed' and WorkItemType eq 'Bug'. Escape a literal apostrophe by doubling it. |
| `select` | `string` | No | Comma-separated properties to return, e.g. WorkItemId,Title,State,StoryPoints. Narrow this - Analytics rows are wide. |
| `orderby` | `string` | No | OData $orderby expression, e.g. ChangedDate desc |
| `apply` | `string` | No | OData $apply aggregation, applied before the other options. Example: filter(StateCategory eq 'Completed')/groupby((Iteration/IterationName), aggregate(StoryPoints with sum as Points)). Supported aggregations are sum, average, min, max, countdistinct and $count. |
| `expand` | `string` | No | Related entities to inline, e.g. Iteration,AssignedTo |
| `limit` | `integer` | No | Maximum number of rows to return (1-1000) |

## Run it

**MCP**

```ts
import { Client } from "@modelcontextprotocol/sdk/client/index.js"
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"
import { PipedreamClient } from "@pipedream/sdk"

const pd = new PipedreamClient({
  projectId: process.env.PIPEDREAM_PROJECT_ID!,
  clientId: process.env.PIPEDREAM_CLIENT_ID!,
  clientSecret: process.env.PIPEDREAM_CLIENT_SECRET!,
  projectEnvironment: "production",
})

const accessToken = await pd.rawAccessToken

const transport = new StreamableHTTPClientTransport(
  new URL("https://remote.mcp.pipedream.net/v3"),
  {
    requestInit: {
      headers: {
        Authorization: `Bearer ${accessToken}`,
        "x-pd-project-id": process.env.PIPEDREAM_PROJECT_ID!,
        "x-pd-environment": "production",
        "x-pd-external-user-id": "{external_user_id}", // any stable ID for this user in your system
        "x-pd-app-slug": "azure_devops",
      },
    },
  },
)

const mcp = new Client({ name: "my-agent", version: "1.0.0" })
await mcp.connect(transport)

const { tools } = await mcp.listTools()

// listTools() hands your model this tool's input schema, so it can
// fill the arguments itself:
const result = await mcp.callTool({
  name: "azure_devops-query-analytics",
  arguments: {
    organization: "Organization",
    project: "Project",
  },
})
```

**TypeScript**

```ts
import { PipedreamClient } from "@pipedream/sdk"

const pd = new PipedreamClient({
  projectId: process.env.PIPEDREAM_PROJECT_ID!,
  clientId: process.env.PIPEDREAM_CLIENT_ID!,
  clientSecret: process.env.PIPEDREAM_CLIENT_SECRET!,
  projectEnvironment: "production",
})

const result = await pd.actions.run({
  id: "azure_devops-query-analytics",
  externalUserId: "{external_user_id}", // any stable ID for this user in your system
  configuredProps: {
    azure_devops: { authProvisionId: "apn_xxxxxxx" },
    organization: "Organization",
    project: "Project",
  },
})

console.log(result)
```

**cURL**

```bash
curl -X POST https://api.pipedream.com/v1/connect/{project_id}/actions/run \
  -H "Content-Type: application/json" \
  -H "X-PD-Environment: production" \
  -H "Authorization: Bearer {access_token}" \
  -d '{
    "external_user_id": "{external_user_id}",
    "id": "azure_devops-query-analytics",
    "configured_props": {
      "azure_devops": { "authProvisionId": "apn_xxxxxxx" },
      "organization": "Organization",
      "project": "Project"
    }
  }'
```

---

- App: https://pipedream.com/apps/azure-devops.md · All apps: https://pipedream.com/apps
