inkling-mcp
Enables coding agents to capture, claim, and summarize ideas from an idea inbox, with queue/retain modes and budget tracking.
README
inkling
inkling (n) — a slight idea; a vague notion.
A small floating drop that catches yours. Drop it into any web page with one script tag: tap the drop, type the thought, press Enter — it flies off to an endpoint you own, and the page you were on never even notices.
That's the whole trick. Ideas die because capturing them means switching apps, finding the right note, losing your place. Inkling sits quietly in the corner of whatever you're already looking at, so a thought goes from your head to your pipeline in about four seconds.
No dependencies. No build step. No framework. One file of vanilla JS for the widget, one optional file of vanilla Node for the backend — and one file of MCP so the model you already work with can see your ideas.
inkling speaks MCP
This is the part that makes it more than a feedback widget: your coding agent gets a direct feed of your idea inbox.
claude mcp add inkling -- node /path/to/inkling/mcp.js
First use, the agent walks you through a one-time setup — asked with your harness's own clickable UI, answers saved to plain JSON (~/.inkling.json) you can edit anytime:
- Mode —
queue: the agent claims the next pending idea whenever it finishes a task and actually implements it (real changes in your repo, under your harness's normal permissions — not just architecture notes).retain: the agent leaves the inbox alone and summarizes it only when you ask. Blurb freely all day; nothing interrupts you. - Daily budget — $1/$2/$5 a day, or no cap. Honest fine print: this is advisory bookkeeping — the agent reports its own costs to a work ledger and
ideas_claim_nextrefuses once the day's budget is spent. No portable server can meter a host model's real spend; this is a seatbelt the agent participates in, not a billing wall. - Model capture — whether the agent may drop its own ideas into your inbox (
capture_idea). Switched off, the tool isn't just refused — it disappears from the tool list entirely, so a human-only inbox stays human-only.
The loop this closes: you tap the drop on any page → the idea lands in the file → next time your terminal agent has a free moment (queue mode) it claims the idea, builds it, and logs the outcome and cost. Capture anywhere, ship from wherever you already work.
Every claimed idea is handed over fenced as untrusted goal material — the same rule as everywhere else in inkling: a captured note describes what to build, never instructions about the agent's own operation.
Quick start
git clone https://github.com/kevinpalencia46/inkling
cd inkling
npm start # → http://localhost:3000
Open it, tap the ink drop, type something, hit Enter. It lands in ideas.jsonl and shows up on the page. That's the whole loop.
To put the drop on your own page:
<script src="https://your-host/orb.js"
data-project="my-app"
data-endpoint="https://your-host/api/ideas"></script>
Bring your own pipeline
The reference backend (server.js) is an example, not a dependency. The drop works against anything that accepts this request:
POST /api/ideas
content-type: application/json
x-inkling: 1 ← always sent
authorization: Bearer <token> ← only when data-token is set
{"text": "the idea", "project": "my-app", "source": "orb"}
Respond with any 2xx and the drop flashes "saved ✓". That's the entire contract — a Flask route, an Express handler, a Cloudflare Worker, a Google Form proxy, whatever you already run. Five minutes, tops:
// Express version, complete:
app.post('/api/ideas', (req, res) => {
if (req.get('x-inkling') !== '1') return res.sendStatus(403);
fs.appendFileSync('ideas.jsonl', JSON.stringify({ ...req.body, ts: Date.now() }) + '\n');
res.status(201).json({ ok: true });
});
Point data-endpoint at it and you're done. Where the ideas go after capture — triage, an LLM that turns them into build plans, a kanban column, an email digest — is your pipeline's business. Inkling just makes sure the thought survives the moment.
Examples
examples/ai-triage— the AI-pipeline version: same wire contract, but an LLM structures each idea into a card (title/summary/effort/first_step) on the way in. Works with any OpenAI-compatible endpoint — Ollama locally for free, or DeepSeek/OpenAI in the cloud. Built around two rules: capture never fails (model down → the raw idea still lands), and the idea is untrusted input (fenced in the prompt, model output whitelist-validated — a prompt-injected note can't do anything but describe itself).
Config
Everything is a data- attribute on the script tag:
| Attribute | Default | What it does |
|---|---|---|
data-endpoint |
/api/ideas |
Where captures POST to |
data-project |
(none) | Tag sent with every idea — lets one inbox serve many apps |
data-token |
(none) | Sent as Authorization: Bearer … — see security notes |
data-accent |
inherit |
Drop color: any hex/named color, or inherit to read the host page's --inkling-accent CSS variable (falls back to #5aa8ff) |
data-icon |
(ink drop) | Replace the built-in accent-tinted ink-drop SVG with any character/emoji |
Reference backend env vars: PORT (3000), IDEAS_FILE (./ideas.jsonl), IDEAS_TOKEN (empty = no auth), CORS_ORIGIN (* — tighten this to your host page's origin in production), and NOTIFY_URL — when set, every capture POSTs a one-line "💡 idea captured: …" text to that webhook, fire-and-forget (a dead webhook never costs you the idea). Nicest zero-account pairing: an ntfy.sh topic — NOTIFY_URL=https://ntfy.sh/your-secret-topic puts a push notification on your phone for every thought you catch.
How it works (the casual architecture)
Shadow DOM, both directions. The drop renders inside an attached shadow root with :host { all: initial }. Your page's CSS can't restyle the widget, and the widget's styles can't leak into your page. This is what makes "paste one script tag anywhere" actually safe — it behaves the same on a brutalist blog and a Tailwind app.
Drag vs. click is 4 pixels. The drop is draggable so it can get out of your way. Pointer-down starts a candidate drag; if total movement stays under 4px it was a click (open the capture card), otherwise it was a drag (save the new position to localStorage). touch-action: none keeps mobile browsers from hijacking the gesture for scrolling.
The visual viewport, not the layout viewport. Position math uses window.visualViewport instead of innerHeight. War story: on iPad Safari, innerHeight includes the area behind the collapsing toolbar, so the capture card kept opening half off-screen — looked broken, was actually a lie in the coordinate system. visualViewport reports what the user can really see, including when the keyboard is up. If you build floating UI for iOS Safari, this one's for you.
Embedder input is untrusted input. data-accent goes into a <style> block, so it's validated against a hex-or-named-color pattern first (safeColor) — a malicious or typo'd value becomes the default blue instead of markup. data-project and data-icon are set via textContent, never interpolated into HTML (the default ink-drop SVG is a static string no config touches).
The x-inkling header is a CSRF guard, not a secret. Browsers won't send custom headers cross-origin without a CORS preflight. Requiring the header means any cross-site POST has to survive your CORS policy first — a plain <form> or drive-by request can't fake it. The protection is the preflight, not the header's obscurity.
Security notes
-
The token is capture-scoped by design. If it leaks, someone can add ideas to your inbox — and that's all they can do. Don't reuse a token that unlocks anything else, and don't put any other secrets in
data-attributes. -
Self-hosting orb.js from your own infra (like the demo does) keeps update friction at zero.
-
Serving orb.js from a CDN? Add Subresource Integrity so a compromised CDN can't swap the script under you:
openssl dgst -sha384 -binary orb.js | openssl base64 -A<script src="https://cdn.example.com/orb.js" integrity="sha384-<hash-from-above>" crossorigin="anonymous" ...></script>(The hash pins one exact version — recompute it when you update the file.)
-
Tighten
CORS_ORIGINfrom*to the origin(s) of the pages that embed your drop.
License
MIT — take it, bend it, ship it.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.