Tools and guidance: what you get, and where it comes from¶
This page explains what the three kinds of tool this server registers actually are, and — for the two documentation-guidance tools specifically — exactly whose words you're reading when you use them.
Public tool counts (current, source-derived)¶
- 95 pfSense READ tools — each one calls exactly one fixed pfREST
GETendpoint through one statically checked client method, gated by a namedCapability. See the full reference and Compatibility for per-tool detail. - 2 guidance tools — documentation lookup, not a pfSense appliance call. Counted separately, never blended into the 95:
pfsense_get_official_guidance— official Netgate pfSense product documentation.pfsense_get_api_guidance— this project's own tool interpretation, the community-maintained pfREST package's live API reference, and the connected appliance's own OpenAPI schema.- 0 registered WRITE tools in the default profile. Exactly one
WRITE-capable tool exists in this codebase at all
(
set_firewall_alias_description_v1) and is reachable only under an explicitwrite_protectedopt-in — see the security model.
These counts are enforced mechanically, not just documented: a snapshot test fails CI if the registered tool set drifts from the reviewed, approved contract.
READ tools vs. the guidance tools¶
A READ tool (pfsense_get_*) tells you what is true about your
specific, connected appliance right now — configuration, live status,
or derived state, depending on the tool (see the per-tool notes in
the API reference).
The guidance tools tell you something different: general documentation, not observed live state. Neither can reflect your appliance's actual configuration by itself — for that, use the matching READ tool instead. Every result either guidance tool returns carries a fixed disclaimer field saying exactly this, structurally, not just in prose.
Four provenance labels, never blended¶
Every piece of guidance content this server can return is labeled with exactly one of four provenance values. Authority is dimension-specific — no single source outranks the others on every question:
| Label | Authoritative for | Source |
|---|---|---|
OFFICIAL_NETGATE |
pfSense's general product/operational meaning | docs.netgate.com, cited by URL — the guidance tool's own text is project-authored, never a quotation |
PFREST_UPSTREAM |
General pfREST API semantics (auth modes, query syntax, endpoint/model reference) | The community-maintained pfREST package's own live documentation at pfrest.org — explicitly not Netgate documentation |
LIVE_APPLIANCE_SCHEMA |
Whether a specific endpoint/model exists on your connected appliance right now | The appliance's own /api/v2/schema/openapi response, fetched through the same authenticated transport every READ tool uses |
PROJECT_AUTHORED |
What this project's own tool returns and how to interpret it | This codebase, reviewed like source code |
When two sources disagree on a question neither is authoritative for
(e.g. PFREST_UPSTREAM describes an endpoint the connected appliance's
own schema doesn't have), both are surfaced side by side with the
disagreement stated explicitly — never silently merged, never silently
dropped, never resolved by picking a "winner" outside the rule above.
Documentation guidance — from any of the four sources above — is always advisory. It is never observed live state by itself, and it can never authorize, select, or influence any action this server takes. See the security model and ADR-017/ADR-018 for the full architecture and the tests that prove this boundary holds.
pfsense_get_official_guidance¶
Every entry in the Netgate guidance registry is project-authored —
written and reviewed by this project, describing what a
Netgate-documented pfSense feature generally is, never a quotation of
Netgate's own text. Each entry cites its official source page
(docs.netgate.com) for provenance, and carries a computed
applicability state (does this appear to match your appliance's
observed edition/version, or not) — resolved automatically from the
appliance's own reported version, never something you supply.
Current coverage: 28 of 86 distinct READ capabilities have a
registered guidance entry today. This is an honest, unpadded number,
not a target dressed up as an achievement — a capability with no
registered entry simply returns an empty result (NO_OFFICIAL_GUIDANCE_FOUND),
never a fabricated answer.
pfsense_get_api_guidance¶
Covers the gap pfsense_get_official_guidance deliberately does not:
the pfSense REST API package itself (pfrest/pfSense-pkg-RESTAPI) is
not Netgate product documentation — it's a separate,
community-maintained package, documented at
pfrest.org, not docs.netgate.com.
Four bounded query modes — every input is used only as a lookup key into already-fetched, cached, parsed documentation; none of them can make this tool fetch an arbitrary URL:
query_mode |
Required arguments | Returns |
|---|---|---|
tool |
tool_name (a real pfsense-mcp-server tool name) |
This project's own PROJECT_AUTHORED interpretation of that tool, plus (if it maps to a known pfREST endpoint) PFREST_UPSTREAM and LIVE_APPLIANCE_SCHEMA evidence for it |
endpoint |
endpoint_path (e.g. /api/v2/firewall/alias), endpoint_method (GET/POST/PUT/PATCH/DELETE) |
PFREST_UPSTREAM and LIVE_APPLIANCE_SCHEMA evidence for that exact path/method |
model |
model_name (a real pfREST OpenAPI schema name, e.g. FirewallAlias) |
PFREST_UPSTREAM and LIVE_APPLIANCE_SCHEMA evidence for that model's fields |
topic |
topic (one of AUTHENTICATION_AND_AUTHORIZATION, WORKING_WITH_OBJECT_IDS, QUERIES_FILTERS_AND_SORTING, COMMON_CONTROL_PARAMETERS, WORKING_WITH_HATEOAS, SWAGGER_AND_OPENAPI) |
A bounded PFREST_UPSTREAM excerpt of that guide page |
Example: "What does pfsense_get_firewall_aliases actually call, and
does my appliance have that endpoint?"
{"name": "pfsense_get_api_guidance", "arguments": {"query_mode": "tool", "tool_name": "pfsense_get_firewall_aliases"}}
Returns three independently labeled evidence entries (PROJECT_AUTHORED,
PFREST_UPSTREAM, LIVE_APPLIANCE_SCHEMA) plus, if they disagree on
existence, an explicit conflicts entry explaining which source is
authoritative for that question and why.
How it fetches PFREST_UPSTREAM content: a narrow, allowlisted
(exact host pfrest.org only), HTTPS-only, GET-only fetcher with a hard
response-size cap, single-redirect tolerance restricted to the same
allowlisted host, content-type validation, and a bounded in-memory
cache honoring the upstream's own Cache-Control headers. No network
call happens at server import or startup — only when this tool is
actually invoked with a query that needs it. Never fetches from any
other host, regardless of what string is passed as endpoint_path,
model_name, or topic — those are always lookup keys against
already-fetched data, never URLs.
How it fetches LIVE_APPLIANCE_SCHEMA content: through the same
authenticated PfSenseClient transport every READ tool already uses —
a single GET to your configured appliance's /api/v2/schema/openapi,
cached in memory for the server process's lifetime (falling back to a
stale cached copy if a later refresh fails, never failing the whole
tool call over one transient appliance error).
When either source is unreachable, the corresponding evidence entry
says so explicitly (freshness: upstream_unavailable) rather than
silently omitting itself or fabricating an answer.
Privilege drift check (maintainer/operator tool, not part of the MCP surface)¶
make pfrest-privilege-crosscheck (scripts/pfrest_privilege_crosscheck.py)
compares what PFREST_UPSTREAM and, if a real appliance is configured,
LIVE_APPLIANCE_SCHEMA each declare as a READ tool's required pfSense
privilege, and reports MATCH / EXPLAINED_DIFFERENCE / DRIFT for every
tool with a real endpoint. Strictly advisory and read-only — it never
grants a privilege, modifies a service account, or changes this
project's own ADR-033 privilege mapping. Deliberately not part of
pfsense_get_api_guidance or any other MCP tool (it would expand the
public surface for a maintainer-facing check); run it manually or wire
it into your own CI. Requires network access, so it is not part of
make quick/make validate, matching this project's established
pattern for every other live-network check
(make docs-freshness-check, make guidance-corpus-audit).
Schema diff (maintainer/operator tool, not part of the MCP surface)¶
make pfrest-schema-diff (scripts/pfrest_schema_diff.py) performs a
semantic, dimension-classified comparison between two OpenAPI
documents — by default, live PFREST_UPSTREAM vs. a configured
appliance's live LIVE_APPLIANCE_SCHEMA. Twelve dimensions are compared
(paths/methods, operationIds, parameters, schemas/models, fields,
enums, field default values, required_packages, auth metadata,
allowed_privileges, applies_immediately, x- extensions, top-level
version metadata) and classified as added/removed/changed — never a
raw JSON/byte diff, and never an attributed cause. --a file/--b
file loads a previously saved snapshot from disk instead of making a
live call, which is how a future, separately-authorized comparison
between two different appliances (e.g. pfSense CE vs. Plus running the
same pfREST version) can be performed offline. Strictly advisory and
read-only; deliberately not part of pfsense_get_api_guidance or
any other MCP tool, for the same reason as the privilege cross-check
above. Requires network access, so it is not part of make
quick/make validate. See
ADR-035
for the real LAB-vs-upstream findings from the arc that introduced it.