Skip to main content

Reusable utility methods for MCP servers

Project description

mcp-methods

Shared Rust-powered utilities for MCP servers. Pip-installable Python library AND a native Rust crate — they're the same set of primitives reachable through whichever interface fits your project. Fast file search, GitHub integration, text compaction, and an rmcp-backed MCP server framework. The common building blocks needed when writing MCP tool servers.

The Rust library is the source of truth; the Python wheel is a thin PyO3 binding over it. Rust consumers see zero Python in their dep tree.

Install — Python

pip install mcp-methods
from mcp_methods import ElementCache, ripgrep, list_dir, github_issues, read_file, html_to_text

Single abi3 wheel per OS — works on Python 3.10 through 3.13 without reinstall.

Install — Rust library

[dependencies]
mcp-methods = "0.3"
use mcp_methods::cache::ElementCache;
use mcp_methods::{github, files, grep, list_dir, compact, html};
use mcp_methods::server::{McpServer, ServerOptions, Manifest}; // with default `server` feature

Zero pyo3 in the dep tree. The server feature (default-on) adds the rmcp-backed framework; disable with default-features = false for the bare primitives.

Install — mcp-server CLI

cargo install mcp-server

Generic MCP server binary that loads YAML manifests and serves the protocol over stdio. Separate crate; not bundled in the Python wheel.

Local development

make dev           # build + install editable wheel
make test          # python tests
make test-rust     # rust library tests
make test-rust-all # all workspace tests

What's included

Function Purpose
list_dir Tree-formatted directory listing with depth control, glob filtering, .gitignore support, dir summaries, and annotation callback
ripgrep_files Ripgrep-powered file search with parallel walking, early termination, context lines, and multiple output modes
ripgrep Drop-in replacement for the Claude Code Grep tool interface
read_file Safe file reading with path traversal protection and line range support
github_discussions Fetch a single issue/PR with smart compaction, or list issues/PRs with filters
git_api GitHub REST API wrapper with token auth
has_git_token Returns whether a usable GITHUB_TOKEN is reachable (used for honest tool listing)
ElementCache Drill-down cache for collapsed elements (code blocks, comments, patches, thread segments) in GitHub discussions
html_to_text Lightweight HTML → plain-text converter (markdown-flavoured)
ripgrep_lines Search through text lines with context window merging
ripgrep_json_fields Extract fields from JSON text
compact_discussion / compact_text / collapse_code_blocks Text compaction utilities
extract_github_refs Parse GitHub issue/PR references from text
detect_git_repo / validate_repo Git repository detection and validation
mcp_methods.fastmcp Composable tool registrations for FastMCP servers — see below

Python API

list_dir(path, *, depth=1, glob=None, dirs_only=False, relative_to=None, respect_gitignore=True, skip_dirs=None, include_size=False, annotate=None)

Tree-formatted directory listing.

from mcp_methods import list_dir

# Basic tree
tree = list_dir("/project/src", depth=2, glob="*.py", relative_to="/project")

# With annotation callback (e.g. loc from knowledge graph)
def get_loc(rel_path):
    node = graph.get_file(rel_path)
    return f"({node.loc} loc)" if node else None

tree = list_dir("/project/src", depth=2, annotate=get_loc)
# src/
# ├── main.py        (144 loc)
# ├── utils.py       (28 loc)
# └── models/
#     ├── user.py    (89 loc)
#     └── post.py    (112 loc)

ripgrep(pattern, *, path=".", glob="*", type=None, output_mode="files_with_matches", max_results=None, offset=0, ...)

Claude Code Grep-compatible interface.

from mcp_methods import ripgrep

results = ripgrep(r"def \w+", path="/project", type="py", max_results=50)

ripgrep_files(source_dirs, pattern, *, glob="*", type_filter=None, output_mode="content", max_results=None, offset=0, match_limit=None, relative_to=None, ...)

Full interface with multi-directory search. max_results limits output entries, match_limit caps the search engine for early termination.

from mcp_methods import ripgrep_files

results = ripgrep_files(
    ["/project"],
    r"def \w+",
    type_filter="py",
    relative_to="/project",
    match_limit=500,
    max_results=100,
)

github_discussions(*, repo=None, number=None, kind="all", state="open", sort="created", limit=20, labels=None)

Fetch a single discussion or list discussions.

from mcp_methods import github_discussions, ElementCache

# List open issues
issues = github_discussions(repo="owner/repo", kind="issue", state="open")

# List pull requests
prs = github_discussions(repo="owner/repo", kind="pr", limit=10)

# Fetch a single issue/PR with smart compaction
issue = github_discussions(repo="owner/repo", number=123)

ElementCache — progressive disclosure for GitHub discussions

Cache for drill-down into collapsed elements. Fetches a discussion once, then lets you explore code blocks, comments, and PR diffs without re-fetching.

from mcp_methods import ElementCache

cache = ElementCache()

# First call fetches from GitHub API, compacts, and caches elements
text = cache.fetch_issue("owner/repo", 123)

# Subsequent calls return cached summary (no network)
summary = cache.fetch_issue("owner/repo", 123)
# → "Cached owner/repo#123 — 5 elements available: cb_1, comment_2, patch_1, patch_2, patch_3"

# Force re-fetch when the issue has changed upstream
text = cache.fetch_issue("owner/repo", 123, refresh=True)

# Drill into a collapsed code block
code = cache.retrieve("owner/repo", 123, "cb_1")

# Drill into a PR patch with grep
result = cache.retrieve("owner/repo", 123, "patch_1", grep="error_handler")

# Drill into a patch with line range
result = cache.retrieve("owner/repo", 123, "patch_2", lines="10-30")

# List available elements
ids = cache.available("owner/repo", 123)

PR diffs are automatically collapsed into patch_N elements in the compact view. Each patch stores the filename, additions/deletions, and full diff text — supporting grep and line-range drill-down.

Large discussions (50+ comments) are automatically digested: first 5 + maintainer highlights + last 5 comments shown inline, with the full middle cached as individual comment_N elements and a searchable comments_middle segment.

git_api(repo, path, *, truncate_at=80000)

GitHub REST API wrapper. For comparing branches/tags, use compare:

from mcp_methods import git_api

# Compare two refs
diff = git_api("owner/repo", "compare/main...feature-branch")

# List commits
commits = git_api("owner/repo", "commits?per_page=10")

read_file(path, allowed_dirs, *, offset=0, limit=0, max_chars=0, transform=None)

Safe file reading with path traversal protection.

from mcp_methods import read_file

content = read_file("src/main.py", ["/project"])

mcp_methods.fastmcp — drop-in tools for FastMCP servers

If you're running your own FastMCP server but want the same tool surface the bundled mcp-server binary ships (source navigation, graph overview, Cypher with CSV export, save_graph), import these helpers and register them on your app:

from mcp.server.fastmcp import FastMCP
from mcp_methods.fastmcp import (
    register_overview,
    register_cypher_query,
    register_source_tools,
    register_save_graph,
    serve_csv_via_http,
)

app = FastMCP("My Server")
register_overview(app, graph, overview_prefix="My custom guidance")
register_cypher_query(app, graph, csv_dir="temp/")
register_source_tools(app, source_roots=["./source"])
register_save_graph(app, graph)
_server, base_url = serve_csv_via_http("temp/")  # optional CORS-enabled HTTP server
app.run(transport="stdio")

Each helper is a thin (~10-line) wrapper over the existing Rust PyO3 surface — there's no logic duplication between the YAML-driven binary and these helpers, so agent behaviour is identical regardless of which path booted the server. graph is any object exposing describe() / cypher() / save(); kglite's KnowledgeGraph satisfies it. A runnable end-to-end stub lives at examples/fastmcp_demo.py.

Deployment — mcp-server CLI

Get the binary via crates.io:

cargo install mcp-server
# → ~/.cargo/bin/mcp-server

Generic MCP server, domain-agnostic: source tools + GitHub access + a manifest-driven tool surface. Reads YAML manifests and serves the MCP protocol over stdio.

Downstream Rust crates (e.g. kglite-mcp-server) depend on mcp-methods directly and re-use mcp_methods::server::McpServer::new(...) to layer domain-specific tools on top while reusing the boot sequence, .env loading, workspace mode, and watch mode.

Cargo features

Feature What it enables Default
server The MCP server framework: rmcp + tokio + clap + manifest + tool routing + the mcp_methods::server module tree. on

PyO3 bindings live in a separate crate (mcp-methods-py) and are only built by maturin for the Python wheel — they don't live in mcp-methods's source or dep tree. cargo add mcp-methods is zero-Python:

# Pure-Rust framework (default):
mcp-methods = "0.3"

# Just the primitives — no rmcp / tokio:
mcp-methods = { version = "0.3", default-features = false }

Operating modes (set via CLI flag or the YAML manifest)

Mode How to set When to use
bare no flag testing the protocol layer in isolation
source-root --source-root DIR or YAML source_root: fixed local directory; no clone
workspace (github) --workspace DIR clone-and-track GitHub repos
workspace (local) YAML workspace: { kind: local, root: ..., watch: ... } fixed local dir + optional file watcher; alternative to the legacy code_review server
watch --watch DIR rebuild downstream artifacts on file changes

YAML manifest declarations win over CLI flags when both are set (same precedence rule as source_root:).

Architecture

All heavy lifting is in Rust (PyO3/maturin), compiled to a native Python extension:

  • grep: Uses grep-regex, grep-searcher, and ignore crates directly (not a ripgrep subprocess). Parallel file walking with per-thread searcher reuse, mmap, SIMD literal optimization, and .gitignore support.
  • GitHub: HTTP via ureq, JSON processing via serde_json, text compaction in Rust. PR diffs are collapsed into cacheable elements for progressive disclosure.
  • File I/O: Path validation and traversal protection in Rust.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

mcp_methods-0.3.28-cp310-abi3-win_amd64.whl (2.7 MB view details)

Uploaded CPython 3.10+Windows x86-64

mcp_methods-0.3.28-cp310-abi3-manylinux_2_39_x86_64.whl (3.2 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.39+ x86-64

mcp_methods-0.3.28-cp310-abi3-macosx_11_0_arm64.whl (2.8 MB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

File details

Details for the file mcp_methods-0.3.28-cp310-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for mcp_methods-0.3.28-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 5f44b145cd6fe97bc2de2c5cc5c868d5fc89c89ed72669441deff4cec09d8642
MD5 ddb66b40fdf0c7ead08b8b2379db6ee1
BLAKE2b-256 1ebf362f429e42d3d28e785e417a6d655d2a36109c35f42666912bbcc13e48fb

See more details on using hashes here.

File details

Details for the file mcp_methods-0.3.28-cp310-abi3-manylinux_2_39_x86_64.whl.

File metadata

File hashes

Hashes for mcp_methods-0.3.28-cp310-abi3-manylinux_2_39_x86_64.whl
Algorithm Hash digest
SHA256 9dec854474b0fc398eb5b9ac16de2f5133ece2e3227a358f7136621a06d6be83
MD5 d049f1bd2cf26cd2d2a80982b5c330f3
BLAKE2b-256 3a5b71ca38fc254f30b523b3f54b7362d4c826e6eda79cd5efc244536ac28342

See more details on using hashes here.

File details

Details for the file mcp_methods-0.3.28-cp310-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for mcp_methods-0.3.28-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 708524315be83113694858c6b1a7f7db07f39c3cfb41a23b083e8e21cd94e396
MD5 8c0b573120eb277feaf90beae2ed443b
BLAKE2b-256 fae215060de7f4740bbc02fb6926de3693943e9f7ec527038b17fe70905a9f93

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page