Skip to content

feat!: migrate to MCP 2026-07-28 stateless spec - #93

Merged
nickytonline merged 8 commits into
mainfrom
migrate-mcp-v2-stateless
Aug 2, 2026
Merged

feat!: migrate to MCP 2026-07-28 stateless spec#93
nickytonline merged 8 commits into
mainfrom
migrate-mcp-v2-stateless

Conversation

@nickytonline

@nickytonline nickytonline commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Summary

Migrates from @modelcontextprotocol/sdk (v1, stateful) to the new @modelcontextprotocol/server / @modelcontextprotocol/node (v2.0.0) packages implementing the MCP 2026-07-28 spec revision, per #issue draft: no initialize/initialized handshake, no Mcp-Session-Id, protocol version/client identity/capabilities travel per-request instead of being negotiated once per connection.

  • src/index.ts — replaced the hand-rolled transports session map and manual POST/GET/DELETE branching with createMcpHandler + toNodeHandler, mounted on Express. Added a dedicated GET /health liveness endpoint since GET /mcp no longer doubles as one.
  • src/tools.tsregisterTool's callback param is now ctx (ServerContext), not extra; dropped sessionId (no longer meaningful) in favor of ctx.mcpReq.id. Rewrote elicit_echo from the old synchronous elicitInput() push request (which throws on a 2026-07-28-era request) to the new inputRequired()/inputResponse() multi-round-trip pattern. inputSchema/outputSchema now use z.object() (the bare-shape form is deprecated in v2).
  • src/tools.test.ts — updated for @modelcontextprotocol/client; added an explicit modern-era (2026-07-28) end-to-end test through the real createMcpHandler production entry point (via a fetch-bridged StreamableHTTPClientTransport), alongside the existing legacy-era in-memory harness — both wire eras are covered.
  • docker-compose.yml — healthcheck now targets /health instead of /mcp.
  • Updated README.md, AGENTS.md, and the create-mcp-tool skill to match.

On backward compatibility

createMcpHandler's default legacy: 'stateless' mode serves 2025-era clients automatically. So this is not a client-compatibility break — no dual-transport wiring was needed. The breaking change is at the dependency/developer level only (package swap, extractx, elicitInput()inputRequired() for anything that forked this template's old pattern).

Manual verification

1. A legacy 2025-era client still round-trips correctly. Sending an old-style initialize handshake with protocolVersion: "2025-06-18" gets that same version echoed back — the server negotiates down to match the client instead of forcing an upgrade, so nothing forked from the old stateful pattern breaks:

curl -s http://localhost:3000/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"1.0.0"}}}'

event: message
data: {"result":{"protocolVersion":"2025-06-18","capabilities":{"logging":{},"tools":{"listChanged":true}},"serverInfo":{"name":"mcp-typescript-template","version":"1.0.0"}},"jsonrpc":"2.0","id":1}

2. A real 2026-07-28 client needs no handshake at all. Per the new spec, initialize/initialized is gone entirely — a modern client goes straight to a method like tools/list, with no session id and no prior negotiation step:

curl -s http://localhost:3000/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

event: message
data: {"result":{"tools":[{"name":"elicit_echo", ...}, {"name":"echo", ...}]},"jsonrpc":"2.0","id":1}

Both requests hit the same /mcp endpoint and the same createMcpHandler instance — the legacy fallback and the stateless modern path coexist without any dual-transport wiring.

Related Issues

Close #92

Test plan

  • npm run lint
  • npm run format:check
  • npm run build
  • npm run test:ci (17/17 passing, including new modern-era elicitation tests)
  • Manual smoke test of the built server: GET /health → 200, GET /mcp → 405 (no session), legacy POST /mcp initialize (protocolVersion: 2025-06-18) → valid response, POST /mcp tools/list with no handshake → valid response

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added stateless MCP request handling with improved compatibility for legacy clients.
    • Added a dedicated /health endpoint for service monitoring.
    • Improved interactive tool responses with retry and cancellation handling.
    • Added request-scoped logging and graceful shutdown behavior.
  • Documentation

    • Updated setup, architecture, tool-authoring, testing, and health-check guidance for the current MCP API.

Replace @modelcontextprotocol/sdk (v1, stateful) with the 2.0.0
@modelcontextprotocol/server + @modelcontextprotocol/node packages, which
implement the 2026-07-28 spec revision: no initialize/initialized
handshake, no Mcp-Session-Id header, no session map. createMcpHandler runs
getServer() fresh per HTTP request and transparently serves older 2025-era
clients too via its built-in stateless fallback, so no dual-transport
wiring is needed for backward compatibility.

- src/index.ts: replaced the hand-rolled transports map and manual
  POST/GET/DELETE session branching with createMcpHandler + toNodeHandler
  mounted on Express. Added GET /health as a dedicated liveness endpoint,
  since GET /mcp no longer doubles as one.
- src/tools.ts: registerTool's extra param is now ctx (ServerContext);
  dropped sessionId (no longer meaningful) in favor of ctx.mcpReq.id.
  Rewrote elicit_echo's elicitation flow from the old synchronous
  elicitInput() push request (which throws on a 2026-07-28-era request) to
  the new inputRequired()/inputResponse() multi-round-trip pattern.
  inputSchema/outputSchema now use z.object() (the bare-shape form is
  deprecated).
- src/tools.test.ts: updated for @modelcontextprotocol/client, and added
  an explicit 2026-07-28-era test path (via createMcpHandler + a
  fetch-bridged StreamableHTTPClientTransport) alongside the existing
  legacy-era in-memory harness, so both wire eras are covered.
- docker-compose.yml: healthcheck now targets /health instead of /mcp.
- Updated README.md, AGENTS.md, and the create-mcp-tool skill to match.

BREAKING CHANGE: @modelcontextprotocol/sdk is replaced by
@modelcontextprotocol/server and @modelcontextprotocol/node. Tool handler
signatures change (extra -> ctx), inputSchema/outputSchema must be
z.object(...), and any tool using elicitInput() must move to
inputRequired()/inputResponse(). This does not break MCP client
compatibility: createMcpHandler's default legacy stateless fallback keeps
serving 2025-era clients automatically.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@nickytonline, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 57 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 559bd5a7-e3c2-414b-84bf-22de813c71e2

📥 Commits

Reviewing files that changed from the base of the PR and between 9157bbc and d6d1f39.

📒 Files selected for processing (5)
  • .agents/skills/create-mcp-tool/SKILL.md
  • AGENTS.md
  • README.md
  • src/index.ts
  • src/tools.test.ts
📝 Walkthrough

Walkthrough

The template migrates to MCP 2.0 stateless HTTP handling. It replaces session-based transport code with createMcpHandler, updates tool context and elicitation APIs, refreshes tests and dependencies, and revises project documentation.

Changes

Stateless MCP support

Layer / File(s) Summary
Stateless HTTP runtime
src/index.ts, package.json, vite.config.ts, docker-compose.yml
MCP requests use per-request server creation through createMcpHandler and toNodeHandler. The application exposes /health, updates shutdown handling, and uses the MCP 2.0 packages.
Context-based tool execution
src/tools.ts, src/lib/utils.ts
Tools use Zod object schemas and ServerContext. elicit_echo uses inputRequired and inputResponse handling with request-scoped logging.
Modern MCP integration coverage
src/tools.test.ts
Tests use current MCP client/server APIs, typed CallToolResult values, HTTP transport coverage, and modern elicitation negotiation.
Migration guidance
README.md, AGENTS.md, .agents/skills/create-mcp-tool/SKILL.md
Documentation describes stateless routing, request context, health checks, current schemas, elicitation flow, and updated testing APIs.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MCPClient
  participant toNodeHandler
  participant createMcpHandler
  participant McpServer
  participant elicit_echo
  MCPClient->>toNodeHandler: Send MCP request to /mcp
  toNodeHandler->>createMcpHandler: Dispatch request
  createMcpHandler->>McpServer: Create server and register tools
  McpServer->>elicit_echo: Execute tool with ServerContext
  elicit_echo-->>McpClient: Return inputRequired or tool result
Loading

Possibly related PRs

Suggested labels: released

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.43% 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
Linked Issues check ✅ Passed The changes satisfy issue #92 by adopting v2 packages, stateless handlers, updated tools and tests, health checks, fallback support, and documentation.
Out of Scope Changes check ✅ Passed The package, source, test, health-check, configuration, and documentation changes all support the linked stateless MCP migration.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely identifies the breaking migration to the MCP 2026-07-28 stateless specification.
✨ 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 migrate-mcp-v2-stateless

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@socket-security

socket-security Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​modelcontextprotocol/​node@​2.0.0751009397100
Added@​modelcontextprotocol/​client@​2.0.0781008497100
Added@​modelcontextprotocol/​server@​2.0.0801008597100
Updatedconcurrently@​9.2.3 ⏵ 9.2.49910010093 +2100
Updatedsemantic-release@​25.0.5 ⏵ 25.0.89710010097 +2100

View full report

@socket-security

socket-security Bot commented Aug 1, 2026

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
Obfuscated code: npm npm is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: package-lock.jsonnpm/semantic-release@25.0.8npm/npm@11.19.0

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/npm@11.19.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
Obfuscated code: npm npm is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: package-lock.jsonnpm/semantic-release@25.0.8npm/npm@11.19.0

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/npm@11.19.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (6)
.agents/skills/create-mcp-tool/SKILL.md (1)

26-26: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Clarify the boundary between tool wiring and business logic.

Everything for a tool lives in src/tools.ts conflicts with the project guidance that business logic belongs under src/. Keep registerTools(server) and thin handlers in src/tools.ts. Allow reusable domain logic in focused modules as tools grow.

As per coding guidelines, src/tools.ts is the registration source of truth, while business logic may be added under src/.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.agents/skills/create-mcp-tool/SKILL.md at line 26, Revise the guidance
around registerTools(server) to distinguish tool wiring and thin handlers in
src/tools.ts from reusable business logic in focused modules under src/. Keep
src/tools.ts as the single registration source of truth while allowing domain
logic to move out of the tool handlers as implementations grow.

Source: Coding guidelines

src/tools.test.ts (1)

230-273: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Release the modern-era client and handler even when an assertion fails.

client.close() and handler.close() run after the assertions. If an assertion fails, both stay open for the rest of the run. Register the cleanup in afterEach, or wrap the body in try/finally.

♻️ Proposed refactor
+  let modernEra: { client: Client; handler: { close: () => Promise<void> } } | undefined;
+
+  afterEach(async () => {
+    await modernEra?.client.close();
+    await modernEra?.handler.close();
+    modernEra = undefined;
+  });
+
   async function setupModernEraClient(options: { supportsElicitation?: boolean } = {}) {

Then assign the result and drop the trailing close() calls in each test:

-    const { client, handler } = await setupModernEraClient();
+    modernEra = await setupModernEraClient();
+    const { client } = modernEra;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tools.test.ts` around lines 230 - 273, Update setupModernEraClient and
its modern-era tests so the client and handler are always closed when assertions
fail. Register cleanup through afterEach or move the test body into try/finally,
then remove the now-redundant trailing close calls while preserving existing
test behavior.
src/index.ts (2)

43-44: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Raise the JSON body limit and add Helmet.

express.json() applies a 100kb default limit. Tool arguments larger than that fail with a 413 before the MCP handler runs. Static analysis also reports that the app serves without Helmet security headers.

♻️ Proposed change
 const app = express();
-app.use(express.json());
+app.use(helmet());
+app.use(express.json({ limit: "4mb" }));

Add the import at the top of the file:

import helmet from "helmet";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/index.ts` around lines 43 - 44, Update the Express app initialization
around app to add Helmet middleware and configure express.json with a
sufficiently larger body limit, preserving the existing middleware setup and
ensuring large tool arguments reach the MCP handler.

Source: Linters/SAST tools


68-79: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Close the HTTP listener during shutdown and bound the shutdown time.

app.listen returns a server that is never closed. process.exit(0) therefore terminates in-flight requests as soon as handler.close() settles. If handler.close() never settles, the process never exits and the container is killed by the orchestrator instead. Keep the listener reference, close it, and add a forced-exit timer.

♻️ Proposed refactor
 async function main() {
   const config = getConfig();
 
+  const httpServer = app.listen(config.PORT, () => {
+    logger.info(
+      {
+        environment: config.NODE_ENV,
+        serverName: config.SERVER_NAME,
+        version: config.SERVER_VERSION,
+      },
+      `MCP TypeScript Template Server running on port ${config.PORT}`,
+    );
+  });
+
+  const shutdown = (signal: string) => {
+    logger.info({ signal }, "Signal received, shutting down gracefully");
+    const forceExit = setTimeout(() => process.exit(1), 10_000);
+    forceExit.unref();
+    httpServer.close(() => {
+      void handler.close().finally(() => process.exit(0));
+    });
+  };
+
-  process.on("SIGTERM", () => {
-    logger.info("SIGTERM received, shutting down gracefully");
-    void handler.close().finally(() => process.exit(0));
-  });
-
-  process.on("SIGINT", () => {
-    logger.info("SIGINT received, shutting down gracefully");
-    void handler.close().finally(() => process.exit(0));
-  });
-
-  app.listen(config.PORT, () => {
-    logger.info(
-      {
-        environment: config.NODE_ENV,
-        serverName: config.SERVER_NAME,
-        version: config.SERVER_VERSION,
-      },
-      `MCP TypeScript Template Server running on port ${config.PORT}`,
-    );
-  });
+  process.on("SIGTERM", () => shutdown("SIGTERM"));
+  process.on("SIGINT", () => shutdown("SIGINT"));
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/index.ts` around lines 68 - 79, Update main so the server returned by
app.listen is retained and closed during both SIGTERM and SIGINT shutdown paths.
Add a forced process-exit timeout that bounds shutdown if handler.close or
server.close never settles, while preserving graceful cleanup and immediate exit
on successful completion.
src/tools.ts (2)

113-118: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Move the decline and cancel comment to the branch it describes.

The comment describes decline and cancel outcomes. It sits above the response.kind !== "elicit" branch, which returns an error result. Readers of this template can misread the control flow.

♻️ Proposed change
-  // Decline and cancel are valid user outcomes, not errors — return them as
-  // normal results (no isError) so the model treats them as a real answer.
   if (response.kind !== "elicit") {
     logger.error({ toolName, requestId, kind: response.kind }, "Tool execution failed");
     return createErrorResult({ error: "Expected an elicitation response" });
   }
 
+  // Decline and cancel are valid user outcomes, not errors — return them as
+  // normal results (no isError) so the model treats them as a real answer.
   if (response.action === "decline") {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tools.ts` around lines 113 - 118, Move the decline-and-cancel explanatory
comment from above the response.kind !== "elicit" check to the branch that
handles those valid outcomes, keeping it adjacent to the normal-result return
and separate from the error-result path.

68-68: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Use request-scoped logging in the handler.

server.sendLoggingMessage works for MCP logging, but v2 marks it deprecated for request handlers. Prefer ctx.mcpReq.log(level, data, logger?) so the notification is request-scoped and context-aware.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tools.ts` at line 68, Update the handler callback around
server.sendLoggingMessage to use the request-scoped ctx.mcpReq.log(level, data,
logger?) API, preserving the existing arguments and logging behavior while
removing the deprecated server method usage.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@AGENTS.md`:
- Around line 98-116: Define one canonical structured logging contract across
AGENTS.md: lines 98-116 and .agents/skills/create-mcp-tool/SKILL.md: lines
69-84, matching the request context used by src/tools.ts. Add requestId to both
success and failure examples in AGENTS.md, and add args to the skill examples or
explicitly document when inputs must be omitted; state whether args require
redaction. Update both sites consistently.

In `@README.md`:
- Around line 188-193: Update the README Error Handling bullet to limit the
no-throw guarantee to tool execution failures: tool handlers should return
createErrorResult for genuine execution errors, while protocol, transport, and
capability failures may still cause client.callTool() to reject.
- Around line 207-213: Add the missing z import to the TypeScript example that
defines inputSchema and outputSchema, alongside the existing createErrorResult
and createTextResult imports, so its z.object calls compile when copied.

In `@src/index.ts`:
- Around line 59-66: Update the rejection handler in the /mcp route around
nodeHandler so that, after logging, it sends a 500 JSON-RPC error response when
the response headers have not already been sent. Preserve any response already
started by checking the response state before writing.

In `@src/tools.test.ts`:
- Around line 275-278: Rename the test case around client.callTool in the
“supportsElicitation: false” scenario to state that the call is rejected,
including the expected missing-capability error behavior and code -32021. Leave
the assertion and test logic unchanged.

---

Nitpick comments:
In @.agents/skills/create-mcp-tool/SKILL.md:
- Line 26: Revise the guidance around registerTools(server) to distinguish tool
wiring and thin handlers in src/tools.ts from reusable business logic in focused
modules under src/. Keep src/tools.ts as the single registration source of truth
while allowing domain logic to move out of the tool handlers as implementations
grow.

In `@src/index.ts`:
- Around line 43-44: Update the Express app initialization around app to add
Helmet middleware and configure express.json with a sufficiently larger body
limit, preserving the existing middleware setup and ensuring large tool
arguments reach the MCP handler.
- Around line 68-79: Update main so the server returned by app.listen is
retained and closed during both SIGTERM and SIGINT shutdown paths. Add a forced
process-exit timeout that bounds shutdown if handler.close or server.close never
settles, while preserving graceful cleanup and immediate exit on successful
completion.

In `@src/tools.test.ts`:
- Around line 230-273: Update setupModernEraClient and its modern-era tests so
the client and handler are always closed when assertions fail. Register cleanup
through afterEach or move the test body into try/finally, then remove the
now-redundant trailing close calls while preserving existing test behavior.

In `@src/tools.ts`:
- Around line 113-118: Move the decline-and-cancel explanatory comment from
above the response.kind !== "elicit" check to the branch that handles those
valid outcomes, keeping it adjacent to the normal-result return and separate
from the error-result path.
- Line 68: Update the handler callback around server.sendLoggingMessage to use
the request-scoped ctx.mcpReq.log(level, data, logger?) API, preserving the
existing arguments and logging behavior while removing the deprecated server
method usage.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b04fd1e7-2c93-415c-894d-91d9f3e1c654

📥 Commits

Reviewing files that changed from the base of the PR and between 032e414 and 9157bbc.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (10)
  • .agents/skills/create-mcp-tool/SKILL.md
  • AGENTS.md
  • README.md
  • docker-compose.yml
  • package.json
  • src/index.ts
  • src/lib/utils.ts
  • src/tools.test.ts
  • src/tools.ts
  • vite.config.ts

Comment thread AGENTS.md
Comment thread README.md
Comment thread README.md
Comment thread src/index.ts
Comment thread src/tools.test.ts Outdated
nickytonline and others added 6 commits August 1, 2026 13:38
If the request never got a response before nodeHandler's promise rejects, the client would hang
until it or a proxy times out. Send a JSON-RPC 500 when headers aren't sent yet, otherwise close
the connection.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
No session to key richer metadata off anymore, so trim it to a
liveness ping matching the Docker healthcheck's actual need.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
AGENTS.md and the create-mcp-tool skill described different log
shapes ({toolName, args} vs {toolName, requestId}). Standardize on
{toolName, requestId, ...safe fields}, matching what src/tools.ts
actually logs, and state explicitly that raw args must be omitted
rather than logged wholesale.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Protocol, transport, and capability failures (e.g. unsupported
elicitation) can still reject the client call, as covered by
src/tools.test.ts.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The example used z.object() without importing z, so copying it verbatim
would fail to compile.
@nickytonline
nickytonline force-pushed the migrate-mcp-v2-stateless branch from 8c099a4 to 98b542c Compare August 2, 2026 04:08
@nickytonline
nickytonline marked this pull request as ready for review August 2, 2026 04:12
The test asserted client.callTool() rejects, but was named as if it
returned a normal error result.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Your trial has ended. Reactivate Greptile to resume code reviews.

@nickytonline
nickytonline enabled auto-merge (squash) August 2, 2026 04:12

@nickytonline nickytonline left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

:shipit:

@nickytonline
nickytonline merged commit dc6a57e into main Aug 2, 2026
8 of 9 checks passed
@nickytonline
nickytonline deleted the migrate-mcp-v2-stateless branch August 2, 2026 04:13
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown

🎉 This PR is included in version 2.0.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement Stateless MCP Support

1 participant