Skip to main content
Glama
JuanCamiloMendoza99

mcp-document-chat

MCP Document Chat

A command-line chat client for Claude that reaches its capabilities through a Model Context Protocol server rather than hard-coded functions. The server exposes a document store over all three MCP primitives — tools, resources and prompts — and the CLI wires them into a tool-use loop, @-mention context injection and /-slash commands.

Built with FastMCP and the Anthropic Python SDK.

> /summarize deposition.md
> Tell me about @report.pdf and @plan.md
> Reformat @spec.txt as markdown

Why this exists

Most "chat with an LLM" samples bolt tools directly onto the model call. This one puts an MCP server in between, which is the part worth practising: the server is a separate process that could be swapped, reused by any MCP host (Claude Desktop, an IDE, another agent), and tested on its own.

Attribution

This started from the MCP project in Anthropic's Building with the Claude API course. To keep the record straight:

  • Provided by the course — the CLI shell (core/, main.py), packaging and the original README. The first commit in this repository is that scaffold, unmodified, so git log shows exactly what was given.

  • My work — the MCP server and client (mcp_server.py, mcp_client.py), which the exercise leaves as stubs, plus everything after: the FastMCP migration, the bug fixes described below, the test suite and the tooling.

Architecture

main.py                 wires config, clients and the CLI together
  core/cli.py           prompt-toolkit REPL, completion for / and @
  core/cli_chat.py      expands @mentions, dispatches /commands
  core/chat.py          the tool-use loop
  core/claude.py        Anthropic Messages API wrapper
  core/tools.py         collects MCP tools, executes tool_use blocks
  mcp_client.py         async MCP client over stdio
       |
       | stdio (JSON-RPC)
       v
  mcp_server.py         FastMCP server over the document store

The server exposes:

Primitive

Name

Purpose

Tool

read_doc_contents

Return a document's contents

Tool

edit_doc

Exact-match string replacement in a document

Resource

docs://documents

The document index

Resource

docs://documents/{doc_id}

A single document

Prompt

format

Rewrite a document as markdown

Prompt

summarize

Summarize a document in three sentences

Resources back the @-mention autocompletion, prompts back the /-commands, and tools are what Claude calls during the loop.

Setup

Requires Python 3.10+ and an Anthropic API key.

git clone <this-repo>
cd mcp-document-chat

cp .env.example .env      # then add your ANTHROPIC_API_KEY

uv sync                   # or: pip install -e .
uv run main.py            # or: python main.py

.env holds ANTHROPIC_API_KEY, CLAUDE_MODEL and USE_UV; see .env.example. .env is gitignored — do not commit a real key.

Usage

Input

Effect

plain text

Ordinary chat turn; Claude may call the MCP tools

@doc_id

Inlines that document's contents as context

/format <doc_id>

Runs the format prompt from the server

/summarize <doc_id>

Runs the summarize prompt from the server

Tab completes both document ids and command names. Ctrl+C or Ctrl+D exits.

Development

uv sync --all-groups
uv run pytest             # 27 tests, no network or API key needed
uv run ruff check .
uv run ruff format .

The server tests drive it through FastMCP's in-memory client transport, so the real MCP request path is exercised without spawning a subprocess.

Notes on the implementation

Beyond completing the stubs, working through this surfaced a handful of defects in the scaffold, each fixed in its own commit with a regression test:

  • Tool errors crashed the session. The handler for a failed tool call read a variable that only gets bound by the call that had just raised, so every transport failure surfaced as UnboundLocalError instead of being reported back to Claude.

  • A bare /format killed the REPL. The command parser indexed the argument without checking it was there, and the loop only caught KeyboardInterrupt.

  • Document completion never fired. The completer treated resource ids as dicts when they are strings, so its guard was silently false for every document — and would have raised TypeError for any id containing "id".

  • The format prompt was malformed. An unclosed <document_id tag, an instruction that trailed off mid-sentence, and a reference to an edit_document tool that is registered as edit_doc.

  • /summarize was documented but never implemented, so the first command a new user copied out of the README failed.

The server was also migrated from FastMCP 1.x (the snapshot vendored into the MCP Python SDK as mcp.server.fastmcp) to the standalone fastmcp package, including the move from Field() defaults to Annotated[str, Field(description=...)], which the FastMCP docs prefer.

-
license - not tested
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/JuanCamiloMendoza99/mcp-document-chat'

If you have feedback or need assistance with the MCP directory API, please join our Discord server