markdown-mcp
by Ilviann
README.md
# Markdown MCP
Markdown MCP is a small, dependency-free MCP server for reading and optionally
editing existing Markdown files beneath one configured root folder. It is
offline-first, uses newline-delimited JSON-RPC over stdio, and is suitable for
LM Studio and other MCP hosts.
Version: **0.1.0**. Python 3.10 or newer is required.
## Run from the repository
No installation or runtime download is needed:
```sh
python /path/to/markdown-mcp/server.py /path/to/markdown/root
```
The default is read-only. Add `--writable` to publish editing tools:
```sh
python /path/to/markdown-mcp/server.py /path/to/markdown/root --writable
```
The root is required and must already be a folder. There is no configuration
file, account, network access, telemetry, file creation, file deletion, or
directory-listing tool.
## Install the console command
The application has no runtime dependencies. Its build backend is pinned to
`setuptools==80.9.0`. For an offline installation, download that wheel on a
connected machine and copy the wheelhouse with the repository. Run these
commands from the repository root:
```sh
python -m pip download setuptools==80.9.0 -d wheelhouse
python -m pip install --no-index --find-links wheelhouse .
```
Then run `markdown-mcp ROOT [--writable]`.
## LM Studio configuration
Read-only example:
```json
{
"mcpServers": {
"markdown": {
"command": "python",
"args": [
"/absolute/path/to/markdown-mcp/server.py",
"/absolute/path/to/markdown/root"
]
}
}
}
```
Add `"--writable"` to the `args` array to enable edits. On Windows, JSON paths
may use forward slashes or escaped backslashes.
## Configuration helper
The local Tkinter helper generates copyable configuration with absolute paths.
Launch it from macOS or Linux with:
```sh
/path/to/markdown-mcp/scripts/generate_mcp_config.sh
```
On Windows, use:
```bat
C:\path\to\markdown-mcp\scripts\generate_mcp_config.cmd
```
Choose the existing Markdown root and leave editing disabled for read-only
access, or enable it to add `--writable`. The helper shows a complete LM Studio
`mcp.json` object and a Codex `[mcp_servers.markdown]` `config.toml` entry. Copy
and merge the applicable snippet into the host configuration. The helper never
writes or merges host configuration files.
## Tools
Read-only mode exposes:
- `read_markdown({"path": "guide.md#installation"})` reads a whole file, one
exact heading section, or leading front matter through `#---` or `#===`.
- `list_sections({"path": "guide.md", "max_level": 3})` returns
`has_front_matter` and a flat source-ordered list of heading levels, titles,
and anchors. `max_level` defaults to 3 and accepts 1 through 6.
Writable mode additionally exposes:
- `overwrite_section` preserves the selected heading and replaces its body and
descendants.
- `append_section` appends a level-1 section to a file or exactly one level
below a selected parent.
- `set_front_matter` adds, replaces, deletes, or idempotently leaves absent
leading front matter.
- `delete_section` deletes a selected heading, body, and descendants.
Mutation tools operate only on existing files. A tool omitted in read-only mode
is also rejected if called directly.
## Paths, fragments, and Markdown syntax
Paths may be root-relative or absolute. Absolute paths are only a convenience:
the resolved existing regular file must remain beneath the configured root.
Hidden and dot-prefixed folders are accessible when explicitly addressed.
Only `.md` and `.markdown` suffixes are accepted, without regard to suffix case.
Traversal and symbolic-link or junction escapes are rejected.
Only the final `#fragment` after a supported Markdown suffix is a selector, so
filenames such as `draft#notes.md` remain valid. Fragments are percent-decoded
once as strict UTF-8. Whitespace, controls, `/`, `\`, `#`, malformed escapes,
and empty fragments are rejected.
The parser recognizes level 1–6 ATX headings and level 1–2 Setext headings.
Heading-like text in leading front matter, fenced code, or indented code is
ignored. A section includes its heading, body, and descendants and stops before
the next heading at the same or a higher level.
Anchors approximate GitHub heading anchors without a Markdown dependency:
visible link text replaces inline links, HTML tags and backticks are removed,
HTML entities and backslash escapes are decoded, whitespace collapses, text is
lowercased, spaces become `-`, Unicode is retained, punctuation except `-` and
`_` is removed, and duplicate anchors receive `-1`, `-2`, and later suffixes.
Leading front matter must start on the first logical line after an optional
UTF-8 BOM. The exact opener must be `---` or `===`, and the closer must exactly
match it. Both selector aliases read either valid form. Malformed leading front
matter is never reinterpreted by a front-matter edit.
## Preservation and limits
Every source is decoded completely as strict UTF-8 before use. A leading UTF-8
BOM is omitted from logical tool text and preserved by edits. Unaffected source
text, newline style, final-newline behavior, and file mode are preserved. Writes
use a flushed and fsynced same-directory temporary file, repeat path and source
validation, then atomically replace the original. Failed writes remove their
temporary files.
Source files, edited files, and semantic tool results have a hard 256 KiB UTF-8
limit. Paths are limited to 4,096 characters and generated heading titles to
1,000 characters through MCP. NUL-containing paths or documents and invalid
UTF-8 are rejected with bounded errors.
Compact UTF-8 catalog measurements for 0.1.0 are 923 bytes for read-only mode
and 2,092 bytes for writable mode.
## Test
From the repository root:
```sh
python -m unittest discover -s tests -v
```
The suite covers parser and mutation behavior, path confinement, source and
result limits, atomic revalidation and cleanup, catalog filtering, LM
Studio-compatible framing, and strict UTF-8 stdio under an inherited ASCII
encoding.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues