Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,28 @@ jobs:

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1

build-mcpb:
name: Build MCPB Bundle
runs-on: ubuntu-latest
permissions:
contents: write
# MCPB bundles enable one-click installation in Claude Desktop.
# Note: Local MCP servers currently only work in Chat mode, not Cowork mode.
# See: https://github.com/anthropics/claude-code/issues/20377
steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"

- name: Build MCPB bundle
working-directory: everyrow-mcp
run: npx -y @anthropic-ai/mcpb pack
Comment on lines +49 to +51

This comment was marked as outdated.


- name: Upload MCPB to release
uses: softprops/action-gh-release@v2
with:
files: everyrow-mcp/everyrow-mcp.mcpb
Comment on lines +53 to +56

This comment was marked as outdated.

6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -217,3 +217,9 @@ __marimo__/

.history/
.python-version

# MCPB bundles
*.mcpb

# MCP registry tokens
.mcpregistry_*
13 changes: 13 additions & 0 deletions everyrow-mcp/.mcpbignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.venv/
__pycache__/
*.pyc
.pytest_cache/
.mypy_cache/
*.egg-info/
server/lib/
server/venv/
.mcpregistry_github_token
.mcpregistry_registry_token
tests/
dist/
.ruff_cache/
12 changes: 10 additions & 2 deletions everyrow-mcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@ This server exposes everyrow's 5 core operations as MCP tools, allowing LLM appl

**All tools operate on local CSV files.** Provide absolute file paths as input, and transformed results are written to new CSV files at your specified output path.

## Setup
## Installation

### Claude Desktop

Download the latest `.mcpb` bundle from the [GitHub Releases](https://github.com/futuresearch/everyrow-sdk/releases) page and double-click to install in Claude Desktop. You'll be prompted to enter your everyrow API key during setup.

> **Note:** The MCPB bundle works in Claude Desktop's **Chat** mode. Due to a [known limitation](https://github.com/anthropics/claude-code/issues/20377), local MCP servers are not currently exposed in Cowork mode.

### Manual Config

The server requires an everyrow API key. Get one at [everyrow.io/api-key](https://everyrow.io/api-key) ($20 free credit).

Expand Down Expand Up @@ -129,7 +137,7 @@ cd everyrow-mcp
uv sync
uv run pytest
```
For MCP registry publishing:
For MCP [registry publishing](https://modelcontextprotocol.info/tools/registry/publishing/#package-deployment):

mcp-name: io.github.futuresearch/everyrow-mcp

Expand Down
70 changes: 70 additions & 0 deletions everyrow-mcp/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{
"manifest_version": "0.4",
"name": "everyrow-mcp",
"display_name": "Everyrow MCP Server",
"version": "0.1.9",
"description": "AI-powered dataframe ops: transform, dedupe, merge, rank, and screen with natural language",
"long_description": "MCP server for everyrow: agent ops at spreadsheet scale. This server exposes everyrow's 5 core operations as MCP tools, allowing LLM applications to screen, rank, dedupe, merge, and run agents on CSV files. All tools operate on local CSV files.",
"author": {
"name": "FutureSearch",
"url": "https://everyrow.io"
},
"repository": {
"type": "git",
"url": "https://github.com/futuresearch/everyrow-sdk.git"
},
"homepage": "https://everyrow.io",
"documentation": "https://github.com/futuresearch/everyrow-sdk/tree/main/everyrow-mcp",
"support": "https://github.com/futuresearch/everyrow-sdk/issues",
"server": {
"type": "uv",
"entry_point": "src/everyrow_mcp/server.py",
"mcp_config": {
"command": "uv",
"args": ["run", "${__dirname}/src/everyrow_mcp/server.py"],
"env": {
"EVERYROW_API_KEY": "${user_config.api_key}"
}
}
},
"tools": [
{
"name": "everyrow_screen",
"description": "Filter CSV rows based on criteria that require judgment"
},
{
"name": "everyrow_rank",
"description": "Score and sort CSV rows based on qualitative criteria"
},
{
"name": "everyrow_dedupe",
"description": "Remove duplicate rows using semantic equivalence"
},
{
"name": "everyrow_merge",
"description": "Join two CSV files using intelligent entity matching"
},
{
"name": "everyrow_agent",
"description": "Run web research agents on each row of a CSV"
}
],
"user_config": {
"api_key": {
"type": "string",
"title": "Everyrow API Key",
"description": "Your API key from https://everyrow.io/api-key ($20 free credit)",
"sensitive": true,
"required": true
}
},
"compatibility": {
"platforms": ["darwin", "linux", "win32"],
"runtimes": {
"python": ">=3.12"
}
},
"keywords": ["everyrow", "dataframe", "csv", "ai", "data-processing", "dedupe", "merge", "rank", "screen"],
"license": "MIT",
"privacy_policies": ["https://futuresearch.ai/privacy/"]
}
10 changes: 9 additions & 1 deletion everyrow-mcp/src/everyrow_mcp/server.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""MCP server for everyrow SDK operations."""

import json
import logging
import os
import sys
from contextlib import asynccontextmanager
Comment on lines 1 to 7

This comment was marked as outdated.

Expand Down Expand Up @@ -30,7 +31,6 @@ async def lifespan(_server: FastMCP):
response = await whoami(client=c)
if response is None:
raise RuntimeError("Failed to authenticate with everyrow API")
print("everyrow-mcp: Authenticated successfully")
except Exception as e:
raise RuntimeError(f"everyrow-mcp startup failed: {e}") from e

Expand Down Expand Up @@ -539,6 +539,14 @@ def _schema_to_model(name: str, schema: dict[str, Any]) -> type[BaseModel]:

def main():
"""Run the MCP server."""
# Configure logging to use stderr only (stdout is reserved for JSON-RPC)
logging.basicConfig(
level=logging.WARNING,
stream=sys.stderr,
format="%(levelname)s: %(message)s",
force=True,
)
Comment on lines +543 to +548

This comment was marked as outdated.


# Check for API key before starting
if "EVERYROW_API_KEY" not in os.environ:
print(
Expand Down
6 changes: 3 additions & 3 deletions everyrow-mcp/uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions tests/test_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ def test_version_consistency(pytestconfig: pytest.Config):
server_json_version = server_json["version"]
server_json_package_version = server_json["packages"][0]["version"]

manifest_json_path = root / "everyrow-mcp" / "manifest.json"
with open(manifest_json_path) as f:
manifest_json = json.load(f)
manifest_version = manifest_json["version"]

assert pyproject_version == plugin_version, (
f"pyproject.toml version ({pyproject_version}) != plugin.json version ({plugin_version})"
)
Expand All @@ -59,6 +64,9 @@ def test_version_consistency(pytestconfig: pytest.Config):
assert pyproject_version == server_json_package_version, (
f"pyproject.toml version ({pyproject_version}) != everyrow-mcp/server.json packages[0].version ({server_json_package_version})"
)
assert pyproject_version == manifest_version, (
f"pyproject.toml version ({pyproject_version}) != everyrow-mcp/manifest.json version ({manifest_version})"
)


def test_server_json_schema(pytestconfig: pytest.Config):
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.