MCP Python SDK

autociso-mcp-client is the first-party Python SDK for the AutoCISO MCP server. It gives you a typed method per tool, sync and async clients, and built-in retries.

Install

pip install autociso-mcp-client

The import name is autociso_mcp:

from autociso_mcp import AutocisoMcpClient

Create a client

base_url is required — there is no default. Pass the full URL including /mcp:

import os
from autociso_mcp import AutocisoMcpClient

client = AutocisoMcpClient(
  base_url="https://api.autociso.io/mcp",
  token=os.environ["AUTOCISO_MCP_TOKEN"],  # mcp:read scope
)

First call

Each tool maps 1:1 to a namespaced, snake_case method. Use the sync client for scripts or the async client inside an event loop:

import os
from autociso_mcp import AutocisoMcpClient

client = AutocisoMcpClient(
  base_url="https://api.autociso.io/mcp",
  token=os.environ["AUTOCISO_MCP_TOKEN"],
)

posture = client.posture.summary()
print("Overall score:", posture.overall_score)

stale = client.access.stale_accounts()
print("Stale accounts:", len(stale))

Results are PII-masked — emails appear as a***@domain.com and personal names are redacted (to resolve an employeeId to a name, see Employee identity):

{
  "overallScore": 72,
  "staleAccounts": 14,
  "openRisks": 6,
  "isoGapsOpen": 23,
  "topConcern": "14 stale accounts pending review"
}

Typed results

Methods for typed tools return TypedToolResult[XResult]. .data, .is_error and .raw work as before and never raise. .result validates .data lazily into a generated Pydantic model and raises ResultSchemaError on a mismatch; the error carries the tool name and field paths only, never values. Tools without a published schema return a plain result. The package ships py.typed, and the client prefers structuredContent, falling back to the text block.

res = await client.access.anomaly_discovery()
res.data["totalCount"]        # unchanged dict access
res.result.total_count        # typed, validated on first access

Patterns

  • Typed method per tool. client.access.stale_accounts(), client.risk.get(id="risk_…"), client.iso.gap_status() map to the same tools as the TypeScript SDK. See the Tool Catalog.
  • No org_id, ever. Your org is bound to the token on the server (see Org binding). There is no org argument — you can’t query another tenant. By design.
  • Retries on reads. Idempotent reads retry automatically on 429 and transient errors with exponential backoff and jitter (capped at ~3 attempts).
  • Writes are not auto-retried. There are five write tools (risk_create_draft, iso_audit_simulate, supplier_questionnaire_clone, supplier_questionnaire_update_question, supplier_questionnaire_update_option), for example client.risk.create_draft(title="…"). None is ever retried automatically: the server has no idempotency key, so a blind retry could create a duplicate or spend a second AI request.
  • Timeout override. Pass timeout= per call when a tool is slow.
  • call_raw escape hatch. For a tool the typed surface doesn’t cover, call it by name; the result is an untyped dict:
raw = client.call_raw("audit_trail_search", {"limit": 25, "offset": 0})
# raw is a dict — validate before use

Error handling

Tool failures raise typed exceptions (e.g. AutocisoScopeError, AutocisoRateLimitError). See MCP Errors and Retries for the full mapping and retry behavior.

Last reviewed: 2026-10-14

Was this page helpful?

Esc