MCP Server
How to read and change PentaTrail CTEM data from an AI tool you have approved. This page covers connecting and approving, and what each tool does with a worked example.
Connecting
https://api.pentatrail.co/mcp1. Register the endpoint
Add https://api.pentatrail.co/mcp to your MCP-capable AI tool as a remote server. No key or user name is needed.
2. Approve it in your browser
When the tool connects, your browser opens the PentaTrail sign-in and approval screen. The screen lists what that connection can actually do. Read it and choose “Approve”.
3. The tools become available
Once approved, the tools on this page are callable from your AI tool. If you hold more than one contract, use ctem_list_my_contracts to find the contract_id and pass it to the other tools.
4. You can revoke it at any time
Approved tools can be revoked at any time from Settings in the admin console (admin.pentatrail.co). Once revoked, that tool can read nothing.
Read tools
Tools that answer questions about the current state, bundled so one call is usually enough.
This page lists the required arguments and what each action needs. Optional arguments such as filters and sort keys are described by the tools themselves — the tool list your AI client receives (tools/list) is the authority for the full set.
ctem_list_domainsThe monitored domains and their verification state. Start here — every id in the default result can be passed to the other tools as domain_id.
Arguments
contract_idoptionalOptional when you belong to a single contract. Required only if you belong to more than one.include_archivedoptionalAlso return domains removed from monitoring (default false). Ids that are not active cannot be used as domain_id elsewhere.domain_idoptionalWhen given, the WHOIS registration facts for that domain are included.ctem_list_domains()
{
"data": { "domains": [ … ], "plan": { … } }
}ctem_get_domain_overviewThe current state of one domain: asset counts, open findings by Threat Discovery Level, and what changed recently — in one call.
Arguments
contract_idoptionalOptional when you belong to a single contract. Required only if you belong to more than one.domain_idrequiredThe domain to work on. Pass an id returned by ctem_list_domains.ctem_get_domain_overview({ domain_id: "…" })
{
"data": {
"assets_counts": { … },
"findings_severity": { … },
"changes": [ … ]
}
}ctem_list_assetsLists discovered assets. Pick what to look at with kind (hosts, IPs, URLs, ports, technologies, buckets, exclusions, and the hosts approved for active scanning).
Arguments
contract_idoptionalOptional when you belong to a single contract. Required only if you belong to more than one.domain_idrequiredThe domain to work on. Pass an id returned by ctem_list_domains.kindrequiredWhich assets to list: host / ip / url / port / port_group / tech / tech_group / bucket / exclusion / scan_scope. exclusion is the only place exclusion ids come from, and scan_scope lists the hosts approved for active scanning.pageoptionalPage number (default 1).limitoptionalItems per page (default 20).searchoptionalKind-specific search. Filters a kind does not accept are rejected rather than silently ignored.ctem_list_assets({ domain_id: "…", kind: "host" })
{
"data": { "assets": [ … ] },
"pagination": { "page": 1, "limit": 20, … }
}ctem_list_findingsLists findings, highest Threat Discovery Level first. With status omitted you get open findings only, excluding informational ones.
Arguments
contract_idoptionalOptional when you belong to a single contract. Required only if you belong to more than one.domain_idrequiredThe domain to work on. Pass an id returned by ctem_list_domains.pageoptionalPage number (default 1).limitoptionalItems per page (default 20).statusoptionalFilter by status. Pass all to see every status.ctem_list_findings({ domain_id: "…" })
{
"data": { "findings": [ … ], "matrix": [ … ] },
"pagination": { … }
}ctem_get_findingOne finding in detail, together with its detection history and the AI deep scan jobs tied to it.
Arguments
contract_idoptionalOptional when you belong to a single contract. Required only if you belong to more than one.finding_idrequiredThe finding to read. Pass an id returned by ctem_list_findings. This tool takes no domain — the finding id is enough.ctem_get_finding({ finding_id: "…" })
{
"data": {
"finding": { … },
"detection_history": { "first_detected": "…", "events": [ … ] },
"deep_scan_jobs": [ … ]
}
}ctem_get_prioritizationWhat to work on next: risk bands, the hosts behind them, owners, classification, and attack-path chokepoints — in one call.
Arguments
contract_idoptionalOptional when you belong to a single contract. Required only if you belong to more than one.domain_idrequiredThe domain to work on. Pass an id returned by ctem_list_domains.fqdnoptionalOptional. When given, the detail for that host is included as well.asset_typeoptionalOptional. When given, the classification tags for that asset type are included as well.ctem_get_prioritization({ domain_id: "…" })
{
"data": {
"bands": [ … ],
"hosts": [ … ],
"host_owners": [ … ],
"chokepoints": { "rows": [ … ], "uncovered_finding_count": … }
}
}ctem_list_groupsGroups, their members, and the people on the contract. Pass group_id to include that group’s members as well.
Arguments
contract_idoptionalOptional when you belong to a single contract. Required only if you belong to more than one.domain_idrequiredThe domain to work on. Pass an id returned by ctem_list_domains.group_idoptionalOptional. When given, that group’s members are included as well.ctem_list_groups({ domain_id: "…" })
{
"data": {
"groups": [ … ],
"contract_members": [ … ],
"triage_summary": { … }
}
}ctem_get_validation_stateWhether AI deep scanning is running — and if not, why. Includes the batches in flight and the history.
Arguments
contract_idoptionalOptional when you belong to a single contract. Required only if you belong to more than one.domain_idrequiredThe domain to work on. Pass an id returned by ctem_list_domains.ctem_get_validation_state({ domain_id: "…" })
{
"data": {
"origin_state": { … },
"active_batches": [ … ],
"finding_stats": { … },
"history": [ … ]
}
}ctem_list_tasksThe remediation tasks and how far they have got. Pass task_id to also learn which page a single task is on.
Arguments
contract_idoptionalOptional when you belong to a single contract. Required only if you belong to more than one.domain_idrequiredThe domain to work on. Pass an id returned by ctem_list_domains.pageoptionalPage number (default 1).limitoptionalItems per page (default 20).task_idoptionalOptional. When given, the location of that one task is included as well.ctem_list_tasks({ domain_id: "…" })
{
"data": { "tasks": [ … ], "progress": { … } },
"pagination": { … }
}ctem_get_executive_summaryThe executive view: score trend and the weekly summary. With week_start omitted it uses the latest week available. When a contract has no week to choose from, weekly_snapshot and week_start are absent from the reply rather than null; when a week exists but carries no summary, weekly_snapshot is null, and the briefing is null until one has been produced.
Arguments
contract_idoptionalOptional when you belong to a single contract. Required only if you belong to more than one.domain_idrequiredThe domain to work on. Pass an id returned by ctem_list_domains.week_startoptionalOptional. When omitted the latest available week is used. If no week is available, the weekly section is skipped.ctem_get_executive_summary({ domain_id: "…" })
{
"data": {
"score_trend": [ … ],
"snapshot_weeks": [ … ],
"weekly_snapshot": { … },
"briefing": { … }
}
}Write tools
Tools that change state. Related operations share one tool; pick the operation with action.
ctem_manage_domainStart monitoring a domain, ask for ownership verification, or remove it from monitoring.
registerrequest_verificationarchiveArguments
contract_idoptionalOptional when you belong to a single contract. Required only if you belong to more than one.actionrequiredWhich operation to perform: register / request_verification / archive. Each action needs its own arguments; when one is missing the tool tells you which.domainoptionalFor action="register": the domain name to start monitoring.origin_domain_idoptionalFor action="request_verification" / "archive": which monitored domain.ctem_manage_domain({ action: "register", domain: "example.com" })
{
"data": { "domain_id": "…", "domain": "example.com", "status": "active" }
}ctem_manage_exclusionsExclude assets from monitoring, or restore them — one at a time or in bulk. The exclusion ids you need to restore come from ctem_list_assets({ kind: "exclusion" }).
excludeexclude_bulkrestorerestore_bulkArguments
contract_idoptionalOptional when you belong to a single contract. Required only if you belong to more than one.actionrequiredWhich operation to perform: exclude / exclude_bulk / restore / restore_bulk. Each action needs its own arguments; when one is missing the tool tells you which.domain_idoptionalFor action="exclude": which domain the asset belongs to.origin_domain_idoptionalFor action="exclude_bulk" / "restore_bulk": which domain the assets belong to.categoryoptionalFor action="exclude" / "exclude_bulk" / "restore_bulk": the asset category.category_keyoptionalFor action="exclude": the single asset key.category_keysoptionalFor action="exclude_bulk" / "restore_bulk": the asset keys.exclusion_idoptionalFor action="restore": which exclusion to lift.ctem_manage_exclusions({ action: "restore", exclusion_id: "…" })
{
"data": null
}ctem_manage_groupCreate, change and delete groups, assign hosts to them, and add or remove people.
createupdatedeleteassign_hostsadd_memberremove_memberArguments
contract_idoptionalOptional when you belong to a single contract. Required only if you belong to more than one.actionrequiredWhich operation to perform: create / update / delete / assign_hosts / add_member / remove_member. Each action needs its own arguments; when one is missing the tool tells you which.group_idoptionalFor every action but create: which group. If you omit it with action="assign_hosts", the assets you list are removed from their current group.nameoptionalFor action="create" (required) / "update": the group name.user_idoptionalFor action="add_member" / "remove_member": which person.asset_typeoptionalFor action="assign_hosts": host or ip.asset_idsoptionalFor action="assign_hosts": which assets.ctem_manage_group({ action: "create", name: "公開Web" })
{
"data": { "group_id": "…" }
}ctem_classify_assetAdd and remove classification tags, and set the management type.
add_tagsremove_tagsset_management_typeArguments
contract_idoptionalOptional when you belong to a single contract. Required only if you belong to more than one.actionrequiredWhich operation to perform: add_tags / remove_tags / set_management_type. Each action needs its own arguments; when one is missing the tool tells you which.tagsoptionalFor action="add_tags": the tag rows to write.asset_typeoptionalFor action="remove_tags": host or ip.asset_idsoptionalFor action="remove_tags": which assets.tag_keyoptionalFor action="remove_tags": which tag.host_idoptionalFor action="set_management_type": which host.management_typeoptionalFor action="set_management_type": the new management type.ctem_classify_asset({ action: "set_management_type", host_id: "…", management_type: "…" })
{
"data": null
}ctem_manage_validationOnly the stopping side of AI deep scanning. ⚠ Starting it stays in the console — approving hosts and consenting to automatic runs are done there.
revoke_host_approvalrevoke_autorun_consentdisablecancel_batchArguments
contract_idoptionalOptional when you belong to a single contract. Required only if you belong to more than one.actionrequiredWhich operation to perform: revoke_host_approval / revoke_autorun_consent / disable / cancel_batch. Each action needs its own arguments; when one is missing the tool tells you which.origin_domain_idoptionalWhich domain (needed by every action but cancel_batch).fqdnsoptionalFor action="revoke_host_approval": the hosts whose approval is taken back.batch_idoptionalFor action="cancel_batch": which batch.confirmoptionalFor action="disable" this must be true. Turning deep scanning off for a domain cannot be undone from here.ctem_manage_validation({ action: "revoke_host_approval", origin_domain_id: "…", fqdns: ["www.example.com"] })
{
"data": {
"approved_count": 0,
"revoked_count": 1,
"purged_jobs": 0,
"skipped": []
}
}ctem_manage_taskComplete a remediation task, reopen it, change its status, or set the owner and due date.
completereopenset_statusset_assignmentArguments
contract_idoptionalOptional when you belong to a single contract. Required only if you belong to more than one.actionrequiredWhich operation to perform: complete / reopen / set_status / set_assignment. Each action needs its own arguments; when one is missing the tool tells you which.task_idoptionalWhich task. Pass an id returned by ctem_list_tasks.statusoptionalFor action="set_status": the new status.assignee_user_idoptionalFor action="set_assignment": who owns it now.ctem_manage_task({ action: "complete", task_id: "…" })
{
"data": null
}Connection helper
One extra tool, separate from the CTEM set, used when you first connect.
ctem_list_my_contractsLists the contracts you belong to. Use it to find the contract_id to pass to the other tools when you belong to more than one. If you belong to none it returns an empty list rather than failing.
ctem_list_my_contracts()
{
"contracts": [
{ "contract_id": "…", "name": "…" }
]
}