Commit graph

13 commits

Author SHA1 Message Date
Aaron Bockelie
2b4ef6a9b4 fix(network): address PR #211 self-review findings (ADR-107)
Blocking — userSuppliedCert discriminator:
- Was: certificateConfig.selfSigned === false (never set false in UI;
  rows 5/7/9 of the ADR-107 table unreachable, defaulting to over-warn).
- Now: !!(certPath && keyPath) — actual cert provenance signal.
  Fixed in src/mcp-server.ts and src/main.ts settings UI badge.

Non-blocking #1 — migration Notice race:
- Was: isExistingPreBindModeInstall() re-read data.json after
  loadSettings() may have already persisted bindMode='loopback' as
  part of the apiKey auto-save.
- Now: snapshot raw loadData() before loadSettings(), test the snapshot.

Non-blocking #2 — loopback host matcher tightened:
- Was: startsWith('127.') accepted '127.evil.com'.
- Now: strict dotted-quad regex /^127(\.\d{1,3}){3}$/ with octet range.
  New tests cover hostile inputs (127.evil.com, 127.0.0.1.attacker.tld,
  127.300.0.1, 1270.0.0.1).

Non-blocking #3 — Reconfigure hint:
- ADR-107 specifies the 🔴 badge includes a Reconfigure hint;
  implementation now renders 'Reconfigure: switch the bind address
  below to Loopback, or enable HTTPS.' beneath the verdict reason.

Non-blocking #4 — empty custom host UX:
- When bindMode='custom' && customBindHost is empty, render an
  explicit Notice that the server will fall back to loopback until a
  host is entered (resolves the silent 🟢 OK in that state).

Lint clean, 296/296 tests pass.
2026-05-24 17:06:16 -05:00
Aaron Bockelie
104b40af90 feat(network): wire classifier into server, settings, UI (ADR-107)
Replaces the implicit 0.0.0.0 Node-default bind with a deliberate,
classified network exposure model.

Server: MCPHttpServer.start() now resolves the listen host from
settings (bindMode + customBindHost), passes it to listen(), and
classifies the combined (protocol × bind × certSource) state. On 🔴
fires a 15s Notice + Debug.error; on 🟡 logs Debug.warn; on 🟢 silent.
The verdict-derived agent-visible warning is pushed into MCPServerPool
which conditionally injects it into the MCP initialize.instructions
field for every session created after bind, so an LLM client sees the
warning on its first turn against the server. node-mcp-server.ts (the
unused fallback) is hardcoded to loopback for consistency.

Settings: MCPPluginSettings gains bindMode ('loopback' | 'all' |
'custom') default 'loopback', customBindHost default '', and a
one-shot hasShownBindMigrationNotice flag. Existing installs with a
data.json that predates bindMode see a one-time 20s Notice on next
load pointing them at the new setting; fresh installs are silent.

UI: a new "Network binding" section between server config and the
HTTPS section, with a live colored verdict badge that re-classifies
on every change, the bind dropdown (Loopback / All interfaces /
Custom), an inline red caution under "All interfaces" whose wording
adapts to whether HTTPS is enabled, and a custom-host text field
that normalizes loopback/wildcard aliases on blur (typing 127.0.0.1
collapses the dropdown to Loopback; 0.0.0.0 collapses to All).

Tests: 7 integration assertions verifying the source wires listen()
to the resolved host, pushes verdict-derived instructions into the
pool, conditionally injects on 🔴 only, and that the pool spread-
pattern omits the field on ok/warn.

Inspired by PR #208 (fa1k3) — preserves the security instinct while
keeping the LAN/remote escape hatch the hardcoded approach removed.
2026-05-24 16:56:24 -05:00
Aaron Bockelie
69be0a007e fix(onboarding): restore one-command Claude Code setup; drop misinformed CLI warning
#192 replaced the Claude Code copy/paste command with a hand-edit-this-JSON
blob plus a warning against `claude mcp add --header`. That was a real UX
regression, and the security premise was wrong for THIS transport:

- The argv / macOS-unified-log exposure applies to **stdio** transports
  (a spawned `npx mcp-remote --header ...` child), NOT native **HTTP**
  transport — there is no spawned child carrying the header in argv. #143's
  threat model was conflated with the mcp-remote setup it was also removing.
- Cleartext-at-rest in ~/.claude.json / .mcp.json is identical whether the
  entry is added via the CLI or hand-edited, so "edit the file instead"
  bought no at-rest improvement either.

(Confirmed against current Claude Code docs via claude-code-guide.)

Restores the single `claude mcp add --transport http ...` command as the
Claude Code path in the Settings UI, README, and the issue-32 template.
Removes the inaccurate warning and its now-dead `.mcp-security-warning` CSS
and the eslint-disable it required.

Kept from #192 (those parts were legit): native HTTP transport over the
deprecated mcp-remote, and the self-signed-cert / NODE_EXTRA_CA_CERTS
trust docs.

ADR-104's context has a passing line calling the `--header` form
deprecated; left as-is (accepted ADRs are immutable records of what we
believed then) — this commit is the corrective record.
2026-05-18 21:43:28 -05:00
Aaron Bockelie
0bd8020804 security(docs): replace claude mcp add --header with safe config-file approach
`claude mcp add --header "Authorization: Bearer <token>"` defeats
secret-at-rest protection: the CLI resolves and echoes the header value to
stdout (captured by any parent process, incl. AI agents) and on macOS the
spawned MCP child argv is written to the unified log. Editing the MCP config
file directly avoids both vectors.

- Settings UI: new shared `renderClaudeCodeConnection()` renders a
  ready-to-paste JSON config + a security warning for the authenticated
  path, and the safe plain CLI command only when auth is disabled. Used by
  both the initial render and the live-refresh handler so they cannot drift
  (the previous two copies had already diverged).
- README / SECURITY.md / troubleshooting.md / issue-32 response template:
  drop `mcp-remote` + `NODE_TLS_REJECT_UNAUTHORIZED=0`, document native HTTP
  transport and proper self-signed-cert trust (macOS Keychain +
  NODE_EXTRA_CA_CERTS for Bun-based runtimes), add the `--header` warning.
- styles.css: `.mcp-security-warning`.

Reimplemented from PR #143 against current `main` (the settings UI had been
restructured since the PR was opened); supersedes and closes out #143.
ADR-100 left untouched — accepted ADRs are immutable records; the `--header`
deprecation is recorded in ADR-104's context instead.

Co-authored-by: Earl Plak <5597016+laplaque@users.noreply.github.com>
2026-05-18 08:10:00 -05:00
Aaron Bockelie
e6c52570a1 fix(css): remove !important via selector specificity
Obsidian CSS-lint flags !important. Replace with element-qualified selectors
that win on specificity instead:
- button.mcp-hidden out-specifies framework button display (was the reason
  for display:none !important)
- input.mcp-api-key-input out-specifies container user-select:none, keeping
  the API key selectable/copyable
Behavior-preserving by design; needs a visual confirm (see PR).
2026-05-16 12:58:40 -05:00
Aaron Bockelie
26d82bac19 feat: Add tree-based MCP tool visibility gating (ADR-101)
Users can now control which MCP tools are exposed to connecting agents
via a tri-state tree UI in the plugin settings panel. Disabled tools
are excluded from the MCP tools/list enumeration — agents cannot
discover or call them. Includes defense-in-depth runtime check.

Also adds ADR-101 (tool visibility gating) and ADR-200 (CLI parity gaps).
2026-03-26 11:08:27 -05:00
Aaron Bockelie
e46c78df34 feat: Add easter egg to settings panel
Click the version number 7 times to reveal a hidden surprise.
Image embedded as base64 for portability.
2025-12-14 22:50:18 -06:00
Aaron Bockelie
ee104a14a7 fix: Replace inline styles with CSS classes for theme compatibility
Addresses ObsidianReviewBot feedback by removing inline style
setAttribute calls and replacing with proper CSS classes.

Changes:
- Added .mcp-statusbar-disabled, .mcp-statusbar-running,
  .mcp-statusbar-error classes to styles.css
- Updated status bar item rendering to use addClass/removeClass
- Ensures proper theme compatibility and CSS override support

Version bumped to 0.10.2
2025-11-21 08:21:54 -06:00
Aaron Bockelie
f28563c0a1 fix: Address ObsidianReviewBot code quality requirements
This commit addresses all required issues identified by ObsidianReviewBot:

1. Console Logging Cleanup
   - Replaced all console.log/error/warn/info statements with Debug utility
   - All logging now respects the "Debug Logging" plugin setting
   - Only errors are logged by default; other logs require debug mode
   - Consistent [MCP] prefix for easy filtering

2. Inline Styles to CSS
   - Moved all inline JavaScript style assignments to CSS classes
   - Added semantic class names: mcp-monospace-input, mcp-security-note,
     mcp-auth-note, mcp-warning-box, mcp-status-active, mcp-status-inactive,
     mcp-section-header, mcp-cert-note, mcp-copy-button, mcp-config-container
   - Improved theme compatibility and maintainability
   - CSS now handles hover states instead of JavaScript event handlers

3. Code Quality
   - Removed unused event handlers
   - Cleaned up empty style assignment sections
   - All tests passing (92 tests)
   - Build successful with no errors
   - ESLint passing with no warnings

Files modified: 12 (11 TypeScript, 1 CSS)
Test results: 10/10 suites passed, 92/92 tests passed
2025-11-14 13:32:38 -06:00
Aaron Bockelie
0ef8eec8a0 feat: Add API key authentication for enhanced security
- Generate secure API key on first plugin load
- Implement HTTP Basic Auth middleware for all endpoints
- Add authentication settings UI with copy/regenerate functionality
- Update configuration examples to include auth credentials
- Maintain backward compatibility (auth optional if no key set)
- Closes #9

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-15 18:11:57 -05:00
Aaron Bockelie
382e050149 feat: Make configuration examples selectable and copyable in settings UI
- Added user-select: text CSS properties to code blocks and config examples
- Users can now highlight and copy configuration commands and JSON examples
- Improved UX for setting up MCP connections

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-13 21:44:45 -05:00
Aaron Bockelie
47d1fd7365 fix: Address Obsidian review requirements (part 1)
- Replace type casting with instanceof checks for TFile/TFolder
- Move all inline styles to CSS classes in styles.css
- Add Debug utility to reduce console.log pollution
- Update settings title and tool count
- Fix test file mock objects to use proper prototypes
2025-07-05 10:26:46 -05:00
Aaron Bockelie
8ca6fc4942 Initial working plugin for BRAT testing
- Complete Obsidian plugin structure with TypeScript build pipeline
- Basic plugin lifecycle (onload/onunload) with settings management
- Settings UI for HTTP server configuration (ports, SSL, debug)
- Status bar indicator and restart command
- Ready for BRAT installation and testing

Phase 1 foundation complete - plugin loads successfully in Obsidian
2025-06-27 11:00:05 -05:00