Your backlog as plain Markdown, and your vault as an MCP server for Claude Code

If your planning happens in Markdown, you know the gap: a decision is written down in a meeting note, and tracking it means opening another tool and retyping it. With the Autoplans Obsidian plugin you sign in once, a project's task list becomes an ordinary note, a checklist line you add under it becomes a task on autoplans.dev, and any note can be pushed up as a task with one command. The same plugin can serve the vault over MCP on localhost, so a coding agent working the backlog can read the note the task came from. This post walks through each step and says what leaves your machine.
Install and sign in
Install with BRAT from mohamedgb00714/obsidian-autoplans, or copy main.js, manifest.json and styles.css from the latest release into <vault>/.obsidian/plugins/autoplans/; the plugin docs have the details. Sign-in is a browser round trip; a pasted key also works. Sign in with browser under Settings → Autoplans.dev opens autoplans.dev/auth/plugin with a one-time state value, you approve the connection, and the site mints an API key named "Obsidian plugin (<today's date>)" with the projects:read, projects:write, tasks:read and tasks:write scopes and hands it back through an obsidian://autoplans-auth link. The plugin ignores a callback whose state does not match, verifies the key with a tools/list request, and stores it in .obsidian/plugins/autoplans/data.json. A key made by hand under Settings → API keys on the dashboard goes in the API key field instead; scopes are explained in Accounts and API keys.
The MCP endpoint setting defaults to https://autoplans.dev/api/v1/mcp. Every project and task call the plugin makes is a JSON-RPC tools/call against that endpoint (key verification uses tools/list), sent through Obsidian's requestUrl with the key as a bearer token. Change it only for a self-hosted deployment; sign-in and error reporting follow the new origin.
Tasks into a note
Sync to note on a project in the side panel, or the Sync a project into the vault command, writes the project to Autoplans/<project name>.md. The folder is the Sync folder setting. The note is built from the live project on every sync:
---
autoplans_project_id: "1fb3fe7d-e3f9-4992-ae18-29b2bade4bd4"
title: "Billing rework"
status: "in_progress"
repo: "https://github.com/acme/billing"
tags: [autoplans]
---
# Billing rework
## Tasks
- [ ] Rotate the webhook secret _(pending, high)_ ^7a68cf19-c06d-4b0e-9d2a-3f1c2e5b8a41
The secret is in two places; consolidate before rotating.
- [x] Choose the payment provider _(completed, high)_ ^0bf0293d-e3f4-4c7a-8b1d-6e2f9a0c4d55
---
_Synced from [autoplans.dev](https://autoplans.dev). Edits here are not pushed back automatically._
A project description, when there is one, goes between the heading and ## Tasks. Three things in that file matter. autoplans_project_id in the frontmatter is how the plugin finds the note again, so you can move or rename it and the link survives. Each task is a standard - [ ] / - [x] checklist line: the checkbox mirrors the task's status, the italics carry status, priority, indented lines beneath it are the description, and the line ends with an Obsidian block reference, ^<task id>. That is plain Markdown: Dataview and the Tasks plugin read those lines the way they read any checklist, with no integration on either side. The block id also means [[Billing rework#^7a68cf19-…]] links to one task from anywhere in the vault.
A note written this way is a snapshot: the next sync replaces it. To keep it current, open Settings → Two-way sync and tick the project under Synced projects. From then on the note is re-rendered from the project on the Sync interval (five minutes by default, minimum one), the footer changes to say two-way sync is on, and Sync projects now (both ways) forces a round trip.
A note into a task
There are two ways up.
A checklist line in a synced note
For a project ticked under Synced projects, the plugin listens for the vault's modify event on that note and pushes 2.5 seconds after the last edit. It parses the lines between ## Tasks and the next ## heading or --- rule, which is why the footer sits behind one. A line that ends in a task id and whose checkbox disagrees with the server sets that task to completed or pending. A line with no id yet, because you typed - [ ] Rotate the webhook secret under the heading, becomes a create_task call with that title, and the plugin rewrites the line in place as - [ ] Rotate the webhook secret _(pending, medium)_ ^<new id> so it is tracked from then on. Nothing else on the note travels: titles, descriptions, priorities and ordering are the project's, and editing them in the note is undone by the next pull.
Any note, as a whole
The meeting-note case is the Push current note as a task command. It works on any open note, not only those in the sync folder. It strips the frontmatter, opens a project picker, and creates one task in the project you choose: the filename without .md becomes the title, the body becomes the description, cut at 5,000 characters, and the type is documentation. So a note called Rotate the webhook secret.md whose body reads "Decided in the 27 Aug billing sync; Sam owns it, before the provider switch" becomes a task with that title and that description. Name the note for the task you want, or write the decision as its own short note first. The command creates and does not update: running it twice makes two tasks, and no link is kept between the note and the task.
The vault as an MCP server for your coding agent
The task now exists, and an agent working the backlog through the Autoplans MCP server can pick it up. What it cannot do is read the meeting note the task came from. Settings → MCP server → Serve MCP from this vault covers that: it starts a Streamable HTTP endpoint at http://127.0.0.1:28765/mcp (the Port setting), bound to loopback only, behind a bearer token of 32 random bytes generated the first time you enable it. It is desktop only: it loads Node's http module at runtime, which Obsidian on mobile does not have.
Copy config puts the obsidian-vault entry below on the clipboard. For Claude Code, paste it inside the mcpServers object of .mcp.json in the repository root, or ~/.claude.json for every project, next to the Autoplans entry from the MCP server page:
{
"mcpServers": {
"autoplans": {
"type": "http",
"url": "https://autoplans.dev/api/v1/mcp",
"headers": { "Authorization": "Bearer apk_live_..." }
},
"obsidian-vault": {
"type": "http",
"url": "http://127.0.0.1:28765/mcp",
"headers": { "Authorization": "Bearer 9f1c…" }
}
}
}
The server answers initialize (protocol version 2025-03-26, server name autoplans-obsidian), ping, tools/list and tools/call; a GET gets 405 and bodies over 4 MB are rejected. A bare POST with the token is enough to try it:
curl -s http://127.0.0.1:28765/mcp \
-H 'Authorization: Bearer 9f1c…' \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"obsidian_search_notes","arguments":{"query":"webhook secret"}}}'
The result comes back as one text content item whose text is JSON: a count and a matches array of path and snippet. The server exposes eight tools:
obsidian_list_notes—folder?,limit?(default 200). Paths, sizes and modification times.obsidian_read_note—path. The note's text.obsidian_search_notes—query,limit?(default 20). Case-insensitive substring match over every note; the snippet is 60 characters either side of the first hit.obsidian_write_note—path,content. Creates or overwrites;.mdonly; parent folders are created.obsidian_append_note—path,content. Same rules, appended to the end; creates the note if it is missing.autoplans_list_projects— the account's projects.autoplans_sync_project_note—projectId. Writes or refreshes the project's note and returns its path.autoplans_push_note_as_task—path,projectId. The same filename-to-title, body-to-description rule as the command.
In a Claude Code session with both servers connected, "find the meeting note about the webhook secret and read it before starting the task" is an obsidian_search_notes call followed by obsidian_read_note, and "file the follow-ups from today's note as tasks" is autoplans_push_note_as_task. Regenerate token invalidates the old token; update .mcp.json after using it.
What stays local
Sent to the configured endpoint, always with your API key: the tool calls the plugin makes, which are list_projects, get_project, list_tasks, get_task (when you open a task in the map), create_task and update_task, plus a tools/list request when it verifies the key. Note contents reach autoplans.dev in three cases: you push a note as a task (its title and up to 5,000 characters of body, frontmatter removed), you add a checklist line to a synced note (its title), or an MCP client calls autoplans_push_note_as_task against the vault server. Ticking a box sends a status.
Never sent: everything else in the vault. The five obsidian_* tools read and write files locally and make no network call. The vault server binds 127.0.0.1, is off by default, and refuses every MCP request without the token. The key the browser flow mints does not carry ai:execute, the scope that gates /api/v1/chat/completions, the metered inference route; that scope goes only to the desktop, CLI, VS Code and Chrome keys, so the Obsidian key cannot call it.
Opt-in: Send error reports is off by default. When on, it posts the error message, stack trace and plugin version to /api/telemetry/report on the same origin as the endpoint, after stripping API keys, GitHub tokens, JWTs, bearer headers, e-mail addresses and home-directory paths. It never includes note contents.
The full command and settings reference is in the Obsidian plugin docs; the server-side tools are listed in MCP tools.
Tags
Ready to Transform Your Development Workflow?
Join developers who are building faster with AI-powered project management.
Get Started Free