pfsense-mcp-server 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. pfsense_mcp_server-0.2.2/.gitignore +44 -0
  2. pfsense_mcp_server-0.2.2/CHANGELOG.md +97 -0
  3. pfsense_mcp_server-0.2.2/CODE_OF_CONDUCT.md +72 -0
  4. pfsense_mcp_server-0.2.2/CONTRIBUTING.md +92 -0
  5. pfsense_mcp_server-0.2.2/LICENSE +21 -0
  6. pfsense_mcp_server-0.2.2/PKG-INFO +309 -0
  7. pfsense_mcp_server-0.2.2/README.md +271 -0
  8. pfsense_mcp_server-0.2.2/SECURITY.md +43 -0
  9. pfsense_mcp_server-0.2.2/docs/ACCEPTANCE_v0.2.1.md +47 -0
  10. pfsense_mcp_server-0.2.2/docs/ACCEPTANCE_v0.2.2.md +129 -0
  11. pfsense_mcp_server-0.2.2/docs/API.md +466 -0
  12. pfsense_mcp_server-0.2.2/docs/PYPI_RELEASE.md +168 -0
  13. pfsense_mcp_server-0.2.2/docs/RECOVERY_CONTRACT_SPEC.md +152 -0
  14. pfsense_mcp_server-0.2.2/docs/RELEASE_CHECKLIST.md +78 -0
  15. pfsense_mcp_server-0.2.2/docs/SECURITY_MODEL.md +105 -0
  16. pfsense_mcp_server-0.2.2/docs/TIER1_ROADMAP.md +447 -0
  17. pfsense_mcp_server-0.2.2/pyproject.toml +118 -0
  18. pfsense_mcp_server-0.2.2/src/pfsense_mcp/__init__.py +1 -0
  19. pfsense_mcp_server-0.2.2/src/pfsense_mcp/api_version.py +26 -0
  20. pfsense_mcp_server-0.2.2/src/pfsense_mcp/application.py +80 -0
  21. pfsense_mcp_server-0.2.2/src/pfsense_mcp/capabilities.py +87 -0
  22. pfsense_mcp_server-0.2.2/src/pfsense_mcp/config.py +256 -0
  23. pfsense_mcp_server-0.2.2/src/pfsense_mcp/diagnostics.py +37 -0
  24. pfsense_mcp_server-0.2.2/src/pfsense_mcp/endpoints.py +231 -0
  25. pfsense_mcp_server-0.2.2/src/pfsense_mcp/errors.py +56 -0
  26. pfsense_mcp_server-0.2.2/src/pfsense_mcp/factory.py +24 -0
  27. pfsense_mcp_server-0.2.2/src/pfsense_mcp/logging_setup.py +86 -0
  28. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/__init__.py +3 -0
  29. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/acme_settings.py +25 -0
  30. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/arp_table_entry.py +39 -0
  31. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/auth_key.py +31 -0
  32. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/bind_settings.py +59 -0
  33. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/carp_status.py +26 -0
  34. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/cron_job.py +37 -0
  35. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/dhcp_lease.py +46 -0
  36. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/dhcp_server.py +81 -0
  37. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/dhcp_static_mapping.py +59 -0
  38. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/diagnostics_table.py +27 -0
  39. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/dns_resolver_host_override.py +33 -0
  40. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/dns_resolver_settings.py +57 -0
  41. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/email_notification_settings.py +60 -0
  42. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/firewall.py +167 -0
  43. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/firewall_advanced_settings.py +25 -0
  44. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/firewall_alias.py +44 -0
  45. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/firewall_nat_outbound_mode.py +23 -0
  46. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/firewall_nat_port_forward.py +81 -0
  47. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/firewall_traffic_shaper_limiter.py +123 -0
  48. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/free_radius_eap.py +79 -0
  49. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/gateways.py +104 -0
  50. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/interface_bridge.py +33 -0
  51. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/interface_config.py +141 -0
  52. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/interfaces.py +100 -0
  53. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/ntp_settings.py +53 -0
  54. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/ntp_time_server.py +31 -0
  55. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/pf_sense_user.py +51 -0
  56. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/pf_sense_user_group.py +35 -0
  57. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/service_status.py +31 -0
  58. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/ssh_settings.py +29 -0
  59. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/system.py +40 -0
  60. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/system_certificate.py +46 -0
  61. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/system_ha_sync.py +95 -0
  62. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/system_package.py +35 -0
  63. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/system_rest_api_settings.py +71 -0
  64. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/system_tunable.py +29 -0
  65. pfsense_mcp_server-0.2.2/src/pfsense_mcp/models/system_version.py +29 -0
  66. pfsense_mcp_server-0.2.2/src/pfsense_mcp/pfsense_client.py +516 -0
  67. pfsense_mcp_server-0.2.2/src/pfsense_mcp/pfsense_write_client.py +75 -0
  68. pfsense_mcp_server-0.2.2/src/pfsense_mcp/profiles.py +46 -0
  69. pfsense_mcp_server-0.2.2/src/pfsense_mcp/py.typed +1 -0
  70. pfsense_mcp_server-0.2.2/src/pfsense_mcp/recovery.py +95 -0
  71. pfsense_mcp_server-0.2.2/src/pfsense_mcp/rest_api_client.py +100 -0
  72. pfsense_mcp_server-0.2.2/src/pfsense_mcp/rollback.py +40 -0
  73. pfsense_mcp_server-0.2.2/src/pfsense_mcp/server.py +13 -0
  74. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tls.py +54 -0
  75. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/__init__.py +2 -0
  76. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/audit.py +70 -0
  77. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/__init__.py +1 -0
  78. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/acme_settings.py +18 -0
  79. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/arp_table.py +16 -0
  80. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/auth_keys.py +22 -0
  81. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/bind_settings.py +16 -0
  82. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/carp_status.py +18 -0
  83. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/cron_jobs.py +16 -0
  84. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/dhcp_leases.py +20 -0
  85. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/dhcp_servers.py +22 -0
  86. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/dhcp_static_mappings.py +21 -0
  87. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/diagnostics_tables.py +18 -0
  88. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/dns_resolver_host_overrides.py +16 -0
  89. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/dns_resolver_settings.py +18 -0
  90. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/email_notification_settings.py +24 -0
  91. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/firewall_advanced_settings.py +16 -0
  92. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/firewall_aliases.py +27 -0
  93. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/firewall_apply_status.py +19 -0
  94. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/firewall_nat_outbound_mode.py +17 -0
  95. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/firewall_nat_port_forwards.py +28 -0
  96. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/firewall_rules.py +22 -0
  97. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/firewall_states.py +28 -0
  98. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/firewall_states_size.py +18 -0
  99. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/firewall_traffic_shaper_limiters.py +18 -0
  100. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/freeradius_eap.py +18 -0
  101. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/gateway_status.py +22 -0
  102. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/gateways.py +22 -0
  103. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/interface_bridges.py +20 -0
  104. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/interface_configs.py +26 -0
  105. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/interfaces.py +23 -0
  106. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/ntp_settings.py +18 -0
  107. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/ntp_time_servers.py +16 -0
  108. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/service_status.py +20 -0
  109. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/ssh_settings.py +18 -0
  110. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/system_certificates.py +22 -0
  111. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/system_hasync.py +22 -0
  112. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/system_packages.py +16 -0
  113. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/system_restapi_settings.py +21 -0
  114. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/system_status.py +20 -0
  115. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/system_tunables.py +16 -0
  116. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/system_version.py +18 -0
  117. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/user_groups.py +20 -0
  118. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/read/users.py +25 -0
  119. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/registry.py +425 -0
  120. pfsense_mcp_server-0.2.2/src/pfsense_mcp/tools/write/__init__.py +3 -0
  121. pfsense_mcp_server-0.2.2/src/pfsense_mcp/transport/__init__.py +3 -0
  122. pfsense_mcp_server-0.2.2/src/pfsense_mcp/transport/base.py +33 -0
  123. pfsense_mcp_server-0.2.2/src/pfsense_mcp/transport/http.py +31 -0
  124. pfsense_mcp_server-0.2.2/src/pfsense_mcp/transport/mock.py +21 -0
  125. pfsense_mcp_server-0.2.2/src/pfsense_mcp/write_api_client.py +105 -0
  126. pfsense_mcp_server-0.2.2/src/pfsense_mcp/write_audit.py +110 -0
  127. pfsense_mcp_server-0.2.2/src/pfsense_mcp/write_endpoints.py +33 -0
  128. pfsense_mcp_server-0.2.2/src/pfsense_mcp/write_types.py +49 -0
@@ -0,0 +1,44 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .venv/
6
+ venv/
7
+ .pytest_cache/
8
+ .mypy_cache/
9
+ .ruff_cache/
10
+ dist/
11
+ build/
12
+ .coverage
13
+ coverage.xml
14
+ htmlcov/
15
+
16
+ # make validate output (junit-xml report) — working output, not a repo artifact
17
+ .validate/
18
+
19
+ # capture_fixture.py proposals — untrusted, unaudited candidates.
20
+ # Never committed directly; audit_fixture.py --approve copies an
21
+ # audited proposal into tests/fixtures/ explicitly.
22
+ .fixture_proposals/
23
+
24
+ # scaffold_capability.py proposals — generated code proposals for
25
+ # human review only. Never applied, staged, or committed by the tool.
26
+ .capability_proposals/
27
+
28
+ # Local logs (must never be committed)
29
+ *.log
30
+ logs/
31
+
32
+ # Local tooling state — never part of the repository
33
+ .claude/
34
+
35
+ # External AI handoff reports — local symlink to an external reports directory
36
+ reports-ai
37
+
38
+ # Defensive only — no secret material should ever exist in this repo,
39
+ # but these patterns guard against an accidental copy.
40
+ *.key
41
+ *secret*
42
+ *credential*
43
+ !tests/test_credential_non_disclosure.py
44
+ .env
@@ -0,0 +1,97 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and the project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.2.2] - 2026-08-07
11
+
12
+ ### Added
13
+
14
+ - Public CI across Python 3.11, 3.12, and 3.13.
15
+ - Branch coverage reporting, Bandit, and CodeQL configuration.
16
+ - Sdist/wheel inspection and clean installed-entry-point verification.
17
+ - Security, contribution, release-workflow, and project-agent guidance.
18
+ - Threat model, architecture diagrams and decisions, public roadmap, benchmark
19
+ methodology, and MCP client setup guides.
20
+ - GitHub issue and pull-request templates.
21
+ - Public API, type-quality, documentation, and final repository reviews.
22
+ - MCP ToolAnnotations on every production READ tool.
23
+ - Deterministic public MCP contract snapshot and offline release-candidate,
24
+ reproducible-build, documentation-consistency, and artifact-manifest checks.
25
+ - Implementation-independent Recovery Contract field, canonicalization, state,
26
+ fault, and reconciliation specification for future Tier 1 review.
27
+
28
+ ### Changed
29
+
30
+ - Package version prepared for v0.2.2 project hardening.
31
+ - README expanded for first-time installation and operation.
32
+ - Optional exact-name `PFSENSE_ALLOWED_TOOLS` restriction intersects with the
33
+ selected capability profile and fails closed on unknown names.
34
+ - Tier 1 roadmap strengthened for canonical target fingerprints, unstable IDs,
35
+ config-history conflicts, atomic rate/concurrency policy, and compensation
36
+ failure reconciliation; Tier 1 remains blocked.
37
+ - Auditor profile now derives directly from the supported READ capability set,
38
+ removing a duplicated activation list without changing the capability surface.
39
+
40
+ ### Security
41
+
42
+ - Tool annotations remain untrusted client hints; capability, endpoint,
43
+ GET-only, credential, audit, and WRITE-inactivity controls remain
44
+ authoritative.
45
+ - Bound API-key metadata validation and bounded reading to one non-following
46
+ file descriptor, eliminating path replacement between check and use.
47
+ - Replaced certificate inventory fixtures prospectively with wholly synthetic
48
+ `.invalid` certificate identities. No private key is committed; historical
49
+ public certificate material remains in Git history and contained no secret.
50
+ - Reject all non-2xx upstream statuses, including redirects, and normalize
51
+ remaining HTTP transport failures without exposing upstream exception text.
52
+ - Reject encoded and Unicode control/format characters at configuration
53
+ boundaries that can reach URLs, tool restrictions, or logs.
54
+ - Distribution inspection rejects private-key content and additional private,
55
+ generated, database, backup, and SSH artifact paths.
56
+
57
+ ## [0.2.1] - 2026-08-06
58
+
59
+ ### Security
60
+
61
+ - Removed IPsec PSKs, SMTP passwords, and API-key plaintext from public models
62
+ and MCP schemas.
63
+ - Removed the auth-key identifying-metadata disclosure argument.
64
+ - Hardened audit records without logging arguments, responses, or exception
65
+ messages.
66
+ - Sanitized authentication and malformed-response errors.
67
+ - Added fail-closed URL, identity, TLS, key-file, and logging validation.
68
+ - Prohibited credential fields in approved fixtures and added negative
69
+ disclosure tests.
70
+
71
+ ## [0.2.0] - 2026-08-06
72
+
73
+ ### Added
74
+
75
+ - Tier 0 WRITE infrastructure, including recovery, rollback, audit, and write
76
+ client primitives.
77
+ - Independent checks for an empty WRITE endpoint allow-list and inactive WRITE
78
+ capabilities.
79
+
80
+ ### Security
81
+
82
+ - Kept all Tier 0 WRITE infrastructure inert and unreachable from production
83
+ bootstrap. No WRITE tool or endpoint was activated.
84
+
85
+ ## [0.1.0] - 2026-08-06
86
+
87
+ ### Added
88
+
89
+ - Initial production-ready READ-only MCP server.
90
+ - Strongly typed pfSense REST API models and capability-gated tools.
91
+ - GET-only transport enforcement, sanitized fixtures, and offline tests.
92
+
93
+ [Unreleased]: https://github.com/night4me/pfsense-mcp-server/compare/v0.2.2...HEAD
94
+ [0.2.2]: https://github.com/night4me/pfsense-mcp-server/releases/tag/v0.2.2
95
+ [0.2.1]: https://github.com/night4me/pfsense-mcp-server/releases/tag/v0.2.1
96
+ [0.2.0]: https://github.com/night4me/pfsense-mcp-server/releases/tag/v0.2.0
97
+ [0.1.0]: https://github.com/night4me/pfsense-mcp-server/releases/tag/v0.1.0
@@ -0,0 +1,72 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our pledge
4
+
5
+ We pledge to make participation in this project a harassment-free experience
6
+ for everyone, regardless of age, body size, visible or invisible disability,
7
+ ethnicity, sex characteristics, gender identity and expression, level of
8
+ experience, education, socio-economic status, nationality, personal
9
+ appearance, race, caste, color, religion, or sexual identity and orientation.
10
+
11
+ We pledge to act and interact in ways that contribute to an open, welcoming,
12
+ diverse, inclusive, and healthy community.
13
+
14
+ ## Our standards
15
+
16
+ Examples of behavior that contributes to a positive environment include:
17
+
18
+ - demonstrating empathy and kindness;
19
+ - respecting differing opinions, viewpoints, and experiences;
20
+ - giving and gracefully accepting constructive feedback;
21
+ - accepting responsibility, apologizing, and learning from mistakes;
22
+ - focusing on what is best for the community and project.
23
+
24
+ Examples of unacceptable behavior include:
25
+
26
+ - sexualized language or imagery and unwelcome attention or advances;
27
+ - trolling, insulting or derogatory comments, and personal or political
28
+ attacks;
29
+ - public or private harassment;
30
+ - publishing another person's private information without explicit
31
+ permission;
32
+ - publishing credentials, appliance details, or other sensitive operational
33
+ data;
34
+ - conduct that could reasonably be considered inappropriate in a professional
35
+ setting.
36
+
37
+ ## Enforcement responsibilities
38
+
39
+ Project maintainers are responsible for clarifying and enforcing acceptable
40
+ behavior. They may remove, edit, or reject contributions, comments, commits,
41
+ code, issues, and other contributions that do not align with this Code of
42
+ Conduct, and will communicate moderation reasons when appropriate.
43
+
44
+ ## Scope
45
+
46
+ This Code of Conduct applies in project spaces and when an individual is
47
+ officially representing the project in public spaces.
48
+
49
+ ## Enforcement
50
+
51
+ Report abusive, harassing, or otherwise unacceptable behavior privately to the
52
+ repository owner through their published GitHub contact channel. Do not use a
53
+ public issue for a conduct report. Reports will be reviewed promptly and
54
+ fairly, with respect for the reporter's privacy and safety.
55
+
56
+ Maintainers who do not follow or enforce this Code of Conduct in good faith may
57
+ face temporary or permanent consequences as determined by other project
58
+ leadership or platform administrators.
59
+
60
+ ## Enforcement guidelines
61
+
62
+ Maintainers will consider context, severity, repetition, and impact when
63
+ deciding a proportionate response. Responses may include a private correction,
64
+ warning, temporary restriction, or permanent removal from project spaces.
65
+
66
+ ## Attribution
67
+
68
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
69
+ version 2.1, available at
70
+ <https://www.contributor-covenant.org/version/2/1/code_of_conduct.html>.
71
+
72
+ [homepage]: https://www.contributor-covenant.org
@@ -0,0 +1,92 @@
1
+ # Contributing
2
+
3
+ Thank you for helping improve `pfsense-mcp-server`. This project prioritizes
4
+ security, explicit capability boundaries, and reviewable changes over feature
5
+ velocity.
6
+
7
+ ## Before you begin
8
+
9
+ - Read [AGENTS.md](AGENTS.md), [the architecture overview](README.md#architecture),
10
+ and [the security model](docs/SECURITY_MODEL.md).
11
+ - Search existing issues and discussions before proposing substantial work.
12
+ - Open an issue for public design discussion unless the subject is a security
13
+ vulnerability. Report vulnerabilities privately through [SECURITY.md](SECURITY.md).
14
+ - Do not include credentials, real appliance details, raw responses, or
15
+ unsanitized logs in an issue, pull request, fixture, or test.
16
+
17
+ ## Development setup
18
+
19
+ Python 3.11 or newer is supported.
20
+
21
+ ```console
22
+ python -m venv .venv
23
+ .venv/bin/python -m pip install --upgrade pip
24
+ .venv/bin/python -m pip install -e ".[dev]"
25
+ ```
26
+
27
+ The public test suite is fully offline. It uses `MockTransport` and approved,
28
+ sanitized fixtures; no pfSense appliance or credential is required.
29
+
30
+ ## Making a change
31
+
32
+ 1. Keep the change focused and preserve the capability-gated architecture.
33
+ 2. Do not add or activate a capability, MCP tool, or WRITE endpoint without
34
+ explicit project approval.
35
+ 3. Add tests for behavior and negative security properties.
36
+ 4. Update public documentation when behavior or configuration changes.
37
+ 5. Never weaken GET-only enforcement, credential non-disclosure, fixture
38
+ safety, or WRITE-inactivity checks.
39
+
40
+ For new fixture work, use the proposal/audit workflow documented in the
41
+ Makefile. Never commit a direct capture from a real appliance.
42
+
43
+ ## Verification
44
+
45
+ Run the fast feedback loop while developing:
46
+
47
+ ```console
48
+ make quick
49
+ ```
50
+
51
+ Before requesting review, run the authoritative local gate:
52
+
53
+ ```console
54
+ make validate
55
+ ```
56
+
57
+ For packaging, coverage, or security-sensitive changes, also run the relevant
58
+ targets:
59
+
60
+ ```console
61
+ make coverage
62
+ make security-static
63
+ make package-check
64
+ ```
65
+
66
+ Live private-infrastructure acceptance is maintainer-only, requires separate
67
+ approval, and is never a contributor or public CI requirement. See the
68
+ [release checklist](docs/RELEASE_CHECKLIST.md).
69
+
70
+ ## Pull requests
71
+
72
+ A good pull request:
73
+
74
+ - explains the problem and the chosen scope;
75
+ - identifies compatibility and security impact;
76
+ - lists verification actually run;
77
+ - keeps unrelated formatting/refactoring out of the diff;
78
+ - includes no generated caches, reports containing private data, or build
79
+ artifacts.
80
+
81
+ Use clear commit messages in the imperative mood. Maintainers may squash or
82
+ reword commits during review.
83
+
84
+ ## Code style
85
+
86
+ - Prefer typed, explicit code over reflection or implicit registration.
87
+ - Keep MCP tool functions thin and preserve precise public signatures.
88
+ - Translate upstream shape failures into sanitized typed exceptions.
89
+ - Never log arguments, response bodies, exception messages, or credentials.
90
+ - Follow Ruff formatting/lint and mypy configuration in `pyproject.toml`.
91
+
92
+ Participation is governed by [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 pfsense-mcp-server contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,309 @@
1
+ Metadata-Version: 2.4
2
+ Name: pfsense-mcp-server
3
+ Version: 0.2.2
4
+ Summary: Security-focused local MCP server exposing strongly typed READ tools for pfSense.
5
+ Project-URL: Homepage, https://github.com/night4me/pfsense-mcp-server
6
+ Project-URL: Repository, https://github.com/night4me/pfsense-mcp-server
7
+ Project-URL: Issues, https://github.com/night4me/pfsense-mcp-server/issues
8
+ Project-URL: Changelog, https://github.com/night4me/pfsense-mcp-server/blob/main/CHANGELOG.md
9
+ Project-URL: Security, https://github.com/night4me/pfsense-mcp-server/security/policy
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: firewall,mcp,networking,observability,pfsense
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: System Administrators
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: System :: Networking :: Firewalls
22
+ Classifier: Typing :: Typed
23
+ Requires-Python: >=3.11
24
+ Requires-Dist: httpx<1.0,>=0.27
25
+ Requires-Dist: mcp<2.0.0,>=1.0.0
26
+ Requires-Dist: pydantic<3.0,>=2.0
27
+ Provides-Extra: dev
28
+ Requires-Dist: bandit<2.0,>=1.7; extra == 'dev'
29
+ Requires-Dist: build<2.0,>=1.2; extra == 'dev'
30
+ Requires-Dist: hatchling<2.0,>=1.25; extra == 'dev'
31
+ Requires-Dist: mypy<2.0,>=1.10; extra == 'dev'
32
+ Requires-Dist: pytest-cov<8.0,>=5.0; extra == 'dev'
33
+ Requires-Dist: pytest<9.0,>=8.0; extra == 'dev'
34
+ Requires-Dist: respx<1.0,>=0.21; extra == 'dev'
35
+ Requires-Dist: ruff<1.0,>=0.6; extra == 'dev'
36
+ Requires-Dist: twine<7.0,>=5.0; extra == 'dev'
37
+ Description-Content-Type: text/markdown
38
+
39
+ # pfsense-mcp-server
40
+
41
+ [![CI](https://github.com/night4me/pfsense-mcp-server/actions/workflows/ci.yml/badge.svg)](https://github.com/night4me/pfsense-mcp-server/actions/workflows/ci.yml)
42
+ [![CodeQL](https://github.com/night4me/pfsense-mcp-server/actions/workflows/codeql.yml/badge.svg)](https://github.com/night4me/pfsense-mcp-server/actions/workflows/codeql.yml)
43
+ ![Python](https://img.shields.io/badge/python-3.11%20%7C%203.12%20%7C%203.13-blue)
44
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
45
+
46
+ A security-focused local MCP server exposing 41 strongly typed pfSense REST
47
+ API tools. It gives an MCP client operational visibility into one managed
48
+ pfSense Plus appliance while keeping the production path GET-only.
49
+
50
+ Key properties:
51
+
52
+ - explicit capability gates and typed Pydantic responses;
53
+ - credential fields excluded from models, schemas, logs, errors, and fixtures;
54
+ - optional sensitive metadata omitted by default;
55
+ - fail-closed configuration and TLS verification by default;
56
+ - 41 READ tools, zero WRITE tools, and an empty WRITE endpoint allow-list.
57
+
58
+ ## Status
59
+
60
+ v0.2.2 is the current release state. It completes project, packaging,
61
+ documentation, and defense-in-depth hardening while preserving the 41-tool READ
62
+ API. It is not yet published on PyPI. No mutating capability is active, and the
63
+ accepted Tier 0 WRITE infrastructure remains inert.
64
+
65
+ ## Scope (current phase)
66
+
67
+ - REST API only — SSH is out of scope.
68
+ - The production server is read-only. Accepted Tier 0 WRITE infrastructure
69
+ exists as dormant library code, but it is not constructed by production
70
+ bootstrap, has no allow-listed endpoint, and registers no MCP tool.
71
+ - 34 capabilities, 41 tools, spanning system, interfaces, gateways,
72
+ firewall, users, certificates, DHCP, DNS, NTP, SSH, cron, ACME,
73
+ FreeRADIUS, HA/CARP, and diagnostics. See `src/pfsense_mcp/capabilities.py`
74
+ for the authoritative list.
75
+
76
+ ## Architecture
77
+
78
+ Transport (swappable: HttpTransport / MockTransport)
79
+
80
+ RestApiClient GET-only enforcement, API-version resolution,
81
+ ↓ JSON parsing, error mapping, duration logging
82
+ PfSenseClient semantic methods, raw JSON → typed models
83
+
84
+ ToolRegistry / MCP Tools thin, capability-gated
85
+
86
+ `Application` (application.py) owns startup, dependency construction,
87
+ and lifecycle — via `factory.py` for client construction and
88
+ `profiles.py` for capability-set selection. `server.py`'s only job is
89
+ `Application().run()`.
90
+
91
+ `diagnostics.py` reports local server health (configuration validity,
92
+ TLS mode, active API version, registered capabilities, transport
93
+ type) without ever contacting pfSense.
94
+
95
+ The authoritative capability profile gates registration before a tool can
96
+ be exposed. The default auditor profile contains the accepted READ set;
97
+ the engineer placeholder contains no capabilities. Endpoint registries
98
+ independently enforce GET-only access and an empty WRITE allow-list.
99
+ An optional exact-name restriction can further reduce the tools authorized by
100
+ the selected profile; it can never add a tool or capability.
101
+
102
+ ## Credentials
103
+
104
+ This project never stores, logs, or contains an API key. The key is
105
+ loaded at runtime from a local file outside this repository — only
106
+ its **first line** is read — path supplied via `PFSENSE_API_KEY_FILE`.
107
+ The server fails closed if the key cannot be loaded.
108
+
109
+ ## Configuration (missing/invalid values fail closed)
110
+
111
+ | Variable | Required | Example |
112
+ |---|---|---|
113
+ | `PFSENSE_API_URL` | yes | `https://pfsense.example.invalid` |
114
+ | `PFSENSE_IDENTITY` | yes | `api-mcp-admin` |
115
+ | `PFSENSE_API_KEY_FILE` | yes | `/path/outside/repository/pfsense-api.key` |
116
+ | `PFSENSE_TLS_MODE` | no (default `strict`) | `strict` / `auto` / `insecure` |
117
+ | `PFSENSE_TLS_CA_FILE` | required if `PFSENSE_TLS_MODE=auto` | path to a CA bundle |
118
+ | `PFSENSE_API_VERSION` | no (default `v2`) | `v2` |
119
+ | `PFSENSE_PROFILE` | no (default `auditor`) | `auditor` / `engineer` |
120
+ | `PFSENSE_ALLOWED_TOOLS` | no | comma-separated exact MCP tool names |
121
+ | `PFSENSE_LOG_MAX_BYTES` | no (default `5000000`) | log-file rotation size |
122
+ | `PFSENSE_LOG_BACKUP_COUNT` | no (default `5`) | rotated log files kept |
123
+
124
+ `PFSENSE_TLS_MODE=insecure` disables certificate verification and must
125
+ be set explicitly. Switching to `auto` later (once a CA file exists)
126
+ requires no code change — only this configuration.
127
+
128
+ `PFSENSE_PROFILE=engineer` currently grants no capabilities — write
129
+ tools are not registered or reachable. It is a named placeholder for
130
+ a separate, explicitly authorized future phase.
131
+
132
+ `PFSENSE_ALLOWED_TOOLS` is an optional restriction applied after the selected
133
+ profile. If absent, the auditor profile keeps all 41 tools. If present, only
134
+ the comma-separated exact names in both the profile and restriction register.
135
+ Whitespace around names is ignored and duplicate names are normalized. An
136
+ explicitly empty value registers zero tools. Unknown names, empty list entries,
137
+ wildcards, and prefix patterns fail closed at startup. The setting can only
138
+ remove tools; it cannot grant a capability, activate WRITE, or override an
139
+ endpoint check.
140
+
141
+ ## Security policy
142
+
143
+ Credential material is never part of a public model or MCP schema and
144
+ is ignored if pfSense includes it in a READ response. Optional
145
+ `include_identifying_metadata` arguments disclose sensitive operational
146
+ metadata only; they never disclose passwords, pre-shared keys, private
147
+ keys, or API-key plaintext. See the [security model](docs/SECURITY_MODEL.md)
148
+ and [vulnerability reporting policy](SECURITY.md).
149
+
150
+ The supported MCP transport is local stdio. The process launching and
151
+ controlling that channel is the caller-authentication boundary; this is
152
+ not a multi-tenant network service. Public CI has no production
153
+ configuration and never contacts a pfSense appliance.
154
+
155
+ Every current tool advertises MCP `readOnlyHint=true` and
156
+ `openWorldHint=true`: it does not mutate pfSense, but it reads dynamic data
157
+ from an external appliance. These annotations are untrusted client hints for
158
+ presentation and tool selection, not authorization. They do not relax
159
+ capability profiles, the optional exact-name restriction, GET-only or endpoint
160
+ enforcement, credential handling, auditing, or WRITE inactivity.
161
+
162
+ ## Installation from source
163
+
164
+ Linux is the supported production platform because secure credential loading
165
+ depends on descriptor-bound Unix file semantics. Python 3.11 or newer is
166
+ required. Clone the repository, create an isolated environment, and install
167
+ the project:
168
+
169
+ ```console
170
+ git clone https://github.com/night4me/pfsense-mcp-server.git
171
+ cd pfsense-mcp-server
172
+ python -m venv .venv
173
+ .venv/bin/python -m pip install --upgrade pip
174
+ .venv/bin/python -m pip install .
175
+ ```
176
+
177
+ The project is not currently published on PyPI. Do not use a similarly named
178
+ package from a package index. After the owner publishes the authenticated
179
+ release, the exact-version installation command will be:
180
+
181
+ ```console
182
+ python -m pip install 'pfsense-mcp-server==0.2.2'
183
+ ```
184
+
185
+ Until the project page and release provenance are publicly verifiable, install
186
+ from the reviewed source tree as shown above.
187
+
188
+ ## Quick start
189
+
190
+ Create the API-key file outside the repository and restrict it to the account
191
+ that runs the MCP server:
192
+
193
+ ```console
194
+ install -m 600 /dev/null /absolute/private/path/pfsense-api.key
195
+ ```
196
+
197
+ Place the key on the first line without printing it in shell history or logs.
198
+ Then configure your MCP client to launch the console entry point with these
199
+ environment variables:
200
+
201
+ ```json
202
+ {
203
+ "command": "/absolute/path/to/.venv/bin/pfsense-mcp-server",
204
+ "env": {
205
+ "PFSENSE_API_URL": "https://pfsense.example.invalid",
206
+ "PFSENSE_IDENTITY": "api-mcp-admin",
207
+ "PFSENSE_API_KEY_FILE": "/absolute/private/path/pfsense-api.key",
208
+ "PFSENSE_TLS_MODE": "strict"
209
+ }
210
+ }
211
+ ```
212
+
213
+ The exact outer MCP-client configuration key varies by client. Use one of the
214
+ [verified client examples](examples/README.md), then confirm that the client
215
+ shows 41 READ tools and no WRITE tools. A first safe call is
216
+ `pfsense_get_system_status`. The server communicates over stdio and produces
217
+ no web interface or screenshotable UI.
218
+
219
+ For development, install the project with its test and analysis tools:
220
+
221
+ ```console
222
+ .venv/bin/python -m pip install -e ".[dev]"
223
+ make quick
224
+ make validate
225
+ ```
226
+
227
+ Additional release checks are documented in the
228
+ [release checklist](docs/RELEASE_CHECKLIST.md). Live private-infrastructure
229
+ acceptance is separate, opt-in, and never part of public CI.
230
+
231
+ ## Direct launch
232
+
233
+ Direct launch is useful for confirming configuration and MCP startup. The
234
+ process waits for MCP messages on stdin when configuration is valid.
235
+
236
+ ```console
237
+ PFSENSE_API_URL=https://pfsense.example.invalid \
238
+ PFSENSE_IDENTITY=api-mcp-admin \
239
+ PFSENSE_API_KEY_FILE=/absolute/private/path/pfsense-api.key \
240
+ PFSENSE_TLS_MODE=strict \
241
+ pfsense-mcp-server
242
+ ```
243
+
244
+ ## Troubleshooting
245
+
246
+ ### The server exits with a configuration error
247
+
248
+ Configuration fails closed. Confirm every required variable is present, the
249
+ API URL is an HTTPS origin without a path, and the identity contains no control
250
+ characters. Error messages identify the invalid setting but never print the
251
+ key value.
252
+
253
+ ### The API-key file is rejected
254
+
255
+ The file must be a regular non-symlink file owned by the process user, with no
256
+ group or other permission bits, and its first line must be non-empty and
257
+ bounded. Parent directories should normally be mode 0700.
258
+
259
+ ### TLS verification fails
260
+
261
+ Prefer `strict` with the system trust store. For an internal CA, set
262
+ `PFSENSE_TLS_MODE=auto` and point `PFSENSE_TLS_CA_FILE` to a readable CA
263
+ bundle. `insecure` disables certificate verification and should be limited to
264
+ short, explicitly accepted diagnostics.
265
+
266
+ ### No tools appear
267
+
268
+ Use `PFSENSE_PROFILE=auditor`, the default accepted READ profile. The
269
+ `engineer` placeholder intentionally grants no capabilities in this build.
270
+ Also check `PFSENSE_ALLOWED_TOOLS`: an explicitly empty value intentionally
271
+ registers zero tools, and a configured subset hides every unlisted tool.
272
+
273
+ ### Can this server manage more than one appliance?
274
+
275
+ No. One process has one configured upstream identity and appliance. Launch a
276
+ separate process with separate configuration for another appliance.
277
+
278
+ ## Documentation
279
+
280
+ - [MCP tool reference](docs/API.md)
281
+ - [Future-major API review](docs/API_REVIEW.md)
282
+ - [Client setup examples](examples/README.md)
283
+ - [Architecture diagrams](docs/ARCHITECTURE_DIAGRAMS.md)
284
+ - [Architecture decisions](docs/adr/README.md)
285
+ - [Offline benchmark methodology](docs/BENCHMARKS.md)
286
+ - [Threat model](docs/THREAT_MODEL.md)
287
+ - [Security abuse-case catalog](docs/SECURITY_TEST_CATALOG.md)
288
+ - [Security model](docs/SECURITY_MODEL.md)
289
+ - [Vulnerability reporting](SECURITY.md)
290
+ - [Public roadmap](docs/ROADMAP.md)
291
+ - [Future Recovery Contract specification](docs/RECOVERY_CONTRACT_SPEC.md)
292
+ - [Contribution guide](CONTRIBUTING.md)
293
+ - [Release checklist](docs/RELEASE_CHECKLIST.md)
294
+ - [PyPI release procedure](docs/PYPI_RELEASE.md)
295
+ - [Dependency policy](docs/DEPENDENCY_POLICY.md)
296
+ - [v0.2.2 acceptance](docs/ACCEPTANCE_v0.2.2.md)
297
+ - [v0.2.1 acceptance](docs/ACCEPTANCE_v0.2.1.md)
298
+
299
+ ## Contributing
300
+
301
+ Contributions are welcome within the documented security and approval
302
+ boundaries. Read [CONTRIBUTING.md](CONTRIBUTING.md) before opening a change.
303
+ Report vulnerabilities privately as described in [SECURITY.md](SECURITY.md).
304
+
305
+ ## License
306
+
307
+ Licensed under the [MIT License](LICENSE). The copyright notice uses the
308
+ project contributor identity and does not assert ownership by an invented
309
+ person or organization.