streamable-httpupdated 2mo ago
A production-grade Model Context Protocol server in Python ā four LLM-callable tools, two transports, deployed two different ways.
What can you do with MCP Automations?
MCP Automations
A production-grade Model Context Protocol server in Python ā four LLM-callable tools, two transports, deployed two different ways.
| URL | |
|---|---|
| Source | https://github.com/wzltmp/mcp-automations |
| Playground (browser demo) | https://mcp-automations-5vgea2ynuyrvbzkcxm6yoh.streamlit.app/ |
| MCP HTTP server | https://mcp-automations.fly.dev/mcp |
# 30-second proof the server is up:
curl -X POST https://mcp-automations.fly.dev/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","method":"initialize","id":1,
"params":{"protocolVersion":"2024-11-05",
"capabilities":{},
"clientInfo":{"name":"curl","version":"1"}}}'
What this is
Most "AI engineer" portfolio projects are applications (a RAG chatbot, an agent that does research). This project is the layer underneath ā the typed tools an LLM can call and the transport plumbing that exposes them. MCP is the emerging standard for LLM tool use (~97M monthly SDK downloads as of early 2026); building one ā not just consuming one ā is the rare skill.
For a deeper look at the design decisions ā why two transports, how cost telemetry works, the exception hierarchy, what I'd do differently ā see WRITEUP.md.
Tools
| Tool | Model | What it does |
|---|---|---|
summarize_url(url, n_bullets) |
Haiku 4.5 | Fetch a page, extract clean text with trafilatura, return an N-bullet summary |
repurpose_content(text, format) |
Sonnet 4.6 | Turn long-form text into a twitter thread, linkedin post, or newsletter |
daily_digest(topic, n_results) |
Haiku 4.5 | Tavily news search + ~200-word digest with citations |
find_competitors(domain, n) |
Sonnet 4.6 | Identify N plausible competitors for a company by domain |
Plus one MCP resource (automations://catalog) and one MCP prompt (daily_brief) ā using all three MCP primitives, not just tools.
Every tool returns a typed Pydantic model with per-call token usage and dollar cost attached. Cheap tasks route to Haiku 4.5 ($1/M in, $5/M out), writing-heavy tasks to Sonnet 4.6 ($3/M in, $15/M out).
Connect Claude Desktop to this server
Add one of these to ~/Library/Application Support/Claude/claude_desktop_config.json (Mac) or %APPDATA%/Claude/claude_desktop_config.json (Windows), then restart Claude Desktop.
Option A ā local stdio (no network, runs the server as a subprocess):
{
"mcpServers": {
"mcp-automations": {
"command": "python",
"args": ["-m", "mcp_server.server"],
"cwd": "/absolute/path/to/mcp-automations",
"env": {
"ANTHROPIC_API_KEY": "sk-ant-...",
"TAVILY_API_KEY": "tvly-..."
}
}
}
}
Option B ā remote HTTP (talks to the live Fly server, no local setup):
{
"mcpServers": {
"mcp-automations": {
"url": "https://mcp-automations.fly.dev/mcp",
"transport": "http"
}
}
}
Then ask Claude something like "summarize https://www.paulgraham.com/greatwork.html in 3 bullets" ā it'll call summarize_url automatically.
Run locally
pip install -r requirements.txt
# Stdio (for Claude Desktop):
python -m mcp_server.server
# HTTP server (defaults to 0.0.0.0:8765):
MCP_TRANSPORT=http python -m mcp_server.server
# Streamlit playground:
streamlit run playground/app.py
Requires Python 3.13. Needs ANTHROPIC_API_KEY and TAVILY_API_KEY in .env (see .env.example).
Architecture
āāāāāāāāāāāāāāāāāā stdio āāāāāāāāāāāāāāāāāāāāāāāā
ā Claude Desktop āāāāāāāāāāāāāāāāāŗā ā
āāāāāāāāāāāāāāāāāā ā ā
ā mcp_server/ ā
āāāāāāāāāāāāāāāāāā HTTP/JSON ā server.py ā
ā Remote client āāāāāāāāāāāāāāāāāŗā (FastMCP) ā
āāāāāāāāāāāāāāāāāā (Fly.io) ā ā
ā 4 tools ā
āāāāāāāāāāāāāāāāāā direct call ā 1 resource ā
ā Streamlit UI āāāāāāāāāāāāāāāāāŗā 1 prompt ā
āāāāāāāāāāāāāāāāāā āāāāāāāāāāāā¬āāāāāāāāāāāā
ā
āāāāāāāāāāāā“āāāāāāāāāāāā
ā Anthropic + Tavily ā
ā (lazy clients) ā
āāāāāāāāāāāāāāāāāāāāāāāā
The same Python callables back all three entry points. The transport is just a wrapper.
What's in this repo
mcp-automations/
āāā mcp_server/
ā āāā server.py # FastMCP server: 4 tools + 1 resource + 1 prompt
ā āāā models.py # Pydantic I/O schemas (incl. per-call Cost telemetry)
ā āāā exceptions.py # MCPToolError + UpstreamAPIError / EmptyLLMResponseError / ExtractionError
āāā playground/
ā āāā app.py # Streamlit UI with per-session call + spend caps
āāā tests/ # offline unit tests (httpx/anthropic/tavily all mocked)
āāā Dockerfile # python:3.13-slim, MCP_TRANSPORT=http for Fly
āāā fly.toml # shared-cpu-1x, 256mb, auto-stop when idle
āāā .github/workflows/ # ruff + strict mypy + pytest on every push
Production touches worth noting
- Cost telemetry on every tool response (
models.Cost) ā token counts and USD attached so a client doesn't have to re-derive it. - Cost-aware model routing ā cheap tasks ā Haiku, writing tasks ā Sonnet.
- Domain-specific exception hierarchy ā
UpstreamAPIError,EmptyLLMResponseError,ExtractionErroreach route differently in logs and the Streamlit UI. - Two transports, one codebase ā
MCP_TRANSPORT=stdio|httpenv switch; HTTP host/port from env so the same image runs on Fly. - Per-session abuse caps in the playground ā 20 calls / $0.50 max per session; backed by a $2/mo hard cap on the Anthropic console.
- Strict mypy + ruff + pytest in CI on every push (
.github/workflows/ci.yml).
Why MCP
MCP is transport-agnostic, so one server serves both a local Claude Desktop user (stdio subprocess) and a hosted multi-tenant deployment (HTTPS). It also exposes three primitives that most demos skip:
- Tools ā functions the model decides to call (4 of them here)
- Resources ā read-only data the client can fetch by URI (
automations://catalogreturns the tool list as JSON) - Prompts ā server-side templates the user explicitly invokes (
daily_briefchainsdaily_digest+repurpose_content)
Using all three is a signal of reading the spec, not just a quickstart.
Status
ā
Code on GitHub, CI green
ā
Public playground on Streamlit Cloud
ā
Public MCP HTTP server on Fly.io
ā
Cost protection (per-session caps + monthly Anthropic cap)
ā
Real test coverage (23 offline unit tests)
ā
Listed on the Official MCP Registry as io.github.wzltmp/mcp-automations
ā
Long-form writeup of design decisions
ā
Consumed by another agent, not just demoed ā langgraph-research-agent's read_node calls this server's summarize_url tool over HTTP (with local fallback if the call fails)
š§ Demo gif + screenshots (planned)
š§ n8n self-host via docker-compose (planned)
License
MIT.
Install
Add MCP Automations to your client. Pick the one you use.
claude mcp add --transport http mcp-automations https://mcp-automations.fly.dev/mcpcodex mcp add mcp-automations --url https://mcp-automations.fly.dev/mcp{
"mcpServers": {
"mcp-automations": {
"url": "https://mcp-automations.fly.dev/mcp"
}
}
}Add to `~/.cursor/mcp.json`, or `.cursor/mcp.json` for a single project.
{
"servers": {
"mcp-automations": {
"type": "http",
"url": "https://mcp-automations.fly.dev/mcp"
}
}
}Add to `.vscode/mcp.json` in your workspace.
{
"mcpServers": {
"mcp-automations": {
"url": "https://mcp-automations.fly.dev/mcp"
}
}
}Add to `claude_desktop_config.json`, then restart Claude Desktop.
{
"mcpServers": {
"mcp-automations": {
"serverUrl": "https://mcp-automations.fly.dev/mcp"
}
}
}Add to `~/.codeium/windsurf/mcp_config.json`.
Score
39 / 100
Incomplete
- Documentation25/25
- Maintenance16/25
- Trust6/20
- Capability0/15
- Install experience12/15
- Documents what it does and how to connect
- Has a resolvable package or endpoint
- Exposes at least one tool, prompt or resource
- README has substantive content
- Includes a code example
- Documents its configuration
- Mentions credentials or security posture
- Last commit 59 days ago
- Has a release history
- Repository is not archived
- No licence detected
- Namespace verified in the official MCP registry
- Claimed by its owner
- Published under an organisation
- 0 tool(s) documented
- Provides prompt templates
- Provides resources
- 6 documented install method(s)
- Published to a package registry
- Offers a hosted endpoint ā no local install
Version history
| Versions | Published |
|---|---|
| 0.1.0Latest | May 28, 2026 |