jev-search
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@jev-searchsearch /home/me/notes/todo.txt for lines about feeling overwhelmed"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
jev-search-mcp
Find by meaning what keywords miss — as an MCP tool for your agents.
English · Русский
grep finds the words you typed. jev_search finds the lines that mean what you asked, even when they use different words.
This is a small stdio MCP server that gives any MCP-capable agent the jev-search CLI as one tool: jev_search.
What it is
Complementary semantic line search. Every nonblank line of a few small text files is judged against your intent by the TypeSafe Jev model. It adds to lexical search; it does not replace it.
Runs locally, next to your files. The server is a local process that your client starts over stdio. There is no port to open and nothing to host; only the model call itself is remote.
Works with every client that speaks MCP. Claude Code, Claude Desktop, OpenCode, or any other stdio MCP client.
Related MCP server: embgrep
How it works
flowchart LR
subgraph local["Your machine"]
A["AI agent<br/>(MCP client)"] -->|stdio| B["jev-search-mcp"]
B -->|subprocess| C["jev-search CLI"]
end
C -->|HTTPS| D["OpenRouter"]
D --> E["TypeSafe Jev model"]The agent calls jev_search with a query and 1–8 absolute file paths. The server runs the pinned jev-search CLI, which reads the files, sends the nonblank lines and the query in one request, and returns a score for every line. The agent then merges these matches with its exact-search hits and reads the original context.
Why complement grep? In the upstream author's exploratory evaluation, across six simulated tasks, lexical search plus Jev recovered 29 of 34 labeled relevant passages, compared with 22 of 34 for lexical search alone. These were small, manually curated experiments, not a general accuracy claim.
Quick start
1. Install uv (skip this if uv --version already works), then open a new terminal.
# Windows (PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"# Linux / macOS
curl -LsSf https://astral.sh/uv/install.sh | sh2. Set your key. Create your own OpenRouter key with a spending limit at https://openrouter.ai/settings/keys and store it as JEV_SEARCH_API_KEY.
# Windows (PowerShell): paste the key when asked, then fully restart your terminal and MCP client
$s = Read-Host 'Paste your OpenRouter key' -AsSecureString
[Environment]::SetEnvironmentVariable('JEV_SEARCH_API_KEY', [System.Net.NetworkCredential]::new('', $s).Password, 'User')# Linux / VPS (bash): paste the key when asked; it is not shown and stays out of shell history
read -rsp 'Paste your OpenRouter key: ' K; echo
echo "export JEV_SEARCH_API_KEY='$K'" >> ~/.bashrc; unset K; chmod 600 ~/.bashrc; source ~/.bashrcUse ~/.bashrc, because ~/.profile alone misses non-login shells. This covers interactive shells only; for services or non-interactive launches, put the key in the client's env block. On macOS (zsh), run the same lines with read -rs 'K?Paste your OpenRouter key: ' and ~/.zshrc.
3. Install and connect (the example uses Claude Code; other clients are covered below).
uv tool install git+https://github.com/Vento741/jev-search-mcp@v0.1.1
jev-search-mcp --version # prints 0.1.1
claude mcp add --scope user jev-search -- jev-search-mcpUsing OpenCode instead? Run opencode mcp add --global jev-search -- jev-search-mcp and then opencode reload (see OpenCode).
To check the setup for free, ask your agent: "Run jev_search with dry_run on /home/me/notes/sample.txt for 'greeting'" (use the absolute path of one of your own files, e.g. C:\Users\you\notes\sample.txt on Windows).
If the shell reports thatjev-search-mcp is not found, run uv tool update-shell and open a new terminal.
# update to a newer release tag
uv tool install --force git+https://github.com/Vento741/jev-search-mcp@<new-tag>
# remove
uv tool uninstall jev-search-mcpOn Windows, close the MCP clients that run the server (Claude Desktop, OpenCode, Claude Code sessions) before updating: a running jev-search-mcp.exe locks its files, and the update fails with "Access is denied". If that happens, close the clients and run the same command again.
Connect your client
The server itself never takes a key as an argument; it reads JEV_SEARCH_API_KEY from the environment its client gives it. Clients differ in what environment they pass on, which determines where the key has to go.
Claude Code
claude mcp add --scope user jev-search -- jev-search-mcpClaude Code passes its whole environment to stdio servers, so the user variable from step 2 is enough. If you set the variable after starting Claude Code, fully restart it. With --scope user, the server is available in all your projects.
Claude Desktop
Claude Desktop passes only a small default set of variables (such as PATH and APPDATA) to servers, not your user variables. The key must therefore go into the config's env block, and command must be the full path to the executable.
Find the path:
where.exe jev-search-mcp(Windows) orwhich jev-search-mcp(macOS/Linux).Open the config file. You can use Settings → Developer → Edit Config, or open it directly at
%APPDATA%\Claude\claude_desktop_config.json(Windows).Add the server (merge it into
mcpServersif the file already has one), then fully quit and reopen Claude Desktop.
{
"mcpServers": {
"jev-search": {
"command": "C:\\Users\\you\\.local\\bin\\jev-search-mcp.exe",
"env": { "JEV_SEARCH_API_KEY": "<your-key>" }
}
}
}File: ~/Library/Application Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"jev-search": {
"command": "/Users/you/.local/bin/jev-search-mcp",
"env": { "JEV_SEARCH_API_KEY": "<your-key>" }
}
}
}CI covers only Windows and Linux; macOS is expected to work but is not tested.
In this file the key is stored asplain text. It lives in your user profile, so keep it private: never commit, sync, or share it.
OpenCode
opencode mcp add --global jev-search -- jev-search-mcp
opencode reload # the OpenCode app runs a background service that caches its config
opencode mcp list # expect: jev-search connectedOpenCode passes your environment to local servers, so the user variable from step 2 is enough (checked with OpenCode 2.0 on Windows). --global writes to ~/.config/opencode/opencode.jsonc and makes the server available in all projects; without it the server goes into the current project's opencode.json. If you set the key after OpenCode started, restart its background service with opencode service restart (or fully quit and reopen the app).
{
"mcp": {
"servers": {
"jev-search": {
"type": "local",
"command": ["jev-search-mcp"]
}
}
}
}If OpenCode is started by a service that does not have your variables, add "environment": { "JEV_SEARCH_API_KEY": "<your-key>" } to the server entry (plaintext, same warning as for Claude Desktop). Do not pass the key with opencode mcp add --env: it would end up in your shell history.
Any other MCP client
Use the generic stdio configuration. The same rule applies: unless your client is documented to pass on your full environment, put the key in env.
{
"mcpServers": {
"jev-search": {
"command": "jev-search-mcp",
"args": [],
"env": { "JEV_SEARCH_API_KEY": "<your-key>" }
}
}
}Zero-install alternative. To run without uv tool install, use uvx as the command. It starts more slowly and may contact GitHub each time it starts.
uvx --from git+https://github.com/Vento741/jev-search-mcp@v0.1.1 jev-search-mcpIn JSON this is "command": "uvx" with "args": ["--from", "git+https://github.com/Vento741/jev-search-mcp@v0.1.1", "jev-search-mcp"]. In Claude Code, use claude mcp add --scope user jev-search -- uvx --from git+https://github.com/Vento741/jev-search-mcp@v0.1.1 jev-search-mcp.
Variable | Values | Default |
|
|
|
| model identifier |
|
Calling TypeSafe directly (JEV_SEARCH_PROVIDER=typesafe) requires a key issued by TypeSafe. OpenRouter and TypeSafe keys are not interchangeable. Set these variables the same way as the key, either in your environment or in the client's env block.
Tool
The server is named jev-search and exposes one read-only tool.
jev_search(query, files, top_k=None, dry_run=False)
Parameter | Type | Rules |
| string | Required. The intent to find, in natural language. At most 512 bytes (UTF-8), one line, with nothing that looks like a secret. |
| list of strings | Required. 1–8 absolute paths to UTF-8 |
| integer or null | Optional, 1–64. Also returns |
| boolean | Default |
Example call
{ "query": "greeting", "files": ["/home/me/notes/sample.txt"], "dry_run": true }Dry-run output, for a two-line file:
{
"mode": "dry-run",
"requests": 1,
"payload_bytes": 984,
"rows": [
{ "file": "/home/me/notes/sample.txt", "line": 1, "original": "Hello, nice to meet you." },
{ "file": "/home/me/notes/sample.txt", "line": 2, "original": "The invoice is due Friday." }
],
"unjudged": { "reason": "dry-run", "candidates": ["l0", "l1"] },
"model": "typesafe/jev-1.13",
"provider": "openrouter"
}Real search (dry_run: false), measured 2026-09-30 through this MCP server; scores vary slightly between runs. Call:
{ "query": "greeting", "files": ["/home/me/notes/sample.txt"], "top_k": 3 }Output (file path synthetic, generation id truncated):
{
"mode": "sent",
"latency_seconds": 0.94,
"results": [
{ "file": "/home/me/notes/sample.txt", "line": 1, "original": "Hello, nice to meet you.", "probability": 0.8, "match": true },
{ "file": "/home/me/notes/sample.txt", "line": 2, "original": "The invoice is due Friday.", "probability": 0.04, "match": false }
],
"ranked_results": [
{ "file": "/home/me/notes/sample.txt", "line": 1, "original": "Hello, nice to meet you.", "probability": 0.8, "match": true }
],
"meta": {
"model": "typesafe/jev-1.13-20260917",
"generation_id": "gen-...",
"cost": 1.953e-05,
"input_tokens": 465,
"output_tokens": 38
}
}results contains every nonblank line with its file, 1-based line number and score, and match is probability >= 0.5. The scores are useful for ordering, but they are not calibrated probabilities, so cite files and lines rather than numbers. With top_k, an extra ranked_results list holds only the matches, best first.
Limits
These limits come from the upstream CLI, which deliberately works on small, reviewed context. It does not scan or truncate anything implicitly.
Limit | Value |
Files per call | 1–8, absolute paths, no directories or globs |
File types |
|
Combined size | ≤ 16 KB (16,384 bytes) and ≤ 64 lines across all files |
Line length | ≤ 2 KB (2,048 bytes) per line |
Query | ≤ 512 bytes |
Requests | exactly one per call, no retries |
Timeout | 330 s per call, set by this wrapper around the CLI subprocess (the CLI's own network timeout is 300 s) |
For a bigger file, search a reviewed excerpt of it instead. The CLI also rejects symlinks, paths where any component starts with . or contains secret, credential, password or id_rsa, and text that looks like a key or password.
Privacy & cost
Your lines leave your machine. Every selected nonblank line, plus the query, is sent to OpenRouter and on to TypeSafe. On the default route, the request pins TypeSafe as the only provider, with fallbacks disabled and data_collection: deny. Only send content you are allowed to share.
Real searches cost money. A two-line search cost about $0.00002 (measured 2026-09-30; prices vary). The cost grows with the number of lines.
Use your own key with a spending limit set in the provider's dashboard. Never share it.
A missing
costdoes not mean the search was free. A timeout or network failure may still have been charged. Nothing is ever retried automatically.dry_runis always free and never touches the network.
Documentation
For detailed scenarios (notes and docs, log triage on a VPS, CSV tickets, combining grep with semantic search, working within the limits), key management and troubleshooting, see the detailed guide (in Russian).
Credits & license
Built on larguesa/jev-search by Ricardo Pupo Larguesa (MIT), pinned to commit
8aa4035.Inspired by uehaj/jev-semgrep.
This wrapper: MIT © 2026 Vento741.
Not affiliated with TypeSafe or OpenRouter.
Available Tools
1 tooljev_searchARead-only
Complementary semantic search over lines of small text files.
Returns every nonblank line with probability and match (>=0.5), plus source file and 1-based line. All selected lines leave the machine; a real search costs money.
| Name | Required | Description | Default |
|---|---|---|---|
| files | Yes | 1-8 ABSOLUTE paths to UTF-8 .txt/.md/.csv/.jsonl/.log files (no directories or globs); <=16 KB and <=64 lines combined. | |
| query | Yes | The intent to find, in natural language (<=512 bytes). | |
| top_k | No | Also return up to k matches sorted by score (ranked_results). | |
| dry_run | No | Free offline preview of what would be sent; no key, no network. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish readOnly/openWorld/non-destructive, so the description's real value is the extra disclosure: selected lines 'leave the machine' (data egress/privacy) and a real search 'costs money'. It also reveals the >=0.5 match threshold. It stops short of stating auth/key requirements, which the dry_run note only implies.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core operation, then the cost/privacy caveat. Two tight sentences with no wasted filler, though the trailing return-shape sentence partially duplicates the output schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Output schema exists, so return values need not be explained, yet the description still sketches the probability/match shape. Combined with the cost and data-egress warnings, an agent has enough to call this correctly, though key/auth prerequisites remain unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all four parameters are already documented in the schema, making 3 the baseline. The description does not add syntax or format detail beyond what the schema provides for query/files/top_k/dry_run.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (semantic search) and resource (lines of small text files), with scope qualifiers (small, line-level). The word 'complementary' is unexplained but the core operation is unambiguous. No siblings exist to differentiate from.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage context is implied rather than stated: 'a real search costs money' and the dry_run parameter hint that agents should preview before paying, but there is no explicit when-to-use-this-vs-alternatives guidance. With no sibling tools, there is little to route between, so 3 is fair.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
v0.1.1- First observed
jev_search
TDQS
Scored across 1 tool
There is only one tool, so there is no possibility of confusing it with another. Its purpose is clearly stated as semantic search over text file lines.
The single tool name 'jev_search' uses a clear snake_case convention with a domain prefix and action verb. With only one tool, there is no inconsistency to evaluate.
A single tool is borderline thin for a server, even if the server's apparent purpose is narrow. It covers the core search operation but provides no supporting operations.
The core semantic search operation is present and returns detailed results. Minor gaps exist, such as no way to limit results, filter files, or configure the match threshold, but these are workable.
Maintenance
Related MCP Connectors
Persistent memory, hybrid search and a goal graph for AI agents, over stdio or remote HTTP.
Code intelligence for coding agents: semantic, AST, graph, and full-text search. 279+ languages.
Local ML: speech to text (SRT/VTT), text embeddings, reranking, similarity, entities, zero-shot.
Ingest and search LogsLoom logs from coding agents.
Related MCP Servers
- AlicenseAqualityDmaintenanceProvides semantic code search over codebases using local embeddings with natural language queries. Supports hybrid search, file watching, and respects .gitignore.116MIT
- AlicenseNot gradedqualityDmaintenanceProvides local semantic search over files using embeddings, enabling directory indexing and natural language queries without external services.34 PyPIMIT
- AlicenseAqualityBmaintenanceEnables natural-language semantic search over your own local files through an MCP server, fully offline without API keys or a server daemon, with optional LLM-grounded answers and exact file:line sources.5MIT
- AlicenseNot gradedqualityBmaintenanceEnables coding agents to find code by behavior across an authorized repository, returning exact source excerpts with paths and line numbers. It exposes a single semantic search tool over stdio so agents can locate relevant code without knowing file names or symbols.8 npmMIT