Skip to content

Bring back MCP endpoint, scoped to the two /ask tools#246

Merged
tomusdrw merged 6 commits into
mainfrom
td-mcp-endpoint
Apr 23, 2026
Merged

Bring back MCP endpoint, scoped to the two /ask tools#246
tomusdrw merged 6 commits into
mainfrom
td-mcp-endpoint

Conversation

@tomusdrw

@tomusdrw tomusdrw commented Apr 23, 2026

Copy link
Copy Markdown
Member

Summary

  • Re-adds the MCP (Model Context Protocol) endpoint at POST/GET/DELETE /mcp using Streamable HTTP with session management.
  • Exposes only the two tools the /ask agent uses: search_all and get_full_document. The MCP tool handlers call the same executeSearchAll / executeGetFullDocument helpers from backend/src/ask/tools.ts, so both surfaces stay in sync.
  • Adds @modelcontextprotocol/sdk@^1.29.0 to the backend.

The original MCP server (commit ecac46b, removed 2026-04-17) exposed five per-source search tools. This version intentionally restricts the surface to the unified tool pair, matching the current /ask agent.

Test plan

  • npm run typecheck clean
  • Smoke-tested the live endpoint: initialize handshake, tools/list returns exactly search_all + get_full_document, tools/call search_all returns real indexed results
  • CI

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added a Model Context Protocol (MCP) endpoint at /mcp exposing two tools: search_all and get_full_document.
    • search_all can run as fulltext-only (no embeddings) for anonymous/stateless traffic.
  • Behavior Change

    • /mcp responses intentionally omit CORS headers; other endpoints retain CORS.
  • Documentation

    • Added docs and examples for MCP, tools, and the /ask streaming endpoint.

tomusdrw and others added 2 commits April 23, 2026 22:11
Exposes search_all and get_full_document over Streamable HTTP at /mcp,
reusing the same executeSearchAll / executeGetFullDocument helpers that
back the /ask agent loop so both stay in sync.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@netlify

netlify Bot commented Apr 23, 2026

Copy link
Copy Markdown

Deploy Preview for jam-search2 ready!

Name Link
🔨 Latest commit 56bf9b3
🔍 Latest deploy log https://app.netlify.com/projects/jam-search2/deploys/69ea86da5308be0008ae0b75
😎 Deploy Preview https://deploy-preview-246--jam-search2.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai

coderabbitai Bot commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7acbddf0-c0b3-47b2-b7d4-4b0c4ef3366b

📥 Commits

Reviewing files that changed from the base of the PR and between d46da10 and 56bf9b3.

📒 Files selected for processing (2)
  • backend/src/__tests__/mcp/server.test.ts
  • backend/src/mcp/server.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/src/tests/mcp/server.test.ts

📝 Walkthrough

Walkthrough

Adds a Model Context Protocol (MCP) endpoint: new MCP server and HTTP handler, /mcp route wiring, dependency addition, refactored tool schemas to Zod, optional fulltext-only search flag, documentation updates, and tests for MCP behavior and tool contracts.

Changes

Cohort / File(s) Summary
MCP Handler & Server
backend/src/mcp/handler.ts, backend/src/mcp/server.ts
New MCP server factory and HTTP handler. Handler creates a per-request transport and server, delegates raw HTTP handling, and returns JSON-RPC errors on failure. Server exposes search_all and get_full_document, validates args with Zod, and returns text/JSON tool outputs.
API Routing & Middleware
backend/src/api.ts
Registers /mcp route via createMcpHandler. Adjusts CORS middleware so MCP requests bypass global CORS while other routes keep existing CORS behavior.
Tool Definitions & Search Logic
backend/src/ask/tools.ts
Introduces TOOL_SPECS (Zod schemas) and derives TOOL_DEFINITIONS from them. executeSearchAll gains options with useEmbeddings?: boolean; when false, forces fulltext-only search by skipping embedding computation.
Dependencies
backend/package.json
Adds @modelcontextprotocol/sdk dependency.
Documentation
README.md, backend/README.md
Documents new /mcp endpoint, available tools (search_all, get_full_document), expected request/response shapes, CORS notes, and example client probes.
Tests
backend/src/__tests__/mcp/server.test.ts, backend/src/__tests__/mcp/handler.test.ts, backend/src/__tests__/ask/tools.test.ts
Adds tests for MCP server and handler: tool listing, argument validation, successful/failed tool calls, CORS behavior, and that TOOL_SPECS correctly derives TOOL_DEFINITIONS (ensuring search_all requires only query).

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Handler as MCP Handler
    participant Transport as WebStandardStreamableHTTPServerTransport
    participant Server as MCP Server
    participant Tools as Tool Execution
    participant DB as SearchDB

    Client->>Handler: POST /mcp (initialize / call-tool)
    activate Handler
    Handler->>Transport: create transport (per-request)
    Handler->>Server: createMcpServer(db, dataDir)
    activate Server
    Server->>Transport: server.connect(transport)
    Handler->>Transport: transport.handleRequest(rawReq)
    activate Transport
    Transport->>Server: dispatch initialize or callTool
    activate Server
    alt callTool (search_all / get_full_document)
        Server->>Tools: validate args (Zod) & execute
        activate Tools
        Tools->>DB: query or fetch document (fulltext or embedding-controlled)
        DB-->>Tools: results/document
        Tools-->>Server: formatted JSON/text result
        deactivate Tools
    else unknown tool / error
        Server-->>Server: produce error response
    end
    Server-->>Transport: MCP response stream
    deactivate Server
    Transport-->>Handler: stream/response
    Handler-->>Client: HTTP response (SSE / JSON-RPC)
    deactivate Transport
    deactivate Handler
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A rabbit scurries through the code,
new MCP gates now gently flowed.
Tools listed, queries find their mark,
fulltext paths light up the dark.
Hop on, clients — stream and go!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: re-adding the MCP endpoint with the two /ask tools (search_all and get_full_document).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch td-mcp-endpoint

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
backend/src/mcp/handler.ts (1)

72-87: Unreachable branch: existingTransport check after transports.has() is always truthy.

Line 72 already verifies transports.has(sessionId) before calling transports.get(). The subsequent if (!existingTransport) check on line 74 is dead code since Map.get() will always return a defined value after has() returns true.

♻️ Simplify by using non-null assertion or restructuring
   if (sessionId && transports.has(sessionId)) {
-    const existingTransport = transports.get(sessionId);
-    if (!existingTransport) {
-      return c.json(
-        {
-          jsonrpc: "2.0",
-          error: {
-            code: -32000,
-            message: "Session not found",
-          },
-          id: (body as { id?: unknown })?.id ?? null,
-        },
-        400
-      );
-    }
-    transport = existingTransport;
+    transport = transports.get(sessionId)!;
   } else if (!sessionId && isInitializeRequest(body)) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/mcp/handler.ts` around lines 72 - 87, The null-check on
existingTransport is unreachable because you already ensure
transports.has(sessionId) is true; remove the redundant branch and either (a)
drop the has() call and handle the undefined from transports.get(sessionId) (use
the existing error response when get returns undefined), or (b) keep
has(sessionId) and replace transports.get(sessionId) with a non-null assertion
(e.g., existingTransport = transports.get(sessionId)!); update the code paths
around transports, sessionId, and existingTransport in handler.ts accordingly so
there is a single clear existence check.
backend/src/index.ts (1)

71-71: Transport cleanup is fire-and-forget; may leave connections unclean.

cleanupMcpTransports() calls transport.close().catch(console.error) without awaiting. The server then closes immediately, potentially interrupting in-flight MCP sessions.

Consider making cleanup async and awaiting transport closures before closing the HTTP server:

♻️ Suggested change to await cleanup

In backend/src/mcp/handler.ts:

-export function cleanupMcpTransports(): void {
+export async function cleanupMcpTransports(): Promise<void> {
+  const closePromises: Promise<void>[] = [];
   for (const [sessionId, transport] of transports) {
     console.log(`Closing MCP transport for session ${sessionId}`);
-    transport.close().catch(console.error);
+    closePromises.push(transport.close().catch(console.error));
   }
+  await Promise.all(closePromises);
   transports.clear();
 }

In backend/src/index.ts:

-    cleanupMcpTransports();
+    await cleanupMcpTransports();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/index.ts` at line 71, cleanupMcpTransports() currently invokes
transport.close().catch(console.error) fire-and-forget, so make
cleanupMcpTransports async and await all transport closures (e.g., replace
per-transport .catch with collecting promises and await
Promise.all(transports.map(t => t.close())) and handle errors appropriately),
then in backend/src/index.ts await cleanupMcpTransports() before shutting down
the HTTP server (i.e., await cleanupMcpTransports() prior to calling
server.close()/process exit) so in-flight MCP sessions are allowed to finish.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/package.json`:
- Line 19: Update the incorrect MCP SDK version in package.json: replace the
dependency entry "@modelcontextprotocol/sdk": "^1.29.0" with the valid published
version (e.g. "@modelcontextprotocol/sdk": "^1.9.0") so installs succeed; locate
the dependency string in package.json and change the version specifier
accordingly or confirm and use the intended published version.

---

Nitpick comments:
In `@backend/src/index.ts`:
- Line 71: cleanupMcpTransports() currently invokes
transport.close().catch(console.error) fire-and-forget, so make
cleanupMcpTransports async and await all transport closures (e.g., replace
per-transport .catch with collecting promises and await
Promise.all(transports.map(t => t.close())) and handle errors appropriately),
then in backend/src/index.ts await cleanupMcpTransports() before shutting down
the HTTP server (i.e., await cleanupMcpTransports() prior to calling
server.close()/process exit) so in-flight MCP sessions are allowed to finish.

In `@backend/src/mcp/handler.ts`:
- Around line 72-87: The null-check on existingTransport is unreachable because
you already ensure transports.has(sessionId) is true; remove the redundant
branch and either (a) drop the has() call and handle the undefined from
transports.get(sessionId) (use the existing error response when get returns
undefined), or (b) keep has(sessionId) and replace transports.get(sessionId)
with a non-null assertion (e.g., existingTransport =
transports.get(sessionId)!); update the code paths around transports, sessionId,
and existingTransport in handler.ts accordingly so there is a single clear
existence check.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4cd7cfb1-1cb6-4dfc-8b5d-f9052b211401

📥 Commits

Reviewing files that changed from the base of the PR and between 45a1a81 and 5d964a2.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (5)
  • backend/package.json
  • backend/src/api.ts
  • backend/src/index.ts
  • backend/src/mcp/handler.ts
  • backend/src/mcp/server.ts

Comment thread backend/package.json
tomusdrw and others added 2 commits April 23, 2026 22:22
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Mark `limit` as `.default(10).optional()` so it drops out of the JSON-schema
  `required` list — strict MCP clients shouldn't have to pass a tunable.
- Register /mcp route handlers directly instead of wrapping in arrow functions.
- Add a header comment pointing mcp/server.ts readers at ask/tools.ts, where the
  actual search implementations live.
- Add a vitest that wires Client + Server via InMemoryTransport and covers:
  tools/list names, the `limit` non-required invariant, search_all and
  get_full_document happy paths, and unknown-id isError on get_full_document.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
backend/src/mcp/server.ts (1)

73-74: Use compact JSON for MCP tool payloads.

Pretty-printing increases response size without functional benefit for tool consumers.

Payload-size optimization diff
-            content: [{ type: "text", text: JSON.stringify(results, null, 2) }],
+            content: [{ type: "text", text: JSON.stringify(results) }],
@@
-            content: [{ type: "text", text: JSON.stringify(doc, null, 2) }],
+            content: [{ type: "text", text: JSON.stringify(doc) }],

Also applies to: 88-89

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/mcp/server.ts` around lines 73 - 74, The payloads in
backend/src/mcp/server.ts are using pretty-printed JSON (JSON.stringify(results,
null, 2)) which increases response size; replace those calls with compact JSON
serialization (use JSON.stringify(results) instead) wherever the content array
is built (the entries producing content: [{ type: "text", text:
JSON.stringify(results, null, 2) }] and the similar occurrence around lines
88-89) so MCP tool payloads send compact JSON; ensure both spots that create the
content text field use the compact JSON form.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/src/__tests__/mcp/server.test.ts`:
- Around line 52-57: The test currently assumes result.content[0] exists before
calling JSON.parse, which can throw a TypeError; update the test around the
result/content parsing (the const content = result.content ... and subsequent
JSON.parse lines) to first assert that result.content is an array and that
result.content[0] is defined and has type "text" (e.g.,
expect(Array.isArray(result.content)).toBe(true);
expect(result.content.length).toBeGreaterThan(0);
expect(result.content[0]).toBeDefined();) before parsing, then parse
result.content[0].text into parsed and continue with the existing assertions
about parsed and parsed[0].id.
- Around line 7-17: connectClient currently creates a server (createMcpServer)
and a client (new Client) with transports (InMemoryTransport.createLinkedPair)
but never returns or closes the server/client, leaking handles; modify
connectClient to return both { client, server, db } (or a cleanup function) and
ensure tests call await Promise.all([client.close(), server.close()]) in an
afterEach() hook (or invoke the returned cleanup) so transport resources are
deterministically torn down; note that `@modelcontextprotocol/sdk` v1.29.0 close
methods are idempotent so calling client.close and server.close is safe.

In `@backend/src/mcp/server.ts`:
- Around line 97-102: Avoid returning raw exception messages to MCP clients: in
the catch block that currently constructs `message` and returns `content: [{
type: "text", text: \`Error: ${message}\` }]` with `isError: true`, replace that
client-facing string with a generic, non-sensitive message (e.g., "An internal
error occurred") and move the detailed `message` (or the full `error`) into a
server-side log call (use the existing logger or `console.error`) so
implementation details are recorded but not sent to the client.

---

Nitpick comments:
In `@backend/src/mcp/server.ts`:
- Around line 73-74: The payloads in backend/src/mcp/server.ts are using
pretty-printed JSON (JSON.stringify(results, null, 2)) which increases response
size; replace those calls with compact JSON serialization (use
JSON.stringify(results) instead) wherever the content array is built (the
entries producing content: [{ type: "text", text: JSON.stringify(results, null,
2) }] and the similar occurrence around lines 88-89) so MCP tool payloads send
compact JSON; ensure both spots that create the content text field use the
compact JSON form.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3f9ca01f-f1bf-470d-9c8e-2e843fb32967

📥 Commits

Reviewing files that changed from the base of the PR and between 3be42ca and caae504.

📒 Files selected for processing (3)
  • backend/src/__tests__/mcp/server.test.ts
  • backend/src/api.ts
  • backend/src/mcp/server.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/src/api.ts

Comment thread backend/src/__tests__/mcp/server.test.ts Outdated
Comment thread backend/src/__tests__/mcp/server.test.ts
Comment thread backend/src/mcp/server.ts
- Stateless /mcp: fresh Server + Transport per request via createMcpHandler
  factory. No session map, no module-level state, no GET/DELETE lifecycle.
  Registered as app.all("/mcp", ...) so any method hits the transport.
- CORS scoped to non-MCP routes so /mcp sends no Access-Control-* headers.
- executeSearchAll gains a useEmbeddings option (default true). MCP passes
  false so anonymous MCP traffic cannot spend the server's OpenAI quota.
- TOOL_SPECS in ask/tools.ts is now the single source of truth for both
  the OpenAI tool-call format (TOOL_DEFINITIONS) and the MCP tools/list
  shape (derived in mcp/server.ts). No more parallel schema definitions.
- Tests: handler integration test asserts stateless behaviour and
  verifies /mcp has no CORS header while /health still does. ask/tools
  test pins the TOOL_DEFINITIONS <- TOOL_SPECS derivation.
- README updated to describe the three design choices (stateless,
  no CORS, no embeddings).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
backend/src/mcp/server.ts (1)

88-93: ⚠️ Potential issue | 🟠 Major

Do not expose raw exception messages to MCP clients.

Line 89-Line 92 currently echoes internal error text. Return a generic client-safe message and log details server-side instead.

Proposed hardening diff
     } catch (error) {
-      const message = error instanceof Error ? error.message : String(error);
+      console.error("[mcp] tool execution failed", { tool: name, error });
       return {
-        content: [{ type: "text", text: `Error: ${message}` }],
+        content: [{ type: "text", text: "Tool execution failed" }],
         isError: true,
       };
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/mcp/server.ts` around lines 88 - 93, The catch block returning
error details to MCP clients exposes internal exception messages; modify the
handler in backend/src/mcp/server.ts (the catch that builds the returned object
with content/isError) to return a generic client-safe message like "An internal
error occurred" instead of `Error: ${message}`, and move the original error
logging to server-side (e.g., use processLogger.error or console.error to log
the full `error` or `message` and stack) so internal details are recorded but
not sent to the client; update the returned object created in that catch (the
content array and isError flag) accordingly.
🧹 Nitpick comments (1)
backend/src/__tests__/mcp/handler.test.ts (1)

43-52: Also assert SSE Content-Type on successful initialize.

Body text checks are useful; adding a header assertion makes the contract tighter.

Suggested test hardening
     expect(res.status).toBe(200);
+    expect(res.headers.get("content-type")).toContain("text/event-stream");
     // CORS must not be advertised for server-to-server endpoint.
     expect(res.headers.get("access-control-allow-origin")).toBeNull();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/__tests__/mcp/handler.test.ts` around lines 43 - 52, The test in
handler.test.ts currently verifies status and some headers but omits asserting
the SSE Content-Type; update the test (after checking mcp-session-id) to assert
that res.headers.get("content-type") indicates an SSE response (e.g., equals or
matches "text/event-stream" including possible charset), so the successful
initialize response explicitly guarantees SSE Content-Type.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@backend/src/mcp/server.ts`:
- Around line 88-93: The catch block returning error details to MCP clients
exposes internal exception messages; modify the handler in
backend/src/mcp/server.ts (the catch that builds the returned object with
content/isError) to return a generic client-safe message like "An internal error
occurred" instead of `Error: ${message}`, and move the original error logging to
server-side (e.g., use processLogger.error or console.error to log the full
`error` or `message` and stack) so internal details are recorded but not sent to
the client; update the returned object created in that catch (the content array
and isError flag) accordingly.

---

Nitpick comments:
In `@backend/src/__tests__/mcp/handler.test.ts`:
- Around line 43-52: The test in handler.test.ts currently verifies status and
some headers but omits asserting the SSE Content-Type; update the test (after
checking mcp-session-id) to assert that res.headers.get("content-type")
indicates an SSE response (e.g., equals or matches "text/event-stream" including
possible charset), so the successful initialize response explicitly guarantees
SSE Content-Type.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 60c01aa7-911c-4a4b-a57e-9053b528ef32

📥 Commits

Reviewing files that changed from the base of the PR and between caae504 and d46da10.

📒 Files selected for processing (7)
  • backend/README.md
  • backend/src/__tests__/ask/tools.test.ts
  • backend/src/__tests__/mcp/handler.test.ts
  • backend/src/api.ts
  • backend/src/ask/tools.ts
  • backend/src/mcp/handler.ts
  • backend/src/mcp/server.ts
✅ Files skipped from review due to trivial changes (1)
  • backend/README.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • backend/src/api.ts
  • backend/src/mcp/handler.ts

- MCP tool error handler now distinguishes caller-facing ZodError (safe
  to surface — describes the caller's own arguments) from unexpected
  errors (logged server-side, returned as a generic "Tool execution
  failed" to avoid leaking paths / DB / internal detail).
- server.test.ts: add afterEach teardown that calls client.close() and
  server.close() so InMemoryTransport pairs don't accumulate across
  the test suite. SDK close() is idempotent.

Addresses CodeRabbit review comments on #246.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@tomusdrw tomusdrw merged commit c0929ae into main Apr 23, 2026
11 checks passed
@tomusdrw tomusdrw deleted the td-mcp-endpoint branch April 23, 2026 20:57
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.

1 participant