Skip to main content
Glama

mcp-server-example — MCP-Server für eine Markdown-Notizdatenbank

Ein funktionsfähiger, getesteter Beispiel-MCP-Server (Model Context Protocol), der einem Assistenten Zugriff auf ein Second Brain gibt: ein lokales Verzeichnis mit Markdown-Notizen, das er erstellen, lesen, aktualisieren, auflisten, durchsuchen und messen kann.

Der Fokus liegt hier nicht auf der Menge der Funktionen, sondern darauf, einen ehrlichen MCP-Server zu zeigen: Schemas, die aus den Type Hints generiert werden, echte Sanitisierung gegen Path Traversal und eine Testsuite, die die Tools wirklich aufruft, statt den Aufruf zu simulieren.


Was ist MCP

Das Model Context Protocol ist ein offenes Protokoll, das standardisiert, wie ein Assistent mit externen Systemen kommuniziert. Statt dass jede Anwendung ihr eigenes Plugin-Format erfindet, deklariert der MCP-Server drei Dinge — Tools (Aktionen, die das Modell ausführen kann), Resources (Daten, die es lesen kann, adressiert per URI) und Prompts (Gesprächsvorlagen, die der Benutzer aufrufen kann) — und jeder kompatible Client entdeckt und nutzt all das von selbst. Die Kommunikation erfolgt über JSON-RPC, normalerweise über stdio: Der Client startet den Server als Subprozess und tauscht Nachrichten über die Standardeingabe und -ausgabe aus.


Related MCP server: Notes MCP Server

Was es hier gibt

Datei

Funktion

mcp_notas/server.py

Definiert den FastMCP-Server: Tools, Ressourcen, Prompts und die Pydantic-Ausgabemodelle.

mcp_notas/storage.py

Das gesamte Datei-I/O und die Sanitisierung von Bezeichnern. Einziger Punkt, der Pfade zusammensetzt.

mcp_notas/search.py

Textsuche mit Ranking nach Feld (Titel > Tags > Textkörper), akzentunabhängig.

mcp_notas/__main__.py

Einstiegspunkt für python3 -m mcp_notas.

tests/test_server.py

45 Tests, die den Server wirklich ausüben, einschließlich einer vollständigen MCP-Sitzung.

requirements.txt

Laufzeit- und Testabhängigkeiten.

pytest.ini

Konfiguration von pytest-asyncio.

Jede Notiz ist eine .md-Datei mit einem minimalen Front Matter:

---
title: Teste env
tags: []
created: 2026-08-25T00:20:24+00:00
updated: 2026-08-25T00:20:24+00:00
---

Was der Server bereitstellt

Tools

Tool

Argumente

Gibt zurück

criar_nota

titulo (erforderlich), corpo, tags, slug

Die erstellte Notiz mit ausgefüllten Daten.

ler_nota

slug

Die vollständige Notiz (Textkörper, Tags, Daten).

atualizar_nota

slug, corpo, titulo, tags, anexar

Die bereits aktualisierte Notiz.

apagar_nota

slug

Textbestätigung.

listar_notas

tag (optional)

Gesamtzahl und Zusammenfassung jeder Notiz, ohne den Textkörper.

buscar_notas

consulta, limite

Nach Relevanz sortierte Ergebnisse mit Ausschnitt.

estatisticas_base

Zählungen, am häufigsten verwendete Tags, längste Notiz.

Resources

URI

Typ

Inhalt

notas://index

application/json

Index der gesamten Basis: Slug, Titel, Tags und URI jeder Notiz.

notas://{slug}

text/markdown

Vollständiges Markdown einer Notiz, mit Front Matter.

Prompts

Prompt

Argumente

Was zusammengestellt wird

resumir_nota

slug, tamanho (curto/longo)

Eine Zusammenfassungsanfrage mit dem bereits eingebetteten Inhalt der Notiz.

sugerir_conexoes

slug, quantidade

Vier Nachrichten: Anweisung, Ausgangsnotiz, Katalog der übrigen Notizen und die Eröffnung des Assistenten.


Installation

git clone <url-do-repositorio> mcp-server-example
cd mcp-server-example
pip install -r requirements.txt

Erfordert Python 3.11+ und mcp >= 1.27.0.


So führen Sie es aus

Der Standardtransport ist stdio — so startet ein MCP-Client den Server:

cd mcp-server-example
python3 -m mcp_notas

Der Prozess bleibt still und wartet auf JSON-RPC-Nachrichten auf der Standardeingabe; das ist das korrekte Verhalten, kein Absturz.

Das Basisverzeichnis ist über die Umgebungsvariable MCP_NOTAS_DIR konfigurierbar (Standard: ./notas, wird automatisch erstellt):

MCP_NOTAS_DIR=~/meu-second-brain python3 -m mcp_notas

Konfiguration im Client

Fertiger Block zum Einfügen in die Konfiguration eines MCP-Clients:

{
  "mcpServers": {
    "notas": {
      "command": "python3",
      "args": ["-m", "mcp_notas"],
      "cwd": "/caminho/absoluto/para/mcp-server-example",
      "env": {
        "MCP_NOTAS_DIR": "/caminho/absoluto/para/suas-notas"
      }
    }
  }
}

⚠️ Dieser Block wurde in dieser Umgebung nicht gegen einen echten MCP-Client getestet. Was hier tatsächlich verifiziert wurde, ist das programmatische Äquivalent: Der Server wurde als Subprozess mit python3 -m mcp_notas gestartet, und eine ClientSession aus dem SDK selbst hat den Handshake über stdio abgeschlossen, die Tools aufgelistet und Aufrufe ausgeführt (siehe „Verifizierungsstatus"). Die Übersetzung dieses Handshakes in das Konfigurationsformat eines bestimmten Clients wurde nicht erprobt.


Nutzungsbeispiel

Echte Ausgaben, aufgezeichnet beim Ausführen des Servers in-process (criar_servidor() + call_tool). Das Feld diretorio wurde durch einen generischen Pfad ersetzt; der Rest ist wörtlich.

>>> criar_nota
{
  "slug": "protocolo-mcp",
  "titulo": "Protocolo MCP",
  "tags": [
    "mcp",
    "protocolo"
  ],
  "corpo": "O Model Context Protocol padroniza como um assistente acessa ferramentas e dados externos.",
  "criada_em": "2026-08-25T00:20:03+00:00",
  "atualizada_em": "2026-08-25T00:20:03+00:00"
}

>>> listar_notas(tag='mcp')
{
  "total": 1,
  "filtro_tag": "mcp",
  "notas": [
    {
      "slug": "protocolo-mcp",
      "titulo": "Protocolo MCP",
      "tags": [
        "mcp",
        "protocolo"
      ],
      "atualizada_em": "2026-08-25T00:20:03+00:00",
      "resumo": "O Model Context Protocol padroniza como um assistente acessa ferramentas e dados externos.",
      "tamanho": 90
    }
  ]
}

>>> buscar_notas(consulta='protocolo')
{
  "consulta": "protocolo",
  "total": 2,
  "resultados": [
    {
      "slug": "protocolo-mcp",
      "titulo": "Protocolo MCP",
      "tags": [
        "mcp",
        "protocolo"
      ],
      "pontuacao": 8.0,
      "trecho": "O Model Context Protocol padroniza como um assistente acessa ferramentas e dados externos."
    },
    {
      "slug": "memoria-de-longo-prazo",
      "titulo": "Memória de longo prazo",
      "tags": [
        "produtividade"
      ],
      "pontuacao": 1.0,
      "trecho": "Anotações sobre second brain. Cita o protocolo de revisão semanal."
    }
  ]
}

Beachten Sie das Ranking: Das Wort „protocolo" steht im Titel und in den Tags der ersten Notiz (Punktzahl 8.0) und nur im Textkörper der zweiten (Punktzahl 1.0).

>>> estatisticas_base()
{
  "total_de_notas": 2,
  "total_de_caracteres": 156,
  "total_de_palavras": 23,
  "media_de_caracteres": 78.0,
  "total_de_tags": 3,
  "tags_mais_usadas": {
    "mcp": 1,
    "produtividade": 1,
    "protocolo": 1
  },
  "nota_mais_longa": "protocolo-mcp",
  "ultima_atualizacao": "2026-08-25T00:20:03+00:00",
  "diretorio": "/caminho/para/notas"
}

>>> read_resource('notas://index')
{
  "diretorio": "/caminho/para/notas",
  "total": 2,
  "notas": [
    {
      "slug": "memoria-de-longo-prazo",
      "titulo": "Memória de longo prazo",
      "tags": [
        "produtividade"
      ],
      "uri": "notas://memoria-de-longo-prazo"
    },
    {
      "slug": "protocolo-mcp",
      "titulo": "Protocolo MCP",
      "tags": [
        "mcp",
        "protocolo"
      ],
      "uri": "notas://protocolo-mcp"
    }
  ]
}

>>> get_prompt('resumir_nota', {'slug': 'protocolo-mcp'})
Resuma em no máximo 3 bullets.
Não invente informação que não esteja na nota.

# Protocolo MCP
Tags: mcp, protocolo

O Model Context Protocol padroniza como um assistente acessa ferramentas e dados externos.

Und der echte Handshake über stdio, mit dem Server als Subprozess und einer ClientSession aus dem SDK auf der anderen Seite (wörtliche Ausgabe, ohne die INFO-Logs des Servers):

serverInfo: mcp-notas 1.27.0
instructions[:60]: Servidor de uma base local de notas em Markdown. Use 'listar
tools: ['apagar_nota', 'atualizar_nota', 'buscar_notas', 'criar_nota', 'estatisticas_base', 'ler_nota', 'listar_notas']
criar_nota isError: False slug: handshake-stdio
estatisticas: 1 nota(s)
traversal isError: True
traversal msg: Error executing tool ler_nota: Identificador inválido '../../etc/passwd': separadores de caminho não são permitidos. Use

Sicherheit

Der klassische Fehler eines MCP-Servers, der mit Dateien arbeitet, besteht darin, einen vom Modell stammenden Bezeichner zu akzeptieren und ihn direkt in den Pfad zu verketten: Path(base) / slug. Mit slug = "../../etc/passwd" wird so die gesamte Festplatte an diejenigen ausgeliefert, die den Prompt kontrollieren.

Hier liegt die Verteidigung in mcp_notas/storage.py und hat zwei Schichten.

1. sanitizar_slug() — Validierung über eine Positivliste. Ein Bezeichner wird nur durchgelassen, wenn er mit ^[a-z0-9][a-z0-9._-]{0,79}$ übereinstimmt, nachdem Pfadtrennzeichen (/, \), Nullbyte, Windows-Laufwerksbuchstaben (C:) und jedes Vorkommen von .. explizit abgelehnt wurden. Die Anforderung, mit einem Buchstaben oder einer Ziffer zu beginnen, weist auch versteckte Namen wie .ssh ab.

2. BaseDeNotas.caminho() — Prüfung des aufgelösten Pfads. Nach der Sanitisierung wird der Pfad mit Path.resolve() aufgelöst, und der Code prüft, dass sein Elternverzeichnis exakt das Basisverzeichnis ist. Diese Prüfung ist konstruktionsbedingt redundant — und genau das ist der Punkt: Sollte die erste Schicht jemals ein Loch haben, kommt es trotzdem nicht zum Leck.

Der kanonische Angriff, tatsächlich gegen das Tool ausgeführt:

>>> call_tool('ler_nota', {'slug': '../../etc/passwd'})
ToolError: Error executing tool ler_nota: Identificador inválido '../../etc/passwd': separadores de caminho não são permitidos. Use apenas o slug da nota, sem diretórios.

Die Ressource notas://{slug} hat denselben Schutz, und zwar auf zwei verschiedenen Wegen: Die rohe URI notas://../../etc/passwd passt nicht einmal auf die Vorlage (Unknown resource), während die percent-encodierte Form notas://..%2F..%2Fetc%2Fpasswd passt, zur Sanitisierung gelangt und dort abgewiesen wird — genau dieser zweite, gefährliche Fall wird vom Test abgedeckt.

Ein Test beweist außerdem im Dateisystem, dass das Angriffsziel gar nicht erst erstellt wird: Nach einem Versuch von criar_nota mit slug="../vazamento" bleibt das Basisverzeichnis leer, und die Datei außerhalb davon existiert nicht.

Darüber hinaus: keine API-Schlüssel, kein Netzwerkzugriff, und der Server liest oder schreibt niemals außerhalb des konfigurierten Verzeichnisses.


Tests

$ python3 -m pytest tests/ -q
.............................................                            [100%]
45 passed in 1.48s

Nur die Path-Traversal-Tests:

$ python3 -m pytest tests/ -q -k traversal
.................                                                        [100%]
17 passed, 28 deselected in 0.67s

Die Suite deckt in dieser Reihenfolge ab:

  1. Sanitisierung — 13 parametrisierte bösartige Eingaben (../../etc/passwd, /etc/passwd, ..\\..\\windows\\system32\\config\\sam, C:\Windows\win.ini, nota\x00.md, leere Zeichenkette…), plus der Beweis im Dateisystem, dass außerhalb der Basis nichts erstellt wird.

  2. MCP-Oberflächelist_tools gibt exakt die sieben Tools zurück, und die Schemas (required, type, default, outputSchema) sind die aus den Type Hints und Docstrings generierten.

  3. Echter Aufruf jedes Tools — Erstellung mit im Dateisystem verifizierter Persistenz, Duplikat, Lesen, Lesen einer nicht existierenden Notiz, Aktualisierung, Aktualisierung mit anexar, Auflistung mit und ohne Tag-Filter, Suche mit Ranking und mit Limit, Statistiken und Entfernung.

  4. Resourceslist_resources, list_resource_templates, Lesen des JSON-Index, Lesen einer einzelnen Notiz und die beiden Traversal-Formen.

  5. Promptslist_prompts, get_prompt der beiden Prompts, wobei geprüft wird, dass der Inhalt der Notiz tatsächlich eingebettet ist und dass die Ausgangsnotiz nicht im Katalog der übrigen Notizen erscheint.

  6. Ende-zu-Ende-Sitzungcreate_connected_server_and_client_session startet einen verbundenen MCP-Client und -Server im Speicher; der Test listet Tools, erstellt eine Notiz, listet, liest eine Ressource, holt einen Prompt und bestätigt isError: True beim Traversal-Versuch.

  7. Isolierter Speicher — Round-Trip des Front Matter, und Dateien, die keine Notizen sind, werden bei der Auflistung ignoriert.


Verifizierungsstatus

Alles unten wurde in dieser Umgebung ausgeführt, mit mcp 1.27.0, pytest 9.1.1 und pytest-asyncio 1.4.0 unter Python 3.11.

Verifiziert

  • python3 -m pytest tests/ -q45 passed.

  • Die sieben Tools tatsächlich über FastMCP.call_tool aufgerufen, mit geprüften Ergebnissen.

  • Die beiden Resources über FastMCP.read_resource gelesen; die beiden Prompts über FastMCP.get_prompt.

  • Vollständige MCP-Sitzung Client↔Server im Speicher mit mcp.shared.memory.create_connected_server_and_client_session.

  • Echter stdio-Handshake: Server als Subprozess gestartet (python3 -m mcp_notas) und eine ClientSession aus dem SDK, die initialize, list_tools und call_tool darüber ausführt.

  • Path Traversal in sanitizar_slug, im Tool, in der Ressource und im Dateisystem abgewiesen.

  • MCP_NOTAS_DIR wird respektiert: Die erstellte Notiz erschien im von der Variablen angegebenen Verzeichnis.

  • Alle in diesem README gezeigten Ausgaben wurden aus echten Ausführungen kopiert.

⚠️ Nicht getestet

  • Der mcpServers-Block wurde nicht gegen einen echten MCP-Client getestet (Claude Desktop, Editoren usw.). In dieser Umgebung ist kein Client installiert; was diese Verifizierung ersetzt, ist der oben beschriebene programmatische stdio-Handshake.

  • Die Transporte sse und streamable-http existieren in FastMCP.run, aber dieses Projekt übt nur stdio aus.

  • Keine Konkurrenztests: Gleichzeitige Schreibvorgänge auf dieselbe Notiz werden nicht durch einen Lock koordiniert.

  • Keine Tests unter Windows oder macOS — nur Linux.


Lizenz

MIT

A
license - permissive license
Not graded
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.

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Manages markdown notes in a specified directory, allowing users to create, read, update, and list notes through the Model Context Protocol.
    1
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI assistants to search, read, create, update, and remove personal markdown notes stored locally, providing persistent memory across sessions.
    13
    2
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Enables AI assistants to interact with a local folder of Markdown notes, supporting listing, reading, searching, creating, and appending to notes with strict security boundaries.
    5
    MIT

View all related MCP servers

Related MCP Connectors

  • AI access to your aNotepad online notes: read, search, write, and organize via 22 tools.

  • Read and write your Fresh Jots notes from Claude, Cursor, and any MCP client.

  • Create, validate, edit, export (markdown/svg/png/mermaid), and search JSON Canvas files.

View all MCP Connectors

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/herickbrandao483-jpg/mcp-server-example'

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