Connecting MCP clients
conmcp is a standard MCP server over stdio. Any MCP client can launch it; the only decision is how the client starts the process and which directories you grant it.
There are two ways to launch the server:
uvxfrom git — no install step, always pulls the pinned source. Best for client configs.- From a local clone —
uv run --directory /path/to/conmcp conmcp serve. Best if you're developing conmcp itself.
Always set CONMCP_ALLOWED_DIRS
The server only reads files inside the directories listed in CONMCP_ALLOWED_DIRS
(colon-separated). If unset, it defaults to the server's working directory —
which for GUI-launched clients like Claude Desktop is rarely where your plans
live. Set it explicitly to just your plans folder. Details in
Privacy & safety.
Claude Desktop
Edit claude_desktop_config.json (macOS:
~/Library/Application Support/Claude/claude_desktop_config.json; Windows:
%APPDATA%\Claude\claude_desktop_config.json):
{
"mcpServers": {
"conmcp": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/ContractorKeith/conmcp.git",
"conmcp",
"serve"
],
"env": {
"CONMCP_ALLOWED_DIRS": "/Users/you/plans"
}
}
}
}
Or, launching from a local clone:
{
"mcpServers": {
"conmcp": {
"command": "uv",
"args": ["run", "--directory", "/Users/you/code/conmcp", "conmcp", "serve"],
"env": {
"CONMCP_ALLOWED_DIRS": "/Users/you/plans"
}
}
}
}
Restart Claude Desktop after editing. The conmcp tools appear in the tools menu, and
fence_takeoff shows up in the prompts picker.
Note
Claude Desktop launches servers with a minimal PATH. If it can't find uvx, use the
absolute path (e.g. /Users/you/.local/bin/uvx — find yours with which uvx).
Claude Code
One command:
claude mcp add conmcp \
--env CONMCP_ALLOWED_DIRS="$HOME/plans" \
-- uvx --from git+https://github.com/ContractorKeith/conmcp.git conmcp serve
Add --scope user to make it available in every project instead of just the current one.
From a local clone instead:
claude mcp add conmcp \
--env CONMCP_ALLOWED_DIRS="$HOME/plans" \
-- uv run --directory "$HOME/code/conmcp" conmcp serve
Verify with claude mcp list, then use /conmcp:fence_takeoff or just ask Claude to run
a takeoff.
Cursor
Create .cursor/mcp.json in your project (or ~/.cursor/mcp.json for all projects):
{
"mcpServers": {
"conmcp": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/ContractorKeith/conmcp.git",
"conmcp",
"serve"
],
"env": {
"CONMCP_ALLOWED_DIRS": "/Users/you/plans"
}
}
}
}
Enable the server under Settings → MCP if Cursor doesn't pick it up automatically.
Other MCP clients (generic stdio)
Any client that can spawn a stdio MCP server — Grok Build, OpenHands, a custom agent on the MCP SDK — needs three things:
- Command:
uvx --from git+https://github.com/ContractorKeith/conmcp.git conmcp serve(orconmcp serveif you installed it on PATH, oruv run --directory /path/to/conmcp conmcp servefrom a clone) - Transport: stdio (that's what
conmcp servespeaks) - Environment:
CONMCP_ALLOWED_DIRS=/path/to/your/plans
For example, with the Python MCP SDK:
from mcp import StdioServerParameters
server = StdioServerParameters(
command="uvx",
args=["--from", "git+https://github.com/ContractorKeith/conmcp.git", "conmcp", "serve"],
env={"CONMCP_ALLOWED_DIRS": "/Users/you/plans"},
)
Optional environment variables
Set these in the same env block if you need them:
| Variable | Default | What it does |
|---|---|---|
CONMCP_ALLOWED_DIRS |
server working directory | Colon-separated list of directories the server may read/write. Set it. |
CONMCP_MAX_RENDER_DPI |
300 |
Hard cap on render_page resolution. |
CONMCP_MAX_PAGES_PER_CALL |
20 |
Max pages one extract_quantities call scans. |
CONMCP_AUDIT |
on | Set to off to disable the file-access audit log. |
CONMCP_AUDIT_LOG |
~/.conmcp/audit.jsonl |
Where the audit log is written. |
Smoke test
Whichever client you use, this prompt should exercise the whole loop (adjust the path to
wherever you ran conmcp sample):
Call get_plan_overview on /Users/you/plans/sample_plan.pdf and tell me what sheets are in it.
If the client reports a sandbox error, your CONMCP_ALLOWED_DIRS doesn't cover the PDF's
folder — fix the env block and restart the client.