Projet : Mon Journal (journal personnel MCP)
Journal personnel construit autour d'un serveur MCP Laravel + plugin Claude Code, accessible depuis les 3 runtimes Claude.
Architecture
- Backend : Laravel 13 + PHP 8.4 + MySQL en prod (déployé sur Ploi →
https://j.pham.fr) - Plugin Claude Code : marketplace personnel (
spham/plugin-marketplace) avec skilljournal:j(extractioncollection X, anti-typo, ton FR court) - Auth dual côté MCP :
- Bearer statique (
JOURNAL_MCP_TOKEN) pour Claude Code - OAuth 2.0 + Dynamic Client Registration (Passport 13 +
Mcp::oauthRoutes()) pour claude.ai web/desktop/mobile
- Bearer statique (
Modèle de données
JournalEntry:content,collection_id?,tags(legacy, non utilisé)Collection:name,slug(slug figé pour matching, name renommable)- Notes orphelines = pas rattachées à une collection
- Slug normalisé via
Collection::makeSlug(): trim → lowercase → ASCII → spaces collapse → dash
UX
- Home publique en lecture seule (sans login) avec sidebar collections + recherche full-text
- Auth Fortify (Livewire Flux) avec
SESSION_LIFETIME=1 anpour rester loggé partout - Page
/collections(auth) pour rename/delete - Kebab
⋮par entrée pour réassigner / détacher / supprimer (auth) - Vue OAuth de consentement custom à
resources/views/oauth/authorize.blade.php
Outils MCP exposés
write-entry: écrit une note, acceptecollection(find-or-create par slug)read-entries: N dernières entrées, filtrable par collection ounone(orphelines)search-entries: recherche par mot-clé, combinable avec collectionlist-collections: liste triée parentries_count desc(utilisé en anti-typo avant write)
Tests
- Pest 4 + RefreshDatabase
- 57+ tests passants, dont 8 OAuth (metadata, DCR, dual-token middleware) et 11 MCP fonctionnels
Validé end-to-end
- Note écrite depuis claude.ai web via OAuth-issued Bearer → prod MySQL → visible sur
https://j.pham.fr✓ - Note écrite depuis Claude Code via static Bearer → idem ✓
- Plugin marketplace installable via
/plugin marketplace add✓
À faire potentiellement
- Désactiver
Features::registration()dans Fortify (mono-utilisateur) - Multi-utilisateur si besoin (scope
JournalEntryparuser_id) - Lecture des notes sans login via URL secrète (capability URL) — option B initialement écartée au profit du long session, mais reste sur la table