feat(evi): expose the agent over mcp for external harnesses - #544
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
4 Skipped Deployments
|
|
|
Thank you for following the naming conventions! 🙏 |
📝 WalkthroughWalkthroughAdds an authenticated MCP HTTP endpoint for Evi. It handles JSON-RPC lifecycle requests, tool calls, streamed Evi responses, MCP session IDs, maintainer trust, CORS, and operational documentation. ChangesEvi MCP channel
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant MCPChannel
participant handleMcpRequest
participant EviSession
Client->>MCPChannel: POST JSON-RPC request with bearer token
MCPChannel->>handleMcpRequest: authenticated request and callEvi callback
handleMcpRequest->>EviSession: execute evi tool message
EviSession-->>handleMcpRequest: streamed Evi events
handleMcpRequest-->>MCPChannel: JSON-RPC response
MCPChannel-->>Client: response with MCP session ID
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration. 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. Comment |
commit: |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 `@apps/evi/agent/lib/mcp.ts`:
- Around line 95-99: Update the documentation comment above the MCP request
handler to remove the implementation-history reference to “V's proven MCP proxy
shape,” while preserving the durable description of JSON-RPC protocol errors and
callEvi failures.
- Line 4: Align the MCP protocol declaration and transport routes: in
apps/evi/agent/lib/mcp.ts at line 4 and apps/evi/agent/channels/mcp.ts at lines
33-41, either implement the 2024-11-05 separate SSE and POST JSON-RPC endpoints,
or change PROTOCOL_VERSION to the Streamable HTTP version and add GET handling
to the existing /eve/v1/mcp endpoint. Ensure the selected transport matches the
declared protocol and clients can complete session setup.
🪄 Autofix
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: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: b8dde181-4ff9-4cce-a694-c6248248fccc
📒 Files selected for processing (6)
apps/evi/agent/channels/mcp.tsapps/evi/agent/lib/mcp.test.tsapps/evi/agent/lib/mcp.tsapps/evi/agent/lib/trust.test.tsapps/evi/agent/lib/trust.tsapps/evi/docs/notes.md
| import { createHash, timingSafeEqual } from 'node:crypto' | ||
| import type { SessionAuthContext } from 'eve/context' | ||
|
|
||
| const PROTOCOL_VERSION = '2024-11-05' |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n -C 3 "PROTOCOL_VERSION|mcp-session-id|POST\\('/eve/v1/mcp'|GET\\('/eve/v1/mcp'" \
apps/evi/agent/lib/mcp.ts apps/evi/agent/channels/mcp.ts
curl -fsSL https://modelcontextprotocol.io/specification/2024-11-05/basic/transports \
| grep -E "SSE endpoint|regular HTTP POST endpoint" || true
curl -fsSL https://modelcontextprotocol.io/specification/2025-03-26/basic/transports \
| grep -E "supports both POST and GET|Mcp-Session-Id" || trueRepository: HugoRCD/evlog
Length of output: 50370
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== files =="
git ls-files | rg '(^|/)apps/evi/agent/(lib|channels)/mcp\.ts$'
echo "== relevant source snippets =="
for f in apps/evi/agent/lib/mcp.ts apps/evi/agent/channels/mcp.ts; do
echo "--- $f ($(wc -l < "$f") lines) ---"
sed -n '1,240p' "$f" | nl -ba
done
echo "== mcp references =="
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' 'PROTOCOL_VERSION|mcp-session-id|session-id|Mcp-Session-Id|streamable|mcp-/sse|POST\(\x27/eve/v1/mcp\x27|GET\(\x27/eve/v1/mcp\x27|GET\("`/eve/v1/mcp`"|POST\("`/eve/v1/mcp`"' apps/evi/agent/package.json package.json pnpm-lock.yaml 2>/dev/null || trueRepository: HugoRCD/evlog
Length of output: 338
🌐 Web query:
Model Context Protocol 2024-11-05 transports SSE endpoint POST endpoint separate endpoints
💡 Result:
In the Model Context Protocol (MCP) specification dated 2024-11-05, the HTTP with Server-Sent Events (SSE) transport requires the server to provide two distinct endpoints to facilitate bidirectional communication [1][2]: 1. An SSE endpoint: Used by clients to establish a connection and receive messages (server-to-client) [1][2]. 2. A separate HTTP POST endpoint: Used by clients to send messages to the server (client-to-server) [1][2]. When a client connects to the SSE endpoint, the server sends an endpoint event containing the URI for the POST endpoint [1][3]. The client then sends all subsequent messages as HTTP POST requests to that specific URI [1][2]. Note that this HTTP+SSE transport was later superseded by the Streamable HTTP transport (introduced in the 2025-03-26 specification), which utilizes a single MCP endpoint that handles both GET and POST methods [4][5][6]. While newer specifications recommend the Streamable HTTP approach, they generally provide guidance for maintaining backwards compatibility by continuing to host the separate SSE and POST endpoints of the 2024-11-05 transport [4][7][6].
Citations:
- 1: https://modelcontextprotocol.io/specification/2024-11-05/basic/transports
- 2: https://modelcontextprotocol.info/specification/2024-11-05/basic/transports/
- 3: https://deepwiki.com/modelcontextprotocol/java-sdk/5.2-http-sse-transport
- 4: https://spec.modelcontextprotocol.io/specification/2025-03-26/basic/transports/
- 5: https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http
- 6: https://modelcontextprotocol.io/specification/2025-03-26/basic/transports
- 7: https://modelcontextprotocol.org/specification/2025-11-25/basic/transports
🌐 Web query:
Model Context Protocol streamable HTTP transports 2025-03-26 GET POST same endpoint mcp-protocol-version mcp-session-id
💡 Result:
The "Streamable HTTP" transport, introduced in the Model Context Protocol (MCP) specification version 2025-03-26, defines a method for MCP clients and servers to communicate using a single HTTP endpoint that supports both GET and POST requests [1][2][3]. Key aspects of this transport include: MCP Endpoint: Servers expose a single URL path (the MCP endpoint) to handle all traffic [1][2]. POST Requests: All JSON-RPC messages from the client to the server must be sent as HTTP POST requests to the MCP endpoint [1][2]. GET Requests: Clients may issue an HTTP GET request to the MCP endpoint to initiate a Server-Sent Events (SSE) stream [1][2]. This allows the server to send messages (notifications or requests) to the client asynchronously [2][4]. Header Requirements: MCP-Protocol-Version: Starting with the 2025-03-26 release and evolving in subsequent versions, this header is used to negotiate and specify the protocol version [5][6][7][8]. Mcp-Session-Id: In earlier stateful revisions of the Streamable HTTP transport (such as 2025-03-26 and 2025-11-25), this header was used to manage session state between the client and server [5][6][8]. Servers could return a session ID during initialization, which the client then included in subsequent requests [6][9]. Evolution: Later protocol revisions, such as the 2026-07-28 draft, transitioned toward a stateless model [5][8][10]. In these stateless revisions, the Mcp-Session-Id header and GET-based SSE streams have been deprecated or removed in favor of stateless requests where context is provided via the _meta field in the JSON-RPC request body [5][8][10]. Servers maintaining backward compatibility may still support the older stateful headers (like Mcp-Session-Id) alongside the newer stateless implementation [11][8][10].
Citations:
- 1: https://spec.modelcontextprotocol.io/specification/2025-03-26/basic/transports/
- 2: https://modelcontextprotocol.io/specification/2025-03-26/basic/transports
- 3: https://modelcontextprotocol.io/specification/2025-03-26/changelog
- 4: [RFC] Replace HTTP+SSE with new "Streamable HTTP" transport modelcontextprotocol/modelcontextprotocol#206
- 5: https://modelcontextprotocol.io/specification/draft/basic/transports/streamable-http
- 6: https://modelcontextprotocol.org/specification/2025-11-25/basic/transports
- 7: https://github.com/helynranta/cpp-mcp
- 8: https://mcpg.dev/docs/concepts/protocol-versions
- 9: https://mcp.mintlify.app/specification/2025-11-25/basic/transports
- 10: https://www.ssdnodes.com/learn/stateless-mcp-explained
- 11: https://docs.rs/tower-mcp/latest/tower_mcp/transport/http/index.html
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== relevant source snippets =="
for f in apps/evi/agent/lib/mcp.ts apps/evi/agent/channels/mcp.ts; do
echo "--- $f ($(wc -l < "$f") lines) ---"
sed -n '1,240p' "$f" | awk '{printf "%6d %s\n", NR, $0}'
done
echo "== mcp references in tracked code =="
rg -n 'PROTOCOL_VERSION|mcp-session-id|session-id|Mcp-Session-Id|mcp-protocol-version|streamable|mcp-/sse|POST\(' 'apps/evi/agent/lib/mcp.ts' 'apps/evi/agent/channels/mcp.ts' 'apps/evi/agent/package.json' 2>/dev/null || true
echo "== deterministic route shape check =="
python3 - <<'PY'
from pathlib import Path
import re
for path in ["apps/evi/agent/lib/mcp.ts", "apps/evi/agent/channels/mcp.ts"]:
text = Path(path).read_text()
print(f"\n{path}:")
print("declares 2024-11-05:", bool(re.search(r"PROTOCOL_VERSION\s*=\s*['\"]2024-11-05['\"]", text)))
print("mentions Streamable/2025:", bool(re.search(r"streamable|2025-03-26|mcp-session-id|Mcp-Session-Id", text)))
print("declares SSE endpoint:", bool(re.search(r"(GET\(|POST\(|route\(|'/eve/v1/mcp/sse|/mcp/sse)", text)))
print("declares POST endpoint:", bool(re.search(r"(GET\(|POST\(|route\(|'/eve/v1/mcp|/eve/v1/mcp)", text)))
print("declares GET endpoint:", bool(re.search(r"GET\(|route\([^)]*GET|method\s*[=:][^<]*GET", text)))
PYRepository: HugoRCD/evlog
Length of output: 10912
Align the MCP transport with the declared protocol version.
PROTOCOL_VERSION returns 2024-11-05, but /eve/v1/mcp is defined as POST-only. That version requires a separate server-sent-events SSE endpoint and a distinct POST JSON-RPC endpoint; clients cannot complete HTTP+SSE setup. Implement both 2024-11-05 endpoints, or declare the Streamable HTTP version and add GET handling on the same endpoint.
📍 Affects 2 files
apps/evi/agent/lib/mcp.ts#L4-L4(this comment)apps/evi/agent/channels/mcp.ts#L33-L41
🤖 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 `@apps/evi/agent/lib/mcp.ts` at line 4, Align the MCP protocol declaration and
transport routes: in apps/evi/agent/lib/mcp.ts at line 4 and
apps/evi/agent/channels/mcp.ts at lines 33-41, either implement the 2024-11-05
separate SSE and POST JSON-RPC endpoints, or change PROTOCOL_VERSION to the
Streamable HTTP version and add GET handling to the existing /eve/v1/mcp
endpoint. Ensure the selected transport matches the declared protocol and
clients can complete session setup.
| /** | ||
| * Handles one parsed MCP JSON-RPC request. Protocol problems map to JSON-RPC | ||
| * errors; a thrown `callEvi` becomes an `isError` tool result. Ported from | ||
| * V's proven MCP proxy shape. | ||
| */ |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
Remove implementation-history text.
V's proven MCP proxy shape does not state a durable constraint. Remove it.
As per coding guidelines, “comments should state only durable constraints and should not narrate implementation history.”
🤖 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 `@apps/evi/agent/lib/mcp.ts` around lines 95 - 99, Update the documentation
comment above the MCP request handler to remove the implementation-history
reference to “V's proven MCP proxy shape,” while preserving the durable
description of JSON-RPC protocol errors and callEvi failures.
Source: Coding guidelines
Makes Evi reachable from MCP clients — Raycast AI first, Claude Code and Cursor for free — following the pattern of V's MCP channel.
POST /eve/v1/mcp: a custom channel serving MCP JSON-RPC (initialize, tools/list, tools/call, ping). Oneevitool forwards the message into a real Evi session via the routesend()and collects the reply from the session event stream.maxDuration: 800so a shipping flow can complete within the synchronous call.EVI_MCP_TOKEN), compared in constant time over digests. Verified requests run under themcp:hugoprincipal, whichtrust.tscounts as the maintainer only while the token is configured — full admin surface (push, captures, Linear, gateway) from the harness, revocable by rotating one env var. No OAuth AS on purpose: single-user surface.mcp-session-idissued on initialize keys the eve continuation token: one Raycast chat, one continuous Evi conversation.agent/lib/mcp.tswith colocated tests (10 new; 63 total).Setup after merge:
openssl rand -hex 32→EVI_MCP_TOKENon the evi project, then add an HTTP MCP server in Raycast pointing athttps://evi.evlog.cloud/eve/v1/mcpwith theAuthorization: Bearer …header. Documented indocs/notes.md.No changeset: confined to
apps/evi. Verified:tsc, 63 unit tests,eve build. End-to-end validates against the preview with a curlinitialize/tools/callonceEVI_MCP_TOKENis set.Summary by CodeRabbit
New Features
Documentation
Bug Fixes