# Vaulken : serveur MCP remote pour mes fichiers

Vaulken ouvre tes fichiers S3 à Claude via un serveur MCP remote. Ce qu'il fait, pour qui, et comment il est construit : OAuth, ton bucket, Qdrant, 12 tools.

Source : https://simotech.dev/blog/vaulken-serveur-mcp-remote

Je brainstorm beaucoup avec Claude. Claude Code sur le desktop pour le dev, Claude.ai web quand je réfléchis à un problème, le mobile quand une idée me tombe dessus dans le train. Et à chaque fois que je quittais Claude Code sur mon PC, je perdais l'accès à mes notes. Mon vault Obsidian, mes specs, mes décisions d'architecture, tout restait coincé sur ma machine.

Quand j'ai fait le tour des serveurs MCP pour Obsidian, j'ai trouvé une dizaine de projets. Tous en stdio, tous locaux. Certains proposaient des tunnels Tailscale ou du Docker + reverse proxy, mais aucun n'offrait du remote natif avec OAuth.

Alors j'ai construit Vaulken, un serveur MCP remote qui donne à Claude l'accès à mes fichiers depuis n'importe où. Cet article se lit en deux temps. D'abord ce que fait Vaulken et à qui il sert. Ensuite comment il est construit : la stack, les choix d'architecture, et la conception de ses tools. La première moitié t'intéressera si tu cherches à brancher tes notes sur un LLM, la seconde si tu conçois toi-même un serveur MCP.

Le service est en bêta sur [vaulken.dev](https://vaulken.dev), et il est gratuit. Pour la petite histoire, cet article a été écrit avec Claude branché sur mes notes via Vaulken.

## Un bucket S3 entre tes notes et Claude

Vaulken s'adresse à ceux qui travaillent avec un LLM sur plusieurs appareils et qui gardent leurs connaissances dans des fichiers : notes Obsidian, specs, documentation, comptes rendus. Le problème de départ est simple. Un assistant qui tourne sur ton poste lit ton disque, mais Claude sur le web ou sur ton téléphone n'y a pas accès.

La réponse de Vaulken passe par un bucket S3-compatible. Tes fichiers y vivent. Si tu utilises Obsidian, le plugin Remotely Save synchronise ton vault vers le bucket. Sinon, n'importe quel contenu texte déposé dans un bucket fonctionne.

Vaulken se branche sur ce bucket et expose son contenu via [MCP](/blog/mcp-pour-les-developpeurs), le protocole qui permet à un LLM d'appeler des outils externes. Claude s'y connecte par une URL HTTPS, avec une authentification OAuth. Tu n'as ni tunnel ni serveur à maintenir, et aucun token à copier-coller.

```mermaid
flowchart LR
    O["Obsidian<br/>(Remotely Save)"] -- sync --> B[("Ton bucket S3<br/>Scaleway, AWS, R2, MinIO")]
    V["Vaulken<br/>serveur MCP remote"] -- "lit et écrit" --> B
    C["Claude<br/>web, mobile, desktop"] -- "HTTPS + OAuth" --> V
```

## Ce que ça change au quotidien

Je commence un brainstorm sur Claude.ai web, je continue sur mobile dans le train, je repasse en Claude Code pour implémenter. Les mêmes notes partout, plus de rupture de contexte quand je change de device.

Les idées qui me viennent loin du bureau finissaient dans les mémos vocaux, et j'oubliais de les réécouter. Maintenant je dicte à Claude, et il range la note dans Obsidian avec le bon nom, les bons tags, dans le bon dossier.

« Retrouve ce qu'on avait décidé sur la stratégie de pricing en février. » Claude cherche par concept, lit les fichiers, me fait une synthèse. Le genre de requête qui me prenait 15 minutes de navigation à la main.

Et quand Claude rédige un article technique, il a accès à ma doc, mes specs, mes analyses. Il travaille avec mon contexte réel.

## Tu apportes ton bucket

Vaulken fonctionne en **BYOB** (Bring Your Own Bucket) : tu connectes ton propre stockage S3-compatible, chez AWS, Scaleway, Cloudflare R2, Backblaze B2 ou sur un MinIO. Je ne voulais pas héberger les notes des gens, et je ne voulais pas que les miennes partent chez un tiers. Vaulken lit et écrit directement dans ton bucket. De son côté, il ne garde que les paramètres de connexion, avec la clé secrète chiffrée en base, et les index de recherche.

Vaulken a proposé un temps un stockage géré. Depuis octobre 2026, il n'existe plus : tout vault est branché sur un bucket qui t'appartient. Si tu supprimes un vault, la connexion et les index disparaissent, tes fichiers restent où ils sont.

Un **vault**, dans Vaulken, c'est cette connexion entre le service et un bucket. Tu peux la restreindre à un dossier avec un préfixe de chemin. Chaque vault fournit deux URLs MCP :

- une URL en lecture seule, avec laquelle Claude lit et cherche sans pouvoir modifier ;
- une URL en lecture-écriture.

Tu colles l'une ou l'autre dans Claude.ai, Claude Code ou Cursor. L'URL en lecture seule convient bien au téléphone : aucun risque d'écraser un fichier. Tu gardes la lecture-écriture pour Claude Code, par exemple. Chaque URL porte son propre identifiant aléatoire, que tu peux régénérer sans toucher à l'autre.

### Deux textes pour guider l'agent

Un LLM qui arrive dans un dossier inconnu ne sait ni ce qu'il contient ni comment tu le ranges. Vaulken lui transmet deux textes dès la connexion, dans les instructions du serveur MCP.

Le premier est la description du vault, une ou deux phrases saisies dans le dashboard. Quand plusieurs vaults sont connectés à la même conversation, c'est elle qui permet à Claude de choisir le bon.

Le second est un fichier `VAULKEN.md` à la racine du vault. Tu y écris tes conventions : la structure des dossiers, le nommage, ce que l'agent ne doit pas toucher sans demander. Seul le début du fichier est injecté. S'il est long, l'agent voit qu'il est tronqué et peut lire la suite.

Si tu déclares le vault comme un vault Obsidian, Vaulken ajoute les conventions d'Obsidian : frontmatter YAML, liens `[[wiki]]`, fichiers canvas.

## Comment Vaulken est construit

Tout est en TypeScript sur Node.js. Le serveur est une application Express, bundlée avec esbuild. Le dashboard, où tu crées tes vaults, est en React Router v7. Prisma gère la base relationnelle, Qdrant stocke les vecteurs de la recherche sémantique, et Redis complète l'ensemble. Le service est hébergé chez Scaleway et déployé sur K3s, une distribution allégée de Kubernetes, avec KEDA pour l'autoscaling.

```mermaid
flowchart LR
    C["Clients MCP<br/>Claude, Claude Code, Cursor"] -- "Streamable HTTP<br/>+ OAuth" --> S["Serveur MCP<br/>Node.js, Express"]
    S -- "API S3" --> B[("Ton bucket")]
    O["Obsidian"] -- sync --> B
    I["Indexeur<br/>en arrière-plan"] -- "parcourt" --> B
    I --> Q[("Qdrant<br/>vecteurs")]
    I --> D[("Base SQL, Prisma<br/>vaults, index")]
    S -- "recherche" --> Q
    S --> D
```

### Un serveur remote en Streamable HTTP, derrière OAuth

Vaulken parle **Streamable HTTP**, le transport de MCP pour les serveurs distants : le client envoie ses requêtes en POST sur une URL HTTPS. Chaque URL de vault désigne à la fois le vault et le mode d'accès, lecture seule ou lecture-écriture.

L'authentification passe par OAuth. À la première connexion, le client ouvre ton navigateur sur un écran de consentement, tu autorises, et il reçoit un jeton. Tu ne manipules aucun secret à la main. J'ai détaillé ce transport et le parcours OAuth dans [l'article sur le MCP remote](/blog/mcp-remote-serveurs-locaux-obsoletes).

### Un stockage derrière une interface

Les tools n'appellent jamais S3 eux-mêmes. Ils passent par une interface `StorageProvider` de quelques méthodes : lister, lire les métadonnées, lire, écrire, ajouter, déplacer, supprimer. S3 est le seul backend en service aujourd'hui, via le SDK AWS v3, qui accepte n'importe quel endpoint compatible.

L'interface fixe aussi le contrat du contrôle de concurrence décrit plus bas : chaque backend doit fournir un hash par fichier, et la règle reste la même quel que soit le stockage.

### Trois index construits en arrière-plan

Un bucket S3 sait lister et renvoyer des objets. Il ne sait pas chercher dedans. Et des fichiers y arrivent sans passer par Vaulken, par exemple quand Obsidian synchronise. Un indexeur parcourt donc le bucket à intervalles réguliers et maintient trois index.

L'index de fichiers retient les chemins, les tailles et les dates. Il sert à répondre vite à « quels fichiers ont changé récemment » sur un gros vault, sans relister tout le bucket.

L'index de **trigrammes** sert à la recherche exacte. Un trigramme est une suite de trois caractères. Pour une requête, l'index désigne les fichiers qui contiennent tous ses trigrammes, puis chaque candidat est vérifié contre la chaîne exacte. Le résultat est précis, sans relire tout le bucket à chaque recherche.

L'index vectoriel sert à la recherche sémantique. Les fichiers sont découpés en morceaux, section par section pour le Markdown. Chaque morceau est transformé en **embedding**, un vecteur de nombres qui représente son sens, et stocké dans Qdrant. Tous les vaults partagent une même collection, et chaque vecteur porte l'identifiant de son vault, ce qui cloisonne les recherches.

> [!NOTE]
> Conséquence de ce choix : un fichier écrit il y a quelques minutes peut ne pas encore apparaître dans les résultats de recherche. La lecture et le listing par chemin, eux, interrogent le bucket en direct.

### Écrire sans écraser le travail d'un autre

Plusieurs clients peuvent écrire dans le même bucket : Claude sur le web, Claude Code, et Obsidian qui synchronise de son côté. Pour éviter qu'une écriture en efface une autre, chaque lecture complète renvoie un **hash** du fichier, et chaque écriture doit fournir ce hash. Si le fichier a changé entre-temps, le serveur refuse avec une erreur `HASH_MISMATCH`. L'agent relit, puis réessaie.

C'est du contrôle de concurrence optimiste, le même principe qu'un `If-Match` en HTTP. Côté S3, le hash est l'ETag de l'objet : Vaulken n'a rien à stocker pour le calculer. Pour créer un fichier, l'agent passe la valeur spéciale `new` à la place du hash.

### Un versioning délégué au bucket

Vaulken ne garde pas l'historique de tes fichiers. Il s'appuie sur le versioning de S3, que tu actives sur ton bucket. L'indexeur détecte s'il est actif. Si oui, le serveur expose les deux tools qui listent les versions d'un fichier et en restaurent une. Restaurer ne détruit rien : la version courante devient à son tour une version de l'historique.

> [!WARNING]
> `vaulken_delete_file` supprime définitivement, il n'y a pas de corbeille. Sans versioning sur le bucket, un fichier supprimé ou écrasé par un agent est perdu. Active-le avant de donner un accès en écriture.

## Douze tools conçus pour un LLM

Le serveur expose douze tools, dont deux réservés aux buckets versionnés. Ils portent tous le préfixe `vaulken_`, ce qui évite les collisions quand d'autres serveurs MCP exposent eux aussi un `read` ou un `list`.

| Catégorie | Tools | Rôle |
|---|---|---|
| Lecture | `vaulken_read`, `vaulken_list`, `vaulken_get_file_url` | Lire un fichier, lister un dossier, obtenir un lien de téléchargement temporaire pour un fichier trop lourd |
| Écriture | `vaulken_edit_file`, `vaulken_patch_file`, `vaulken_move_file`, `vaulken_delete_file` | Écrire ou modifier un fichier, appliquer plusieurs retouches d'un coup, déplacer, supprimer |
| Recherche | `vaulken_search_text`, `vaulken_search_semantic`, `vaulken_get_related` | Recherche exacte, recherche par le sens, fichiers proches d'un fichier donné |
| Versions | `vaulken_list_versions`, `vaulken_restore_version` | Lister et restaurer les versions précédentes d'un fichier |

`vaulken_read` a quatre modes. `content` renvoie le fichier, avec une pagination par lignes pour les gros fichiers. `outline` renvoie le plan d'un fichier Markdown. `section` renvoie le contenu d'un seul titre. `metadata` renvoie le frontmatter, la taille et les dates. Les PDF sont convertis en Markdown par OCR.

`vaulken_edit_file` regroupe les modifications simples sous cinq commandes : écrire le fichier, ajouter à la fin, remplacer une chaîne unique, remplacer le contenu d'une section, fusionner des champs dans le frontmatter. `vaulken_patch_file` applique jusqu'à 50 retouches en un appel. Toutes sont validées avant la moindre écriture : si une cible est absente ou ambiguë, rien n'est modifié.

C'est la recherche sémantique qui m'a le plus surpris à l'usage. Quand je demande « retrouve mes notes sur l'architecture de la base de données », Claude tombe sur les bons fichiers même si je n'y ai jamais écrit ces mots-là.

## Des tools sobres en tokens

Chaque résultat de tool occupe de la place dans le contexte du LLM, et la description de chaque tool est envoyée à chaque conversation. J'ai posé les principes généraux dans [l'article MCP remote](/blog/mcp-remote-serveurs-locaux-obsoletes#des-tools-sobres-en-tokens). Voici comment Vaulken les applique.

Il y a peu de tools, et ils ont des modes. Lire le plan d'un fichier, une section ou ses métadonnées sont des modes de `vaulken_read`, et les variantes d'écriture sont des commandes de `vaulken_edit_file`. Moins de tools, c'est moins de descriptions chargées avant même la première question.

L'agent lit le plan avant le contenu. Sur une longue spec, Claude demande l'`outline`, puis la seule section qui l'intéresse. Il ne charge le fichier entier que s'il en a besoin.

Les listes sont bornées. `vaulken_list` renvoie 200 fichiers par défaut et accepte un préfixe de chemin. Les recherches renvoient des lignes ou des extraits avec le chemin et le numéro de ligne, jamais des fichiers entiers.

Les écritures sont ciblées. Pour corriger une phrase, l'agent envoie seulement la chaîne à remplacer et sa remplaçante. Chaque écriture renvoie le nouveau hash, ce qui lui permet d'enchaîner une autre modification sans relire.

Les fichiers lourds restent hors du contexte. Une image de moins de 3 Mo est renvoyée telle quelle. Au-delà, comme pour l'audio ou la vidéo, `vaulken_get_file_url` fournit un lien de téléchargement signé et temporaire. Le résultat de l'OCR d'un PDF est mis en cache, la conversion n'est faite qu'une fois.

Les descriptions orientent l'agent. Chaque description dit quand utiliser le tool et lequel préférer dans le cas voisin. Celle de la recherche exacte renvoie vers la recherche sémantique quand on ne connaît pas les mots, et inversement. L'agent hésite moins, donc il fait moins d'appels inutiles.

## Brancher ton vault

1. Crée un compte sur [vaulken.dev](https://vaulken.dev), puis un vault avec les paramètres de ton bucket : endpoint, région, nom du bucket, clé d'accès et clé secrète.
2. Copie l'une des deux URLs MCP depuis la page du vault.
3. Ajoute-la dans Claude.ai (Settings → Connectors). Dans Claude Code, la commande est `claude mcp add --transport http notes <url>`.
4. À la première utilisation, ton navigateur s'ouvre sur l'écran de consentement. Tu autorises, et Claude accède à tes fichiers.

La [documentation](https://vaulken.dev/docs/connect-obsidian-s3-vaulken) détaille le montage complet avec Obsidian et Remotely Save.

## Au-delà d'Obsidian

Vaulken est un serveur MCP pour S3. J'ai choisi Obsidian comme porte d'entrée parce que la communauté est large et que le problème mobile y est bien identifié. Mais le serveur se moque de ce qu'il y a dans le bucket, tant que c'est du texte.

Quelques usages auxquels je n'avais pas pensé au départ :

- Un agent écrit ses résultats dans S3, un autre les lit via Vaulken. Le bucket devient une mémoire partagée entre agents.
- Un script dépose des rapports ou des extractions dans S3, et tu interroges le contenu depuis Claude.
- Des fichiers Markdown de doc dans un bucket, pour faire du Q&A sans monter un RAG.

## La suite

Deux chantiers devant moi : améliorer la recherche sémantique, et simplifier la configuration du bucket S3.

Si tu veux écrire ton propre serveur plutôt qu'utiliser le mien, [l'article MCP remote](/blog/mcp-remote-serveurs-locaux-obsoletes) montre un serveur Streamable HTTP minimal en TypeScript et le parcours OAuth qu'un client suit pour s'y connecter.
