A360 MCP Documentation / Tool documentation

Integration basics

How the dashboard calls any tool on the MCP direct door. Every tool page builds on this.

The flow

  1. Log in to Audit 360. You already have the user's auth_token, tenant base URL, subdomain and active role id.
  2. Open a session once, when the user opens the Dashboard (details: How to use the session ID): POST /api/session with the four tenant headers. You get a sessionId. The server starts loading the last 6 months of issues into that session in the background, so later tool calls are fast.
  3. Call a tool: POST /mcp-direct/ with a JSON-RPC tools/call body, the four tenant headers and X-A360-Session-Id. No initialize call is needed.
  4. Read result.structuredContent. Check success first, then use data.

Base URL

This is the dev server. It changes per environment. Every example on this site uses it.

Browser calls are allowed from Audit 360 dashboards (https://<tenant>.audit360.solutions, .com, .in) and from http://localhost or http://127.0.0.1 on any port (not https://localhost). The response header X-A360-Session-Id is exposed to browser JavaScript.

Headers

The server does not validate the token itself. A widget tool uses it to fetch data from Audit 360. When Audit 360 answers 401, the tool returns HTTP 200 with success: false and error_code: "token_expired" on /mcp-direct/ (HTTP 401 on the REST door). Send the user to log in again. A data call answered from the session's cache does not reach Audit 360, so it does not notice an expired token. See Errors for the other token cases.

Step 2 · Open a session

Response (real, from the dev server):

  • The id is in the body (sessionId) and in the response header X-A360-Session-Id.
  • Send it on every later call, always together with the four tenant headers.
  • It expires after 20 minutes without use (idleTimeoutSeconds: 1200). An expired, unknown or other user's id is not an error: the server quietly starts a new session and returns the new id in X-A360-Session-Id. Always keep the id from the latest response.

Step 3 · The JSON-RPC body

Every tool call has the same body. Only name and arguments change. Each tool page lists its arguments.

  • Keep the trailing slash: /mcp-direct/. Without it you get 307.
  • id is any number you choose. The answer carries the same id.
  • A misspelled argument is ignored, not rejected. Check params_used in the answer: it echoes every non-empty argument the tool received, as sent, plus the defaults it filled in (top_n, stack_by). A misspelled name is missing from it.

Step 4 · Read the answer

  • result.structuredContent is the tool's answer as an object. Use it.
  • result.content[0].text is the same answer as a JSON string (for AI clients). You do not need it.
  • A section that does not apply to the current filter or drill-down is {"applicable": false}. Hide that block on screen.
  • "" (empty string) means "not computable", for example a percentage change from zero, or an entity absent from one period. Show it as "–".
  • Widget tools: data.comparisonMeta.isComputable: false with incomputableReason means the call worked (success: true) but there is nothing to compare, e.g. no issues in this scope, or a clicked month that a period does not have. Show the reason instead of the widget.
  • Widget tools: data.drillBreakdown is always present. Without a drill-down it is {"applicable": false}. Dropped issues are left out of every count.

Rules every widget tool follows

These hold for every widget tool (compare_*). Each tool page adds only what is special to it.

Dates

  • Accepted formats: YYYY-MM-DD, DD-MM-YYYY or DD-Mon-YYYY (e.g. 2026-04-01, 01-04-2026, 01-Apr-2026). Both ends are included.
  • T1 is the baseline. It must not start after T2: "T1 must be the earlier period: it starts after T2". The same start day and overlapping periods are accepted.
  • T1 and T2 together must fit in 2 years (Audit 360's limit), e.g. "T1 and T2 together span 2024-04-01 to 2026-09-30; Audit 360 allows at most 2 years in one request, so from 2024-04-01 the latest end is 2026-04-01".
  • An issue belongs to a period by its created date.

Filters

  • Names (*_names) match exactly, and case matters: "north" is not "North". An unknown name gives an empty result, not an error.
  • Ids (*_ids) come from the dashboard's filter list. 3002 and "3002" are the same. "15,27" (same-named entries merged in a dropdown) counts as two ids.
  • A malformed id (0, -1, "abc") is dropped silently. If every id of a field is malformed, the call is refused with an error that names the field; it is never run unfiltered. [] or leaving the field out means no filter. A well-formed id that does not exist gives an empty result and shows as "id 999999" in comparisonMeta.context.filters.
  • Ids and names on the same field must both match (AND). Sending cluster_ids: [3001] with cluster_names: ["Maharastra"] (a different cluster) gives 0 issues.
  • Leave a filter out, or send [], for "all". Filters still apply under a drill-down.

Drill-down

  • Every drill starts at one clicked item (the tool's first drill_* argument). Every other drill_* argument needs it, or you get e.g. "a drill-down starts at a zone point: give drill_zone".
  • The server is stateless about clicks: send the whole path on every call.
  • drill_view can be left out. The server then picks it from what you send: the across path → across, drill_geo_path → geography, else time. drill_geo_path or the across path sent with a different, explicit view is an error, e.g. "drill_geo_path belongs to the geography view". drill_time_path is the exception (see below).
  • Time view opening level. It depends on Period 2's span, counted as end date minus start date in days: up to 35 → week, up to 100 → month, up to 365 → quarter, longer → year. Example: Jul 1–Sep 30 is 91 → month; Jul 1–Aug 5 is 35 → week. The first drill_time_path step must be that level, and each next step one level finer (year → quarter → month → week). Otherwise: "time step 1 must be a month: Period 2's range opens at month level, and each click goes one level finer (year > quarter > month > week)".
  • A time step is {"level": "year"|"quarter"|"month", "period_number": 1..60}, with no other keys. A week is never drilled into: its click opens the raw records.
  • period_number counts from each period's own start: Month 1 is the first month of T1 and of T2. A number a period does not have (Month 4 of a 3-month period) is not an error: isComputable becomes false.
  • drill_time_path also narrows the geography view (and the across view, where the tool allows it): both periods shrink to the clicked bucket. Send it only while the screen is inside that bucket.
  • drill_geo_path lists names clicked in the order zone → region → state → cluster, at most 4 names. A 5th gives "an auditee is not drilled into: its click opens the raw records".
  • A clicked name must lie inside an active filter on the same level, or you get e.g. "drill-down zone 'North' is outside the active zone filter". A clicked name with no issues is not an error: you get zeros or isComputable: false.
  • drill_risk_levels (where the tool has it) narrows nothing. Every drillBreakdown.items[] always has riskSplit: [] without levels, else one {riskLevel, T1Count, T2Count, change} per picked level. A level sent twice is an error.
  • drillBreakdown has description, dimension (time / geography / across), level, windows (each period's real dates), totalItems and items[] with name, periodNumber, T1Label, T2Label (dates for time items, "" otherwise), presence (both / T1_only / T2_only), T1Count, T2Count, change, changePct, direction, riskSplit.

Errors

There are four kinds. Check them in this order.

The REST door is different

Narrator prompts

Each widget tool has a narrator prompt that turns its JSON into a written summary. Get it with prompts/get on the same door, or call the tool get_all_prompts. Send the prompt text to the LLM as the system prompt and the tool's JSON as the user message.

Summary "i" button

Call get_all_summary_definitions once at app load, or when a comparison summary first opens. Send category: "comparison". Cache the answer for the session because definitions change only with a server release.

Each point has one definition string containing one sentence, up to 100 words. Period 1 is the dashboard's Comparison range; Period 2 is its Primary range.

JSON-RPC request

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_all_summary_definitions",
    "arguments": { "category": "comparison" }
  }
}

Match a summary point

  1. Take the widget whose name equals the summary's narrator prompt name.
  2. Read the exact label from - **<label>:** at the start of the summary point.
  3. Find the point whose labels contains that label and whose metric is any or the current chart metric.
  4. For Top/Bottom Auditees, use metric issues for No Of Issues and compliance for Achieved Compliance %.

Show the "i" button only when a point matches. The Drill-Down point has no definition, so it has no "i" button.

Small JavaScript example

const data = response.result.structuredContent.data;
sessionStorage.setItem("summaryDefinitions", JSON.stringify(data));

function findDefinition(promptName, label, metric) {
  const widget = data.widgets.find(item => item.name === promptName);
  const point = widget?.points.find(point =>
    point.labels.includes(label) &&
    (point.metric === "any" || point.metric === metric)
  );
  return point?.definition;
}

const definition = findDefinition(promptName, label, metric);
infoButton.hidden = !definition;
infoText.textContent = definition ?? "";

What to show

Show the matched point's definition string as one text entry in the information button. Do not split it into fields. Allow the text to wrap on a small screen.

For Status Mix in Schedule By Audit Type, the button shows:

Schedules by Audit Start Date are counted under their Execution Status, leaving out statuses outside the 16 documented values, and the 3 statuses with the most Period 2 schedules, out of all statuses, show Period 1 and Period 2 counts and the status's share of all Period 2 schedules with its change in percentage points.