Org Mcp について
org-mcp は、Org-mode 向けに MCP サーバーを実装する Emacs パッケージです。AI アシスタントや他の MCP クライアントが、構造化された API を通じて Org ファイルを読み取り、編集できます。Org ファイルでメモやタスクを管理する Emacs ユーザーを対象としています。アクセスは設定で許可したファイルに限定されます。
主な機能
- 01URI による生のファイル内容とアウトラインの取得
- 02ID または見出しパスによる特定ノードへのアクセス
- 03TODO キーワードとタグ設定の照会
- 04許可ファイルとカスタムアジェンダコマンドの一覧表示
- 05許可ファイル設定によるアクセス制限
活用シーン
- 01AI アシスタントによる Org ファイルのタスクと見出し構造の確認
- 02MCP クライアントからの TODO 状態とアジェンダコマンドの照会
- 03Emacs 内の Org ノートへの LLM による制御されたアクセス
MCP 対応
本プロジェクトは MCP サーバーであり、Org ファイルの内容と構造を リソース(org://、org-outline://、org-headline://、org-id://)として公開し、設定の照会や書き込み操作のためのツールを提供します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
インストール方法は未掲載です
このサーバーのパッケージやリモートエンドポイントはまだ取得できていません。プロジェクトの README の手順に従ってください。
ツール
ツール一覧はまだ取得されていません
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
README(原文)English
プロジェクトの README よりこの README の日本語訳はまだありません。以下は英語の原文です。日本語の紹介はページ上部をご覧ください。
#+TITLE: org-mcp
[[https://github.com/laurynas-biveinis/org-mcp/actions/workflows/elisp-test.yml][https://github.com/laurynas-biveinis/org-mcp/actions/workflows/elisp-test.yml/badge.svg]]
[[https://github.com/laurynas-biveinis/org-mcp/actions/workflows/super-linter.yml][https://github.com/laurynas-biveinis/org-mcp/actions/workflows/super-linter.yml/badge.svg]]
[[https://melpa.org/#/org-mcp][https://melpa.org/packages/org-mcp-badge.svg]]
[[https://stable.melpa.org/#/org-mcp][file:https://stable.melpa.org/packages/org-mcp-badge.svg]]
* Overview
org-mcp is an Emacs package that implements a Model Context Protocol (MCP) server for Org-mode. It enables AI assistants and other MCP clients to interact with your Org files through a structured API.
* Installation
From [[https://melpa.org/#/org-mcp][MELPA]] or [[https://stable.melpa.org/#/org-mcp][MELPA Stable]]:
=M-x package-install RET org-mcp RET=
See [[file:NEWS][NEWS]] for the changelog.
* Usage
*WARNING:* some of the tools in this package give LLMs WRITE access to your Org
files, and, once in a thousand invocations, LLMs *will* try to delete everything,
because they are like that. Backups and automatic versioning on every change are
strongly advised.
** Configuring allowed files
Once you read and internalized the warning above, set the allowed Org file set, using
absolute paths:
#+begin_src emacs-lisp
(setq org-mcp-allowed-files '("/path/to/foo.org" "/path/to/bar.org"))
#+end_src
** Registering with an MCP Client
After =mcp-server-lib= has been properly installed (including =M-x mcp-server-lib-install=), register =org-mcp= with your MCP client:
#+begin_src bash
claude mcp add -s user -t stdio org-mcp -- ~/.emacs.d/emacs-mcp-stdio.sh --server-id=org-mcp --init-function=org-mcp-enable --stop-function=org-mcp-disable
#+end_src
Before using the MCP server, you must start it in Emacs with =M-x mcp-server-lib-start=. Stop it with =M-x mcp-server-lib-stop= when done.
** Available MCP Resources
*Note:* File paths in URIs use minimal encoding (only =#= characters are encoded). Avoid using =%= characters in Org file names.
*** org://{filename}
- *Description:* Access the raw content of an allowed Org file
- *URI Pattern:* =org://{filename}= where filename is the absolute path to the file
- *Configuration:* Files must be explicitly allowed via =org-mcp-allowed-files= using absolute paths
- *Returns:* Plain text content of the Org file
- *Buffer behavior:* Reads the file from disk; unsaved changes in an Emacs buffer visiting the file are not reflected.
*** org-outline://{filename}
- *Description:* Get the hierarchical structure of an Org file
- *URI Pattern:* =org-outline://{filename}= where filename is the absolute path to the file
- *Configuration:* Files must be explicitly allowed via =org-mcp-allowed-files= using absolute paths
- *Returns:* JSON representation of the document structure, up to two levels deep (level-3 and deeper headings are omitted). Each node carries =title=, =level=, and =children=, plus the headline's =todo= (state string, or =null= when none), =priority= (single-letter string, or =null= when no =[#x]= cookie), local =tags= (array of the headline's own tags, =[]= when none — inherited tags are not included), =scheduled= and =deadline= (raw timestamp strings, or =null=), and =uri= (=org-id://= when the headline has an =ID= property, =org-headline://= otherwise).
- *Buffer behavior:* Reads the file from disk; unsaved changes in an Emacs buffer visiting the file are not reflected.
Example:
#+begin_example
# Access via MCP:
URI: org-outline:///home/user/org/projects.org
Returns: JSON structure like:
{
"headings": [
{
"title": "Project Alpha",
"todo": "TODO",
"priority": "A",
"tags": ["work"],
"scheduled": null,
"deadline": null,
"uri": "org-headline:///home/user/org/projects.org#Project%20Alpha",
"level": 1,
"children": [
{
"title": "Requirements",
"todo": null,
"priority": null,
"tags": [],
"scheduled": "<2026-06-25 Thu>",
"deadline": null,
"uri": "org-headline:///home/user/org/projects.org#Project%20Alpha/Requirements",
"level": 2,
"children": []
}
]
}
]
}
#+end_example
*** org-headline://{filename}#{path}
- *Description:* Access the content of a specific headline by its path
- *URI Pattern:* =org-headline://{filename}#{path}= where:
- =filename= is the absolute path (with # encoded as %23)
- =path= is URL-encoded headline titles separated by =/=
- Headlines containing # must be encoded as %23 in the path
- Trailing =/= on =filename= and empty =#= fragments are stripped (=FILE=, =FILE/=, =FILE#=, and =FILE/#= all resolve identically)
- *Configuration:* Files must be explicitly allowed via =org-mcp-allowed-files= using absolute paths
- *Returns:* With a headline path: JSON object with =headline_path= — the ancestor chain from the outermost ancestor to the read headline itself, in the same node shape as =org-grep='s =headline_path= (see below) — and =content=, the text of the headline section including all subheadings. With no fragment: the entire file as plain text.
- *Buffer behavior:* Reads the file from disk; unsaved changes in an Emacs buffer visiting the file are not reflected.
Example:
#+begin_example
# Access a headline:
URI: org-headline:///home/user/org/projects.org#Project%20Alpha/Requirements
Returns: JSON with headline_path and content of "Requirements" under "Project Alpha"
# Headline with # character (must be encoded as %23):
URI: org-headline:///home/user/org/projects.org#Issue%20%2342
Returns: JSON with headline_path and content of the "Issue #42" headline
# Access entire file (no fragment):
URI: org-headline:///home/user/org/projects.org
Returns: Full content of the file as plain text
# File with # in the name (must be encoded as %23):
URI: org-headline:///home/user/org/file%231.org#Headline
Returns: JSON for "Headline" from file#1.org
# Both file and headline with # (all encoded):
URI: org-headline:///home/user/org/file%231.org#Task%20%235
Returns: JSON for "Task #5" from file#1.org
#+end_example
*Encoding limitations:* File paths use minimal encoding (only =#= → =%23=) for readability.
Files with =%= characters in their names should be avoided, as they may cause decoding issues.
For such files, rename them or use =org-id://= URIs instead. Headline paths use full URL
encoding.
*** org-id URI Format
- *Description:* Access Org node content by its unique ID property
- *URI Pattern:* =org-id://{uuid}= where uuid is the value of an ID property
- *Configuration:* The file containing the ID must be in =org-mcp-allowed-files=
- *Returns:* JSON object with =headline_path= (the ancestor chain in =org-grep='s node shape, ending with this headline itself) and =content= (text of the headline with the specified ID, including all subheadings)
- *Buffer behavior:* Reads the file from disk; unsaved changes in an Emacs buffer visiting the file are not reflected.
Example:
#+begin_example
# Org file with ID property:
,* Project Meeting Notes
:PROPERTIES:
:ID: 550e8400-e29b-41d4-a716-446655440000
:END:
Meeting content here...
#+end_example
Access via MCP:
- URI: =org-id://550e8400-e29b-41d4-a716-446655440000=
- Returns: Content of "Project Meeting Notes" section
** Available MCP Tools
Note: All write tools will create Org IDs for any touched nodes that did not have
them originally. The IDs will be returned in the tool response.
Note: Full semantics for each tool live in its MCP =description= string,
surfaced by clients via =tools/list=; the summaries below mirror those
descriptions.
*** org-get-todo-config
- *Description:* Get TODO keyword configuration for understanding task states
- *Parameters:* None
- *Returns:* JSON object with =sequences= and =semantics=
Example response:
#+begin_example
{
"sequences": [
{
"type": "sequence",
"keywords": ["TODO", "NEXT", "|", "DONE", "CANCELLED"]
}
],
"semantics": [
{"state": "TODO", "isFinal": false, "sequenceType": "sequence"},
{"state": "NEXT", "isFinal": false, "sequenceType": "sequence"},
{"state": "DONE", "isFinal": true, "sequenceType": "sequence"},
{"state": "CANCELLED", "isFinal": true, "sequenceType": "sequence"}
]
}
#+end_example
*** org-get-tag-config
- *Description:* Get tag configuration as literal Elisp variable values
- *Parameters:* None
- *Returns:* JSON object with literal Elisp strings for all tag-related variables
Example return value:
#+begin_example
{
"org-use-tag-inheritance": "t",
"org-tags-exclude-from-inheritance": "(\"urgent\")",
"org-tag-alist": "((\"work\" . 119) (\"urgent\" . 117) (:startgroup) (\"@office\" . 111) (\"@home\" . 104) (\"@errand\" . 101) (:endgroup) (:startgrouptag) (\"project\") (:grouptags) (\"proj_a\") (\"proj_b\") (:endgrouptag))",
"org-tag-persistent-alist": "nil"
}
#+end_example
*** org-get-allowed-files
- *Description:* Get the list of Org files accessible through the org-mcp server
- *Parameters:* None
- *Returns:* JSON object with =files= array containing absolute paths of allowed Org files
Use cases:
- Discovery: "What Org files can I access through MCP?"
- URI Construction: "I need to build an org-headline:// URI - what's the exact path?"
- Access Troubleshooting: "Why is my file access failing?"
- Configuration Verification: "Did my org-mcp-allowed-files setting work correctly?"
Example response:
#+begin_example
{
"files": [
"/home/user/org/tasks.org",
"/home/user/org/projects.org",
"/home/user/notes/daily.org"
]
}
#+end_example
Empty configuration returns:
#+begin_example
{
"files": []
}
#+end_example
*** org-get-agenda-config
- *Description:* List the custom agenda commands defined in
=org-agenda-custom-commands=. A runnable key can be passed as
=org-get-agenda='s =view=.
- *Parameters:* None
- *Returns:* JSON object with a =commands= array, one entry per
=org-agenda-custom-commands= definition:
- =key=: the command's dispatch key string
- =description=: the command's description
- =type=: the command's kind, one of =prefix= (a bare key group), =agenda=,
=agenda*=, =todo=, =todo-tree=, =alltodo=, =tags=, =tags-todo=,
=tags-tree=, =search=, =occur-tree=, =stuck=, =composite= (a multi-block
command), or =function= (a user function)
- =raw=: present only for =function= entries — the entry's literal Elisp, as
a fallback for a client that wants to inspect it
- *Note:* =type= is reported as a fact and does not promise runnability.
Example response:
#+begin_example
{
"commands": [
{"key": "p", "description": "Projects", "type": "tags-todo"},
{"key": "n", "description": "Next actions", "type": "todo"},
{"key": "h", "description": "Home", "type": "prefix"},
{"key": "r", "description": "Weekly review", "type": "composite"},
{"key": "x", "description": "Custom", "type": "function",
"raw": "(\"x\" \"Custom\" my-agenda-fn)"}
]
}
#+end_example
*** org-get-agenda
- *Description:* Run an Org agenda view and return both its plain text and its
entries as structured data. The view is either a builtin span (=day=, =week=,
=month=, aligned with =org-agenda-day-view=, =org-agenda-week-view=, and
=org-agenda-month-view=) or a dispatch key from =org-agenda-custom-commands=.
- *Parameters:*
- =view= (string, required): =day=, =week=, or =month= (case-insensitive,
reserved for the builtin spans), or any dispatch key defined in
=org-agenda-custom-commands= (discover keys with =org-get-agenda-config=)
- =date= (string, optional): Any string =org-read-date= accepts; omit to use
today (an empty or whitespace-only string is rejected). Fixes which day /
week / calendar month the agenda covers. How unrecognized input is treated
follows your installed Org version. Applies only to the day/week/month
spans; every custom-command view ignores it (a custom agenda block always
anchors on today).
- *Scope:* The agenda is built only from =org-mcp-allowed-files= entries that
exist on disk. It does not pull in other =org-agenda-files= the user may have
configured in Emacs. *Caveat:* a custom command whose own settings set
=org-agenda-files= or a restriction can override this and escape the
allow-list.
- *Returns:* JSON with:
- =view=: the span name or the custom dispatch key you passed
- =date=: your string, or the literal =today= if omitted
- =start_day=: for a span, the first day the agenda covers, as =YYYY-MM-DD=
(resolved; a month snapped to the first of the calendar month, a week
aligned per your =org-agenda-start-on-weekday= — the reference day itself
when that is nil); =null= for a non-dated custom view
- =agenda=: the full agenda buffer text, unchanged — including any lines
(diary, clock, informational) that have no source heading
- =blocks=: array of agenda blocks (one for a span view — its items may be
empty; several for a composite custom command). Each block has
=header= (the block's header line, or
=null=) and =items= (array of entry nodes — =title=, =todo=, =priority=,
=tags=, =scheduled=, =deadline=, =uri=, the same node shape =org-grep=
emits). A heading appears at most once per block — a multi-day span entry
the text shows on several days is a single item. Agenda lines with no
source heading appear only in =agenda= text, not in =items=.
- *Prompting commands:* A custom command that prompts for input (a =tags= or
=search= command with no baked-in match, or a bare prefix key) cannot run
non-interactively and is rejected with an error.
*** org-grep
- *Description:* Search for a literal substring across one or all allowed Org files
- *Parameters:*
- =pattern= (string, required): Literal substring to search for. Must be non-empty and single-line (no newlines). Not a regex.
- =file= (string, optional): Absolute path to an allowed Org file. When omitted, all =org-mcp-allowed-files= are searched.
- =case_sensitive= (boolean, optional, default =false=): When =true=, the match is case-sensitive.
- *Returns:* JSON object with a =groups= array. Each group represents a contiguous run of matching lines within one section:
- =file=: absolute path of the source file
- =headline_path=: array of node objects tracing the path to the containing section, from the outermost ancestor to the section's own headline (empty array for content before the first heading). Each object has =title=, =todo= (state string or =null=), =priority= (single-letter string or =null=), local =tags= (array of the headline's own tags, =[]= when none), =scheduled= and =deadline= (raw timestamp strings or =null=), and =uri= (=org-id://= or =org-headline://=). The last entry's =uri= equals the group =uri= below.
- =uri=: resource URI — =org-id://= when the section has an ID, =org-headline://= otherwise. Pass directly to =resources/read=. To use the read tools instead, extract the =uuid= (for =org-read-by-id=) or the file and fragment path (for =org-read-headline=) from the URI.
- =matches=: array of ={line, text}= objects — =line= is the 1-based line number, =text= is the full line content
- *Group rules:* Groups appear in document order, per file in =org-mcp-allowed-files= order. A new group starts whenever the containing section changes. One match per source line.
- *Configuration:* Searched files must be in =org-mcp-allowed-files=. Returns ={"groups": []}= when no files are configured and no =file= is given.
- *Buffer behavior:* Reads files from disk; unsaved changes in Emacs buffers are not reflected.
*** org-find-tagged-ancestor
- *Description:* Find the nearest enclosing headline that carries a given tag as its own (local) tag
- *Parameters:*
- =uri= (string, required): URI of the headline to start from (supports =org-headline://= or =org-id://=); must identify a headline, not a whole file
- =tag= (string, required): Single tag name to look for (non-empty)
- =include_self= (boolean, optional, default =false=): When =true=, the headline at =uri= is checked before its ancestors
- *Returns:* JSON object with a single =found= key: the node object of the nearest self-or-ancestor headline whose own tag list contains =tag= — same node shape as =org-grep='s =headline_path= entries (=title=, =todo=, =priority=, =tags=, =scheduled=, =deadline=, =uri=; =org-id://= when the headline has an ID, =org-headline://= otherwise) — or =null= when no enclosing headline declares the tag
- *Semantics:* Each level is tested against its local tags only. Tags a headline merely inherits from an ancestor or from =#+FILETAGS= never match (a tag declared only in =#+FILETAGS= has no declaring headline, so the result is =null=), and =org-tags-exclude-from-inheritance= is deliberately ignored. Under Org's default tag inheritance, a non-null result with =include_self= set to =true= means the headline carries the tag.
- *Configuration:* File must be in =org-mcp-allowed-files=
- *Buffer behavior:* Reads the file from disk; unsaved changes in an Emacs buffer visiting the file are not reflected.
*** org-update-todo-state
- *Description:* Update the TODO state of a specific headline
- *Parameters:*
- =uri= (string, required): URI of the headline (supports =org-headline://= or =org-id://=)
- =current_state= (string, required): Current TODO state (empty string "" for no state) - must match actual state
- =new_state= (string, required): New TODO state (must be valid in org-todo-keywords, or empty string "" to clear to no keyword)
- *Returns:* Success status with previous and new states, and ID-based URI of the updated headline. =new_state= is the actual resulting state, which may differ from the request (e.g. a repeating entry marked done is reset to its not-done keyword)
- *Buffer behavior:* Modifies the file on disk; fails if an Emacs buffer visiting the file has unsaved changes; ask the user to save the buffer and retry.
- *Blocked transitions:* If a member of =org-blocker-hook= (e.g. a TODO-dependency or unchecked-checkbox blocker) vetoes the change, the tool returns an error and leaves the file unchanged, rather than reporting success.
Example:
#+begin_example
# Request:
{
"uri": "org-headline:///home/user/org/projects.org/Project%20Alpha",
"current_state": "TODO",
"new_state": "IN-PROGRESS"
}
# Success response:
{
"success": true,
"previous_state": "TODO",
"new_state": "IN-PROGRESS",
"uri": "org-id://554A22F6-E29F-4759-8AD2-E7CA225C6397"
}
# State mismatch error:
{
"error": "State mismatch: expected TODO, found IN-PROGRESS"
}
#+end_example
*** org-edit-headline
- *Description:* Edit an existing headline's title and/or local tags, preserving its TODO state, planning, properties, and body
- *Parameters:*
- =uri= (string, required): URI of the headline (supports =org-headline://= or =org-id://=)
- =current_title= (string, required): Current headline title (without TODO state or tags) - must match actual title
- =new_title= (string, optional): New headline title (without TODO state or tags)
- =add_tags= (string or array, optional): Local tags to add (e.g., "@office" or ["work", "urgent"])
- =remove_tags= (string or array, optional): Local tags to remove
- At least one of =new_title=, =add_tags=, =remove_tags= must be supplied; a tag cannot appear in both =add_tags= and =remove_tags=
- *Returns:* The updated node: =success=, =title=, =todo=, =priority=, =tags= (resulting local tags), =scheduled=, =deadline=, =uri=
- *Buffer behavior:* Modifies the file on disk; fails if an Emacs buffer visiting the file has unsaved changes; ask the user to save the buffer and retry.
- *Tag semantics:*
- Tag edits are a delta over the headline's *own (local)* tags and are idempotent: adding a present tag or removing an absent one is a no-op.
- =add_tags= are validated against the globally configured =org-tag-alist= / =org-tag-persistent-alist= (rejected if unknown); a file's own =#+TAGS:= additions are *not* honored, so a file-local tag not in the global alist is rejected. =remove_tags= accept any syntactically valid tag so a tag no longer in the alist can still be dropped.
- Local tags only: an *inherited* tag (e.g. one applied by a container heading or =#+FILETAGS=) cannot be shed here; move the headline out of the tagged subtree with =org-refile-headline= instead.
- Mutual-exclusion groups are not auto-enforced across the resulting set (adding a group member to a headline that already carries another keeps both); swap within a group by passing the old tag in =remove_tags= and the new one in =add_tags= in the same call. A single =add_tags= list may not itself contain two members of the same group.
- Adding or removing the =crypt= tag changes only the tag; it does not trigger org-crypt encryption or decryption.
Example:
#+begin_example
# Request (swap context tag and retitle in one call):
{
"uri": "org-headline:///home/user/org/projects.org/Buy%20milk",
"current_title": "Buy milk",
"new_title": "Buy oat milk",
"add_tags": ["@office"],
"remove_tags": ["@home"]
}
# Success response:
{
"success": true,
"title": "Buy oat milk",
"todo": "TODO",
"priority": null,
"tags": ["@office"],
"scheduled": null,
"deadline": null,
"uri": "org-id://550e8400-e29b-41d4-a716-446655440002"
}
# Title mismatch error:
{
"error": "Title mismatch: expected 'Original Task', found 'Different Task'"
}
#+end_example
*** org-add-todo
# Canonical references for the tool contract: per-parameter semantics
# live in the `MCP Parameters:' section of `org-mcp--tool-add-todo''s
# docstring (parsed by mcp-server-lib into the tool's input schema);
# tool-level overview, return shape, and positioning behavior live in
# the `:description' string registered for the tool, both in
# org-mcp.el. Summaries below; keep parameter names/types in sync.
- *Description:* Add a new TODO item to an Org file
- *Parameters:*
- =title= (string, required): The headline text
- =todo_state= (string, required): TODO state from =org-todo-keywords=, or empty string "" for a headline with no keyword
- =tags= (string or array, required): Tags to add (e.g., "urgent" or ["work", "urgent"])
- =body= (string, optional): Body text content to add under the heading
- =parent_uri= (string, required): URI of parent item. Use =org-headline://filename.org/= for top-level items in a file (also accepted: =org-headline://filename.org=, =org-headline://filename.org#=, =org-headline://filename.org/#= — not recommended).
- =after_uri= (string, optional): URI of sibling to insert after; omit to append as last child. Cannot be combined with a top-level =parent_uri= or with =position=, and cannot reference =parent_uri= itself. See the MCP tool description for accepted formats.
- =position= (string, optional): Where to place the new item: ="start"= or ="end"= (default ="end"=). At top level, ="start"= inserts after leading =#=-prefixed lines and drawers, before the first existing heading. See the MCP tool description for full placement rules and the mutex with =after_uri=.
- *Returns:* Object with success status, new item URI, file name, and title
- *Buffer behavior:* Modifies the file on disk; fails if an Emacs buffer visiting the file has unsaved changes; ask the user to save the buffer and retry.
Example:
#+begin_example
# Request:
{
"title": "Implement new feature",
"todo_state": "TODO",
"tags": ["work", "urgent"],
"body": "This feature needs to be completed by end of week.",
"parent_uri": "org-headline:///home/user/org/projects.org/"
}
# Success response:
{
"success": true,
"uri": "org-id://550e8400-e29b-41d4-a716-446655440001",
"file": "projects.org",
"title": "Implement new feature"
}
#+end_example
*** org-edit-body
- *Description:* Edit body content of an Org node using partial string replacement
- *Parameters:*
- =resource_uri= (string, required): URI of the node to edit (supports =org-headline://= or =org-id://=)
- =old_body= (string, required): Substring to search for within the node's body (must be unique unless replace_all is true). Use empty string "" to add content to an empty node
- =new_body= (string, required): Replacement text
- =replace_all= (boolean, optional): Replace all occurrences (default: false)
- *Returns:* Success status with ID-based URI of the updated node
- *Special behavior:* When =old_body= is an empty string (""), the tool will only work if the node has no body content, allowing you to add initial content to empty nodes
- *Buffer behavior:* Modifies the file on disk; fails if an Emacs buffer visiting the file has unsaved changes; ask the user to save the buffer and retry.
Example:
#+begin_example
# Request:
{
"resource_uri": "org-id://abc-123",
"old_body": "This is a placeholder.",
"new_body": "Implementation started - using Strategy pattern."
}
# Success response:
{
"success": true,
"uri": "org-id://abc-123"
}
# Adding content to empty node:
{
"resource_uri": "org-id://new-task",
"old_body": "",
"new_body": "Initial task description."
}
#+end_example
*** org-set-planning
- *Description:* Set, change, or clear a headline's =SCHEDULED= and/or =DEADLINE= planning timestamps
- *Parameters:*
- =uri= (string, required): URI of the headline (supports =org-headline://= or =org-id://=)
- =scheduled= (string, optional): Timestamp content to schedule, as written inside =<...>=: a date, optional time-of-day, and optional repeater/warning cookies. Examples: =2026-06-20=, =2026-06-20 14:00=, =+1w= (one week from today), =2026-06-20 +1w -3d=. The first whitespace token is the date (so a lone =+1w= is a relative date, not a repeater); trailing =+N=, =++N=, =.+N= (with unit =h/d/w/m/y=, optionally with a =/M= habit interval) set a repeater and =-N= sets a warning period
- =deadline= (string, optional): Same grammar as =scheduled=, for the =DEADLINE= timestamp
- =clear_scheduled= (boolean, optional): Remove the =SCHEDULED= entry (default: false)
- =clear_deadline= (boolean, optional): Remove the =DEADLINE= entry (default: false)
- *Returns:* Success status, the resulting =scheduled= and =deadline= timestamp strings (=null= when absent), and the ID-based URI of the headline
- *Constraints:* At least one of =scheduled=, =deadline=, =clear_scheduled=, =clear_deadline= must be provided. A field and its =clear_*= cannot be combined, and an empty =scheduled=/=deadline= string is rejected (use =clear_*= to remove)
- *Repeater/warning handling:* Org produces the relative-date resolution, weekday names, and planning-line placement. When re-scheduling, omitting cookies preserves an existing repeater/warning; including any cookie replaces the field's existing cookies
- *Buffer behavior:* Modifies the file on disk; fails if an Emacs buffer visiting the file has unsaved changes; ask the user to save the buffer and retry.
Example:
#+begin_example
# Request (schedule with a weekly repeater, set a deadline):
{
"uri": "org-id://abc-123",
"scheduled": "2026-06-20 +1w",
"deadline": "2026-06-25"
}
# Success response:
{
"success": true,
"scheduled": "<2026-06-20 Sat +1w>",
"deadline": "<2026-06-25 Thu>",
"uri": "org-id://abc-123"
}
# Clear the scheduled date:
{
"uri": "org-id://abc-123",
"clear_scheduled": true
}
# Success response (SCHEDULED removed; DEADLINE retained):
{
"success": true,
"scheduled": null,
"deadline": "<2026-06-25 Thu>",
"uri": "org-id://abc-123"
}
#+end_example
*** org-archive-subtree
- *Description:* Archive an Org headline subtree to its configured archive location
- *Parameters:*
- =uri= (string, required): URI of the headline to archive (supports =org-headline://= or =org-id://=)
- *Returns:* Success status, the absolute archive file path, and the archived headline's =org-id://= URI. The archive file path equals the source file's own path when the archive location is in-file (empty file part before =::=)
- *URI resolvability:* The returned =org-id://= URI identifies the archived headline but is resolvable via =resources/read= only if the archive file is itself a member of =org-mcp-allowed-files=; otherwise it is informational only
- *Archive location:* Honors the headline's =ARCHIVE= property, then the file's =#+ARCHIVE:= setting, then the global =org-archive-location=, in that order. The subtree is always moved to that archive file regardless of =org-archive-default-command=.
- *Buffer behavior:* Modifies the source and archive files on disk; fails if an Emacs buffer visiting either has unsaved changes; ask the user to save the buffer and retry.
Example:
#+begin_example
# Request (headline lacks an ID; the tool mints one):
{
"uri": "org-headline:///home/user/org/projects.org#Project%20Alpha/Old%20Task"
}
# Success response (returns the freshly minted org-id:// URI):
{
"success": true,
"archive_file": "/home/user/org/projects.org_archive",
"uri": "org-id://550e8400-e29b-41d4-a716-446655440003"
}
#+end_example
*** org-refile-headline
# Canonical references for the tool contract: per-parameter semantics
# live in the `MCP Parameters:' section of
# `org-mcp--tool-refile-headline''s docstring (parsed by mcp-server-lib
# into the tool's input schema); tool-level overview, return shape, and
# positioning behavior live in the `:description' string registered for
# the tool, both in org-mcp.el. Summaries below; keep parameter
# names/types in sync.
- *Description:* Move an existing headline and its entire subtree to a new parent or file, preserving its TODO state, tags, properties, ID, body, and child structure
- *Parameters:*
- =uri= (string, required): URI of the headline to move (supports =org-headline://= or =org-id://=); must identify a headline, not a whole file
- =current_title= (string, required): Current headline title (without TODO state or tags) - must match actual title
- =target_parent_uri= (string, required): URI of the new parent. Use =org-headline://filename.org/= for a top-level destination, or a headline / =org-id://= URI to move under that node. Same shape as =org-add-todo='s =parent_uri=.
- =after_uri= (string, optional): URI of sibling to place after; omit to append as last child. Cannot be combined with a top-level =target_parent_uri= or with =position=, and cannot reference =uri= itself. See the MCP tool description for accepted formats.
- =position= (string, optional): Where to place among the target's children: ="start"= or ="end"= (default ="end"=). Mutually exclusive with =after_uri=.
- *Returns:* Object with success status, the moved node's =org-id://= URI, title, and source and target file names
- *Source and target files:* Both must be members of =org-mcp-allowed-files=. The existing ID is preserved, including across files.
- *Rejected moves:* Moving a node into itself or its own subtree is rejected.
- *No-op:* When the node already sits in the requested place (same parent and slot) and already has an ID, the file is left untouched.
- *Buffer behavior:* Modifies the source file, and the target file when different, on disk; fails if an Emacs buffer visiting either has unsaved changes; ask the user to save the buffer and retry.
Example:
#+begin_example
# Request (move an inbox item under a project, given by the project's ID):
{
"uri": "org-headline:///home/user/org/inbox.org#Buy%20milk",
"current_title": "Buy milk",
"target_parent_uri": "org-id://550e8400-e29b-41d4-a716-446655440000"
}
# Success response (the moved headline lacked an ID; the tool mints one):
{
"success": true,
"uri": "org-id://550e8400-e29b-41d4-a716-446655440099",
"title": "Buy milk",
"source_file": "inbox.org",
"target_file": "projects.org"
}
#+end_example
** Workaround Tools Duplicating Resource Templates
*Note:* The following tools are temporary workarounds that duplicate the resource template functionality as tools. They exist because Claude Code currently doesn't discover resource templates.
*** org-read-file
- *Description:* Read complete raw content of an Org file
- *Parameters:*
- =file= (string, required): Absolute path to an Org file
- *Returns:* Plain text content of the entire Org file
- *Configuration:* File must be in =org-mcp-allowed-files=
- *Buffer behavior:* Reads the file from disk; unsaved changes in an Emacs buffer visiting the file are not reflected.
*** org-read-outline
- *Description:* Get hierarchical structure of an Org file as JSON outline
- *Parameters:*
- =file= (string, required): Absolute path to an Org file
- *Returns:* JSON object with hierarchical outline structure. See the =org-outline://= resource above for the per-node fields (=title=, =todo=, =priority=, =tags=, =scheduled=, =deadline=, =uri=, =level=, =children=).
- *Configuration:* File must be in =org-mcp-allowed-files=
- *Buffer behavior:* Reads the file from disk; unsaved changes in an Emacs buffer visiting the file are not reflected.
*** org-read-headline
- *Description:* Read specific Org headline by hierarchical path
- *Parameters:*
- =file= (string, required): Absolute path to an Org file
- =headline_path= (string, required): Non-empty slash-separated path to headline. Only slashes within headline titles must be URL-encoded as =%2F= to distinguish them from path separators. Other characters (spaces, =#=, etc.) do not need encoding. To read entire files, use =org-read-file= instead
- *Returns:* JSON object with =headline_path= — array of node objects from the outermost ancestor to the read headline itself, in the same node shape as =org-grep='s =headline_path= (=title=, =todo=, =priority=, =tags=, =scheduled=, =deadline=, =uri=) — and =content=, the text of the headline and its subtree
- *Configuration:* File must be in =org-mcp-allowed-files=
- *Buffer behavior:* Reads the file from disk; unsaved changes in an Emacs buffer visiting the file are not reflected.
*** org-read-by-id
- *Description:* Read Org headline by its unique ID property
- *Parameters:*
- =uuid= (string, required): UUID from headline's ID property
- *Returns:* JSON object with =headline_path= and =content=, same shape as =org-read-headline=
- *Configuration:* File containing the ID must be in =org-mcp-allowed-files=
- *Note:* More stable than path-based access since IDs don't change when headlines are renamed or moved
- *Buffer behavior:* Reads the file from disk; unsaved changes in an Emacs buffer visiting the file are not reflected.
* License
This project is licensed under the GNU General Public License v3.0 (GPLv3) - see the LICENSE file for details.コメント
Markdown 対応
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。