The project's README from github.com/Cappybara12/mcp-use. As one markdown file: README.md.
A Python service (an article-research-and-drafting pipeline) called directly from a TypeScript dashboard and a Node script through Graftcode, with no REST layer: no FastAPI routes, no Pydantic DTOs, no hand-written fetch client.
Browser (React) ── generated Graft ── WebSocket ─┐
Node test script ─ generated Graft ──────────────┤
▼
Claude / Cursor ── MCP over HTTP ──────► Graftcode Gateway ─► ArticlePipelineService (Python)
:8080 ws · :8081 /mcp plain public methods
There is no HTTP adapter: the browser imports the generated Graft and talks to the Gateway directly. MCP is the Gateway's built-in endpoint, not a separate bridge.
It was built for Wayzyy's content engine. You do not need that pipeline to run this repo: without it the receiver runs in demo mode on bundled sample data.
Implementation video MCPUSE
The repository has one Python service and several ways to use it. The dashboard and Node client use the generated Graft over WebSocket; MCP-compatible clients use the Gateway's built-in HTTP endpoint. They all reach the same public Python methods.
flowchart LR
A[React dashboard] -->|generated Graft<br/>WebSocket :8080| G[Graftcode Gateway]
B[Node.js client] -->|generated Graft<br/>WebSocket :8080| G
C[Claude / Cursor] -->|MCP over HTTP<br/>/mcp :8081| G
G --> S[ArticlePipelineService<br/>plain Python methods]
S --> D[(Topics and drafts)]
S --> P[Optional real pipeline<br/>research, writing, publishing]
The important boundary is the Python service. The UI, scripts, and AI assistants are clients of the same service rather than separate copies of the content logic.
The demo models an editorial workflow from an idea to a reviewable change. Sources and rules inform the draft, while the human review step remains the publishing gate.
flowchart LR
I[Topic queue] --> R[RSS and web research]
I --> K[Keyword research]
R --> O[Outline]
K --> O
B[Existing blog] --> L[Style and rulebook]
L --> O
O --> W[Write draft]
W --> E[SEO and style checks]
E --> H{Human review}
H -->|needs changes| W
H -->|approved| PR[Stage GitHub PR]
H -->|approved| X[Optional publisher]
The bundled receiver runs this flow in demo mode with sample data. Attaching the real article pipeline replaces the sample sources and placeholder writer with the project's live research, LLM, and publishing integrations.
For the expanded diagrams and demo notes, see
docs/architecture.md.
| Method | With the real pipeline attached | Demo mode (default for new users) |
|---|---|---|
getPipelineStatus |
Real provider/queue status | Reports demo mode and sample counts |
listPendingTopics, getTopicSources |
Reads the scanner's review queue | Reads receiver/sample_data/review |
listDrafts, getDraft, saveDraft |
Reads/writes the writer's drafts | Reads/writes receiver/sample_data/drafts |
runStyleCheck |
Heuristic brand check on the draft text | Same |
suggestNextArticle |
Ranks the real queue (keyword tiers + source count) | Ranks the sample queue |
writeArticle |
Runs the full LLM research → outline → write pipeline | Writes a clearly labelled placeholder draft |
runScanner |
Runs the scanner project's main.py --scan |
Reports skipped (demo mode) |
pushToGithub |
Opens a real GitHub PR | Raises an error (needs the pipeline) |
Beyond the original demo, the dashboard includes a visual Pipeline Studio: build a content pipeline from steps (RSS, web research, learn-from-your-blog rules, keyword research, outline, write, SEO check, human review, Reddit ideas, GitHub pull request), run it and watch each step finish, plan content on a calendar by drag and drop, schedule drafts with a GitHub Action, and manage several blogs with their own API keys. It works offline out of the box. See STUDIO.md.
Open http://localhost:5173 after start.sh. It calls the Python receiver straight from the
browser through the generated Graft (WebSocket).
| Tab | What it exercises |
|---|---|
| Dashboard | getPipelineStatus, listPendingTopics, listDrafts, plus the live "Run topic scanner" and "Suggest next article" actions |
| Topic Queue | listPendingTopics, getTopicSources (the sources modal) |
| Draft Studio | getDraft, saveDraft, writeArticle (Auto-Pilot Draft), runStyleCheck, pushToGithub (Stage PR) |
| Style Auditor | Result of runStyleCheck |
| Architecture | Live benchmark of the same method through the Graft and through MCP, the live MCP tool list, and the known limits |
With the real pipeline attached, Auto-Pilot Draft calls LLM APIs, Scan for New Topics calls the search API, and Stage PR can open a real pull request. In demo mode none of these cost anything.
Screenshots are optional, but these four make the project easier to evaluate:
Place them in docs/images/ and redact API keys, personal access tokens, private URLs, and
unpublished customer content.
Client settings (optional): VITE_GRAFT_HOST (default ws://localhost:8080/ws) and
VITE_GRAFT_MCP_URL (default http://localhost:8081/mcp).
pip install -r receiver/requirements.txtgg): https://docs.graftcode.com/quick-startbash scripts/start.sh
This starts the gateway, installs the freshly generated graft package into test-client/
and ui/, runs the Node → Python test, and starts the dashboard at http://localhost:5173.
Graft Vision (the gateway's inspector) is at http://localhost:8081.
bash scripts/stop.sh # stop everything
bash scripts/start.sh --no-ui # skip the dashboard
Run the Python tests (they use demo mode and need no network or keys):
cd receiver && pip install pytest && python -m pytest
Everything niche-specific lives in a YAML file, so the same receiver, Graft, MCP tools and
dashboard can serve any blog. Copy receiver/config/wayzyy.yaml,
edit it, and point PIPELINE_CONFIG at it before starting:
PIPELINE_CONFIG=my-blog.yaml bash scripts/start.sh
| Section | What it controls |
|---|---|
brand |
Name and description (shown in the dashboard), the topic keyword the style check looks for, the fallback research prompt, and niche / offering / offering_plural, which the article pipeline uses in its prompts and closing call to action (set them, or a new niche inherits Wayzyy's) |
categories |
How queue topics are grouped (first matching keyword rule wins, else default) |
suggestion.tiers |
Which topic keywords the "suggest next article" ranking favours, highest priority first |
style |
Banned words and openers, the attribution keyword (for example a stock-photo site), the publish threshold |
data_dir |
Folder with review/ and drafts/ samples used in demo mode |
Keys you leave out fall back to the built-in defaults, and a malformed file stops startup with a
clear Config error message. A second, non-travel example is in
receiver/config/examples/saas/. Try it with no keys:
PIPELINE_CONFIG=receiver/config/examples/saas/config.yaml \
WAYZYY_WRITER_DIR=/nonexistent WAYZYY_SCANNER_DIR=/nonexistent bash scripts/start.sh
The editorial and editorial_rules sections also let a project owner control the quality
contract: minimum length, keyword frequency, required sections, source links, image attribution,
human review, tone, required elements, and banned phrases. These rules are injected into the
planner/writer prompts and enforced again by the receiver's style audit.
Pipeline Studio is designed for more than a single blog owner. A ghostwriter, agency, or in-house content team can use one workspace per client and keep that client's voice in the Rulebook, while reusing the same pipeline shape. Keyword research supports four practical modes:
The Keyword research settings let the user choose country and language, filter by search intent, set minimum volume or maximum difficulty, and exclude phrases such as a competitor, location, or irrelevant product. Provider intent is used when available; otherwise Studio makes a small, transparent phrase-based inference. The output reports how many candidates survived and adds the top ten to Content planner. The user then chooses the primary keyword before the outline and writing steps run.
For repeat work, save the configured keyword step or Rulebook as a workspace template. Templates can be exported and imported between client workspaces, but they contain no API keys. Keep the keys in Settings & keys. The Rulebook is the shared quality contract for every client: voice, length, headings, source requirements, FAQ, calls to action, and banned phrases are used in prompts and checked again by SEO. The intended daily flow is:
brief → keyword shortlist → primary keyword → topic → research → rulebook → outline → draft → SEO → human review → PR
This makes the project useful as a client-facing ghostwriting tool as well as a Wayzyy-specific content engine: a user can change the inputs and editorial rules without rewriting the receiver or the Graft/MCP integration.
The site publisher remains an adapter: agent/site_publisher.py currently targets Wayzyy's
React/TSX blog shape. To publish to another site, keep the receiver and editorial config but
replace that adapter for the target repository, then set PUBLISHER_MODULE and
PUBLISHER_FUNCTION in .env. The adapter should return the same fields (slug, branch,
commit_hash, files_modified, and message) so the dashboard can show the PR result.
If you cloned this as the graftcode/ folder of the mcp-use repo, the real pipeline is the
parent folder. Attach it with an absolute path (the gateway runs from a different working directory):
WAYZYY_WRITER_DIR="$(cd .. && pwd)" bash scripts/start.sh
Copy .env.example and export the variables you need, for example WAYZYY_WRITER_DIR,
WAYZYY_SCANNER_DIR and WAYZYY_SITE_DIR. The pipeline reads its own LLM and search keys
from its own .env; this repo never stores secrets.
The Gateway serves every public receiver method as an MCP tool at http://localhost:8081/mcp
(JSON-RPC over HTTP with an Mcp-Session-Id session). Check it from a terminal:
bash scripts/mcp-check.sh
Cursor (.cursor/mcp.json):
{ "mcpServers": { "graft-content-pipeline": { "url": "http://localhost:8081/mcp" } } }
Claude Desktop only speaks stdio, so bridge the endpoint with mcp-remote:
{
"mcpServers": {
"graft-content-pipeline": {
"command": "npx",
"args": ["-y", "mcp-remote", "http://localhost:8081/mcp"]
}
}
}
The Pipeline Studio adds studio_* tools; studio_write_article and studio_decide write and approve an article in
one call each (see STUDIO.md).
MCP tool names are the Python method names (suggest_next_article, write_article, ...). Results
come back as JSON text. The earlier hand-written FastMCP bridge is kept in legacy/ as a
"before" comparison only.
grep -rn "fetch(" ui/src only finds the MCP
client in ui/src/graft.ts; there are no route handlers anywhere in the repo.bash scripts/mcp-check.sh lists the Gateway's tools with no extra process running.receiver/article_receiver/service.py the Python receiver (plain class, public methods)
receiver/config/ default config and a non-travel example
receiver/sample_data/ demo-mode topics and drafts
receiver/tests/ pytest suite
scripts/ start.sh, stop.sh, run_gateway.sh, mcp-check.sh
test-client/ Node script calling the receiver through the graft
ui/ Vite + React dashboard (calls the Gateway directly)
legacy/ the superseded FastMCP bridge (comparison only)
start.sh reads them from the gateway log
and writes graft-package.json for the callers..., and symlinks that
resolve outside the drafts folder are rejected for every method that reads or writes a draft (regression
tests in receiver/tests/test_security.py). The gateway itself still has no authentication, so this
limits what a caller can reach but does not replace authentication.editorial.minimum_words, maximum_primary_keyword_uses,
required_sections, require_sources, require_image_attribution, and require_human_review
are project-level controls. They produce audit flags; a human still decides whether to publish.
Every point the audit deducts comes with a recommendation. The keyword-frequency limit applies only when a
draft records its own primary_keyword: in its front matter, because the audit cannot know it otherwise.http://localhost:5173 by default (GRAFT_CORS), has
no authentication (including on /mcp), and pushToGithub can open PRs when configured. Do not expose it publicly.Mcp-Session-Id
header. run_gateway.sh writes a CORS config for http://localhost:5173; if you serve the
dashboard from another origin, set GRAFT_CORS and restart.bash scripts/stop.sh, or change GRAFT_PORT, GRAFT_VISION_PORT.PY_HOME to your Python prefix
(for example the python.org framework build) and re-run.MIT. The Graftcode gateway (gg) and the generated Graft packages are
Graftcode's own software and are governed by their terms; this repository does not redistribute them.