Using MCP with Saner APIs
Once your editor is connected to the Saner MCP server, your AI assistant can read the Saner API
and SDK documentation through structured MCP tools.
This allows the assistant to discover APIs, inspect parameters, generate SDK usage examples, and
build automation scripts interactively.
The MCP server is read-only, it supplies the specifications your assistant writes code from, and
never calls the Saner API itself. The scripts on this page run against your live Saner tenant when
you run them. Several of them create organizations, accounts, and other real objects, so review
generated code before running it and prefer a test account while you are experimenting.
Example 1: Discover How to Download an Agent
You can ask your AI assistant:
how can i download an agent on my device in saner ?Behind the scenes, MCP:
- searches relevant endpoints
- retrieves endpoint details
- reads parameter requirements
- generates SDK-ready usage examples
Example response typically includes:
- endpoint description
- required parameters
- optional parameters
- Python SDK example
- request payload structure
- response format


Example 2: Ask about Saner SDK
Example prompt:
how will logs be handled in sdk when downloading binary files ?

Example 3: Build Multi-Step Automation Scripts
Your assistant can chain several APIs into a single generated script, working out the order and the
parameters from the documentation.
Example prompt:
can u write me a python script to first create an organization, create 2 accounts under that organization, and download agents for both of those accounts. Enable logging, and also keep in mind the binary handling.The assistant will:
- identify required endpoints
- determine execution order
- validate parameters
- generate a working SDK script

Example: saner_setup.py
"""
Saner Setup Script
------------------
Workflow:
1. Create an organization
2. Create 2 accounts under that organization
3. Download agents for both accounts
Logging is enabled and binary responses are handled safely.
"""
import os
from saner import SanerClient
# ─────────────────────────────────────────────
# Configuration — replace with your actual values
# ─────────────────────────────────────────────
API_KEY = "<YOUR_API_KEY>"
ACCOUNT_ID = "<YOUR_ACCOUNT_ID>"
BASE_URL = "https://saner.secpod.com" # Change to your regional URL if needed
# Organization details
ORG_NAME = "MyOrganization"
ORG_EMAIL = "[email protected]"
ORG_SUBSCRIPTIONS = "200" # Total subscriptions for the org
# Account details (2 accounts under the org above)
ACCOUNTS = [
{
"name": "Account_One",
"email": "[email protected]",
"numberofsubscriptions": "50",
},
{
"name": "Account_Two",
"email": "[email protected]",
"numberofsubscriptions": "50",
},
]
# Agent download settings
AGENT_TYPE = "exe" # exe | rpm | dpkg | osx | apk | all
AGENT_ARCHITECTURE = "x64" # x86 | x64 | all
OUTPUT_DIR = "agents" # Folder where agent ZIPs will be saved
# ─────────────────────────────────────────────
# Initialize client with logging enabled
# ─────────────────────────────────────────────
client = SanerClient(
api_key=API_KEY,
accountid=ACCOUNT_ID,
base_url=BASE_URL,
enable_logging=True,
log_dir="logs", # Logs saved to ./logs/ as .jsonl files, rotated weekly
)
os.makedirs(OUTPUT_DIR, exist_ok=True)
# ─────────────────────────────────────────────
# Step 1: Create Organization
# ─────────────────────────────────────────────
print(f"\n[1/3] Creating organization: '{ORG_NAME}' ...")
org_response = client.Organization.add(
name=ORG_NAME,
email=ORG_EMAIL,
numberofsubscriptions=ORG_SUBSCRIPTIONS,
)
print(f" Response: {org_response}")
# ─────────────────────────────────────────────
# Step 2: Create 2 Accounts under the Organization
# ─────────────────────────────────────────────
print(f"\n[2/3] Creating accounts under '{ORG_NAME}' ...")
for i, account in enumerate(ACCOUNTS, start=1):
print(f" [{i}/{len(ACCOUNTS)}] Creating account: '{account['name']}' ...")
acc_response = client.Account.add(
name=account["name"],
email=account["email"],
organization=ORG_NAME,
numberofsubscriptions=account["numberofsubscriptions"],
)
print(f" Response: {acc_response}")
# ─────────────────────────────────────────────
# Step 3: Download Agents for Both Accounts
# ─────────────────────────────────────────────
print(f"\n[3/3] Downloading agents (type={AGENT_TYPE}, arch={AGENT_ARCHITECTURE}) ...")
for i, account in enumerate(ACCOUNTS, start=1):
account_name = account["name"]
output_path = os.path.join(OUTPUT_DIR, f"Saner-Agent-{account_name}.zip")
print(f" [{i}/{len(ACCOUNTS)}] Downloading agent for account: '{account_name}' ...")
response = client.Agent.download(
accountid=account_name,
type=AGENT_TYPE,
architecture=AGENT_ARCHITECTURE,
)
# Binary handling: check type before writing to disk.
# If the server returns an error instead of a file,
# the SDK returns a dict/string — not bytes — keeping the script safe.
if isinstance(response, bytes):
with open(output_path, "wb") as f:
f.write(response)
size_mb = len(response) / (1024 * 1024)
print(f" Saved → {output_path} ({size_mb:.2f} MB)")
# Note: the SDK logs this as: "response": "<binary N bytes>"
# so raw binary data is never written to the log file.
else:
print(f" Download failed for '{account_name}': {response}")
print("\nDone. Check the 'agents/' folder for installers and 'logs/' for execution records.")Example 4: Refining the scripts using SDK functionality
You an also ask questions in between prompts, as the Saner MCP has context about SDK it can directly integrate SDK functionalities into the scripts.
Example prompt:
actually i want to create 2 clients, client1 will create it's own org and one account under it, client 2 will do the same , enable logging only for client1, and download agents respectively for them, do saner sdk support multiclient ? or i'll have to create seperte files for 2 clients ?
Example: saner_multiclient_setup.py
"""
Saner Multi-Client Setup Script
--------------------------------
Two independent SanerClient instances run within the same script.
client1 (logging ON) → creates Org1 + Account1 → downloads agent
client2 (logging OFF) → creates Org2 + Account2 → downloads agent
Each client is fully isolated: separate auth, config, and log files.
"""
import os
from saner import SanerClient
# ─────────────────────────────────────────────
# Configuration — replace with your actual values
# ─────────────────────────────────────────────
CLIENT1 = {
"api_key": "<CLIENT1_API_KEY>",
"accountid": "<CLIENT1_ACCOUNT_ID>",
"base_url": "https://saner.secpod.com", # Change to your regional URL if needed
"org_name": "Org_Client1",
"org_email": "[email protected]",
"org_subscriptions": "100",
"account_name": "Account_Client1",
"account_email": "[email protected]",
"account_subscriptions": "50",
}
CLIENT2 = {
"api_key": "<CLIENT2_API_KEY>",
"accountid": "<CLIENT2_ACCOUNT_ID>",
"base_url": "https://saner.secpod.com", # Can be a different regional URL
"org_name": "Org_Client2",
"org_email": "[email protected]",
"org_subscriptions": "100",
"account_name": "Account_Client2",
"account_email": "[email protected]",
"account_subscriptions": "50",
}
# Agent download settings
AGENT_TYPE = "exe" # exe | rpm | dpkg | osx | apk | all
AGENT_ARCHITECTURE = "x64" # x86 | x64 | all
OUTPUT_DIR = "agents" # Folder where downloaded ZIPs will be saved
# ─────────────────────────────────────────────
# Initialize clients
# Each client is fully isolated — separate auth,
# retry config, and log files.
#
# client1 → logging ON (logs saved to ./logs/)
# client2 → logging OFF
# ─────────────────────────────────────────────
client1 = SanerClient(
api_key=CLIENT1["api_key"],
accountid=CLIENT1["accountid"],
base_url=CLIENT1["base_url"],
enable_logging=True,
log_dir="logs",
# Log file will be: logs/saner-sdk__<CLIENT1_ACCOUNT_ID>__<hash>.jsonl
)
client2 = SanerClient(
api_key=CLIENT2["api_key"],
accountid=CLIENT2["accountid"],
base_url=CLIENT2["base_url"],
enable_logging=False, # No logs for client2
)
os.makedirs(OUTPUT_DIR, exist_ok=True)
# ─────────────────────────────────────────────
# Helper: save downloaded agent to disk
# ─────────────────────────────────────────────
def save_agent(response, account_name: str) -> None:
"""
Handle binary agent download response safely.
- If the SDK returns bytes → write to disk.
- If the SDK returns a dict/string → server returned an error; print it.
The SDK never writes raw binary to logs.
It records: "response": "<binary N bytes>" instead.
"""
output_path = os.path.join(OUTPUT_DIR, f"Saner-Agent-{account_name}.zip")
if isinstance(response, bytes):
with open(output_path, "wb") as f:
f.write(response)
size_mb = len(response) / (1024 * 1024)
print(f" Saved → {output_path} ({size_mb:.2f} MB)")
else:
print(f" Download failed for '{account_name}': {response}")
# ═════════════════════════════════════════════
# CLIENT 1 (logging enabled)
# ═════════════════════════════════════════════
print("\n" + "═" * 55)
print(" CLIENT 1 (logging ON)")
print("═" * 55)
# Step 1 — Create Organization
print(f"\n[1/3] Creating organization: '{CLIENT1['org_name']}' ...")
response = client1.Organization.add(
name=CLIENT1["org_name"],
email=CLIENT1["org_email"],
numberofsubscriptions=CLIENT1["org_subscriptions"],
)
print(f" Response: {response}")
# Step 2 — Create Account under that org
print(f"\n[2/3] Creating account: '{CLIENT1['account_name']}' ...")
response = client1.Account.add(
name=CLIENT1["account_name"],
email=CLIENT1["account_email"],
organization=CLIENT1["org_name"],
numberofsubscriptions=CLIENT1["account_subscriptions"],
)
print(f" Response: {response}")
# Step 3 — Download Agent for that account
print(f"\n[3/3] Downloading agent for account: '{CLIENT1['account_name']}' ...")
response = client1.Agent.download(
accountid=CLIENT1["account_name"],
type=AGENT_TYPE,
architecture=AGENT_ARCHITECTURE,
)
save_agent(response, CLIENT1["account_name"])
# ═════════════════════════════════════════════
# CLIENT 2 (logging disabled)
# ═════════════════════════════════════════════
print("\n" + "═" * 55)
print(" CLIENT 2 (logging OFF)")
print("═" * 55)
# Step 1 — Create Organization
print(f"\n[1/3] Creating organization: '{CLIENT2['org_name']}' ...")
response = client2.Organization.add(
name=CLIENT2["org_name"],
email=CLIENT2["org_email"],
numberofsubscriptions=CLIENT2["org_subscriptions"],
)
print(f" Response: {response}")
# Step 2 — Create Account under that org
print(f"\n[2/3] Creating account: '{CLIENT2['account_name']}' ...")
response = client2.Account.add(
name=CLIENT2["account_name"],
email=CLIENT2["account_email"],
organization=CLIENT2["org_name"],
numberofsubscriptions=CLIENT2["account_subscriptions"],
)
print(f" Response: {response}")
# Step 3 — Download Agent for that account
print(f"\n[3/3] Downloading agent for account: '{CLIENT2['account_name']}' ...")
response = client2.Agent.download(
accountid=CLIENT2["account_name"],
type=AGENT_TYPE,
architecture=AGENT_ARCHITECTURE,
)
save_agent(response, CLIENT2["account_name"])
# ─────────────────────────────────────────────
print("\n" + "─" * 55)
print("Done.")
print(f" Agent ZIPs → {OUTPUT_DIR}/")
print(" client1 logs → logs/saner-sdk__<CLIENT1_ACCOUNT_ID>__<hash>.jsonl")
print(" client2 logs → (disabled)")
print("─" * 55)Example 5: Endpoint Discovery Using MCP
Instead of manually browsing documentation, you can ask:
Show APIs related to vulnerability management

Example 6: Inspect Endpoint Parameters
To understand request structure:
What parameters are required for adding an organization in saner?

Example 7: Search Documentation Without Leaving the Editor
Example:
Explain agent download options in Saner



Benefits of MCP-Based API and SDK Usage
Using MCP with Saner APIs and SDK enables:
- automatic endpoint discovery
- parameter-aware code generation
- multi-step workflow scripting
- documentation search inside your editor
- faster onboarding for new developers
- reduced integration effort
With MCP enabled, your AI assistant becomes a context-aware integration partner capable of building Saner automation workflows directly from natural-language prompts.
Updated 1 day ago
