Skip to content

Conversation

@maehwasoo
Copy link
Owner

@maehwasoo maehwasoo commented Jan 14, 2026

What

  • Hardened the MCP HTTP server lifecycle to support safe, authenticated remote shutdown from the Obsidian plugin
    • Added POST /__ailss/shutdown (token-authenticated, localhost-only) to close the HTTP server and all MCP sessions (packages/mcp/src/httpServer.ts).
    • Added a dedicated shutdown test covering auth + port release behavior (packages/mcp/test/httpShutdown.test.ts).
  • Fixed MCP HTTP service restart/port-conflict race conditions in the Obsidian plugin
    • Waits for the service process to fully exit before attempting a restart.
    • Waits for the TCP port to become available before starting the service.
    • If the port is already in use, attempts an authenticated shutdown (/__ailss/shutdown) of the stale service, then re-checks the port.
    • Uses Node’s built-in http client for the shutdown request (works reliably in the Obsidian desktop runtime).
  • Refactored the Obsidian plugin architecture to keep main.ts thin and isolate responsibilities into modules:
    • Indexer orchestration: src/indexer/indexerRunner.ts, src/indexer/indexDbReset.ts, src/indexer/indexerLogFile.ts.
    • Auto-index: src/indexer/autoIndexScheduler.ts + event wiring extracted to src/indexer/autoIndexEvents.ts.
    • MCP integration: src/mcp/mcpHttpServiceController.ts, src/mcp/mcpHttpServiceTypes.ts, src/mcp/semanticSearchService.ts.
    • Plugin persistence: src/persistence/pluginData.ts (normalizes/stores plugin settings + last index success timestamp).
    • UI helpers: src/ui/statusBars.ts, src/ui/pluginModals.ts, src/ui/pluginNotices.ts, and index DB reset confirm flow in src/ui/indexDbResetFlow.ts.
    • Shared utils: src/utils/pluginPaths.ts, src/utils/tcp.ts, src/utils/clipboard.ts, src/utils/codexClipboardService.ts, src/utils/vaultRootPromptInstaller.ts.
  • Updated developer-facing plugin documentation/code map to reflect the new module layout (packages/obsidian-plugin/AGENTS.md).
  • Resolved plugin-local ESLint warnings
    • Fixed onunload() signature mismatch (avoid returning a Promise where Obsidian expects void) while still stopping the service asynchronously (packages/obsidian-plugin/src/main.ts).
    • Adjusted status bar strings to satisfy obsidianmd/ui/sentence-case and configured the rule to treat AILSS as a brand and MCP as an acronym (packages/obsidian-plugin/src/ui/statusBars.ts, packages/obsidian-plugin/eslint.config.mts).

Why

  • Prevent “port already in use” failures caused by fast restarts, crashed/stale MCP HTTP server instances, or overlapping stop/start calls in the Obsidian plugin.
  • Provide a secure and deterministic cleanup path for stale MCP HTTP servers(localhost-only + token auth) instead of requiring manual process killing.
  • Reduce regression risk and improve maintainability by splitting the previous large main.ts into smaller, cohesive modules (process orchestration vs UI glue vs utilities).
  • Keep Obsidian UI status reporting (status bars/modals/notices) consistent while refactoring the internals.

How

  • MCP HTTP server (@ailss/mcp)
    • Added a shutdown endpoint (POST /__ailss/shutdown) that requires the same bearer token used for MCP requests.
    • On shutdown: closes the HTTP server, closes all MCP transports/servers, and (when configured) exits the process.
    • Added tests verifying unauthenticated requests are rejected and authenticated shutdown frees the TCP port.
  • Obsidian plugin MCP service controller
    • Before spawning the MCP HTTP process, probes the configured TCP port for availability.
    • If busy, sends an authenticated shutdown request to /__ailss/shutdown, then re-checks the port with a timeout.
    • On restart, requests stop and waits for the process to exit before starting again, and waits for the port to become reachable/available before proceeding.
  • Refactor plan (behavior-preserving extractions)
    • Moved indexer lifecycle, DB reset, logging, auto-index scheduling/event wiring, and UI helpers into dedicated modules; main.ts now primarily wires these services together and forwards UI actions.

@maehwasoo maehwasoo self-assigned this Jan 14, 2026
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f511e2d6cf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 269 to 271
await new Promise<void>((resolve) => httpServer.close(() => resolve()));
await Promise.allSettled(
Array.from(sessions.values()).flatMap((s) => [s.transport.close(), s.server.close()]),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Close MCP sessions before shutting down the HTTP server

When /__ailss/shutdown is hit, close() waits on httpServer.close() before closing transports. httpServer.close() blocks until all active connections end, but streamable MCP requests can keep SSE/streaming connections open; since s.transport.close() only runs after httpServer.close() resolves, the shutdown can hang indefinitely and the port never frees. Consider closing sessions/transports first (or using closeAllConnections/closeIdleConnections) so active streaming connections are terminated and shutdown reliably completes.

Useful? React with 👍 / 👎.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@codex implemented fix, review changes

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bcff485714

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 258 to 260
const shutdownPathRaw = options.shutdown?.path ?? "/__ailss/shutdown";
const shutdownPath = shutdownPathRaw.startsWith("/") ? shutdownPathRaw : `/${shutdownPathRaw}`;
const exitProcessOnShutdown = options.shutdown?.exitProcess ?? false;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Gate shutdown endpoint behind an explicit opt-in

Because shutdownPathRaw is always defaulted, the shutdown route is effectively enabled for every startAilssMcpHttpServer caller, even when options.shutdown is omitted. That means any authenticated MCP client (i.e., anyone with the normal request token) can now terminate the server, which is a new availability/DoS surface in multi-client or shared-token setups. Consider making shutdown opt-in (e.g., require options.shutdown to be set) or requiring a separate admin token so regular clients cannot stop the service.

Useful? React with 👍 / 👎.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@codex implemented fix, review code

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex Review: Didn't find any major issues. Hooray!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Repository owner deleted a comment from chatgpt-codex-connector bot Jan 14, 2026
@maehwasoo maehwasoo merged commit f4314b7 into main Jan 14, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants