Pter MCP Tool Reference
This document provides a comprehensive reference for the Pter MCP tools available to agents.
CRITICAL: Tool Name Format
All engine tools must be called with the mcp__pter-api-server__ prefix. For example:
- Correct:
mcp__pter-api-server__manage_findings - Wrong:
manage_findings
Local agent tools use mcp__pter__ prefix:
- Correct:
mcp__pter__manage_auth_session
Browser tools use mcp__playwright__ prefix:
- Correct:
mcp__playwright__browser_navigate
Web search tools use mcp__tavily__ prefix:
- Correct:
mcp__tavily__tavily-search
Quick Reference Table
| Tool | Actions | Purpose |
|---|---|---|
mcp__pter-api-server__manage_services | update, get, list, add_technology | Service registry management |
mcp__pter-api-server__create_service | N/A (single action) | Register new service with tech fingerprinting (subagent only) |
mcp__pter-api-server__update_endpoint_details | N/A (single action) | Update endpoint documentation with quality validation (subagent only) |
mcp__pter-api-server__update_service_details | N/A (single action) | Update service documentation with quality validation (subagent only) |
mcp__pter-api-server__update_service_journal | N/A (single action) | Append content to a service journal section (subagent only) |
mcp__pter-api-server__manage_endpoints | update, get, list | API endpoint tracking (read/update only) |
mcp__pter-api-server__create_endpoint | N/A (single action) | Register new endpoint with full documentation (subagent only) |
mcp__pter-api-server__manage_flows | create_flow, update_flow, get_flow, list_flows, delete_flow | User journey flows |
mcp__pter__manage_auth_session | list_sessions, get_current_session, replace_current_session, create_new_session, reauth, set_metadata, get_metadata, add_api_key, list_api_keys, update_capabilities, update_description | Authentication session management |
mcp__pter-api-server__manage_assessments | update, get, list, delete, submit_result | Assessment management (read/update only — create via subagent) |
mcp__pter-api-server__create_assessment | N/A (single action) | Register assessment with quality validation + auto P5 task (subagent only) |
mcp__pter-api-server__manage_findings | create, update, get, list, delete, statistics | Finding submission & tracking |
mcp__pter-api-server__manage_accounts | create, list, get, update, delete, stats | Account management (discovered user accounts) |
mcp__pter-api-server__manage_credentials | create, list, get, update, delete, list_by_account, update_status | Credential management (passwords, API keys, tokens) |
mcp__pter-api-server__manage_attack_chains | create, update, get, list, delete | Attack chain management (multi-step attack paths) |
mcp__pter-api-server__manage_tasks | get_details, update_status | Task lifecycle management |
mcp__pter-api-server__create_task | N/A (single action) | Create downstream task with quality validation (subagent only) |
mcp__pter__manage_auth_session | list_sessions, get_current_session, replace_current_session, create_new_session | Authentication session switching |
mcp__pter-api-server__lookup_reference | N/A (single action) | Look up CWE/CVE by ID (free, instant) |
mcp__pter-api-server__query_knowledge | N/A (single action) | Search encyclopedia (CWE/CVE, playbooks) |
mcp__tavily__tavily-search | search | Web search for exploit research, documentation |
mcp__tavily__tavily-extract | extract | Extract content from specific URLs |
mcp__pter__list_emails, mcp__pter__read_email | list, get | Read verification codes, OTPs, confirmation links |
mcp__pter-api-server__save_memory | N/A (single action) | Save knowledge to RAG |
mcp__pter-api-server__query_memories | N/A (single action) | Query saved memories |
mcp__pter-api-server__manage_services
Service registry management for tracking discovered services.
To CREATE a new service, use the register-service subagent — see "Service Registration" below.
Actions
get
service = mcp__pter-api-server__manage_services(action="get", service_id=1)
update
mcp__pter-api-server__manage_services(
action="update",
service_id=1,
name="auth-service-v2"
)
description is read-only — it is set during service creation and cannot be changed
via update. To update a service's description, use the update-service subagent:
Agent("update-service", "Service 5 needs update. Found..."). To record findings
about a service, use save_memory(content=..., references=["service://ID"]).
list
all_services = mcp__pter-api-server__manage_services(action="list")
# Filter in memory if needed:
matching = [s for s in all_services.get("services", []) if "auth" in s.get("name", "")]
add_technology
mcp__pter-api-server__manage_services(
action="add_technology",
service_id=1,
tech_name="nginx", # Required
tech_category="web_server", # Required: web_server, framework, database, language, library, etc.
tech_version="1.24.0", # Optional
tech_confidence="high", # Optional: low, medium, high
tech_evidence="Server header: nginx/1.24.0" # Optional
)
Note: Assessments
To create assessments targeting a service, use the register-assessment subagent —
see "Assessment Registration" below. Pass target EntityIDs like service://ID.
Service Registration (CRITICAL — READ THIS)
You CANNOT create services directly. Service creation is handled by the
register-service subagent, which fingerprints technologies and documents
the service. A P2 domain exploration task is automatically created.
Use Agent("register-service", "...") to spawn the subagent.
When you discover a new service, delegate: Agent("register-service", "Found new service at https://api.target.com. Server: nginx/1.24. Discovered by subdomain enumeration.")
The subagent will:
- Check for duplicates
- Probe the service root and common paths
- Fingerprint technologies from headers and error pages
- Write a detailed description
- Register and auto-create P2 task
What to include: base_url (required), name, technologies observed, auth info, discovery context
Updating Endpoints and Services
To update an endpoint's description, headers, or examples with new findings, use
Agent("update-endpoint", "Endpoint 42 needs update. Found...").
To update a service's description or add technologies, use
Agent("update-service", "Service 5 needs update. Found...").
To update a service's journal (structured living document), use
Agent("update-service-journal", "Service ID: 5. Section: tips. Add: 'WAF bypass: curl to 203.0.113.42'. Revision summary: Added WAF bypass tip").
Journal sections: overview, architecture, access, surface_highlights, tips, known_issues.
Reference entities using entity_type://id format (e.g., endpoint://42, finding://7).
mcp__pter-api-server__manage_endpoints
Read and update existing API endpoints. Supports get, list, and update only.
To CREATE a new endpoint, use the register-endpoint subagent — see "Endpoint Registration" below.
Actions
get
endpoint = mcp__pter-api-server__manage_endpoints(action="get", endpoint_id=1)
list
all_endpoints = mcp__pter-api-server__manage_endpoints(action="list")
# Filter by service:
service_endpoints = mcp__pter-api-server__manage_endpoints(action="list", service_id=5)
update
# Update non-description fields (discovered_by, openapi_schema, service_id)
mcp__pter-api-server__manage_endpoints(
action="update",
endpoint_id=1,
discovered_by="Also found via JavaScript source map analysis"
)
description is read-only — it is set during endpoint creation and cannot be changed
via update. To record your findings about an endpoint, use save_memory instead:
mcp__pter-api-server__save_memory(
content="Endpoint accepts wildcard queries with no input length limit — potential DoS vector",
memory_type="discovery",
references=["endpoint://1"]
)
Endpoint Registration (CRITICAL — READ THIS)
You CANNOT create endpoints directly. Endpoint creation is handled by the
register-endpoint subagent, which thoroughly investigates each endpoint
before registering it with full documentation.
IMPORTANT: Use Agent("register-endpoint", "...") to spawn the subagent.
Do NOT use Skill("register-endpoint") — the Skill tool only loads instructions
into your context, it does not register anything. The Agent tool spawns an
isolated subagent that actually does the investigation and registration.
When you discover a new endpoint, delegate to the subagent:
Agent("register-endpoint", "Found POST /api/v2/users/search on service_id=5. "
"Requires Bearer auth. Token: Bearer eyJhbGciOi... "
"Saw query and filters params in JS bundle. "
"Discovered by analyzing network traffic during browsing.")
The subagent will:
- Check for duplicates
- Probe the endpoint with curl (authenticated + unauthenticated)
- Map all headers, parameters, and request body
- Capture real curl examples with full response headers and body
- Write a detailed description
- Register via
create_endpoint(which validates quality) - Auto-create a P4 vulnerability recon task
What to include in your delegation message:
- HTTP method + full URL (required)
- Service ID (required)
- Auth tokens/cookies with actual values (if you have them)
- How you discovered it
- Any parameters or headers you already observed
When to delegate:
- Every new URL you encounter — network traffic, JS bundles, error messages, API docs, spidering
- If in doubt, delegate. Registering a duplicate is harmless (the subagent checks)
- An unregistered endpoint is INVISIBLE to the rest of the system
Task Registration
To create downstream tasks (P3 flow analysis, P6 validation, P7 chaining, P8 exploitation), use the register-task subagent:
Agent("register-task", "P3 flow analysis needed. Phase: 3. Service: auth-service (service_id=5). Flow: Password reset. Known steps: request → email → token → reset. Analyze for token predictability, rate limiting, enumeration.")
The subagent validates quality, checks for duplicates, and creates with proper service linkage.
P2/P4/P5 tasks are auto-created — you do NOT create them via this subagent:
- P2 tasks: auto-created by create_service
- P4 tasks: auto-created by create_endpoint
- P5 tasks: auto-created by create_assessment
mcp__pter-api-server__manage_flows
Track user journeys and attack paths.
Actions
create_flow
mcp__pter-api-server__manage_flows(
action="create_flow",
name="user_registration",
start_state="anonymous", # Required: initial state
end_state="registered", # Required: final state
description="Self-service registration: user submits email+password, receives verification email with signed token, clicks link to activate account. Creates user record with 'member' role. No admin approval required. Email uniqueness enforced at DB level.",
criticality="high",
)
get_flow
flow = mcp__pter-api-server__manage_flows(action="get_flow", flow_id=123)
update_flow
# IMPORTANT: Always GET the flow first and read its current description
# before updating. Never blindly overwrite descriptions.
flow = mcp__pter-api-server__manage_flows(action="get_flow", flow_id=123)
mcp__pter-api-server__manage_flows(
action="update_flow",
flow_id=123,
description=flow["description"] + ". Verification token has 24h expiry, no rate limit on resend.",
criticality="critical"
)
list_flows
all_flows = mcp__pter-api-server__manage_flows(action="list_flows")
delete_flow
mcp__pter-api-server__manage_flows(action="delete_flow", flow_id=123)
mcp__pter-api-server__manage_assessments
Manage assessments — investigation items for attack vectors, CVEs, and attack chains.
To CREATE a new assessment, use the register-assessment subagent via the Agent tool — see "Assessment Registration" below.
Actions
get
assessment = mcp__pter-api-server__manage_assessments(action="get", assessment_id=123)
update
mcp__pter-api-server__manage_assessments(
action="update",
assessment_id=123,
status="confirmed"
)
list
all_assessments = mcp__pter-api-server__manage_assessments(action="list")
# Optional filters: type_filter, status_filter, limit
submit_result
mcp__pter-api-server__manage_assessments(
action="submit_result",
assessment_id=123, # Required
status="confirmed", # Required: "confirmed" or "refuted"
description="## Investigation Result\n\n**Verdict: Exploitable**\n\n...", # Required
report_path="work/docs/exploitation/exploitation_123_CWE-89.md" # Required
)
delete
mcp__pter-api-server__manage_assessments(action="delete", assessment_id=123)
Assessment Registration (CRITICAL — READ THIS)
You CANNOT create assessments directly. Assessment creation is handled by the
register-assessment subagent, which validates quality, checks for duplicates,
and auto-creates a P5 deep investigation task.
Use Agent("register-assessment", "...") to spawn the subagent.
When you identify a vulnerability to investigate, delegate:
Agent("register-assessment", "Vector: CWE-89 SQL injection on endpoint 42 (POST /api/v2/users/search). Target location: sort_by query param. Approach: time-based blind. Impact: full DB read. Targets: endpoint://42, service://5.")
The subagent will:
- Check for duplicate assessments on the same target
- Validate description quality (≥100 chars, target location + approach + impact)
- Create the assessment
- Auto-create P5 deep investigation task (with consolidation)
You do NOT need to create P5 tasks separately — the tool handles it atomically.
mcp__pter-api-server__manage_findings
Submit and track validated security findings. Findings are the primary deliverable of the engagement — they go directly into client reports. Write them like a senior pentester would: precise, evidence-backed, and actionable.
Writing High-Quality Findings
title
One line. Name the vulnerability and where it lives. A reader should know what's broken without opening the finding.
- Good:
Stored XSS via unsanitized markdown in /api/comments - Good:
Privilege escalation from viewer to admin via IDOR on /api/users/{id}/role - Bad:
XSS vulnerability(where? what kind?) - Bad:
Security issue in API(meaningless)
description
The full technical write-up in Markdown. This is the primary content readers see — write it like a standalone vulnerability report, not a summary. Use ## headers, fenced code blocks, tables, and lists to make it scannable and thorough. Match the depth and quality of your exploitation report files.
Structure with these sections:
- Summary — 2-3 sentences: what's broken, where, and why it matters
- Vulnerability Details — root cause, affected component, conditions (auth, privileges, rate limits). Include request/response evidence inline with fenced code blocks
- Impact Analysis — concrete impact in context of this application (data exposure, account takeover, lateral movement — not generic risk language). Quantify where possible (e.g., "16 years of media uploads", "~40 documents from other orgs")
- Exposed Data / Affected Resources (if applicable) — tables or lists of what's exposed
## Summary
The `/wp-content/uploads/` directory has Apache `mod_autoindex` enabled,
exposing the entire media library structure from 2010-2026 and multiple
plugin-specific upload directories to unauthenticated users.
## Vulnerability Details
The Apache web server is configured with `Options +Indexes` for the uploads
directory. Any unauthenticated user can browse the full directory tree:
```bash
curl -s "https://target.com/wp-content/uploads/" | head -50
```
```html
<title>Index of /wp-content/uploads</title>
<tr><td><a href="2010/">2010/</a></td><td>2021-08-31 13:39</td></tr>
<tr><td><a href="sucuri/">sucuri/</a></td><td>2021-08-31 13:39</td></tr>
```
No authentication is required. The directory listing is accessible to anyone
with a web browser.
## Impact Analysis
- **16 years of media uploads** (2010–2026) are publicly enumerable
- **Plugin fingerprinting**: security plugins exposed (ithemes-security, sucuri)
- **Debug logs**: `pum-debug-*.log` file accessible (68 bytes)
## Exposed Directories
| Directory | Content |
|-----------|---------|
| 2010/ – 2026/ | Year-based media uploads |
| ithemes-security/ | Security plugin data |
| sucuri/ | WAF plugin data |
| wpcode/cache/ | Code snippet cache |
Don't:
- Write one-liners or 2-paragraph summaries when you have detailed evidence — put it all in
- Repeat the title
- Use filler like "this could potentially allow an attacker to possibly..." — state what happens
- Include CVSS scores, severity ratings, or remediation in the description — those have their own dedicated fields (
cvss_vector,recommended_fix). The description covers what's broken and the impact, not the metadata.
cvss_vector
Required. Every finding must have a CVSS 3.1 vector. The severity field is computed from it — never set severity directly.
Build the vector using the CVSS 3.1 specification:
- Attack Vector (AV), Attack Complexity (AC), Privileges Required (PR), User Interaction (UI)
- Scope (S), Confidentiality (C), Integrity (I), Availability (A)
The score maps to severity automatically:
| Score | Severity |
|---|---|
| 9.0 – 10.0 | critical |
| 7.0 – 8.9 | high |
| 4.0 – 6.9 | medium |
| 0.1 – 3.9 | low |
| 0.0 | informational |
# Unauthenticated IDOR leaking sensitive data
# AV:N (network) AC:L (no special conditions) PR:N (no auth) UI:N (no interaction)
# S:U (no scope change) C:H (full document contents) I:N (read-only) A:N
cvss_vector="CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N" # → 7.5 → high
Don't: File a finding without a cvss_vector. If you can't score it, you don't understand the impact well enough to file it.
reproduction_steps
Step-by-step instructions a human pentester can follow to reproduce the finding independently. Each step must include either a full shell command (curl, sqlmap, nuclei, etc.) or manual browser/UI steps with exact clicks and inputs. Every step must show the expected output that confirms the vulnerability.
Use $VARIABLE shell syntax for placeholders that need to be filled in (e.g., $TOKEN, $SESSION_ID, $TARGET_URL). Never use <VARIABLE> — it breaks copy-paste into a shell and looks like HTML.
1. Authenticate as test@org-a.com (viewer role):
$ curl -s -X POST $TARGET_URL/api/auth/login \
-H 'Content-Type: application/json' \
-d '{"email": "test@org-a.com", "password": "TestPass123!"}'
Output: {"access_token": "eyJhbG...","user": {"org_id": "org-a", "role": "viewer"}}
2. Request a document belonging to a different organization:
$ curl -s -H "Authorization: Bearer $TOKEN" \
$TARGET_URL/api/v2/documents/847
Output: {"id": 847, "org_id": "org-b", "title": "Q3 Financial Report", "body": "..."}
Expected: 403 Forbidden. Actual: 200 with full document body from org-b.
3. Enumerate accessible documents across organizations:
$ for id in $(seq 1 100); do \
curl -s -o /dev/null -w "%{http_code} $id\n" \
-H "Authorization: Bearer $TOKEN" \
$TARGET_URL/api/v2/documents/$id; \
done | grep "^200"
Output:
200 12
200 47
200 103
200 847
... (~40 documents from other organizations returned 200)
For browser-based reproduction, specify exact navigation and interactions:
1. Log in to https://target.com/login as test@org-a.com / TestPass123!
→ Lands on /dashboard showing "Org A" in the top-right corner
2. Open browser DevTools → Network tab
3. Navigate to Documents → click any document → note the URL: /documents/847
→ URL contains a numeric document ID
4. In the browser address bar, change the ID: /documents/1
→ Page loads a document titled "Org B Internal Policy"
→ DevTools shows GET /api/v2/documents/1 returned 200 with org_id: "org-b"
Expected: error page or redirect. Actual: full document rendered.
Don't: Write "send a malicious request" without showing the request. Omit response output. Leave the reader guessing what "success" looks like — always contrast expected vs. actual behavior.
evidence
Proof that the vulnerability exists and was exploited, not just suspected. Each item should have type, the command/request, and the response.
evidence=[
{
"type": "request",
"command": "curl -H 'Authorization: Bearer eyJ...' https://target.com/api/v2/documents/847",
"response": '{"id": 847, "org_id": "org-b", "title": "Q3 Financial Report", "body": "..."}'
},
{
"type": "screenshot",
"path": "work/evidence/idor-document-847.png",
"description": "Document 847 belonging to org-b accessed by org-a user"
}
]
Include enough evidence to prove the finding without re-testing. Redact actual secrets but keep the structure.
recommended_fix
Specific to this codebase. Reference the pattern that should change.
- Good:
Add authorization check in document_router.get_document() to verify request.user.org_id matches document.org_id before returning. Use the existing OrgAccessGuard middleware. - Bad:
Implement proper access controls(says nothing actionable)
Common mistakes to avoid
- Generic descriptions copied from CWE/OWASP — always ground findings in this specific application
- Missing context — don't assume the reader tested the app; explain the feature being tested
- Conflating findings — one vulnerability per finding; don't bundle "XSS and also CSRF" together
- Skipping evidence — a finding without evidence is a claim, not a finding
- No CVSS vector — every finding needs a calculated vector, not a gut-feel severity
Actions
create
mcp__pter-api-server__manage_findings(
action="create",
# --- REQUIRED fields ---
title="Time-based blind SQL injection in /api/users search",
description=(
"## Summary\n\n"
"The `/api/users/search` endpoint is vulnerable to time-based blind SQL injection "
"via the `query` parameter. The parameter value is interpolated directly into a "
"SQL WHERE clause without parameterization, allowing full database extraction.\n\n"
"## Vulnerability Details\n\n"
"The search handler constructs a SQL query using f-string interpolation:\n\n"
"```python\n"
"query = f\"SELECT * FROM users WHERE name LIKE '%{search_query}%'\"\n"
"```\n\n"
"Injecting a `SLEEP()` call confirms the vulnerability:\n\n"
"```bash\n"
"curl -s -w '\\nTime: %{time_total}s\\n' -X POST https://target.com/api/users/search \\\n"
" -H 'Content-Type: application/json' \\\n"
" -d '{\"query\": \"admin\\' AND SLEEP(5)-- -\"}'\n"
"```\n\n"
"```\n"
"Output: {\"users\": []}\n"
"Time: 5.14s (baseline: 0.12s)\n"
"```\n\n"
"No authentication is required. The search endpoint is public-facing and has no "
"rate limiting.\n\n"
"## Impact Analysis\n\n"
"- **Full database extraction**: the `users` table contains email addresses, "
"password hashes (bcrypt), and API keys for all tenants\n"
"- **Cross-tenant data breach**: attacker can extract data belonging to any tenant\n"
"- **No rate limiting**: automated extraction via sqlmap completes in ~30 minutes\n"
),
affected_components=["endpoint://42"], # Required, non-empty. Format: entity_type://id
report_path="work/docs/exploitation/exploitation_42.md", # Required: path to report file
cvss_vector="CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", # Required: severity is derived from this
# --- optional fields ---
cwe_id="CWE-89",
reproduction_steps=(
"1. Send a baseline search request:\n"
" $ curl -s -w '\\nTime: %{time_total}s\\n' -X POST https://target.com/api/users/search \\\n"
" -H 'Content-Type: application/json' \\\n"
" -d '{\"query\": \"admin\"}'\n\n"
" Output: {\"users\": [{\"id\": 1, ...}]}\n"
" Time: 0.12s\n\n"
"2. Send a time-based injection payload:\n"
" $ curl -s -w '\\nTime: %{time_total}s\\n' -X POST https://target.com/api/users/search \\\n"
" -H 'Content-Type: application/json' \\\n"
" -d '{\"query\": \"admin\\' AND SLEEP(5)-- -\"}'\n\n"
" Output: {\"users\": []}\n"
" Time: 5.14s\n"
" Expected: <0.5s response or input rejection. Actual: 5s delay confirms injection."
),
recommended_fix="Use parameterized queries in user_repository.search(). Replace f-string SQL with sqlalchemy text() bind parameters.",
evidence=[
{
"type": "request",
"command": "curl -s -w '\\nTime: %{time_total}s\\n' -X POST https://target.com/api/users/search -H 'Content-Type: application/json' -d '{\"query\": \"admin\\' AND SLEEP(5)-- -\"}'",
"response": "{\"users\": []}\nTime: 5.14s"
}
],
assessment_id=42, # Optional: link to assessment
)
get
finding = mcp__pter-api-server__manage_findings(action="get", finding_id=123)
update
mcp__pter-api-server__manage_findings(
action="update",
finding_id=123,
status="draft", # Valid: draft, validated, submitted, accepted, rejected, remediated, remediation_verified, cancelled, duplicate
cvss_vector="CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N", # Recalculated: requires auth (PR:L), read-only (I:N)
)
list
all_findings = mcp__pter-api-server__manage_findings(action="list")
# Optional filters: severity_filter=["critical", "high"], status_filter=["draft"], limit=25
statistics
stats = mcp__pter-api-server__manage_findings(action="statistics")
# Returns: counts by severity, status, vulnerability type
delete
mcp__pter-api-server__manage_findings(action="delete", finding_id=123)
mcp__pter-api-server__manage_accounts
Manage discovered user accounts on the target application.
Actions
create
mcp__pter-api-server__manage_accounts(
action="create",
username="admin@target.com", # Required
account_role="admin", # Optional: role/privilege level
account_status="active", # Optional
notes="Default admin account found during recon" # Optional
)
list
all_accounts = mcp__pter-api-server__manage_accounts(action="list")
# Optional filters: search, account_role, account_status, limit, offset
get
account = mcp__pter-api-server__manage_accounts(action="get", account_id=1)
update
mcp__pter-api-server__manage_accounts(
action="update",
account_id=1,
account_status="compromised",
notes="Password cracked via brute force"
)
delete
mcp__pter-api-server__manage_accounts(action="delete", account_id=1)
stats
stats = mcp__pter-api-server__manage_accounts(action="stats")
# Returns: account counts by role, status, etc.
mcp__pter-api-server__manage_attack_chains
Manage attack chains — multi-step attack paths linking assessments together.
Actions
create
mcp__pter-api-server__manage_attack_chains(
action="create",
title="Privilege escalation via IDOR + password reset", # Required
description="Chain: enumerate user IDs → reset password → access admin panel",
overall_severity="critical", # Optional: critical, high, medium, low, informational
status="draft", # Optional
impact="Full admin account takeover", # Optional
details={"attack_type": "privilege_escalation"}, # Optional: arbitrary JSON
findings=[ # Optional: list of finding dicts linking findings to this chain
{"finding_id": 1, "step_order": 1, "role_description": "IDOR leaks admin email"},
{"finding_id": 3, "step_order": 2, "role_description": "Password reset via email"},
{"finding_id": 7, "step_order": 3, "role_description": "Admin panel access"}
]
)
get
chain = mcp__pter-api-server__manage_attack_chains(action="get", chain_id=1)
update
mcp__pter-api-server__manage_attack_chains(
action="update",
chain_id=1,
description="Updated chain description with new step",
overall_severity="high"
)
list
all_chains = mcp__pter-api-server__manage_attack_chains(action="list")
# Optional filters: severity_filter=["critical", "high"], status_filter=["draft"], search="IDOR", limit=25
delete
mcp__pter-api-server__manage_attack_chains(action="delete", chain_id=1)
mcp__pter-api-server__manage_credentials
Manage discovered credentials — passwords, API keys, tokens, session cookies.
Actions
create
mcp__pter-api-server__manage_credentials(
action="create",
credential_type="jwt", # Required: user_password, jwt, api_key, session_cookie, other
value="eyJhbGciOiJIUzI1NiIs...", # Required: the credential value
account_id=42, # Optional: link to account
status="valid", # Optional: unknown, valid, invalid, expired
notes="Admin JWT from /auth/login response" # Optional
)
get
credential = mcp__pter-api-server__manage_credentials(action="get", credential_id=123)
list
all_credentials = mcp__pter-api-server__manage_credentials(action="list")
# Optional filters: credential_type, status, account_id, search, limit, offset
list_by_account
account_creds = mcp__pter-api-server__manage_credentials(
action="list_by_account",
account_id=42
)
update
mcp__pter-api-server__manage_credentials(
action="update",
credential_id=123,
status="expired",
notes="Token expired after 1 hour"
)
update_status
mcp__pter-api-server__manage_credentials(
action="update_status",
credential_id=123,
status="revoked"
)
delete
mcp__pter-api-server__manage_credentials(action="delete", credential_id=123)
mcp__pter-api-server__manage_tasks
Task lifecycle management. To CREATE tasks, use the register-task subagent via the Agent tool. P2/P4/P5 tasks are auto-created by create_service/create_endpoint/create_assessment.
Actions
get_details
task = mcp__pter-api-server__manage_tasks(action="get_details", task_id="123")
update_status
mcp__pter-api-server__manage_tasks(
action="update_status",
task_id=TASK_ID,
status="done",
summary="Confirmed SQL injection with time-based technique",
key_learnings=["Parameterized queries not used", "Error messages expose DB type"]
)
mcp__pter__manage_auth_session
Manage authentication sessions, API keys, and metadata for cross-account testing.
IMPORTANT: You must close the browser before switching sessions. Switching with the browser open will cause authentication failures.
Actions
list_sessions
sessions = mcp__pter__manage_auth_session(action="list_sessions")
# Returns list of available sessions with their status
get_current_session
session = mcp__pter__manage_auth_session(
action="get_current_session",
session_id="sess-xxx" # Required
)
replace_current_session
# Step 1: Close the browser FIRST
browser_close()
# Step 2: Switch to a different session
mcp__pter__manage_auth_session(
action="replace_current_session",
session_id="sess-xxx" # Required: session ID to switch to
)
# Step 3: Open browser - you are now authenticated as the other user
create_new_session
mcp__pter__manage_auth_session(
action="create_new_session",
login_url="https://target.com/login", # Required: URL of the login page
credential_id=5, # Optional: link to a stored credential (from manage_credentials)
verification_url="https://target.com/dashboard", # Optional: URL to verify successful login
account_id=3 # Optional: link to a discovered account (from manage_accounts)
)
# Note: Auth agent will authenticate the new session via browser automation.
# Check session status after a few moments with list_sessions.
reauth
# Re-authenticate an expired or failing session
mcp__pter__manage_auth_session(action="reauth", session_id="sess-xxx")
# Spawns an auth agent to re-login using stored credentials. Check status after a few moments.
set_metadata
mcp__pter__manage_auth_session(
action="set_metadata",
session_id="sess-xxx",
metadata_key="user_id",
metadata_value="12345"
)
get_metadata
value = mcp__pter__manage_auth_session(
action="get_metadata",
session_id="sess-xxx",
metadata_key="user_id"
)
add_api_key
mcp__pter__manage_auth_session(
action="add_api_key",
session_id="sess-xxx",
key_name="Primary API Key",
api_key="sk-live-abc123..."
)
list_api_keys
keys = mcp__pter__manage_auth_session(action="list_api_keys", session_id="sess-xxx")
update_capabilities
mcp__pter__manage_auth_session(
action="update_capabilities",
session_id="sess-xxx",
capabilities={"can_create_users": True, "can_delete": False}
)
update_description
mcp__pter__manage_auth_session(
action="update_description",
session_id="sess-xxx",
description="Admin session with full access",
scope="admin"
)
When to use:
- Cross-account testing (IDOR, privilege escalation)
- Your current session is blocked, rate-limited, or expired
- You need to verify behavior as a different user
- You discover new credentials or create accounts
- You need to re-authenticate an expired session
mcp__pter__list_emails / mcp__pter__read_email
Read emails for verification codes, OTPs, and confirmation links.
Actions
list_emails
emails = mcp__pter__list_emails(action="list_emails")
# Optional: Gmail search query
emails = mcp__pter__list_emails(
action="list_emails",
query="from:noreply@target.com newer_than:1h", # Gmail search syntax
limit=10
)
get_email
email = mcp__pter__read_email(
action="get_email",
email_id="msg-xxx" # Required
)
# Returns: id, thread_id, subject, sender, to, date, snippet, body_text, body_html, labels
Common use cases:
- Extracting verification codes during account registration
- Reading OTPs for 2FA testing
- Finding confirmation links in signup flows
- Monitoring for password reset emails
Query examples:
from:noreply@target.com newer_than:1h- Recent emails from targetsubject:verification- Emails with "verification" in subjectis:unread- Unread emails only
mcp__tavily__tavily-search
Search the web for real-time information. Use for exploit research, vulnerability documentation, technology versions, API documentation, and threat intelligence.
results = mcp__tavily__tavily-search(
query="CVE-2024-1234 proof of concept exploit",
search_depth="basic", # "basic" (1 credit) or "advanced" (2 credits)
max_results=5
)
When to use:
- Finding exploit techniques, PoCs, and blog posts
- Looking up API documentation for target technologies
- Checking default credentials for services
- Researching security advisories and patches
Tips:
- Default is
search_depth="basic"(1 credit) — sufficient for most lookups - Only use
search_depth="advanced"(2 credits) when basic results are insufficient - For CWE/CVE reference data, use
mcp__pter-api-server__lookup_referenceinstead (free, instant) - For security knowledge queries, try
mcp__pter-api-server__query_knowledgefirst - Be specific in queries: include CVE IDs, technology names, version numbers
- Do NOT use Tavily for CWE-xxx or CVE-xxx definition lookups — use
lookup_reference
mcp__tavily__tavily-extract
Extract and summarize content from a specific URL.
content = mcp__tavily__tavily-extract(
urls=["https://nvd.nist.gov/vuln/detail/CVE-2024-1234"]
)
When to use:
- Reading full vulnerability advisories
- Extracting API documentation from a known URL
- Getting detailed content from search results
mcp__pter-api-server__lookup_reference
Look up a specific CWE, CVE, or other security reference by its exact ID. This is instant and free — always use this instead of web search for known identifiers.
ref = mcp__pter-api-server__lookup_reference(
external_id="CWE-89"
)
# Returns: source, external_id, title, summary, category, content, metadata
When to use:
- You know the CWE/CVE ID and want its description
- Looking up a specific vulnerability standard reference
- Before submitting a finding, to verify CWE classification
IMPORTANT: Do NOT use Tavily for CWE-xxx or CVE-xxx definition lookups — use this tool instead.
mcp__pter-api-server__query_knowledge
Search the encyclopedia for security reference data using semantic search. Searches CWE definitions, CVE records, playbooks, and other reference data.
results = mcp__pter-api-server__query_knowledge(
query="SQL injection authentication bypass techniques",
limit=10,
source="cwe", # Optional: filter to "cwe", "cve", "playbook", or None for all
)
When to use:
- Researching vulnerability classes or attack techniques
- Finding relevant CWEs for a discovered vulnerability
- Looking up remediation guidance
Search priority:
lookup_referencefor exact IDs (CWE-89, CVE-2024-1234)query_knowledgefor conceptual searchesquery_memoriesfor agent-specific engagement memoriestavily-searchonly when internal knowledge is insufficient
mcp__pter-api-server__save_memory
Save knowledge to RAG for persistence and sharing with other agents.
mcp__pter-api-server__save_memory(
content="VALIDATED: CWE-89 on /api/users/search. Technique: Time-based blind SQL injection.",
title="SQL injection confirmed on user search", # Optional: short title
memory_type="discovery", # Optional: discovery, learning, warning, error_fix, decision, codebase_knowledge
references=["endpoint://42", "service://5", "finding://17"] # Optional: entity IDs in "type://id" format
# Valid reference types: endpoint, service, technology, flow, account, credential,
# finding, assessment, attack_chain, memory, agent, task
)
mcp__pter-api-server__query_memories
Query saved memories using semantic search.
memories = mcp__pter-api-server__query_memories(
query="SQL injection authentication",
memory_type="discovery", # Optional filter (singular string, not list)
limit=10
)
Common Patterns
Endpoint Discovery → Registration
When you find a new endpoint, check if it exists and delegate registration:
# Check for existing endpoint
all_endpoints = mcp__pter-api-server__manage_endpoints(action="list", service_id=service_id)
existing = [e for e in all_endpoints.get("endpoints", []) if target_url in e.get("url", "")]
if not existing:
# NEW ENDPOINT — delegate to register-endpoint subagent
# Include: method, URL, service_id, auth tokens, discovery context
Agent("register-endpoint", f"Found {method} {target_url} on service_id={service_id}. "
f"Auth: Bearer {token}. Discovered by {how_found}.")
# The subagent investigates, registers, and auto-creates a P4 task
Reflection Pattern (Discovery Audit)
After each phase, audit surfaces and flows discovered:
# For each surface touched — delegate endpoint registration
for surface in surfaces_touched:
all_endpoints = mcp__pter-api-server__manage_endpoints(action="list")
existing = [e for e in all_endpoints.get("endpoints", []) if surface["url"] in e.get("url", "")]
if not existing:
# Delegate to subagent — it handles registration + P4 task creation
Agent("register-endpoint", f"Found {surface['method']} {surface['url']} on "
f"service_id={service_id}. Discovered during reflection audit.")
# For each flow observed
for flow in flows_observed:
all_flows = mcp__pter-api-server__manage_flows(action="list_flows")
existing = [f for f in all_flows.get("flows", []) if flow["name"] in f.get("name", "")]
if not existing:
# NEW FLOW — create flow and spawn investigation task
mcp__pter-api-server__manage_flows(action="create_flow", name=flow["name"], ...)
Agent("register-task", f"P3 flow analysis needed. Phase: 3. Service: {service_name} (service_id={service_id}). Flow: {flow['name']}. Steps observed: {flow['steps']}.")
Task Completion Pattern
When finishing a task:
# 1. Save completion memory
mcp__pter-api-server__save_memory(
memory_type="discovery",
content=f"Task complete: {summary}. Key findings: {findings}"
)
# 2. Mark task done with learnings
mcp__pter-api-server__manage_tasks(
action="update_status",
task_id=TASK_ID,
status="done",
summary=f"Investigated {target}: {result}",
key_learnings=[
f"Technique: {technique_used}",
f"Result: {outcome}"
]
)
Finding Submission Pattern
When you confirm a vulnerability, submit a finding:
# 1. Create the finding with full details
mcp__pter-api-server__manage_findings(
action="create",
# --- 5 REQUIRED fields ---
title="SQL injection in /api/users endpoint",
description="## Summary\n\nTime-based blind SQL injection in...\n\n## Vulnerability Details\n\n...\n\n## Impact Analysis\n\n...",
severity="critical",
affected_components=["endpoint://42"], # Required, non-empty. Format: entity_type://id
report_path="work/docs/exploitation/exploitation_42.md", # Required: path to report file
# --- optional fields ---
cwe_id="CWE-89",
reproduction_steps="1. Send payload... 2. Observe delay...",
recommended_fix="Use parameterized queries",
evidence=[{"type": "request", "command": "curl ...", "response": "..."}],
assessment_id=assessment_id, # Link to the assessment being investigated
)
# 2. Save memory about the finding
mcp__pter-api-server__save_memory(
memory_type="discovery",
content="CONFIRMED: SQL injection in /api/users. Time-based blind technique. Severity: critical."
)
Writing Entity Descriptions
Entity descriptions are the primary way other agents and humans understand what a service, endpoint, or flow actually does. A bad description wastes everyone's time. A good description prevents duplicate work and grounds security analysis.
What belongs in a description
Describe what the entity does functionally — its purpose, inputs, outputs, and behavior. Write for someone who has never seen this application.
| Entity | Good description | Bad description |
|---|---|---|
| Service | "OAuth2/OIDC auth service. Handles login, token issuance, session management. RS256 JWT, 1h expiry. Endpoints: /authorize, /token, /userinfo." | "Authentication microservice" |
| Endpoint | "Full-text user search returning paginated results with PII (email, role, last login). Requires any authenticated session. No input length limit on query. Rate-limited to 10 req/min." | "User search endpoint" |
| Flow | "Self-service registration: submit email+password → verification email with signed token → click to activate. Creates 'member' role. No admin approval. Email uniqueness at DB level." | "Complete user registration flow" |
For endpoints, put request/response parameters and types in openapi_schema. Keep description focused on functional purpose, auth requirements, data sensitivity, and security-relevant behavior.
What does NOT belong in a description
Specific discoveries and commentary belong in save_memory(references=["endpoint://42"]). Descriptions are for what the entity is, not what you learned about it.
Updating descriptions
Always read before writing. Call GET first, read the current description, then either:
- Append genuinely new functional detail you discovered (e.g., rate limits, auth requirements, undocumented parameters)
- Leave it alone if your update is commentary — use
save_memory(references=[...])instead
Never replace a detailed description with a shorter one. Never use descriptions as a scratch pad.
Important Notes
- agent_id is automatic - Your identity is resolved from HTTP headers, no need to pass it
- Use list + filter instead of search - Most tools support
listaction; filter results in memory - Save memories for important discoveries - Other agents can query these later
- Check before creating - Avoid duplicate endpoints, flows, etc.
- Endpoint creation goes through the register-endpoint subagent - To register a new endpoint, delegate to
Agent("register-endpoint", ...)which investigates, documents, and registers with quality enforcement. A P4 task is auto-created. - Submit findings for confirmed vulnerabilities - Use manage_findings with full evidence
- Complete tasks with learnings - Always include summary and key_learnings when marking done
- service_ids required for P3-P8 tasks - Every task for phases 3-8 must include
service_ids. Look up services withmanage_services(action="list")first. The tool rejects tasks without it. - Read before updating descriptions - Always GET an entity and read its current description before updating. Never blindly overwrite. See "Writing Entity Descriptions" above.