MCP server that turns planning conversations into ordered feature plans
Project description
Planner API
HTTP wrapper over the personal-stack planner. Two modes: subscription (the host's
claude CLI thinks on a Claude subscription via CLAUDE_CODE_OAUTH_TOKEN, no API key)
or BYOK (the caller sends X-Anthropic-Key). A public deployment locks every
non-health endpoint behind a shared secret (X-Planner-Token).
Endpoints
GET /health— liveness. Always open (Railway healthcheck).POST /plan—{conversation, person}→ ordered, LLM-labeled, personalized plan withanalytics.planId. Auth:X-Planner-TokenifPLANNER_ACCESS_TOKENis set; LLM via the subscription (subscription mode) orX-Anthropic-Key(BYOK).POST /feedback—{person, plan_id, liked, comment?}→ records acceptance or dislike without changing weights.POST /correct—{person, plan_id?, corrected_plan? | corrected_order?, proposed_order?}→ tunes the layer preference immediately and banks decomposition ground truth. No key (offline).POST /analytics/event—{person, kind, payload}→ internal redirect events forplan.deliveredandinvoker.redirect.disabled.GET /analytics/{person}?limit=&kind=— reads recent unified analytics events. Drop-off isplan.deliveredwith no laterfeedback.*for the sameplanId.GET /profile/{person}— the person's current preference graph. No key.
Run locally
pip install -r service/requirements-service.txt
uvicorn service.app:app --reload
curl localhost:8000/health
curl -X POST localhost:8000/plan -H 'X-Anthropic-Key: sk-ant-...' \
-H 'content-type: application/json' \
-d '{"conversation":"...","person":"edbert"}'
Deploy (Railway, subscription mode, key-free)
The API runs on Railway at api.invoker-control.dev from service/Dockerfile,
which bakes in the claude CLI. The static landing page is a separate repo on
Vercel at invoker-control.dev (serverless is a poor fit for /plan — it makes
many sequential LLM calls and exceeds function time limits).
Railway auto-deploys on every push to main (GitHub integration). Set these env vars in Railway (never commit them):
ANALYTICS_ENABLED=1— mirrors local JSONL events to PostHog.ANALYTICS_VENDOR=posthog— the only outbound vendor currently supported.POSTHOG_PROJECT_TOKEN— PostHog project token (phc_...).POSTHOG_HOST=https://us.i.posthog.com— or your EU/self-hosted PostHog host.CLAUDE_CODE_OAUTH_TOKEN— fromclaude setup-token; lets the container'sclaudeCLI think on your Claude subscription, so no Anthropic API key is needed.PLANNER_SUBSCRIPTION_MODE=1—/planskips BYOK and uses that CLI.PLANNER_ACCESS_TOKEN— a shared secret; required asX-Planner-Tokenon every non-health endpoint so the public URL can't spend your subscription.
The MCP redirect (integrations/invoker_planner) defaults PLANNER_URL to
https://api.invoker-control.dev and forwards X-Planner-Token when
PLANNER_ACCESS_TOKEN is set in its env (see install.py --access-token).
BYOK still works: if PLANNER_SUBSCRIPTION_MODE is unset, /plan requires
X-Anthropic-Key and uses the caller's Anthropic API key instead.
Scaling later (subscription → API key)
The container is the unit of scale; Railway can run N replicas and autoscale on load (Railway → service → Settings → enable replicas/autoscaling). No code change.
The subscription path (CLAUDE_CODE_OAUTH_TOKEN + PLANNER_SUBSCRIPTION_MODE) is
for one person / low volume — a Max plan has rate limits and isn't meant to back a
multi-user service, so it won't scale to many concurrent users. To scale for real users:
- In Railway, remove
PLANNER_SUBSCRIPTION_MODE(andCLAUDE_CODE_OAUTH_TOKEN). - Either set a server-side
ANTHROPIC_API_KEY(metered, you pay), or have each caller send their ownX-Anthropic-Key(BYOK —complete_jsonalready prefers the request-scoped key). KeepPLANNER_ACCESS_TOKENas the endpoint lock either way. - Then turn up Railway autoscaling; each request is metered per token, so it scales cleanly.
How the key flows (security)
X-Anthropic-Key → set on a request-scoped contextvar in _byok → read by
registry/.../llm.py::complete_json for that request's Anthropic calls → reset in
a finally. It is excluded from the disk cache (cache key = model+prompt only)
and never logged.
Not yet (next milestones)
- State → managed Postgres + real auth. Profiles/learned/corrections are still
file-based here, keyed by
person. For multi-user production this must move to a per-user database (also where the moat lives). - Rate limiting / quotas, accounts, the frontend.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file drafter_mcp-0.1.0.tar.gz.
File metadata
- Download URL: drafter_mcp-0.1.0.tar.gz
- Upload date:
- Size: 50.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
594327c3b42ed7104e460bc4f414baa90b1540aff7c9c9fd1051666af4f1abe8
|
|
| MD5 |
27ef9918cba739e813f65647c2f0a8f1
|
|
| BLAKE2b-256 |
1b29611dbab932a869192389707d394e5b10bb58a7d4466c791a61e1053d7e22
|
Provenance
The following attestation bundles were made for drafter_mcp-0.1.0.tar.gz:
Publisher:
publish-python.yml on Neko-Catpital-Labs/Drafter
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
drafter_mcp-0.1.0.tar.gz -
Subject digest:
594327c3b42ed7104e460bc4f414baa90b1540aff7c9c9fd1051666af4f1abe8 - Sigstore transparency entry: 2094359589
- Sigstore integration time:
-
Permalink:
Neko-Catpital-Labs/Drafter@c81aa62ff97d95d59d1f6fcfc50e5565e526b285 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Neko-Catpital-Labs
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-python.yml@c81aa62ff97d95d59d1f6fcfc50e5565e526b285 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file drafter_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: drafter_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 66.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
84841768e78d5e8b52a6779c6e216f0ce56cc15d7b4b8f28bbc304d098214008
|
|
| MD5 |
d8302d638d208e7ad2e41fd289a69840
|
|
| BLAKE2b-256 |
def893f021ee731ca833584a0d9c71c2362bdbc1cde9c6b75c00fb5fa84efb73
|
Provenance
The following attestation bundles were made for drafter_mcp-0.1.0-py3-none-any.whl:
Publisher:
publish-python.yml on Neko-Catpital-Labs/Drafter
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
drafter_mcp-0.1.0-py3-none-any.whl -
Subject digest:
84841768e78d5e8b52a6779c6e216f0ce56cc15d7b4b8f28bbc304d098214008 - Sigstore transparency entry: 2094359973
- Sigstore integration time:
-
Permalink:
Neko-Catpital-Labs/Drafter@c81aa62ff97d95d59d1f6fcfc50e5565e526b285 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Neko-Catpital-Labs
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-python.yml@c81aa62ff97d95d59d1f6fcfc50e5565e526b285 -
Trigger Event:
workflow_dispatch
-
Statement type: