hardly
PYPI · HARDLY
Generic HAR analysis MCP server: index and query captures without burning tokens on raw files.
Available components
Last scanned (21 hours ago)
Scores higher than 80% of PyPI servers
Category Developer Tools
How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. How we score → Why this is hard to score →
Supply Chain Security100
- No malware found by supply-chain analysis.Pass
- No known CVEs affecting this package version or its production dependencies.Pass
- Runs hatchling.build at install time, a recognised build step with no custom scripting around it. View diagnostics → Pass
- 1 of 23 dependencies flagged as unhealthy. View diagnostics → Partial
Provenance & Transparency100
- Source repository is publicly reachable at the declared URL. View diagnostics → Pass
- Cryptographically verified build provenance (signed, bound to b1tninja/hardly). View diagnostics → Pass
- Clear OSI-approved license (MPL-2.0).Pass
- Actively maintained (last published 6 days ago).Pass
- Publishes a security disclosure policy (SECURITY.md).Pass
Schema Quality & AI Usability73
- 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).Pass
- AI-judged instruction clarity (good).Pass
- Context-footprint check failed: tool/resource definitions use about 11084 tokens (~136/item across 81 items; 71 tools + 10 resources), over budget; trim descriptions and params. See how to fix → Fail
- Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management20
- Stability observed for 6 of 30 days with no destabilising changes; credit accrues until the full window elapses.Partial
Tool Coverage71
- 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
- 0% of tool parameters carry a description.Fail
- Structured output schemas are declared (100% of tools); any adoption earns full credit.Pass
Tool Safety75
- No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.Pass
- 0 of 7 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation; "hardly_send_catalog_verify" implies "send" and declares no destructiveHint at all, which the MCP spec reads as destructive by default. See how to fix → Fail
- An AI judge read all 73 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
- Implements a current MCP spec version (2026-07-28).Pass
Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.
- 3 Nov 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 13 to 17. That category is still filling its 30-day observation window: 4 days of observed history at the previous scan, 5 at this one. The score rises as the window fills, whether or not the server changes.
- 2 Nov 26 +2
- Stability: unverified → 0.13 ▲ functional
- 30 Oct 26 +15
- Malware scan: unverified → pass ▲ security
- 29 Oct 26 62
First indexed and scored.
Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.
Captured 4 Nov 2026 · Analysed pypi/hardly@1.0.0
Provenance Verified
A signed build attestation was found and verified, binding this exact artifact to the source repository it claims to come from.
| Result | Verified |
|---|---|
| Ecosystem | pypi |
| Reason | Verified |
| Discovered via | Registry attestation endpoint |
| Source repo | b1tninja/hardly |
| Certificate issuer | https://token.actions.githubusercontent.com |
| Certificate SAN | https://github.com/b1tninja/hardly/.github/workflows/release.yml@refs/tags/v1.0.0 |
| Rekor log index | 3558925112 |
| Predicate type | PyPI publish attestation https://docs.pypi.org/attestations/publish/v1 |
| Subject digest | sha256:93338604fb2b1035a72732c25690371184435f36f124a59a97288783545c04eb |
Background: How many MCP packages publish verified provenance →
Install scripts 1 script
| Hook | Tier | Command |
|---|---|---|
| build_backend | allowlisted | hatchling.build |
Background: Why install scripts are a supply-chain risk →
Dependencies 23 packages
| Packages resolved | 23 |
|---|---|
| Stale | 1 |
| Tree resolution | Complete |
Background: SBOMs and build attestations, explained →
The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →
hardly_auth_report Hardly Auth Report ~206
Authentication evidence; sections: quick (default; auth paths, token responses, header names), patterns, credentials, secret_names, cookies. Names, shapes and entry ids only, never values. Example: hardly_auth_report(session_id='S', sections=['credentials','cookies']). quick: a first auth check. patterns: named schemes (bearer+refresh, OIDC+PKCE, SAML POST, double-submit CSRF, signed requests; ``pattern_kinds`` filters). credentials: password fields, session cookies and flags, anti-forgery names, OAuth params, token shapes and a hypothesised login_flow (use before implementing login in a client). secret_names: sensitive header/field/ query NAMES. cookies: per-server timeline of Set-Cookie / Cookie names.
| Name | Type | Req | Description |
|---|---|---|---|
| explain | boolean | – | – |
| host | – | – | – |
| limit | – | – | – |
| pattern_kinds | – | – | – |
| sections | – | – | – |
| session_id | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_browser_capture_discover Hardly Browser Capture Discover ~341
LIVE (confirm-gated): unattended time-boxed browser capture of a URL; analyze=true also discovers its APIs and returns session_id plus a brief. Without confirm=true it returns only the plan. Example: hardly_browser_capture_discover(url='https://example.com', wait_seconds=8, analyze=true, confirm=true). Refuses loopback, private, link-local and metadata start URLs (host_not_allowed; HARDLY_ALLOW_PRIVATE_HOSTS=1 for a local test site). analyze=false: load the URL, wait wait_seconds (default 20), stop; returns the raw HAR (har_output_path) and, with open_session=true, a session. analyze=true (headless only): optional ``steps`` (goto/wait/aria/click/fill/find_click...) then stop, open a session and return a brief (default wait 5). If the brief shows a wall or captcha, STOP and switch to interactive hardly_browser_start(headed=true, channel='chrome') with a person. budget_seconds is a hard per-call budget (env HARDLY_CAPTURE_BUDGET). exclude_noise=true aborts analytics/ad/font/ map-tile/heavy-media requests while loading (default off: blocking can break sites).
| Name | Type | Req | Description |
|---|---|---|---|
| analyze | boolean | – | – |
| budget_seconds | – | – | – |
| channel | – | – | – |
| confirm | boolean | – | – |
| exclude_noise | boolean | – | – |
| har_output_path | – | – | – |
| headed | boolean | – | – |
| open_session | boolean | – | – |
| steps | – | – | – |
| url | string | yes | – |
| url_filter | – | – | – |
| wait_seconds | – | – | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_browser_inspect Hardly Browser Inspect ~196
Read the running browser tab without navigating; sections: url (default), elements (css/xpath locators), aria (accessibility YAML with [ref=eN] handles). Example: hardly_browser_inspect(sections=['aria'], selector='main'). ``url``: current URL and title (cheap check of where a click landed). ``elements``: visible links/buttons/inputs with locators; ``query`` is a CSS selector override, ``limit`` max rows (default 40, max 100). ``aria``: rendered ARIA tree, ``mode='ai'`` (default) asks for refs, ``selector`` scopes it (default body); the refs feed hardly_browser_interact. For offline HAR HTML bodies use hardly_entry_outline.
| Name | Type | Req | Description |
|---|---|---|---|
| capture_id | – | – | – |
| limit | – | – | – |
| mode | – | – | – |
| query | – | – | – |
| sections | – | – | – |
| selector | – | – | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_browser_interact Hardly Browser Interact ~204
Drive the running browser tab: action=goto (needs url), click, fill (needs value) or press (key, default Enter). Prefer ref from hardly_browser_inspect(sections=['aria']). Example: hardly_browser_interact(action='click', ref='e12'). Target one element per call with ``ref``, else ``css`` / ``xpath`` (from hardly_browser_inspect(sections=['elements'])), or ``text`` / ``role`` with ``name`` (click). Never type real credentials yourself: ask the person to use an interactive capture. Omit capture_id for the latest running capture.
| Name | Type | Req | Description |
|---|---|---|---|
| action | string | yes | – |
| capture_id | – | – | – |
| css | – | – | – |
| key | – | – | – |
| name | – | – | – |
| ref | – | – | – |
| role | – | – | – |
| text | – | – | – |
| timeout_seconds | number | – | – |
| url | – | – | – |
| value | – | – | – |
| xpath | – | – | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_browser_run_steps Hardly Browser Run Steps ~223
Run a scripted list of steps on the running browser tab in one call (cheaper than many single calls). Use once you know the selectors; hardly_session_plan_steps suggests steps from a session. Example: hardly_browser_run_steps(steps=[{'op':'goto','url':'https://example.com'}]). Each step: ``{"op":"goto"|"wait"|"elements"|"click"|"fill"|"press"|"url"|"aria", ...}``. Example steps:: [ {"op":"goto","url":"https://example.com/search"}, {"op":"wait","ms":1000}, {"op":"click","text":"I Accept"}, {"op":"fill","css":"#SearchOnName","value":"EXAMPLE"}, {"op":"click","css":"input[type=submit]"}, {"op":"wait","ms":2000}, {"op":"elements","limit":30} ]
| Name | Type | Req | Description |
|---|---|---|---|
| capture_id | – | – | – |
| steps | array | yes | – |
| stop_on_error | boolean | – | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_browser_start Hardly Browser Start ~312
Launch a real browser that records a HAR (needs the capture extra); returns capture_id. headed=true (default) is interactive: ASK THE PERSON to use the window, then call hardly_browser_stop. Example: hardly_browser_start(url='https://example.com', headed=true, channel='chrome'). Refuses loopback, private, link-local and metadata start URLs (host_not_allowed; HARDLY_ALLOW_PRIVATE_HOSTS=1 for a local test site). headed=false is headless: drive it with hardly_browser_inspect / hardly_browser_interact / hardly_browser_run_steps. For a one-shot unattended load prefer hardly_browser_capture_discover. Requires ``pip install -e ".[capture]"`` + ``playwright install chromium`` (see hardly_server_status). Prefer channel='chrome' for bot walls. url_filter is a Playwright glob. profile keeps cookies. Without har_output_path the HAR is ephemeral (memory only). same_tab (default true) forces target=_blank into the current tab. trace=true writes a ``.trace.zip`` beside the HAR. Waits for a capture slot (HARDLY_CAPTURE_SLOTS); the result carries ``slot``.
| Name | Type | Req | Description |
|---|---|---|---|
| channel | – | – | – |
| har_output_path | – | – | – |
| headed | boolean | – | – |
| label | – | – | – |
| omit_content | boolean | – | – |
| profile | – | – | – |
| same_tab | boolean | – | – |
| trace | boolean | – | – |
| url | – | – | – |
| url_filter | – | – | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_browser_stop Hardly Browser Stop ~123
Stop a running browser capture, flush the HAR and optionally open it as a session. Call when the person says they are done (interactive) or your steps are complete; then continue with hardly_session_site_brief(session_id). Example: hardly_browser_stop(open_session=true). An ephemeral capture (started without har_output_path) lives only in the returned session; save it with hardly_write_session_copy(format='index'). Omit capture_id for the latest running one.
| Name | Type | Req | Description |
|---|---|---|---|
| capture_id | – | – | – |
| force | boolean | – | – |
| open_session | boolean | – | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_capture_list Hardly Capture List ~88
List browser captures (running and persisted) with ids and states, or the status of one capture_id. Poll it while a person drives an interactive capture. Example: hardly_capture_list(capture_id='c1'). Use to find a capture_id after a restart. With capture_id the list holds exactly that capture (state, har_output_path, request counts).
| Name | Type | Req | Description |
|---|---|---|---|
| capture_id | – | – | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_catalog_list Hardly Catalog List ~184
List targets from a content-neutral catalog file (JSON/YAML), filtered; no network. detail='summary' returns counts instead of rows. Tags and roles are defined by your project (docs/catalog.md). Example: hardly_catalog_list(catalog_path='/data/targets.json', detail='summary'). One row per endpoint: target, tags, groups, role, kind, status, redacted url, gate classes, stack names. Filters: ``tag`` (comma-separated, all required), ``group`` (object of key->value), ``role``, ``status``, ``target_id``. hardly assigns no meaning to tags, group keys or roles.
| Name | Type | Req | Description |
|---|---|---|---|
| catalog_path | string | yes | – |
| detail | string | – | – |
| group | – | – | – |
| role | – | – | – |
| status | – | – | – |
| tag | – | – | – |
| target_id | – | – | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_client_build Hardly Client Build ~117
Build a minimal Python (urllib) client sketch from story steps or chosen entry_ids and return it as text; secrets become PLACEHOLDER_* values. Writes nothing (hardly_write_export format=client_python saves it). Example: hardly_client_build(session_id='S', entry_ids=[12, 14]). Use as the last step of SDK work, after hardly_session_story / hardly_session_site_brief.
| Name | Type | Req | Description |
|---|---|---|---|
| class_name | – | – | – |
| entry_ids | – | – | – |
| host | – | – | – |
| session_id | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_endpoint_arcgis Hardly Endpoint Arcgis ~76
List ArcGIS REST endpoints (MapServer/FeatureServer/etc.) seen in the capture: layer ids, parameter names, paging evidence. Sends nothing; the live twin is hardly_send_arcgis_explore. Example: hardly_endpoint_arcgis(session_id='S').
| Name | Type | Req | Description |
|---|---|---|---|
| host | – | – | – |
| session_id | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_endpoint_graphql Hardly Endpoint Graphql ~77
Detect GraphQL operations (operationName, query, mutation) behind shared URLs, with evidence entry ids. Use when POSTs share one URL; then hardly_entry_get for a sample. Example: hardly_endpoint_graphql(session_id='S').
| Name | Type | Req | Description |
|---|---|---|---|
| host | – | – | – |
| limit | – | – | – |
| session_id | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_endpoint_list Hardly Endpoint List ~101
List grouped endpoints (METHOD + path template) with counts, paged by limit/offset. The main API surface view for JSON APIs; for server-rendered pages use hardly_session_site_brief or hardly_page_forms. Example: hardly_endpoint_list(session_id='S', host='api.example.com').
| Name | Type | Req | Description |
|---|---|---|---|
| exclude_noise | boolean | – | – |
| host | – | – | – |
| limit | – | – | – |
| offset | – | – | – |
| session_id | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_endpoint_pagination Hardly Endpoint Pagination ~74
Recognise cursor, next-link and Link-header pagination, with evidence entry ids. Shapes only. Use before writing a client loop over results. Example: hardly_endpoint_pagination(session_id='S', host='api.example.com').
| Name | Type | Req | Description |
|---|---|---|---|
| host | – | – | – |
| limit | – | – | – |
| session_id | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_endpoint_schema Hardly Endpoint Schema ~134
Request/response shapes of one endpoint template. Sections: schema (default; JSON field names and types), param_roles (each field static, dynamic or sensitive). Example: hardly_endpoint_schema(session_id='S', method='GET', path_template='/api/items/{id}'). Use after hardly_endpoint_list. param_roles decides which parameters a client must compute versus hard-code. host defaults to the main host. Names and types only.
| Name | Type | Req | Description |
|---|---|---|---|
| host | – | – | – |
| limit | – | – | – |
| method | string | yes | – |
| path_template | string | yes | – |
| sections | – | – | – |
| session_id | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_endpoint_streams Hardly Endpoint Streams ~101
Summarise non-JSON stream/binary formats: gRPC(-web), protobuf, MessagePack, CSV/TSV, SSE, WebSocket frames, with evidence entry ids. Shapes only. Use when endpoints show odd content types. Example: hardly_endpoint_streams(session_id='S').
| Name | Type | Req | Description |
|---|---|---|---|
| exclude_noise | boolean | – | – |
| host | – | – | – |
| kind | – | – | – |
| limit | – | – | – |
| session_id | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_entry_around Hardly Entry Around ~137
Show the requests just before and after one entry in TIME (a click and the XHRs that followed). Use with a navigation or grid-click entry_id to find the API it triggered; inspect rows with positive delta_ms. Example: hardly_entry_around(session_id='S', entry_id=30, after=8). What triggered an entry by the browser's own initiator data is hardly_entry_initiators.
| Name | Type | Req | Description |
|---|---|---|---|
| after | integer | – | – |
| before | integer | – | – |
| entry_id | integer | yes | – |
| exclude_noise | boolean | – | – |
| host | – | – | – |
| session_id | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_entry_body_query Hardly Entry Body Query ~154
Search inside one large body without loading it: JSONPath-lite ($.a[*].b, ..key) or regex, paged (pass next_offset while has_more). Use instead of hardly_entry_get for big payloads; sensitive values come back as shapes. Example: hardly_entry_body_query(session_id='S', entry_id=12, jsonpath='$.items[*].id').
| Name | Type | Req | Description |
|---|---|---|---|
| context | integer | – | – |
| entry_id | integer | yes | – |
| ignore_case | boolean | – | – |
| jsonpath | – | – | – |
| limit | – | – | – |
| max_chars | – | – | – |
| offset | – | – | – |
| regex | – | – | – |
| session_id | string | yes | – |
| side | string | – | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_entry_build_curl Hardly Entry Build Curl ~103
Build a curl command for one entry and return it as text (not executed); secrets are redacted by default. Use to show a person a single request; for a full client use hardly_client_build. Example: hardly_entry_build_curl(session_id='S', entry_id=12).
| Name | Type | Req | Description |
|---|---|---|---|
| entry_id | integer | yes | – |
| redact | boolean | – | – |
| session_id | string | yes | – |
| use_env_placeholders | boolean | – | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_entry_compare Hardly Entry Compare ~87
Diff headers and JSON body keys between two entries of one session. Use to see what changed between a failing and a working request, or pre/post login. Example: hardly_entry_compare(session_id='S', entry_id=3, other_entry_id=9).
| Name | Type | Req | Description |
|---|---|---|---|
| entry_id | integer | yes | – |
| other_entry_id | integer | yes | – |
| session_id | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_entry_dependencies Hardly Entry Dependencies ~118
Trace what one request depends on: the earlier response behind each header, cookie, hidden field or value. Returns ordered minimal steps plus inputs the caller must supply. Offline; names and ids only. Example: hardly_entry_dependencies(session_id='S', entry_id=20). Use before writing a client for a multi-step flow; to track one value across the capture use hardly_session_trace_value.
| Name | Type | Req | Description |
|---|---|---|---|
| entry_id | integer | yes | – |
| host | – | – | – |
| max_depth | integer | – | – |
| session_id | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_entry_get Hardly Entry Get ~95
Show one entry with redacted headers and truncated bodies (max_body_chars, default 4000). Use after entry_search/endpoint_list gives an entry_id; for large bodies use hardly_entry_body_query instead of raising max_body_chars. Example: hardly_entry_get(session_id='S', entry_id=12).
| Name | Type | Req | Description |
|---|---|---|---|
| entry_id | integer | yes | – |
| max_body_chars | – | – | – |
| session_id | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_entry_initiators Hardly Entry Initiators ~104
Show the initiator parent and children of an entry (HAR _initiator/pageref): what triggered a request and what it triggered. Use to find who called an API; for time order use hardly_entry_around. Example: hardly_entry_initiators(session_id='S', entry_id=30).
| Name | Type | Req | Description |
|---|---|---|---|
| child_limit | – | – | – |
| entry_id | integer | yes | – |
| exclude_noise | boolean | – | – |
| session_id | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_entry_outline Hardly Entry Outline ~127
Offline outline of an HTML/XML body from a HAR entry. format: markdown (headings/tables/forms/links), tree (tag tree) or aria (YAML); omit for all three. Example: hardly_entry_outline(session_id='S', entry_id=5, format='markdown'). Use instead of reading raw HTML; for the live tab use hardly_browser_inspect(sections=['aria']).
| Name | Type | Req | Description |
|---|---|---|---|
| entry_id | integer | yes | – |
| format | – | – | – |
| max_depth | integer | – | – |
| session_id | string | yes | – |
| side | string | – | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_entry_search Hardly Entry Search ~204
Find entries by host, path, method, status, body text, header or content_kind; returns small paged rows with entry_ids. Use to locate a specific request, then hardly_entry_get. Example: hardly_entry_search(session_id='S', body_contains='token', limit=10). ``content_kind`` uses the classifier: json, jsonl, jsonp, csv, html, html_table (or table), pdf, image, css, javascript, ... Result rows include ``content_kind`` / hints. exclude_noise=false also returns OPTIONS preflights and tracker traffic.
| Name | Type | Req | Description |
|---|---|---|---|
| body_contains | – | – | – |
| content_kind | – | – | – |
| exclude_noise | boolean | – | – |
| header_contains | – | – | – |
| header_name | – | – | – |
| host | – | – | – |
| limit | – | – | – |
| method | – | – | – |
| mime_contains | – | – | – |
| offset | – | – | – |
| path_contains | – | – | – |
| session_id | string | yes | – |
| status | – | – | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_gate_bot_protection Hardly Gate Bot Protection ~262
Detect gates in a capture: bot walls, captcha, login, rate limits, 401/403/429 challenges and CDN/WAF bot-protection products. Never evades. Example: hardly_gate_bot_protection(session_id='S', explain=true). Call when requests are blocked, before any retry: every gate is a STOP sign (re-capture interactively with a person). barriers: each barrier (environment_blocked, bot_wall, captcha, proof_of_work, waiting_room, click_through_terms, login, paywall, rate_limit) with evidence names, entry_ids and a policy action (stop | accept_click_through | unknown_rerun). http_challenges: WWW-Authenticate schemes, 429/423/Retry-After lockout signals and captcha widget markup. bot_protection: vendors seen (Cloudflare, Akamai, Imperva, DataDome, HUMAN, ...) with a state each (blocked / challenged / clearance_seen / present). Challenge nonces are never returned; a CDN header on a normal page is informational, not a wall.
| Name | Type | Req | Description |
|---|---|---|---|
| explain | boolean | – | – |
| host | – | – | – |
| limit | – | – | – |
| sections | – | – | – |
| session_id | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_guide_help Hardly Guide Help ~76
Categorized catalog of tools and workflows; pass topic to filter. Use when you do not know which tool fits (topics: portal, tokens, capture, modes, or a tool name); for a task-specific plan use hardly_guide_task_plan. Example: hardly_guide_help(topic='capture').
| Name | Type | Req | Description |
|---|---|---|---|
| topic | – | – | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_guide_mode Hardly Guide Mode ~150
List the three operating modes (archive, headless, interactive), or get the playbook for one mode, or auto-pick a mode from goal / har_path / url. Example: hardly_guide_mode(har_path='/data/capture.har'). With no argument it lists the modes and when to use each. With ``mode`` it returns that mode's step-by-step playbook; with goal / har_path / url (and no mode) a mode is chosen for you. ``hardly_guide_task_plan`` is the better first call for a full ordered plan.
| Name | Type | Req | Description |
|---|---|---|---|
| goal | – | – | – |
| har_path | – | – | – |
| mode | – | – | – |
| url | – | – | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_guide_task_plan Hardly Guide Task Plan ~129
FIRST CALL for a new task: ordered plan of hardly tool calls with example arguments, environment state and recommended tools for the goal. Example: hardly_guide_task_plan(goal='reverse engineer the login flow', har_path='/data/capture.har'). Pass what you know: goal (free text, e.g. 'build a client SDK'), har_path, url. Small output (~2 KB). For one mode's playbook use hardly_guide_mode, for the tool catalog hardly_guide_help.
| Name | Type | Req | Description |
|---|---|---|---|
| goal | – | – | – |
| har_path | – | – | – |
| url | – | – | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_har_file_check Hardly Har File Check ~145
Diagnose a HAR file on disk (truncated/omitted bodies, sanitised cookies, clock skew, noise); no session needed. Findings carry a fix_hint such as recapture flags. Example: hardly_har_file_check(har_path='/data/capture.har'). Session-level body counts are hardly_session_body_coverage. Optional ``config`` (object): checks, exclude, severity_overrides, thresholds{max_entry_bytes, truncation_ratio, clock_skew_s, noise_ratio, min_entries}, strict, fail_on, host, ignore_hosts, ignore_paths, max_findings, fix.
| Name | Type | Req | Description |
|---|---|---|---|
| config | – | – | – |
| har_path | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_page_embedded_routes Hardly Page Embedded Routes ~164
Mine endpoints the page embeds. Sections: script_routes (URL path literals in JavaScript), data_attrs (endpoints and config in HTML data-* attributes); default both. Example: hardly_page_embedded_routes(session_id='S', sections=['data_attrs'], entry_id=5). Use when search works but the detail URL is unknown, or on JS-heavy pages to find where the page gets its data; then hardly_entry_around on the click entry. data_attrs reports dataset keys, value kinds, embedded endpoint URLs and JSON config, never free text.
| Name | Type | Req | Description |
|---|---|---|---|
| entry_id | – | – | – |
| explain | boolean | – | – |
| host | – | – | – |
| limit | – | – | – |
| offset | – | – | – |
| sections | – | – | – |
| session_id | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_page_forms Hardly Page Forms ~134
Extract HTML forms and their inputs with signals (hidden fields, tokens, links, handlers). Use to reverse server-rendered pages instead of dumping HTML; entry_id gives the full inventory of one response, omit it to scan the session. Example: hardly_page_forms(session_id='S', entry_id=5). For link/handler/label-first workflows and search links use hardly_page_ui (same scan).
| Name | Type | Req | Description |
|---|---|---|---|
| entry_id | – | – | – |
| exclude_noise | boolean | – | – |
| host | – | – | – |
| limit | – | – | – |
| offset | – | – | – |
| session_id | string | yes | – |
| side | string | – | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_page_list Hardly Page List ~69
List HAR pageref groups (browser page loads) with document hints. Use to split a capture into navigations. Example: hardly_page_list(session_id='S').
| Name | Type | Req | Description |
|---|---|---|---|
| exclude_noise | boolean | – | – |
| host | – | – | – |
| limit | – | – | – |
| session_id | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_page_tables Hardly Page Tables ~80
List HTML data tables: headers, row/column counts, column kinds and a masked first row (cell values never returned). Use to understand result grids before scraping or modelling them. Example: hardly_page_tables(session_id='S', entry_id=14).
| Name | Type | Req | Description |
|---|---|---|---|
| entry_id | – | – | – |
| host | – | – | – |
| session_id | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_page_ui Hardly Page Ui ~188
Inventory UI controls. Sections: links, handlers (onclick/onsubmit), labels (default all three), search_links (ranked links likely to lead to a search page). Example: hardly_page_ui(session_id='S', sections=['search_links'], keywords=['search']). Same scan as hardly_page_forms, projected to the UI parts; handler_functions names feed hardly_page_embedded_routes. entry_id inventories one response, omit it to scan the session. search_links takes ``keywords`` (the site's domain vocabulary): repeat per hop until a form with inputs appears; its next_step feeds hardly_browser_run_steps.
| Name | Type | Req | Description |
|---|---|---|---|
| entry_id | – | – | – |
| exclude_noise | boolean | – | – |
| host | – | – | – |
| keywords | – | – | – |
| limit | – | – | – |
| offset | – | – | – |
| sections | – | – | – |
| session_id | string | yes | – |
| side | string | – | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_send_arcgis_explore Hardly Send Arcgis Explore ~188
LIVE (confirm-gated): politely explore an ArcGIS REST service or layer URL (GET only, at most 7 requests). Without confirm=true it returns only the plan, so show the person the URL first. For captured traffic use hardly_endpoint_arcgis. Example: hardly_send_arcgis_explore(url='https://host/arcgis/rest/services/X/MapServer', confirm=true). Refuses loopback, private, link-local and metadata hosts, also on redirects (host_not_allowed; local test targets: HARDLY_ALLOW_PRIVATE_HOSTS=1). Returns layers, fields (personal-data-like and id fields FLAGGED), query templates and a one-row sample as field names + masked shapes, never values. Stops on 429 and on token-required (498/499); never guesses tokens.
| Name | Type | Req | Description |
|---|---|---|---|
| confirm | boolean | – | – |
| url | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_send_catalog_verify Hardly Send Catalog Verify ~266
LIVE (confirm-gated): politely verify catalog endpoints (verified|blocked|dead|needs_browser). Without confirm=true it returns only the plan and sends nothing; write_back=true also records statuses in catalog_path. Example: hardly_send_catalog_verify(catalog_path='/data/targets.json', confirm=true, write_back=true). Refuses loopback, private, link-local and metadata hosts, also on redirects (host_not_allowed; local test targets: HARDLY_ALLOW_PRIVATE_HOSTS=1). Per endpoint it runs one robots-aware, honest-UA fetch and records status, gate classes and stack names, never bodies or tokens. Per-host delay, request budget, resumable (already-checked endpoints are skipped unless force / recheck_after_seconds). Stops a host on any gate per docs/gate-policy.md; never evades.
| Name | Type | Req | Description |
|---|---|---|---|
| catalog_path | string | yes | – |
| confirm | boolean | – | – |
| delay_seconds | number | – | – |
| force | boolean | – | – |
| group | – | – | – |
| max_endpoints | – | – | – |
| max_requests | integer | – | – |
| recheck_after_seconds | – | – | – |
| role | – | – | – |
| status | – | – | – |
| tag | – | – | – |
| target_id | – | – | – |
| write_back | boolean | – | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_send_entry Hardly Send Entry ~185
LIVE (confirm-gated): replay ONE captured request. Without confirm=true it returns only the plan and sends nothing, so tell the person what will be sent first. Sensitive HAR headers are skipped unless given in header_overrides. Example: hardly_send_entry(session_id='S', entry_id=12, confirm=true). Refuses loopback, private, link-local and metadata hosts, also on redirects (host_not_allowed; local test targets: HARDLY_ALLOW_PRIVATE_HOSTS=1). For an ordered series use hardly_send_entry_series; to learn which elements are required hardly_send_entry_ablation. The offline curl text is hardly_entry_build_curl.
| Name | Type | Req | Description |
|---|---|---|---|
| body_override | – | – | – |
| confirm | boolean | – | – |
| entry_id | integer | yes | – |
| header_overrides | – | – | – |
| session_id | string | yes | – |
| timeout_seconds | number | – | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_send_entry_ablation Hardly Send Entry Ablation ~276
LIVE (confirm-gated): find which headers, cookies, params, body fields and prior steps a request truly needs by replaying it with ONE element removed at a time. Without confirm=true it returns only the plan. Example: hardly_send_entry_ablation(session_id='S', entry_ids=[12], confirm=true). Refuses loopback, private, link-local and metadata hosts, also on redirects (host_not_allowed; local test targets: HARDLY_ALLOW_PRIVATE_HOSTS=1). Reports REQUIRED vs OPTIONAL names only, never bodies. entry_ids may be an ordered flow (earlier ids are prior steps, the last is the target). Secrets only via ``overrides`` {"headers":{},"cookies":{},"query":{},"body":{}}; missing ones are listed under needs_override. GET/HEAD only unless allow_unsafe=true. Hard stop on 429 / Retry-After / gate stop; captcha token fields are never sent. Budget-skipped items appear under not_tested.
| Name | Type | Req | Description |
|---|---|---|---|
| allow_gates | – | – | – |
| allow_unsafe | boolean | – | – |
| confirm | boolean | – | – |
| delay_seconds | number | – | – |
| entry_ids | array | yes | – |
| max_requests | integer | – | – |
| overrides | – | – | – |
| session_id | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_send_entry_series Hardly Send Entry Series ~222
LIVE (confirm-gated): replay an ordered series and report the first step whose status, content-type or body shape diverges. Without confirm=true it returns the dry-run plan and missing inputs. Example: hardly_send_entry_series(session_id='S', entry_id=20, confirm=true). Refuses loopback, private, link-local and metadata hosts, also on redirects (host_not_allowed; local test targets: HARDLY_ALLOW_PRIVATE_HOSTS=1). Use to verify a client flow works. Secrets only via ``env`` {name: value} or HARDLY_INPUT_<NAME> env vars; values are never printed. GET/HEAD only unless allow_unsafe; halts on 429/Retry-After/ gates.
| Name | Type | Req | Description |
|---|---|---|---|
| allow_gates | – | – | – |
| allow_unsafe | boolean | – | – |
| confirm | boolean | – | – |
| delay_seconds | number | – | – |
| entry_id | – | – | – |
| entry_ids | – | – | – |
| env | – | – | – |
| max_requests | integer | – | – |
| session_id | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_send_redirect_walk Hardly Send Redirect Walk ~184
LIVE (confirm-gated): explain a redirect loop (ERR_TOO_MANY_REDIRECTS) by following the chain by hand with and without cookies. Without confirm=true it returns only the plan. Reports statuses, redacted URLs and cookie names only. Example: hardly_send_redirect_walk(url='https://example.com', confirm=true). Refuses loopback, private, link-local and metadata hosts, also on redirects (host_not_allowed; local test targets: HARDLY_ALLOW_PRIVATE_HOSTS=1). Reports the loop shape: www<->apex or http<->https flips, trailing-slash fights, growing return URLs, cookie-dependent redirects, and whether the alternate host resolves. Redirects already in a capture are hardly_session_redirect_history.
| Name | Type | Req | Description |
|---|---|---|---|
| confirm | boolean | – | – |
| max_hops | integer | – | – |
| url | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_send_site_crawl Hardly Send Site Crawl ~339
LIVE (confirm-gated): curl-first, robots-aware, polite crawl that finds candidate pages (search forms first). Without confirm=true it returns only the plan. Use when headless Chromium is blocked or static HTML suffices; it stops at gates and never evades them. Example: hardly_send_site_crawl(url='https://example.com', keywords=['search'], confirm=true). Refuses loopback, private, link-local and metadata hosts, also on redirects (host_not_allowed; local test targets: HARDLY_ALLOW_PRIVATE_HOSTS=1). Follows only links found in fetched HTML (never guesses hosts or paths), ranks them with ``keywords`` (nouns), honours robots.txt, waits delay_seconds between requests per host, strips session ids, and stops at gates and on 429/Retry-After. Caps: max_pages <= 40, depth <= 4. External registrable domains are only recorded unless follow_external=true (one hop). Returns candidates, per-page form field NAMES, gate classes and needs_browser pages (with `next` advice when explain=true); no bodies, URLs redacted. For needs_browser pages use hardly_browser_capture_discover with a find_click step.
| Name | Type | Req | Description |
|---|---|---|---|
| confirm | boolean | – | – |
| delay_seconds | number | – | – |
| depth | integer | – | – |
| explain | boolean | – | – |
| follow_external | boolean | – | – |
| keywords | – | – | – |
| max_pages | integer | – | – |
| respect_robots | boolean | – | – |
| timeout_seconds | number | – | – |
| url | string | yes | – |
| user_agent | – | – | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_server_status Hardly Server Status ~101
Server version, feature flags, tool names and browser availability; sections: capabilities (default), browser_setup. Call when a tool seems missing (restart the MCP server) or capture fails. ``capabilities``: version, features, tools, capture_available (small, ~3 KB). ``browser_setup``: Playwright package and browser binaries, with the exact install commands. Example: hardly_server_status(sections=['browser_setup']).
| Name | Type | Req | Description |
|---|---|---|---|
| sections | – | – | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_session_body_coverage Hardly Session Body Coverage ~106
Count entries with usable body text versus empty or truncated. Use before trusting schema/client output, or when bodies look missing. Example: hardly_session_body_coverage(session_id='S'). Useful after Playwright captures that used to omit XHR bodies (size=-1). For problems in the HAR file itself use hardly_har_file_check.
| Name | Type | Req | Description |
|---|---|---|---|
| exclude_noise | boolean | – | – |
| host | – | – | – |
| limit | – | – | – |
| session_id | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_session_close Hardly Session Close ~50
Close an open session to free memory (the session is discarded; files saved with hardly_write_session_copy stay). Example: hardly_session_close(session_id='S').
| Name | Type | Req | Description |
|---|---|---|---|
| session_id | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_session_compare Hardly Session Compare ~97
Compare endpoint templates (and credential maps) between two sessions: routes that appeared and disappeared. Use for logged out vs in, or before and after a site change. Example: hardly_session_compare(session_id='A', other_session_id='B').
| Name | Type | Req | Description |
|---|---|---|---|
| exclude_noise | boolean | – | – |
| host | – | – | – |
| include_credentials | boolean | – | – |
| other_session_id | string | yes | – |
| session_id | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_session_duplicates Hardly Session Duplicates ~82
Find repeated method+path_template groups (polling, retries). Use to separate noise from real calls before documenting. Example: hardly_session_duplicates(session_id='S', min_count=5).
| Name | Type | Req | Description |
|---|---|---|---|
| exclude_noise | boolean | – | – |
| host | – | – | – |
| limit | – | – | – |
| min_count | integer | – | – |
| session_id | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_session_issues Hardly Session Issues ~76
List capture-quality issues: empty bodies, 4xx/5xx, redirects without Location. Check before trusting other results; for HAR-file problems use hardly_har_file_check. Example: hardly_session_issues(session_id='S').
| Name | Type | Req | Description |
|---|---|---|---|
| host | – | – | – |
| limit | – | – | – |
| session_id | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_session_list Hardly Session List ~41
List open HAR sessions (session_id, har_path, index_path). Use when you lost a session_id. No arguments. Example: hardly_session_list().
Input schema present but exposes no named parameters.
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
hardly_session_open Hardly Session Open ~105
Index a HAR file (or open a saved index) into a queryable session and return session_id plus summary counts. Start here for any HAR; never Read the raw HAR. Writes nothing (save an index with hardly_write_session_copy). Example: hardly_session_open(har_path='/data/capture.har'). Opening the same path again returns the same session; force=true re-ingests the HAR.
| Name | Type | Req | Description |
|---|---|---|---|
| force | boolean | – | – |
| har_path | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| result | string | yes | – |
No examples provided.
How do I install the hardly MCP server?
hardly runs locally as a PyPI package, launched with uvx hardly. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.
pypi · hardly
claude mcp add b1tninja-hardly -- uvx hardly
What is the hardly MCP server?
hardly is an MCP server listed in the public MCP registry as io.github.b1tninja/hardly. Generic HAR analysis MCP server: index and query captures without burning tokens on raw files. This page covers its PyPI package (hardly).
Is the hardly MCP server safe to use?
hardly scores 80 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 4 November 2026. Its build provenance is signed and verified. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.
What tools does the hardly MCP server expose?
hardly exposes 71 tools: hardly_server_status, hardly_guide_help, hardly_guide_mode, hardly_guide_task_plan, hardly_session_open, and 66 more. Their descriptions and schemas cost roughly 10,295 tokens of context every time the server is loaded.
Is the hardly MCP server still maintained?
hardly is still listed as active in the MCP registry. We last reached this channel on 4 November 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.
What licence is the hardly MCP server under?
hardly declares the MPL-2.0 licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.