PF2e Party Read-Only MCP Companion — Full Implementation Plan
Goal
Enable party members to use Claude/Desktop (or other MCP-capable clients) as a read-only campaign companion for Age of Ashes notes.
Success Criteria
- Party members can query campaign notes from their own clients.
- Shared scope is restricted to player-safe notes only.
- No write/delete capability from external clients.
- Access is authenticated and encrypted.
- Operations are easy to maintain in homelab.
Architecture (Recommended)
Main Vault (private)
/srv/docs/homelab-vault/pathfinder
|
| (sync/transform script, allowlist only)
v
Shared Read-Only Dataset
/srv/docs/homelab-vault/pathfinder_party_share
|
| (MCP server, read-only tools)
v
Reverse Proxy + Auth + TLS
(Caddy/Nginx/Cloudflare Tunnel)
|
v
Party clients (Claude Desktop, etc.)Directory Model
Source (existing)
/srv/docs/homelab-vault/pathfinder
New shared dataset
/srv/docs/homelab-vault/pathfinder_party_share
Suggested structure in share
campaign/01_Sessions/CATCH UP.md01_Sessions/RECAP.md- selected session notes
characters/- character sheets, tactics cards, party-at-a-glance
denizens/- curated denizen files
rules/- player-safe quickrefs only
index/README.md,What_to_Read_First.md
Explicitly exclude
- Personal/private notes
- GM-only spoilers
- Secrets/twist notes
- Anything under admin/internal operational paths
Sharing Policy
Implement allowlist sync, not denylist.
Allowlist examples
pathfinder/01_Campaigns/Age of Ashes/01_Sessions/CATCH UP.mdpathfinder/01_Campaigns/Age of Ashes/01_Sessions/RECAP.mdpathfinder/01_Campaigns/Age of Ashes/01_Sessions/* - AoA Session.md(optional)pathfinder/01_Campaigns/Age of Ashes/Discord/exports/md/aoa-denizens/*.mdpathfinder/02_Characters/*/Character_Sheet.mdpathfinder/02_Characters/*/Tactics_Card.mdpathfinder/02_Characters/Party_At_A_Glance.md
Create policy file:
/srv/docs/homelab-vault/pathfinder_party_share/.share-policy.yaml
Sync Pipeline
Create script:
/home/zack/.openclaw/workspace/scripts/pf2e-share/sync_party_share.sh
Behavior:
- Build temp dir.
- Copy allowlisted files.
- Strip prohibited frontmatter/sections if needed.
- Write generated index pages.
- Atomic swap into
pathfinder_party_share. - Fix permissions read-only.
Permissions
- owner root/service account
- group read as needed
- files
0644, dirs0755 - MCP service user has read-only access
MCP Server Choice
Option A (preferred for safety): Filesystem MCP server
- Expose read/list/search tools only.
- Point root to
pathfinder_party_share. - No write/delete tools compiled/enabled.
Option B: Obsidian MCP server (cyanheads)
- Use only if tool-level disable for write/delete is enforceable.
- Still keep source as
pathfinder_party_share, not main vault.
Service Deployment
Use systemd service (or Docker). Example systemd unit:
/etc/systemd/system/pf2e-mcp.service
[Unit]
Description=PF2e Party MCP (Read-only)
After=network.target
[Service]
User=pf2e-mcp
Group=pf2e-mcp
WorkingDirectory=/opt/pf2e-mcp
Environment=NODE_ENV=production
Environment=MCP_ROOT=/srv/docs/homelab-vault/pathfinder_party_share
ExecStart=/usr/bin/node /opt/pf2e-mcp/server.js
Restart=always
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadOnlyPaths=/srv/docs/homelab-vault/pathfinder_party_share
[Install]
WantedBy=multi-user.targetSecure Exposure
Reverse proxy requirements
- HTTPS only
- Auth required (per-user credentials/token)
- Request logging + rate limiting
- IP restriction optional (if party static IPs known)
Caddy example (concept)
pf2e-mcp.example.com {
encode zstd gzip
basicauth {
user1 <hash>
user2 <hash>
}
reverse_proxy 127.0.0.1:8787
}(Use proper identity provider/API tokens if supported by chosen MCP stack.)
Client Onboarding (Party)
Provide one short guide per app:
- Claude Desktop config snippet
- Cursor/Windsurf optional
- “Read-only campaign companion” usage examples:
- “What happened last session?”
- “Give me non-spoiler recap of Rova 10th.”
- “Who are current named NPC allies?”
Document path:
/srv/docs/homelab-vault/homelab-docs/ideas/01_P2E_MCP/Party_Onboarding.md
Operational Runbook
Daily/weekly
- Run share sync after session import pipeline.
- Verify service healthy.
- Verify latest CATCH UP/RECAP visible in MCP queries.
Incident response
- Revoke compromised user credentials.
- Rotate auth secrets.
- Temporarily disable endpoint at proxy layer.
Automation Integration
After existing import pipeline completes (run_pipeline.sh), add:
sync_party_share.sh- optional
systemctl reload pf2e-mcp(if needed) - smoke test query
Also schedule a cron sync fallback (e.g. Fri morning after import cron).
Phase Plan
Phase 1 — Local prototype (1–2 hours)
- Build share folder manually.
- Run local MCP server bound to localhost.
- Validate read/list/search only.
Phase 2 — Security hardening (1–2 hours)
- Service account + systemd hardening.
- Reverse proxy with auth + TLS.
- Logs and rate limits.
Phase 3 — Party pilot (30–60 min)
- Onboard 1 trusted player.
- Validate query quality, no leakage.
Phase 4 — Rollout
- Add remaining players.
- Add feedback loop + iteration cadence.
Risks & Mitigations
- Leakage of private notes
- Mitigation: strict allowlist sync + separate shared dataset.
- Write/delete abuse
- Mitigation: read-only toolset + filesystem perms + hardened service.
- Auth token compromise
- Mitigation: per-user credentials, revocation process, rotation.
- Availability issues
- Mitigation: systemd restart policy + health checks + simple architecture.
Open Decisions
- Preferred auth model (basic auth vs API keys vs SSO).
- Which MCP server implementation to standardize on.
- Whether to include full session files or only curated recaps.
- Whether denizens should include all threads or curated subset.
Concrete Next Actions
- Approve share allowlist.
- I draft
sync_party_share.sh+.share-policy.yaml. - Deploy read-only MCP locally.
- Add reverse proxy + auth.
- Pilot with one party member.
Foundry-VTT-MCP Exposure Feasibility (Scoped)
Why this matters
If the GM already runs foundry-vtt-mcp, it can become a live-state data plane for the party app while Obsidian remains the curated narrative/source-of-truth plane.
Value add for the Pathfinder app
- Pull live actor/combat state (initiative, HP, conditions) for “what’s true right now?” answers.
- Pull journals/scenes where player-safe, reducing manual recap lag.
- Cross-check app summaries against current Foundry state to reduce stale guidance.
- Enable session-time utilities (initiative snapshot cards, status summaries, encounter context).
Security posture (non-negotiable)
Do not expose raw localhost service directly to the public internet.
Minimum safe baseline:
- Keep MCP service bound to localhost/private LAN.
- Publish only through a reverse proxy with TLS.
- Require strong auth at edge (OIDC/Access proxy preferred over static basic auth).
- Enforce per-user identity + revocation path.
- Add rate limiting + request logging.
- Restrict allowed tools to read-only where possible.
Preferred network pattern:
- Best: private overlay (Tailscale/WireGuard) + no public ingress.
- Acceptable: Cloudflare Access / Authelia-protected public endpoint.
Recommended architecture (dual-source)
Foundry VTT (GM server)
└─ foundry-vtt-mcp (localhost)
└─ reverse proxy + auth + TLS
└─ Party app ingestion worker (read-only credentials)
Obsidian curated notes
└─ pathfinder_party_share MCP (read-only)
└─ same app retrieval layer
App retrieval/orchestration
├─ Live state queries => Foundry MCP
├─ Lore/recap/context => Notes MCP
└─ Safety filter => player-facing responseData governance
- Tag all retrieved content with
source=foundry-liveorsource=notes-curated. - Never present GM-only entities unless explicitly marked player-safe.
- Cache short-lived live state (e.g., 15–60s TTL) to reduce load.
- Keep write/mutate actions disabled for party-facing flows.
Integration phases for Foundry-VTT-MCP
- Recon
- Enumerate available tools/resources from
foundry-vtt-mcp. - Classify each as read-safe / sensitive / prohibited.
- Enumerate available tools/resources from
- Secure publish
- Place behind authenticated TLS endpoint.
- Confirm audit logging and credential rotation.
- Read-only app adapter
- Build adapter with allowlisted tool calls only.
- Add schema normalization into app domain objects.
- Spoiler safety layer
- Denylist GM-only compendia/journals/scenes.
- Add response guard that strips hidden/private fields.
- Pilot + validation
- Run with one trusted player account.
- Validate no spoiler leaks and acceptable latency.
- Rollout
- Expand access, keep observability and revocation tested.
Go / No-Go gates
Go only if all are true:
- Authenticated edge in place (no anonymous public access).
- Read-only scoped credentials validated.
- Tool allowlist documented and enforced.
- Spoiler leak test pass.
- Revocation drill tested.
No-Go if any are false.
Immediate next actions (Foundry track)
- Chosen model: Cloudflare Tunnel + Cloudflare Access in front of localhost
foundry-vtt-mcp. - Capture exact
foundry-vtt-mcptool list and permission behavior. - Draft tool allowlist for party app adapter.
- Run a spoiler-safety red-team pass before player rollout.
- Execute
01_P2E_MCP/Phase_1_Checklist_Foundry_Exposure.md.