Skip to content

MCP Server

Ostorlab exposes an MCP server, letting AI assistants and agent frameworks work with your scans, vulnerabilities, tickets and assets directly — no custom GraphQL client required.

Where the GraphQL API gives you the full platform surface to build against, the MCP server gives an AI client a curated set of typed tools it can discover and call on its own. Ask your assistant "what did the last scan of my app find?" and it will pick the right tools, chain them, and answer.

Endpoint

https://api.ostorlab.co/apis/mcp/{api_key}/

The transport is streamable HTTP. The API key is part of the URL path.

Warning

The trailing slash is required. Without it the server answers with a 307 redirect. Clients that follow redirects will still work but pay an extra round trip on every request; clients that do not follow redirects on POST will fail.

Warning

The key in the URL is a credential. URLs are commonly recorded in proxy logs, browser history and shell history, and MCP client configuration files are usually stored in plain text. Treat the endpoint URL exactly as you would the key itself. To retire a key, revoke it — setting an expiry date does not stop the key from working on this path.

Getting an API key

Create one from the web application under Integrations/API → API Keys (https://report.ostorlab.co/integrations/api). The key's role determines what the MCP tools can do — see Permissions.

Connecting a client

Most clients take a server name, a transport and a URL. The transport is streamable HTTP, so where a client asks for a type, use http.

Claude Code

claude mcp add --transport http ostorlab https://api.ostorlab.co/apis/mcp/YOUR_API_KEY/

Claude Desktop, Cursor, VS Code, Windsurf, Zed

These read a JSON configuration file. The location differs per client and per platform — check your client's documentation for where it lives — but the entry has the same shape:

{
  "mcpServers": {
    "ostorlab": {
      "type": "http",
      "url": "https://api.ostorlab.co/apis/mcp/YOUR_API_KEY/"
    }
  }
}

Some clients name the section servers rather than mcpServers, and some use serverUrl in place of url. If yours rejects the block above, check its documentation for the key names — the transport and the URL are the parts that matter.

Confirming it works

Ask the client to run a read tool, for example listing your scans. A bad key returns Invalid API Key. Asking it to list its tools is not a useful check: the tool list is returned for any key, valid or not.

Permissions

Every tool checks the API key's permissions before doing anything. A key carries a role. A role grants a set of actions. Each tool requires one action.

Tool type Required action
Reading scans, vulnerabilities, tickets, comments and checklists read
Creating or modifying tickets, comments and checklists write
Triaging vulnerabilities write
Starting, re-running and stopping scans write
Listing attack-surface assets and tags attack_surface_read
Accepting or rejecting discovered assets, and adding, changing or removing tags attack_surface_audit
Reading and triaging the discovery queue, and reading the attack-surface graph attack_surface_audit, except the graph which needs attack_surface_read
Managing API keys, users and single sign-on, reading the audit log, reading and changing organisation settings, managing ticket agents, scanners and scanner groups, creating automation rules, and configuring, reading or deleting most integrations admin

A key without the required action gets a clear error rather than a partial result.

Roles map to actions like this:

Role read write admin attack_surface_read attack_surface_audit
reader yes no no yes no
user yes yes no yes yes
admin yes yes yes yes yes
attack_surface_auditor no no no yes yes

Two things follow from that table. attack_surface_read is held by every role, so any key can call list_assets and list_tags. And an attack_surface_auditor key has neither read nor write, so it is limited to the attack-surface tools: it can read assets and tags, and it can accept, reject and edit them, but it cannot see a scan, a vulnerability or a ticket.

If your organisation has object-level access enabled, tools respect it, following the same rules as the GraphQL API-key path:

  • Scans and tickets — a non-admin key only sees the individual scans and tickets it has been granted.
  • Assets — the grant is on the owner, not the asset. A key sees every asset belonging to the owners it has been granted. Use list_owners to see which owners a key can reach, and therefore which assets it can see.

Available tools

The tables below group the tools by what they work on. Each table gives the action the key must hold, so you can tell at a glance which tools a key of a given role can reach.

The server always describes itself. Every tool carries its own description and its own argument list, and a client reads both when it connects. If a tool is not listed here, ask your client to show its tool list — that is the authoritative answer for the server you are talking to.

Scans

Tool Action Description
list_scans read List scans, filtered by status, asset_id, scan_profile, risk_rating, created_after, archived.
get_scan read One scan's details.
get_scan_status read A scan's progress, its recent status history, and any errors it reported.
list_scan_profiles read The scan profiles the organisation can run, with the exact profile names create_scan expects.
search_store_applications read Search the public mobile stores for an application, to get the name and package create_scan expects.
create_scan write Start a scan against a web, network or mobile-store target.
create_source_code_scan write Start a scan of a git repository.
create_source_code_archive_scan write Start a scan of a source archive you have uploaded.
create_mobile_file_scan write Start a scan of a mobile binary you have uploaded.
create_multi_asset_scan write Start one scan covering several targets at once.
create_mobile_testflight_scan write Start a scan of an iOS build distributed through TestFlight.
create_autodiscovery_scan write Start a scan across the organisation's discovered attack surface.
create_rescan write Re-run an existing scan with the same asset, profile, credentials and settings.
stop_scan write Stop a running scan.
generate_scan_report write Produce a PDF report for a scan and return a link to download it.

get_scan and get_scan_status do not return archived scans, even though list_scans can list them. Calling either on an archived scan returns Scan not found.

create_scan takes an asset_type of web, network or mobile_store, and the target fields that go with it: urls for web, networks for network, and mobile_asset_type plus application_name and package_name for a mobile store target. It also takes a scan_profile_name, which must be one of the names list_scan_profiles returns. A name the organisation cannot run is rejected up front, and the error names the profiles that are valid, so call list_scan_profiles first.

create_rescan is the shorter path when the target has been scanned before. It takes only the id of an existing scan and copies everything from it, so there is no profile or asset to get wrong. The new scan is titled Rescan of <original title>, and it is always visible even when the original was hidden.

Other tools start a scan against a target create_scan does not cover. create_source_code_scan takes a git repository. create_mobile_testflight_scan takes an iOS build distributed through TestFlight. create_autodiscovery_scan takes no target at all — it scans the organisation's whole accepted discovery set, so what it covers is whatever list_autodiscovery_assets has had accepted into the inventory. create_multi_asset_scan takes several targets together — web, network, repository, mobile-store and uploaded files — and runs them as one scan.

Two of them take a file rather than a target you can name: create_mobile_file_scan scans a mobile binary, and create_source_code_archive_scan scans a source archive. Both take an upload handle, described next.

Uploading a file to scan

A tool argument is JSON, so it cannot carry the bytes of a file. Upload the file first and pass the handle you get back to the scan tool.

curl -X POST https://api.ostorlab.co/apis/upload/ \
     -H "X-API-Key: <your-api-key>" \
     -F "file=@app.apk"

The response carries an upload_id, along with the filename, size and SHA-256 the server recorded, so you can check the file arrived intact:

{
  "upload_id": "de6024a2-8af5-4e0c-87d2-fdc2c306225f",
  "filename": "app.apk",
  "size": 4171034,
  "sha256": "4ad2930d93c3af606582b26c55ac285485e9623bb508dbf05e5d391b8e4b0969",
  "expires_at": "2026-09-10T09:44:04Z"
}

Pass that upload_id as application_upload_id to create_mobile_file_scan, as archive_upload_id to create_source_code_archive_scan, or in one of the upload lists create_multi_asset_scan takes.

Three things to know about a handle:

  • It belongs to the organisation that uploaded it. A handle from another organisation is refused the same way an unknown one is, with Upload not found.
  • It expires. After that it is refused with Upload has expired.
  • A scan spends it. Once the scan is created the handle stops resolving, so upload again to run a second scan. A call that fails leaves the handle usable, so a retry needs no re-upload.

Warning

Every create_* tool here starts a real scan and consumes scan credits. Have your client show you the target and the profile before it calls one.

Warning

generate_scan_report blocks until the PDF is finished, which can take a few minutes. A slow answer is not a failure. Do not time out or retry before it comes back. The response carries a url, not the file itself. Fetch that URL over HTTPS with the same API key in an X-API-Key header.

AI pentests

An AI pentest — also called an agentic deep scan — is a separate family from a regular scan. Its ids are not the same ids as a scan's, and its results are called risks rather than vulnerabilities.

Tool Action Description
get_agentic_deep_scan read One AI pentest: its state, target, timing and summary.
get_ai_pentest_usage read The AI token usage one AI pentest consumed.
list_risks read The risks an AI pentest found, filtered by pentest and by severity.
list_ai_provider_api_keys read The AI provider API keys the organisation has stored.

Note

Risks are not returned by list_vulnerabilities or search_vulnerabilities, and an AI pentest is not returned by get_scan. Passing an AI pentest id to get_scan answers Scan not found. — which means "wrong tool", not "does not exist". A client that only knows the vulnerability tools will report an AI pentest as having found nothing.

Vulnerabilities

Tool Action Description
list_vulnerabilities read Findings in one scan, filtered by scan_id, risk_rating, kb_detail_id, or the ticket they belong to.
search_vulnerabilities read Findings across every scan, filtered by asset, date range, severity, knowledge-base detail and free text.
get_vulnerability read One finding: technical detail, exploitation detail, CVSS vectors and location metadata.
update_vulnerability write Triage: set a custom risk rating or CVSS vector, or mark a finding false positive or an accepted exception.

Use search_vulnerabilities when the question spans more than one scan — "every critical on this application", "what did we find last month". Use list_vulnerabilities only when you already have one scan id. Do not loop list_vulnerabilities over a list of scans to answer a question search_vulnerabilities answers in a single call.

Two things to know about update_vulnerability:

  • Marking a finding false positive or exception acts on the tickets linked to that finding. A finding with no ticket is unchanged, and the call still reports success.
  • Its all_vulnerabilities parameter applies the change to every finding in the same scan sharing the same knowledge-base detail, and recomputes the scan's overall risk rating. The blast radius is much larger than a single finding.

Every finding carries a dna field — a fingerprint derived from the finding's title, technical detail and location. The same issue found again in a later scan keeps the same dna as long as those three are unchanged, which makes it useful for deduplicating when you import findings elsewhere. It is not guaranteed stable when the technical detail varies between runs.

Scan artefacts

A scan collects more than findings. These tools read what one scan captured while it ran.

Tool Action Description
list_api_endpoints read The API endpoints a scan discovered.
list_http_traffic read The HTTP exchanges a scan captured.
list_http_folders read The HTTP folders a scan observed.
list_pcap_files read The packet captures a scan produced.
list_ide_files read The files found inside a scan's binary.
list_ide_functions read The functions decompiled from a scan's binary.
list_ide_logs read The device-side runtime logs a scan captured while it drove the app.
list_call_ui_nodes read The screens a mobile scan reached while driving the app.
list_stack_traces read The call stacks a scan recorded while it drove the app.

What a scan collected depends on what it ran. A web scan has HTTP traffic and no decompiled binary; a mobile scan can have both. An empty result means that scan collected nothing of that kind, not that the scan failed.

Tickets

Tool Action Description
list_tickets read Tickets, filtered by status, priority, assigned_email, agent, tag, title, created_since, modified_since. Sortable, with a limit.
get_ticket read One ticket, by id or by key (for example os-1234).
create_ticket write Create a ticket, optionally with tags, an assignee, a ticket agent, a due date.
update_ticket write Change any of the same fields.
delete_ticket write Delete a ticket. Not reversible.

Comments and checklists

Tool Action Description
list_comments, create_comment, update_comment, delete_comment read to list, write for the rest Comment thread on a ticket.
list_checklists, create_checklist, update_checklist, delete_checklist read to list, write for the rest Remediation checklists attached to a ticket.
create_checklist_item, update_checklist_item, delete_checklist_item write Individual checklist items.

Note

Adding a comment to a ticket that has a ticket agent assigned will start an agent run.

Comments created through MCP have no author attached, because the server authenticates an API key rather than a user. They render without an author in the web application.

Ticket agents

A ticket agent is an AI agent the platform can run on a ticket to do the remediation work. You route a ticket to an agent by assigning it.

Tool Action Description
list_ticket_agents read The agents tickets can be routed to, with an enabled flag and a summary of what each one runs.
assign_ticket_agent write Assign an agent to a ticket, which starts a run.
create_ticket_agent admin Add a new agent, optionally with the run definition it should use.
update_ticket_agent admin Change an agent's name, description or run definition.
delete_ticket_agent admin Delete an agent.

Warning

Assigning an agent starts a run, and a run cannot be undone. Once a ticket has an agent, every later comment on that ticket starts another run. Read the agent_run field in the response to see whether this run actually started or was skipped — do not assume it began.

Deleting an agent clears the assignment on every ticket that held it. The tickets survive, but their agent is set to none, and the only way back is to create a new agent and assign it ticket by ticket. The response carries an unassigned_tickets count, so check that number before deciding an agent is unused. The agent's run definition is also destroyed, and it cannot be read back in full before deletion — list_ticket_agents returns only a redacted summary of it. Argument values are never returned, so these tools cannot be used to read an agent's credentials.

Ticket streams

A stream groups tickets so they can be tracked together across a sprint, a release or an initiative.

Tool Action Description
list_ticket_streams read Streams, filtered by status, by name substring, or by stream id.
get_ticket_stream read One stream's details.
create_ticket_stream write Create a stream, optionally with a lead, members, attached tickets and dates.
update_ticket_stream write Change any of the same fields.
delete_ticket_stream write Delete a stream. The tickets and the user accounts it referenced are kept.

member_emails and ticket_ids replace the current set rather than adding to it. To add one member, pass the full list of members you want the stream to end up with.

Assets and inventory

Tool Action Description
list_assets attack_surface_read Attack-surface assets, filtered by asset_type, owner_id, search, tags.
create_asset write Register one asset — a domain, an app, an IP address, a repository or a generic node — under an owner.
update_asset write Change one asset's owner, location, colour, note, CIA requirements or tags.
delete_asset write Remove one asset from the inventory.
list_fingerprints attack_surface_read The technologies observed across the inventory.
list_ports attack_surface_read The distinct ports observed across the inventory.
list_protocols attack_surface_read The distinct protocols observed across the inventory.

An asset is identified by the pair asset_type and asset_id, not by the id alone. Each asset subtype lives in its own table, so the same number means different assets in different subtypes. Both update_asset and delete_asset take the pair, and it is the pair list_assets returns.

create_asset is idempotent for the same owner: registering an asset that already exists there returns the existing row with a created flag of false instead of failing. An identifier that already exists under a different owner is rejected with a generic error, so a write cannot be used to discover assets the key cannot see.

Deleting an asset does not delete its scans or its findings. The scan links are cleared, and the scans stay.

tags on update_asset replaces the asset's tags wholesale. It does not merge them.

list_fingerprints, list_ports and list_protocols summarise the inventory rather than list it. Each returns the distinct values seen across the assets the key can reach, which answers "what are we running" and "what is exposed" without paging through list_assets.

Owners

An owner is a team, and it is the boundary object-level access is granted on. When object-level access is enabled, a key sees the assets whose owner it can reach. An owner must exist before assets can be assigned to it.

Tool Action Description
list_owners read The organisation's owners, filtered by a name substring.
create_owner write Create an owner with a name, an ownership type and an optional contact and parent.
update_owner write Rename an owner, change its type, reassign its contact, or move it under a different parent.
delete_owner write Delete an owner.

ownership_type is one of rejected, acquisition, third_party_service or internal.

Warning

delete_owner refuses while the owner still has assets, and while any discovered-but-unconfirmed candidate still points at it. Deletion never cascades — the assets are kept, and the refusal is what keeps them. It is protecting you from what would otherwise follow: were the owner removed while assets still hung off it, every object-level access grant made through it would go with it, silently removing visibility of those assets for every key granted that way. Reassign or delete the assets first, then delete the owner.

For a non-admin key under object-level access, list_owners returns the owners the key has been granted plus their parent owners. An admin key sees every owner in the organisation. An empty result therefore means either the organisation has no owners at all, or this key can reach none of them.

Asset locations

A location is a labelled, optionally nested site or region that assets can be grouped under. It is a label only. It is not a scanner and it does not decide where a scan runs.

Tool Action Description
list_asset_locations read The locations configured for the organisation.
create_asset_location write Create a location with a name, an optional address and an optional parent location.
update_asset_location write Rename a location, change its address, or move it under a different parent.
delete_asset_location write Delete a location.

create_asset_location is idempotent: a location with the same name, address and parent is returned as-is with a created flag of false.

delete_asset_location refuses while assets are still pinned to the location, and while any child location still nests under it. Deletion never cascades: the assets and the child locations are kept, and the refusal is what keeps them. Move or remove them first, then delete the location.

Discovered assets

Attack-surface discovery proposes candidates. A candidate sits in a review queue until someone accepts it into the inventory or rejects it.

Tool Action Description
list_autodiscovery_assets attack_surface_audit The pending discovery queue, filtered by key pattern, candidate type, score range and owner.
accept_autodiscovery_asset attack_surface_audit Promote one candidate into the inventory.
reject_autodiscovery_asset attack_surface_audit Dismiss one candidate.
assign_potential_node_owner attack_surface_audit Assign pending candidates to an owner.
compute_potential_assets attack_surface_audit Recompute the queue now instead of waiting for the next run.
suggest_autodiscovery_domains attack_surface_audit Suggest the domains a company owns, from a free-text description of it.
get_attack_surface_graph attack_surface_read The graph neighbourhood around one or more starting points.

Warning

Accepting a candidate makes the asset scannable and billable — it joins the inventory, becomes a scan target, and counts against the organisation's plan. Both accept and reject take a single explicit id and have no bulk or filter form, on purpose, so a model cannot sweep the whole queue into the inventory in one call. Review each candidate.

Rejecting a candidate whose key has no matching inventory asset also records the key so later discovery runs stop proposing it. Rejecting a candidate whose key already matches an existing asset only drops it from the queue, and a later discovery run may propose it again.

assign_potential_node_owner sets the owner a candidate will land under before it is accepted, so the asset arrives in the inventory already attributed to a team. It does not accept the candidate — it stays in the queue until accept_autodiscovery_asset is called on it.

get_attack_surface_graph answers "what is this connected to". You give it one or more starting points and it walks outward from them, returning the neighbourhood it reaches as two flat lists — the nodes, and the edges linking them. The walk is bounded, so a starting point in a dense part of the graph returns a capped neighbourhood rather than everything reachable from it.

compute_potential_assets runs discovery on demand rather than waiting for the next scheduled run. Calling it while a run is already going joins that run instead of starting a second one, so calling it twice is harmless.

Discovery configuration

Discovery is steered by a prompt describing what the organisation owns, so the candidates it proposes are relevant to you rather than to any company with a similar name.

Tool Action Description
get_attack_surface_agent_config read The prompt that steers discovery for the organisation.
create_attack_surface_agent_config write Set that prompt.
update_attack_surface_agent_config write Change it.
delete_attack_surface_agent_config write Remove it.

suggest_autodiscovery_domains is the companion to these: it turns a free-text description of a company into a list of domains it probably owns, which is a way to draft the prompt rather than write it from nothing. It only suggests — nothing is added to the queue or the inventory by calling it.

Tags

A tag is a name and value pair, so the same name can exist several times with different values — env=prod and env=staging are two tags. Pass a value to create one of those. Omit it for a plain label.

Tool Action Description
list_tags attack_surface_read The tags defined in the organisation, filtered by a name substring.
list_asset_tags attack_surface_read The tags actually in use on the assets the key can reach.
add_tag attack_surface_audit Create a tag, with an optional colour, description and icon.
update_tag attack_surface_audit Rename or restyle a tag.
delete_tags attack_surface_audit Delete tags by id.
delete_unused_tags attack_surface_audit Delete every tag nothing references.

Tag names are specific to an organisation, so a guessed name matches nothing rather than failing. Call list_tags before you filter by a tag or attach one.

update_tag changes the tag everywhere it is used, so every ticket and asset carrying it shows the new name. It is not a way to move some items onto a different tag. Renaming a tag onto a name/value pair another tag already holds is refused, so nothing is merged behind your back.

delete_tags removes the tag from every ticket and asset that carried it. Those tickets and assets are kept — only the tag link goes. The call is all-or-nothing: if any id is unknown or unreachable, nothing is deleted and the error names those ids.

list_tags returns every tag defined in the organisation, including ones nothing uses. list_asset_tags returns only the tags in use on assets the key can reach, which is the shorter list to pick a filter from.

delete_unused_tags takes no ids. It deletes every tag that no ticket and no asset references, in one call, and that cannot be undone. Compare list_tags against list_asset_tags first so you know what it will remove.

Test credentials

A test credential is a reusable login the platform can use to authenticate during a scan.

Tool Action Description
list_test_credentials read The stored credentials, filtered by type and by a substring of the non-secret fields.
create_test_credential write Store a new credential of one of the supported types.
update_test_credential write Replace a stored credential's values, keeping its id.
delete_test_credential write Delete a credential.

Stored secrets are never returned. list_test_credentials gives you the non-secret identifiers and a has_secret flag per row.

update_test_credential is a full replacement, not a merge. Every field of the credential type that you leave out is cleared, including the credential_name label. Pass the current value of anything you want to keep. Its credential_type must match the type the credential was created with.

Prefer update_test_credential over delete-and-recreate when you are rotating a value: the id keeps resolving, so scans already configured to use that credential keep authenticating. Deleting a credential makes those scans start failing authentication.

Scheduled scans

A schedule rule fires scans on a recurring cadence, which is how coverage stays current between one-off scans.

Tool Action Description
list_schedule_rules read The organisation's schedule rules, filtered by whether they are enabled.
create_schedule_rule write Create a rule over one or more assets, with a scan profile and a cadence.
update_schedule_rule write Change a rule's assets, profile, cadence or enabled state.
delete_schedule_rule write Delete a rule. Not reversible.

The cadence is one of two kinds. With cadence_type set to cron, crontab is a standard five-field cron expression such as 0 16 * * * for every day at 16:00. With cadence_type set to continuous, max_no_scan_duration_seconds is the longest gap allowed between two scans of the rule's assets.

Warning

A rule is created disabled by default, because an enabled rule fires recurring billable scans. Leave active at its default, check the rule with list_schedule_rules, and only then enable it. Pass active=True on creation only when you mean the rule to start firing straight away.

update_schedule_rule is how you enable a rule once you have checked it, by passing active=True. It is also how you switch one off again without losing it. delete_schedule_rule removes the rule for good; the scans it already fired are kept.

Automation rules

An automation rule runs one action whenever findings match a condition. It is how auto-ticketing and notification routing are wired up.

Tool Action Description
list_automation_rules read The organisation's shared rules, filtered by context and by whether they are enabled.
list_action_definitions read The actions a rule can run, and the arguments each one expects.
update_automation_rule write Change a rule's name, condition, action, context or sharing, or switch it off.
delete_automation_rule write Delete a rule.
create_automation_rule admin Create a rule from a context, a filter query and a single action.

context is one of attack_surface, remediation or inventory. filter_query is the condition, written as a JSON array, and it must contain at least one entry — an empty array applies no filter, so the rule would match every row in its context.

Like a schedule rule, a new automation rule is created disabled. Confirm the condition and the action, then enable it with update_automation_rule.

To switch a rule off but keep it, call update_automation_rule with active=False. That is reversible. delete_automation_rule is not.

Only rules shared with the whole organisation are visible to an API key. Rules a person keeps private to themselves are not returned.

The action a rule runs must be one the platform defines. Call list_action_definitions before create_automation_rule to see which actions exist and what each one takes, rather than guessing an action name and reading the failure.

Scanners

A scanner is a machine of your own that runs scans, so scan traffic leaves your network instead of Ostorlab's. A scanner group collects several of them so a scan can be pointed at the group rather than at one machine.

Tool Action Description
list_scanners read The scanners the organisation can use.
list_scanner_groups read The scanner groups defined in the organisation.
create_scanner admin Register a scanner so a scan can be pinned to it.
update_scanner admin Change a scanner's name, description or group membership.
delete_scanner admin Retire a scanner. Not reversible.
create_scanner_group admin Create a scanner group.
update_scanner_group admin Change a group's name, description or member scanners.
delete_scanner_group admin Delete a scanner group.
grant_scanner_access admin Let child organisations run scans on one of your scanners.
revoke_scanner_access admin Take that access away.

grant_scanner_access and revoke_scanner_access only reach organisations that are children of yours, and the scanner must be one your organisation owns. The grant is all-or-nothing: a list naming an organisation that is not a child of yours is rejected before anything is written, so a mixed list never grants in part.

Integrations

Tool Action Description
list_integrations read The third-party integrations the organisation has connected, with their enabled state and non-secret target.
get_jira_ticket_map read Whether a ticket was pushed to Jira, and which Jira issue it became.
configure_jira_integration write Set or replace the Jira workspace URL, credentials and default project.
configure_slack_integration write Add a Slack webhook and choose which scan-completion events notify on it.
create_servicenow_ticket write Push one ticket to ServiceNow as an incident.
get_slack_integration admin Read the Slack webhooks configured, and their notification toggles.
delete_git_pat_integration admin Delete a Git personal access token integration.
delete_servicenow_sync_config admin Delete a ServiceNow sync configuration.

Call list_integrations before anything that depends on an integration — pushing a ticket, sending a notification, or naming a provider in an answer. It tells you which providers are connected, so you do not have to attempt the action and read a failure to find out. An integration reported as enabled may still have expired or revoked credentials; these tools cannot tell you whether it currently works.

Credentials are never returned by any of these tools. That includes Jira API tokens, OAuth secrets, passwords, and Slack incoming-webhook URLs. Only allow-listed non-secret fields come back.

The two configure tools behave differently on a repeat call. Jira is one configuration per organisation, so calling configure_jira_integration again updates the same row and replaces the previous credentials. Slack is not, so calling configure_slack_integration again adds a second webhook rather than changing the first.

Warning

delete_git_pat_integration stops source-code scans and automated fix pull requests that relied on it. The stored token is removed from Ostorlab but stays valid at the provider, so revoke it at the provider separately.

delete_servicenow_sync_config also destroys the record of which tickets were already pushed under that configuration. The ServiceNow incidents themselves stay, but the link from each Ostorlab ticket to its incident number is lost, so an already-pushed ticket can no longer be traced or updated. Deleting the last enabled sync configuration stops tickets reaching ServiceNow entirely.

The table above is the short list. The sections below cover the rest of the tools for each provider: the tables there add to that list rather than repeat it.

Webhooks

A webhook integration is a URL of yours that Ostorlab posts events to.

Tool Action Description
create_webhook_integration admin Set where Ostorlab posts event notifications.
update_webhook_integration admin Change a webhook's endpoint, headers or enabled state.
delete_webhook_integration admin Delete a webhook integration.

Slack

Tool Action Description
update_slack_integration admin Change one Slack webhook's URL or its notification toggles.
delete_slack_integration admin Delete one Slack webhook.

Because configure_slack_integration adds a webhook rather than replacing the previous one, update_slack_integration is how an existing webhook is changed. Both it and delete_slack_integration take an id, which is the id get_slack_integration returns.

Jira

Tool Action Description
get_jira_integration admin The stored Jira configuration, without its credentials.
test_jira_integration admin Run the Jira checks and report each result by name.
create_jira_ticket_map write Record that a ticket corresponds to a Jira issue that already exists.
update_jira_ticket_map write Repoint a ticket's Jira mapping at another issue.
delete_jira_ticket_map write Detach a ticket from its Jira issue.
create_jira_ticket write File a new Jira issue for a ticket and record the mapping.
list_jira_metadata admin The projects, issue types and fields the stored credentials can see.

A ticket map is the link between one Ostorlab ticket and one Jira issue, and get_jira_ticket_map reads it. The three map write tools maintain that link by hand, for issues filed in Jira outside Ostorlab. They change the link only. No Jira issue is created, edited or deleted by any of them, so detaching a ticket leaves the Jira issue standing.

create_jira_ticket is the one that does reach Jira. It files a new issue for the ticket and records the mapping in the same call, so it is the tool to use when the Jira issue does not exist yet. A failure leaves nothing behind — no issue and no mapping — and names what was wrong, so a project the credentials cannot see is reported as such rather than as a generic error.

list_jira_metadata is how you find the values create_jira_ticket and configure_jira_integration need: the projects the credentials can reach, the issue types each project accepts, and the fields available for mapping. An empty result means the credentials see no project, which is worth checking with test_jira_integration before assuming the tool is at fault.

test_jira_integration reports each check by name, so a failure tells you which part is wrong — the URL, the credentials or the project — rather than only that something is.

Linear

Tool Action Description
configure_linear_integration admin Set or replace the Linear connection.
get_linear_integration admin The stored Linear configuration, without its credentials.
test_linear_integration admin Report whether Linear is set up, enabled and reachable.
list_linear_teams admin The Linear teams issues can be filed against.

ServiceNow

Tool Action Description
configure_servicenow_integration admin Set or replace the ServiceNow connection.
test_servicenow_integration admin Run the checks of one ServiceNow configuration and report each result by name.
delete_servicenow_integration admin Delete a ServiceNow integration.
configure_servicenow_sync_config admin Map tickets onto a ServiceNow table and its fields.
get_servicenow_sync_config read How one sync configuration maps tickets to a table.
list_servicenow_fields read The columns of the ServiceNow table a sync configuration targets.
get_servicenow_ticket_map read Whether a ticket was pushed to ServiceNow, and which record it became.
create_servicenow_ticket_map write Record that a ticket maps to a ServiceNow record that already exists.
update_servicenow_ticket_map write Repoint a ticket's ServiceNow mapping at another record.
delete_servicenow_ticket_map write Detach a ticket from its ServiceNow record.

ServiceNow is set up in two steps. configure_servicenow_integration stores the instance and its credentials. configure_servicenow_sync_config then says which table tickets are written to and which column each ticket field maps onto. Call list_servicenow_fields first to see the columns that table actually has, so the mapping names real columns.

The ticket-map tools work the same way as the Jira ones: they maintain the link between an Ostorlab ticket and a ServiceNow record, and never touch the record itself. create_servicenow_ticket is the tool that does create a record.

Source code

Tool Action Description
list_repositories read The repositories Ostorlab can currently reach.
create_git_pat_integration admin Register a Git personal access token.
update_git_pat_integration admin Replace a stored token or change what it covers.
create_standard_git_integration admin Register a self-hosted Git instance.
update_standard_git_integration admin Change a self-hosted Git registration.
delete_standard_git_integration admin Delete a self-hosted Git registration.
enable_github_app_connection admin Resume source-code scans and pull requests for a GitHub App's repositories.
disable_github_app_connection admin Stop them, keeping the installation in place.
delete_github_app_connection admin Remove a GitHub App installation from the organisation.
update_source_code_oauth_integration admin Activate or deactivate a source-code OAuth integration.
delete_source_code_oauth_integration admin Delete a source-code OAuth integration.

list_repositories is the tool to call before create_source_code_scan. It returns the repositories the connected source-code integrations currently expose, so you scan something the platform can actually clone rather than a name you guessed.

disable_github_app_connection is the reversible form of delete_github_app_connection. Disabling stops scans and pull requests but keeps the installation, so enable_github_app_connection puts it back as it was. Deleting removes the installation, and getting it back means going through GitHub to install the app again.

App Center

Tool Action Description
create_app_center_integration admin Connect an App Center app so its builds are scanned automatically.
update_app_center_integration admin Change an App Center integration.
delete_app_center_integration admin Delete an App Center integration.

Vanta

Tool Action Description
get_vanta_auth_url admin The link to open in a browser to authorise Ostorlab with Vanta.
delete_vanta_integration write Disconnect Vanta.

Connecting Vanta needs a browser. get_vanta_auth_url returns the link a person opens to authorise Ostorlab, and the connection is completed there rather than through a tool, so a client cannot finish this one on its own.

Organisation and access

Tool Action Description
me none beyond a valid key The organisation the key belongs to, and the role the key carries.
list_shared_access_tokens read The organisation's active share links, with the scan each grants and how often it has been used.
list_invitations read The people invited to the organisation who have not joined yet.
create_shared_access_token write Create a link that lets someone without an account read one scan.
revoke_shared_access_token write Disable a share link immediately.
list_organisation_users admin Who has access to the organisation, at what role, and scoped to which owners.
add_user admin Invite someone to join the organisation at a given role.
update_user_access admin Change a member's role, or the owners they are scoped to.
revoke_user admin Remove someone's access to the organisation.
review_invitation admin Accept or decline a pending invitation.
get_organisation_settings admin The organisation's settings and entitlements.
update_organisation_settings admin Change the settings that can be written.
list_api_keys admin The organisation's API keys: name, role, created and expiry dates, revoked state, and a masked form of the key.
update_api_key admin Narrow a key: lower its role, drop owner grants, bring its expiry forward, or rename it.
revoke_api_key admin Disable an API key immediately.
list_audit_actions admin Who changed what, and when, filtered by time range and by actor.

me describes the key, not a person. The server authenticates a key, so the answer to "who am I" is the organisation the key belongs to and the key's own name, prefix, role, owner grants and expiry. No user account is returned.

add_user sends an invitation rather than creating an account. The person shows up in list_invitations until they accept, and only then in list_organisation_users.

update_api_key can only narrow a key. The role it sets must be no higher than the role the key already has, owner grants can be dropped but not added, and an expiry can only be brought forward. So it is not a way to give a key more than it has, and it never returns key material.

Revoking is the only thing that disables an API key. An expiry date on its own does not — the key keeps working on the MCP path until revoked is set. revoke_api_key sets it, and the change cannot be undone. A key cannot revoke itself; that call is refused, since it would cut your own connection mid-session.

The plaintext of an API key is never returned by any tool. It exists only at the moment the key is created, and only its hash is stored afterwards. list_api_keys returns a masked_key instead — the key's prefix followed by asterisks, the same form the web application and the audit trail show. Use that when you need to name a key to a person.

Warning

Anyone holding a shared access token can read the scan it points at, and its findings, without an account. These tokens do not expire. list_shared_access_tokens lists only the shares that are live right now, so every row is access someone currently has. The raw token comes back only once, in the response to create_shared_access_token.

list_audit_actions returns an empty list rather than an error when the organisation has action auditing switched off. The response carries a message field saying so, so that "no rows" is not read as "nothing happened".

Single sign-on

Tool Action Description
get_saml_config admin The organisation's SAML single sign-on configuration.
configure_saml admin Set SAML single sign-on up.
update_saml admin Change the SAML configuration.

configure_saml is a strict create: it is refused when the organisation already has a configuration, and it never replaces one. update_saml is the tool for an existing configuration, and it is a partial update — only the fields you supply are written. Call get_saml_config first to see which of the two applies.

Remediation SLOs

An SLO here is a deadline: the number of days a ticket of a given severity or priority is allowed to stay open.

Tool Action Description
get_slo_config read The organisation's per-severity and per-priority windows, in days.
update_slo_config write Change those windows.

A window of null means there is no deadline for that severity or priority. update_slo_config is a partial update: a key you include with a positive number sets that window, a key you include as null clears it, and a key you leave out is unchanged. An unknown key is rejected.

UI automation prompts

Tool Action Description
list_ui_automation_rules read The UI automation rules available to the organisation.
create_ui_prompts write Create UI automation prompts.
update_ui_prompts write Change the code, name or description of UI automation prompts your organisation owns.
delete_ui_prompts write Delete UI automation prompts your organisation owns. Not reversible.

code is a full replace and is written on every call, while name and description are written only when you supply them. So a call that only means to rename a prompt must still send the prompt's existing code, or the code is overwritten with whatever was sent.

The call is not all-or-nothing. Prompts that could be reached are updated even when others could not. The response names the ids that were updated and, for each of the rest, why it was not.

list_ui_automation_rules also returns rules the organisation does not own, which are the shared ones every organisation can use. Only the ones your organisation owns can be changed or deleted, so a prompt that lists fine can still be refused by update_ui_prompts and delete_ui_prompts.

Knowledge base

The knowledge base is Ostorlab's own reference data. It is the same for every organisation rather than a view of yours, so these tools return rows that have nothing to do with your scans.

Tool Action Description
list_cves read CVE records, looked up by id, by severity, or by text in the description.
list_kb_applications read The public applications Ostorlab watches for newly published CVEs.
list_kb_targets read The rows linking a CVE to the application versions it affects.
list_app_cards read The shared App Cards available in Ostorlab.

list_kb_targets is the join between the other two: given a CVE it names the affected application versions, and given an application it names the CVEs published against it.

Agent store

A scan profile is built out of agents. The store is the catalogue of agents that exist.

Tool Action Description
search_agents read Search the agent store by name.
get_agent read One agent, with the arguments its latest version takes.

search_agents is the discovery step and get_agent is the detail step: search by name to find the agent's key, then read the arguments that key accepts.

Exports

Each of these builds a file and returns a link to it, not the content itself. Fetch that URL over HTTPS with the same API key in an X-API-Key header, the same way generate_scan_report works.

Tool Action Description
export_scan read The full archive of one scan.
export_scan_sarif read One scan's findings as SARIF.
export_vulnerabilities read One scan's findings as CSV.
export_tickets read Remediation tickets as CSV.
export_assets attack_surface_read The confirmed inventory assets as CSV.
export_potential_nodes attack_surface_read The pending discovery candidates as CSV.

The two attack-surface exports need attack_surface_read, which every role holds. The other four need read, so an attack_surface_auditor key can export assets and discovery candidates but not scans, findings or tickets.

Result limits

Every list tool caps how much it returns. What a tool tells you about that cap is not the same everywhere. There are three behaviours.

Some list tools return a cursor. A cursor is an opaque token that marks the point where the page you just received ended. It comes back in a next_cursor field. Pass that value back as the cursor argument on the next call and you get the following page. A next_cursor of null means you have reached the last page. Do not read a cursor or build one yourself — what is inside it is an implementation detail, and it only means anything to the tool that produced it.

Some list tools return a truncated boolean. It tells you that more rows exist, but it gives you no way to fetch them. Narrow the query with filters instead.

A few return neither. For those the cap is silent: you get the capped number of rows, and nothing tells you that more exist.

Tool Default Maximum How more rows are signalled
list_scans 200 200 next_cursor
list_vulnerabilities 200 200 next_cursor
list_assets 200 200 next_cursor
list_risks 200 200 next_cursor
get_scan_status (status history) 50 50 nothing
list_scan_profiles no limit no limit not applicable
list_checklists no limit no limit not applicable
search_vulnerabilities 200 200 truncated
list_tags 200 200 next_cursor
list_api_keys 200 200 truncated
list_shared_access_tokens 200 200 truncated
list_ticket_agents 100 100 truncated
list_owners 200 200 next_cursor
list_asset_locations 200 200 next_cursor
list_autodiscovery_assets 200 200 next_cursor
list_test_credentials 200 200 next_cursor
list_integrations 200 200 next_cursor
list_audit_actions 200 200 next_cursor
list_organisation_users 200 200 next_cursor
list_schedule_rules 100 100 next_cursor
list_automation_rules 100 100 next_cursor
get_slack_integration 100 100 next_cursor
list_ticket_streams 50 200 next_cursor
list_tickets 50 200 truncated and next_cursor
list_comments 50 200 truncated and next_cursor

Asking for more than the maximum is clamped down to it rather than rejected. Asking for zero, a negative number, or something that is not a number is rejected with Invalid limit. A cursor is tied to the filters it was produced under, so replaying one under different filters is rejected with Invalid cursor. rather than quietly returning the wrong page.

Where a tool signals nothing, the cap is the whole answer you get: a scan with 500 status entries returns 50 from get_scan_status, with nothing to indicate the other 450 exist. Narrow with filters when the count matters — do not ask a model to count from a list result.

Deleting

Every delete_* and revoke_* tool on this page removes data permanently. That includes delete_ticket, delete_comment, delete_checklist and delete_checklist_item, and equally delete_asset, delete_owner, delete_asset_location, delete_tags, delete_unused_tags, delete_test_credential, delete_scanner, delete_scanner_group, delete_schedule_rule, delete_automation_rule, delete_ui_prompts, delete_ticket_agent, delete_ticket_stream, delete_checklist, the integration deletes, and revoke_api_key, revoke_shared_access_token and revoke_user.

Some of them refuse rather than cascade. delete_owner and delete_asset_location will not run while something still depends on them, and delete_asset keeps the scans and findings that were attached to the asset. Where a tool cascades or keeps data, the section describing it says so.

Tools advertise annotations to the client. An annotation is a hint that travels with the tool in the tool list and describes what calling it does, so the client can decide whether to ask you first. Three hints are used:

  • readOnlyHint — the tool changes nothing.
  • destructiveHint — the tool changes state in a way that cannot be undone.
  • idempotentHint — calling the tool twice has the same effect as calling it once.

Those tools are annotated as destructive, and so is every other tool that removes or overwrites data.

Warning

An annotation is a hint, not enforcement. Whether you are actually asked to confirm is up to your client. Some clients prompt every time a destructive tool is called, some prompt once and remember the answer, and some do not prompt at all. The server runs the call either way. Check how your client handles destructive hints before you point a model at a key that can write.

Not every tool carries annotations. A tool that carries none leaves the client to fall back on the MCP specification's default, which assumes the call is destructive and not idempotent. That means an unannotated read tool can look more dangerous to a cautious client than it really is.

Errors

A tool that fails returns a normal successful response whose body carries an error field:

{"error": "Invalid API Key."}

The JSON-RPC isError flag stays false. If your client branches on isError, it will read authentication and permission failures as successes — check for the error field instead.

Examples

Prompts that work well once the server is connected:

  • "List the scans that finished in the last week with a high risk rating."
  • "Show me the critical findings from scan 12345 and open a ticket for each one."
  • "What's the technical detail of vulnerability 987, and has anyone commented on its ticket?"
  • "Mark vulnerability 654 as a false positive."
  • "Which open tickets are assigned to rubberduck?"
  • "Which scan profiles can we run against a web target, and start a Fast Scan on example.com."
  • "Which of our API keys have never been revoked and were created more than a year ago?"
  • "What is sitting in the attack-surface discovery queue with a score above 80?"

Troubleshooting

HTTP 404 on connect The URL is missing the key segment, or the trailing slash. It must be /apis/mcp/YOUR_API_KEY/.

Invalid API Key. The key does not resolve. Check it was copied whole, and that it has not been revoked.

API Key does not have write permission. The tool needs a higher role than the key has. Issue a key with the required role.

Scan not found. for a scan you can see in the web application Four possible causes: the scan is archived (get_scan and get_scan_status refuse archived scans), the scan belongs to another organisation, your organisation uses object-level access and this key has not been granted that scan, or the id is an AI pentest rather than a scan — the scan tools do not resolve AI pentest ids, so use get_agentic_deep_scan for those. An inaccessible scan is deliberately reported the same way as one that does not exist.