Skip to content

Commit 7652431

Browse files
Add MCPB bundle to release workflow and fix MCP server logging (#69)
* Add MCPB bundle support for Claude Desktop installation - Add manifest.json with UV runtime for zero-dependency installation - Add .mcpbignore to exclude dev files from bundle - Add manifest.json version to version consistency test - Add *.mcpb and .mcpregistry_* to .gitignore Build with: npx @anthropic-ai/mcpb pack Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Fix stdout corruption in MCP server lifespan Removed print() statement that was writing to stdout, which corrupted the JSON-RPC protocol stream. Per MCP best practices, servers must only write JSON-RPC messages to stdout. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Add MCPB bundle to release workflow and fix MCP server logging - Add build-mcpb job to publish.yaml that builds and attaches the .mcpb bundle to GitHub releases for one-click Claude Desktop installation - Configure logging in server.py to use stderr only (stdout is reserved for JSON-RPC protocol), preventing httpx/rich logging from corrupting the MCP communication stream - Update README with Claude Desktop installation instructions and note about Cowork mode limitation (see issue #20377) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * update readme docs * Update privacy policy URL to futuresearch.ai --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 3d863d9 commit 7652431

9 files changed

Lines changed: 145 additions & 7 deletions

File tree

.github/workflows/publish.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,28 @@ jobs:
2929
3030
- name: Publish to PyPI
3131
uses: pypa/gh-action-pypi-publish@release/v1
32+
33+
build-mcpb:
34+
name: Build MCPB Bundle
35+
runs-on: ubuntu-latest
36+
permissions:
37+
contents: write
38+
# MCPB bundles enable one-click installation in Claude Desktop.
39+
# Note: Local MCP servers currently only work in Chat mode, not Cowork mode.
40+
# See: https://github.com/anthropics/claude-code/issues/20377
41+
steps:
42+
- uses: actions/checkout@v4
43+
44+
- name: Setup Node.js
45+
uses: actions/setup-node@v4
46+
with:
47+
node-version: "20"
48+
49+
- name: Build MCPB bundle
50+
working-directory: everyrow-mcp
51+
run: npx -y @anthropic-ai/mcpb pack
52+
53+
- name: Upload MCPB to release
54+
uses: softprops/action-gh-release@v2
55+
with:
56+
files: everyrow-mcp/everyrow-mcp.mcpb

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,3 +217,9 @@ __marimo__/
217217

218218
.history/
219219
.python-version
220+
221+
# MCPB bundles
222+
*.mcpb
223+
224+
# MCP registry tokens
225+
.mcpregistry_*

everyrow-mcp/.mcpbignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.venv/
2+
__pycache__/
3+
*.pyc
4+
.pytest_cache/
5+
.mypy_cache/
6+
*.egg-info/
7+
server/lib/
8+
server/venv/
9+
.mcpregistry_github_token
10+
.mcpregistry_registry_token
11+
tests/
12+
dist/
13+
.ruff_cache/

everyrow-mcp/README.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,15 @@ This server exposes everyrow's 5 core operations as MCP tools, allowing LLM appl
66

77
**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.
88

9-
## Setup
9+
## Installation
10+
11+
### Claude Desktop
12+
13+
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.
14+
15+
> **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.
16+
17+
### Manual Config
1018

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

@@ -129,7 +137,7 @@ cd everyrow-mcp
129137
uv sync
130138
uv run pytest
131139
```
132-
For MCP registry publishing:
140+
For MCP [registry publishing](https://modelcontextprotocol.info/tools/registry/publishing/#package-deployment):
133141

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

everyrow-mcp/manifest.json

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
{
2+
"manifest_version": "0.4",
3+
"name": "everyrow-mcp",
4+
"display_name": "Everyrow MCP Server",
5+
"version": "0.1.9",
6+
"description": "AI-powered dataframe ops: transform, dedupe, merge, rank, and screen with natural language",
7+
"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.",
8+
"author": {
9+
"name": "FutureSearch",
10+
"url": "https://everyrow.io"
11+
},
12+
"repository": {
13+
"type": "git",
14+
"url": "https://github.com/futuresearch/everyrow-sdk.git"
15+
},
16+
"homepage": "https://everyrow.io",
17+
"documentation": "https://github.com/futuresearch/everyrow-sdk/tree/main/everyrow-mcp",
18+
"support": "https://github.com/futuresearch/everyrow-sdk/issues",
19+
"server": {
20+
"type": "uv",
21+
"entry_point": "src/everyrow_mcp/server.py",
22+
"mcp_config": {
23+
"command": "uv",
24+
"args": ["run", "${__dirname}/src/everyrow_mcp/server.py"],
25+
"env": {
26+
"EVERYROW_API_KEY": "${user_config.api_key}"
27+
}
28+
}
29+
},
30+
"tools": [
31+
{
32+
"name": "everyrow_screen",
33+
"description": "Filter CSV rows based on criteria that require judgment"
34+
},
35+
{
36+
"name": "everyrow_rank",
37+
"description": "Score and sort CSV rows based on qualitative criteria"
38+
},
39+
{
40+
"name": "everyrow_dedupe",
41+
"description": "Remove duplicate rows using semantic equivalence"
42+
},
43+
{
44+
"name": "everyrow_merge",
45+
"description": "Join two CSV files using intelligent entity matching"
46+
},
47+
{
48+
"name": "everyrow_agent",
49+
"description": "Run web research agents on each row of a CSV"
50+
}
51+
],
52+
"user_config": {
53+
"api_key": {
54+
"type": "string",
55+
"title": "Everyrow API Key",
56+
"description": "Your API key from https://everyrow.io/api-key ($20 free credit)",
57+
"sensitive": true,
58+
"required": true
59+
}
60+
},
61+
"compatibility": {
62+
"platforms": ["darwin", "linux", "win32"],
63+
"runtimes": {
64+
"python": ">=3.12"
65+
}
66+
},
67+
"keywords": ["everyrow", "dataframe", "csv", "ai", "data-processing", "dedupe", "merge", "rank", "screen"],
68+
"license": "MIT",
69+
"privacy_policies": ["https://futuresearch.ai/privacy/"]
70+
}

everyrow-mcp/src/everyrow_mcp/server.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""MCP server for everyrow SDK operations."""
22

33
import json
4+
import logging
45
import os
56
import sys
67
from contextlib import asynccontextmanager
@@ -30,7 +31,6 @@ async def lifespan(_server: FastMCP):
3031
response = await whoami(client=c)
3132
if response is None:
3233
raise RuntimeError("Failed to authenticate with everyrow API")
33-
print("everyrow-mcp: Authenticated successfully")
3434
except Exception as e:
3535
raise RuntimeError(f"everyrow-mcp startup failed: {e}") from e
3636

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

540540
def main():
541541
"""Run the MCP server."""
542+
# Configure logging to use stderr only (stdout is reserved for JSON-RPC)
543+
logging.basicConfig(
544+
level=logging.WARNING,
545+
stream=sys.stderr,
546+
format="%(levelname)s: %(message)s",
547+
force=True,
548+
)
549+
542550
# Check for API key before starting
543551
if "EVERYROW_API_KEY" not in os.environ:
544552
print(

everyrow-mcp/uv.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/test_version.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ def test_version_consistency(pytestconfig: pytest.Config):
4141
server_json_version = server_json["version"]
4242
server_json_package_version = server_json["packages"][0]["version"]
4343

44+
manifest_json_path = root / "everyrow-mcp" / "manifest.json"
45+
with open(manifest_json_path) as f:
46+
manifest_json = json.load(f)
47+
manifest_version = manifest_json["version"]
48+
4449
assert pyproject_version == plugin_version, (
4550
f"pyproject.toml version ({pyproject_version}) != plugin.json version ({plugin_version})"
4651
)
@@ -59,6 +64,9 @@ def test_version_consistency(pytestconfig: pytest.Config):
5964
assert pyproject_version == server_json_package_version, (
6065
f"pyproject.toml version ({pyproject_version}) != everyrow-mcp/server.json packages[0].version ({server_json_package_version})"
6166
)
67+
assert pyproject_version == manifest_version, (
68+
f"pyproject.toml version ({pyproject_version}) != everyrow-mcp/manifest.json version ({manifest_version})"
69+
)
6270

6371

6472
def test_server_json_schema(pytestconfig: pytest.Config):

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)