NoNote · Documentation développeur — API & MCP

Piloter NoNote par programme : API REST & serveur MCP

NoNote expose deux surfaces protégées par OAuth2 pour les intégrations tierces : une API REST sous /api/v1/* et un serveur MCP distant sous /mcp. Elles partagent exactement les mêmes gestionnaires de routes que l'application web — un outil MCP create_task et un POST /api/v1/tasks exécutent le même code.

L'API REST s'adresse aux développeurs qui intègrent NoNote dans leurs propres outils (scripts, back-office, automatisations). Le serveur MCP (Model Context Protocol) s'adresse aux agents IA — Claude Desktop, Claude.ai, ChatGPT et tout client compatible MCP — qui peuvent découvrir le serveur, s'authentifier via OAuth2 et appeler les outils listés plus bas pour agir sur les tâches, canvas, Drive et profil de l'utilisateur en son nom.

Chaque appel est autorisé par un jeton d'accès OAuth2 (JWT) portant un ensemble de scopes précis. Un jeton ne peut jamais faire plus que ce que ses scopes autorisent : un jeton tasks:read ne peut pas créer de tâche, et un jeton profil ne peut pas toucher au Drive.

Base de production : https://www.nonote.fr — tous les chemins ci-dessous sont relatifs à cette origine (ex. https://www.nonote.fr/api/v1/tasks). Les chemins REST sont abrégés en /tasks, /canvases… dans le sommaire ; leur préfixe complet est toujours /api/v1.

Flux OAuth2 : Authorization Code + PKCE

NoNote implémente Authorization Code avec PKCE (obligatoire — le serveur refuse tout échange sans code_verifier). Aucun secret client n'est nécessaire : les clients publics s'authentifient avec token_endpoint_auth_method: none + PKCE.

ÉtapeEndpointDétail
DécouverteGET /oauth/.well-known/oauth-authorization-serverMétadonnées RFC 8414 (endpoints, algorithmes, scopes).
Enregistrement dynamiquePOST /oauth/registerRFC 7591, public (aucun jeton initial requis). Renvoie un client_id.
AutorisationGET /oauth/authorizeRedirige l'utilisateur vers l'écran de connexion / consentement.
JetonPOST /oauth/tokenÉchange le code contre un access_token (JWT, 15 min) + refresh_token (30 j).
RévocationPOST /oauth/revokeRFC 7009.

Le jeton d'accès est un JWT d'une durée de vie de 15 minutes ; rafraîchissez-le avec le refresh_token (valable 30 jours). Le JWKS de vérification est publié à GET /oauth/jwks.

Scopes disponibles

Un scope suit la forme domaine:action (read ou write). Demandez uniquement ceux dont vous avez besoin — l'utilisateur voit la liste exacte sur l'écran de consentement.

DomaineScopes
Profilprofile:read · profile:write
Canvascanvas:read · canvas:write
Drivedrive:read · drive:write
Tâchestasks:read · tasks:write
Équipesteams:read · teams:write
Drive d'équipeteamdrive:read · teamdrive:write
Messagesmessages:read · messages:write
Mailmail:read · mail:write
Agendacalendar:read · calendar:write
Appelscalls:read · calls:write
Facturesinvoices:read · invoices:write
Produitsproducts:read · products:write
Dépensesexpenses:read · expenses:write
Facturationbilling:read
Modèlestemplates:read · templates:write
IAai:use
Supportsupport:read · support:write

Par conception, certains scopes n'existent pas. Il n'y a aucun scope admin:* et pas de billing:write (seul billing:read existe). Ils sont structurellement impossibles à demander : le serveur d'autorisation rejette tout scope hors de la liste ci-dessus. Aucun jeton délivré à une intégration ne peut donc administrer l'instance ni modifier la facturation.

Quickstart

Trois étapes : enregistrer un client, obtenir un jeton, appeler un endpoint.

1 · Enregistrer un client (public + PKCE)

POST/oauth/register
Requête
curl -X POST https://www.nonote.fr/oauth/register \
  -H "Content-Type: application/json" \
  -d '{
    "client_name": "Mon intégration",
    "redirect_uris": ["https://mon-app.example/callback"],
    "grant_types": ["authorization_code", "refresh_token"],
    "response_types": ["code"],
    "token_endpoint_auth_method": "none",
    "scope": "tasks:read tasks:write canvas:read"
  }'
Réponse (201)
{
  "client_id": "s6BhdRkqt3",
  "client_id_issued_at": 1784200000,
  "client_name": "Mon intégration",
  "redirect_uris": ["https://mon-app.example/callback"],
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"],
  "token_endpoint_auth_method": "none",
  "scope": "tasks:read tasks:write canvas:read"
}

2 · Autoriser puis échanger le code

Redirigez l'utilisateur vers l'URL d'autorisation (PKCE : code_challenge_method=S256) :

GET/oauth/authorize
https://www.nonote.fr/oauth/authorize
  ?response_type=code
  &client_id=s6BhdRkqt3
  &redirect_uri=https://mon-app.example/callback
  &scope=tasks:read%20tasks:write
  &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
  &code_challenge_method=S256
  &state=af0ifjsldkj

Après consentement, l'utilisateur est renvoyé vers redirect_uri avec ?code=…&state=…. Échangez ce code :

Requête
curl -X POST https://www.nonote.fr/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d grant_type=authorization_code \
  -d code=SplxlOBeZQQYbYS6WxSbIA \
  -d redirect_uri=https://mon-app.example/callback \
  -d client_id=s6BhdRkqt3 \
  -d code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
Réponse (200)
{
  "access_token": "eyJhbGciOiJSUzI1Ni…",
  "token_type": "Bearer",
  "expires_in": 900,
  "refresh_token": "GEbRxBN…",
  "scope": "tasks:read tasks:write"
}

3 · Appeler un endpoint

GET/api/v1/tasks
curl https://www.nonote.fr/api/v1/tasks \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1Ni…"

En JavaScript : await fetch("https://www.nonote.fr/api/v1/tasks", { headers: { Authorization: `Bearer ${token}` } }).then(r => r.json())


API REST · /api/v1/*

Chaque endpoint indique sa méthode, son chemin, le scope requis, un exemple de corps de requête (le cas échéant) et un exemple de réponse réel, obtenu en exécutant le gestionnaire de route contre une base de développement. Sur GET/HEAD le scope requis est domaine:read ; sur toute écriture, domaine:write.

Profil

GET/api/v1/auth/me

Renvoie le profil de l'utilisateur authentifié, ses fonctionnalités de plan et les feature flags de l'app.

Scope requis profile:read
Requête
GET /api/v1/auth/me
Authorization: Bearer <token>
Réponse (200)
{
  "user": {
    "id": "caa35a21-d7b7-4599-812c-35080160b6fe",
    "name": "Ada Lovelace",
    "email": "ada@example.com",
    "plan": "free",
    "role": "user",
    "features": ["canvas", "drive", "chat", "mail",
      "tasks", "tickets", "billing", "priority_support"],
    "avatarUrl": null,
    "avatarColor": "#0B40C7",
    "bio": "Développeuse — pilote NoNote via API.",
    "status": "offline",
    "actif": "actif",
    "confirmedAt": null,
    "onboardingStep": 0,
    "onboardingCompleted": false,
    "persona": null,
    "sousProfil": null,
    "firstCanvasId": null,
    "totpEnabled": false,
    "featureFlags": {
      "templatesMarketplaceVisible": true,
      "callsEnabled": true,
      "mailboxEnabled": true
    }
  }
}
PUT/api/v1/auth/profile

Met à jour le profil. Champs acceptés : name, bio, avatarColor (format #RRGGBB), avatarUrl. Les champs omis restent inchangés.

Scope requis profile:write
Requête
{
  "name": "Ada Lovelace",
  "bio": "Développeuse — pilote NoNote via API.",
  "avatarColor": "#0B40C7"
}
Réponse (200)
{
  "user": {
    "id": "caa35a21-d7b7-4599-812c-35080160b6fe",
    "name": "Ada Lovelace",
    "email": "ada@example.com",
    "plan": "free",
    "role": "user",
    "features": [],
    "avatarUrl": null,
    "avatarColor": "#0B40C7",
    "bio": "Développeuse — pilote NoNote via API.",
    "status": "offline",
    "actif": "actif",
    "confirmedAt": null,
    "onboardingStep": 0,
    "onboardingCompleted": false,
    "persona": null,
    "sousProfil": null,
    "firstCanvasId": null,
    "totpEnabled": false
  },
  "message": "Profil mis a jour."
}

Tâches

Une tâche peut être en mode quick (par défaut — jeu de champs minimal) ou full (champs étendus : status, priority, labels, subtasks…). La réponse ne contient les champs étendus que pour une tâche full.

GET/api/v1/tasks

Liste les tâches de l'utilisateur. Filtres via query : mode, done, status, priority, canvas_id, search, sort, order, limit (≤ 200), offset.

Scope requis tasks:read
Requête
GET /api/v1/tasks?limit=50
Authorization: Bearer <token>
Réponse (200)
{
  "tasks": [
    {
      "id": "2367d366-d66a-40d0-a086-5523f6a953b7",
      "key": null,
      "mode": "quick",
      "title": "Préparer la démo API",
      "done": false,
      "dueDate": "2026-07-20",
      "canvasId": null,
      "postitId": null,
      "createdAt": "2026-07-16T13:57:18.570Z",
      "updatedAt": "2026-07-16T13:57:18.570Z"
    }
  ],
  "total": 1,
  "limit": 50,
  "offset": 0
}
POST/api/v1/tasks

Crée une tâche. Seul title est requis. Passez "mode": "full" pour renseigner status, priority, labels, estimatedHours, etc.

Scope requis tasks:write
Requête
{
  "title": "Migrer le webhook de facturation",
  "mode": "full",
  "status": "in_progress",
  "priority": "high",
  "type": "task",
  "description": "Basculer vers la v1 signee.",
  "labels": ["backend", "api"],
  "estimatedHours": 4,
  "dueDate": "2026-07-22"
}
Réponse (201)
{
  "id": "5f96ffc7-f346-4dbc-9080-cad415892da3",
  "key": null,
  "mode": "full",
  "title": "Migrer le webhook de facturation",
  "done": false,
  "dueDate": "2026-07-22",
  "canvasId": null,
  "postitId": null,
  "createdAt": "2026-07-16T14:02:12.535Z",
  "updatedAt": "2026-07-16T14:02:12.535Z",
  "description": "Basculer vers la v1 signee.",
  "status": "in_progress",
  "priority": "high",
  "type": "task",
  "assignee": "",
  "assigneeId": null,
  "reporter": "",
  "labels": ["backend", "api"],
  "estimatedHours": 4,
  "subtasks": [],
  "activity": [],
  "comments": []
}
PUT/api/v1/tasks/:id

Met à jour une tâche. Envoyez uniquement les champs à modifier. Passer status: "done" coche automatiquement done.

Scope requis tasks:write
Requête
PUT /api/v1/tasks/2367d366-d66a-40d0-a086-5523f6a953b7
{
  "status": "in_progress",
  "description": "Script rédigé, relecture en cours"
}
Réponse (200)
{
  "id": "2367d366-d66a-40d0-a086-5523f6a953b7",
  "key": null,
  "mode": "quick",
  "title": "Préparer la démo API",
  "done": false,
  "dueDate": "2026-07-20",
  "canvasId": null,
  "postitId": null,
  "createdAt": "2026-07-16T13:57:18.570Z",
  "updatedAt": "2026-07-16T13:57:18.612Z"
}
DELETE/api/v1/tasks/:id

Supprime définitivement une tâche. Action irréversible.

Scope requis tasks:write
Requête
DELETE /api/v1/tasks/2367d366-d66a-40d0-a086-5523f6a953b7
Authorization: Bearer <token>
Réponse (200)
{ "ok": true }

Canvas

GET/api/v1/canvases

Liste paginée des canvas accessibles (possédés ou partagés) avec leurs dossiers. Query : page, limit (≤ 100).

Scope requis canvas:read
Requête
GET /api/v1/canvases?page=1&limit=20
Authorization: Bearer <token>
Réponse (200)
{
  "data": [
    {
      "id": "007819e6-fad3-4bdc-a8c8-1ccc5820b3b0",
      "name": "Feuille de route API",
      "createdAt": "2026-07-16T13:57:18.640Z",
      "updatedAt": "2026-07-16T13:57:18.640Z",
      "thumbnail": null,
      "isShared": false,
      "publicShareToken": null,
      "isPublicShare": false,
      "ownerId": "caa35a21-d7b7-4599-812c-35080160b6fe",
      "folderId": null,
      "ownerName": "Ada Lovelace",
      "collaborators": [],
      "postits": [],
      "drawings": [],
      "events": [],
      "connections": [],
      "publishedTemplate": null
    }
  ],
  "folders": [],
  "pagination": { "page": 1, "limit": 20, "total": 1, "totalPages": 1 }
}
GET/api/v1/canvases/:id

Détail complet d'un canvas, avec ses post-its, dessins, événements et connexions déchiffrés.

Scope requis canvas:read
Requête
GET /api/v1/canvases/016dd03b-7cc3-44db-9a96-0721159abfd2
Authorization: Bearer <token>
Réponse (200)
{
  "id": "016dd03b-7cc3-44db-9a96-0721159abfd2",
  "name": "Kanban Sprint 12",
  "createdAt": "2026-07-16T14:02:12.610Z",
  "updatedAt": "2026-07-16T14:02:12.846Z",
  "thumbnail": null,
  "isShared": false,
  "publicShareToken": null,
  "isPublicShare": false,
  "ownerId": "85d832a6-9b1b-496d-abba-49ec07f43bc5",
  "folderId": null,
  "ownerName": "Ada Lovelace",
  "collaborators": [],
  "postits": [
    {
      "id": "f96dc5b7-bfaa-49c6-a3e8-c9936c0b0fa3",
      "type": "sticky",
      "x": 160, "y": 120, "w": 320, "h": 200,
      "data": { "text": "Revue de code", "color": "#E8EEFC" }
    }
  ],
  "drawings": [],
  "events": [],
  "connections": [],
  "publishedTemplate": null
}
POST/api/v1/canvases

Crée un canvas. Champs : name (≤ 200 car.), folderId et postits[] initiaux optionnels.

Scope requis canvas:write
Requête
{ "name": "Feuille de route API" }
Réponse (201)
{
  "id": "007819e6-fad3-4bdc-a8c8-1ccc5820b3b0",
  "name": "Feuille de route API",
  "createdAt": "2026-07-16T13:57:18.640Z",
  "updatedAt": "2026-07-16T13:57:18.640Z",
  "thumbnail": null,
  "isShared": false,
  "publicShareToken": null,
  "isPublicShare": false,
  "ownerId": "caa35a21-d7b7-4599-812c-35080160b6fe",
  "folderId": null,
  "ownerName": null,
  "collaborators": [],
  "postits": [],
  "drawings": [],
  "events": [],
  "connections": [],
  "publishedTemplate": null
}
POST/api/v1/canvases/:id/postits

Ajoute un bloc (post-it) au canvas. Champs : type, x, y (numériques requis), w, h, data. Renvoie l'identifiant du bloc créé.

Scope requis canvas:write
Requête
{
  "type": "sticky",
  "x": 160, "y": 120, "w": 320, "h": 200,
  "data": { "text": "Revue de code", "color": "#E8EEFC" }
}
Réponse (201)
{ "id": "f96dc5b7-bfaa-49c6-a3e8-c9936c0b0fa3" }
DELETE/api/v1/canvases/:id/postits/:pid

Supprime définitivement un bloc du canvas.

Scope requis canvas:write
Requête
DELETE /api/v1/canvases/016dd03b-…/postits/f96dc5b7-…
Authorization: Bearer <token>
Réponse (200)
{ "ok": true }

Drive

GET/api/v1/drive

Liste les fichiers et dossiers du Drive personnel (racine par défaut ; ?parentId= pour un sous-dossier). Les dossiers portent le nombre et la taille cumulée de leurs enfants.

Scope requis drive:read
Requête
GET /api/v1/drive
Authorization: Bearer <token>
Réponse (200)
[
  {
    "id": "982a5c77-c673-4d08-b6a3-c79b655f3e5d",
    "parentId": null,
    "canvasId": null,
    "name": "Exports API",
    "type": "folder",
    "mimeType": null,
    "size": 0,
    "createdAt": "2026-07-16T13:57:18.924Z",
    "childFileCount": 0,
    "childTotalSize": 0
  }
]
POST/api/v1/drive/folder

Crée un dossier. Champs : name (requis), parentId (optionnel).

Scope requis drive:write
Requête
{ "name": "Exports API" }
Réponse (201)
{
  "id": "982a5c77-c673-4d08-b6a3-c79b655f3e5d",
  "parentId": null,
  "canvasId": null,
  "name": "Exports API",
  "type": "folder",
  "mimeType": null,
  "size": 0,
  "createdAt": "2026-07-16T13:57:18.924Z"
}
DELETE/api/v1/drive/:fileId

Supprime définitivement un fichier ou un dossier (et son contenu). Action irréversible.

Scope requis drive:write
Requête
DELETE /api/v1/drive/982a5c77-c673-4d08-b6a3-c79b655f3e5d
Authorization: Bearer <token>
Réponse (200)
{ "ok": true }

Outils MCP · /mcp

Le serveur MCP distant expose 13 outils via JSON-RPC 2.0 sur POST /mcp (transport HTTP streamable). Le serveur s'annonce comme { "name": "nonote", "version": "1.0.0" }. Chaque appel porte l'en-tête Authorization: Bearer <token> ; tools/list ne renvoie que les outils couverts par les scopes du jeton.

Enveloppe de réponse. Le résultat d'un outil est renvoyé dans un bloc content de type text, dont le champ text contient le JSON du résultat (sérialisé) :

ENVELOPPEresult.content[0]
tools/call — requête
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "list_tasks",
    "arguments": {}
  }
}
tools/call — réponse
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"tasks\":[…],\"total\":1,\"limit\":50,\"offset\":0}"
      }
    ]
  }
}

Pour la lisibilité, les exemples ci-dessous montrent le JSON déjà désérialisé du champ text, sans répéter l'enveloppe content.

mutatingSensitive — confirmation en deux temps. Les outils destructifs (delete_task, delete_postit, delete_drive_file) sont marqués mutatingSensitive. Un premier appel n'exécute rien : il renvoie { "needsConfirmation": true, "actionId": "…" }. Un second appel avec { "actionId": "…" } redéclenche l'outil avec les arguments d'origine (les arguments renvoyés avec l'actionId sont ignorés). Voir delete_task pour un exemple complet.

Profil

TOOLget_profile

Récupère le profil de l'utilisateur authentifié (nom, bio, avatar, plan).

Scope profile:readmutatingSensitive false
Input schema
{ "type": "object", "properties": {} }
tools/call
{
  "jsonrpc": "2.0", "id": 2, "method": "tools/call",
  "params": { "name": "get_profile", "arguments": {} }
}
Résultat (texte JSON)
{
  "user": {
    "id": "caa35a21-d7b7-4599-812c-35080160b6fe",
    "name": "Ada Lovelace",
    "email": "ada@example.com",
    "plan": "free",
    "role": "user",
    "features": ["canvas", "drive", "chat", "mail",
      "tasks", "tickets", "billing", "priority_support"],
    "avatarColor": "#0B40C7",
    "bio": "Développeuse — pilote NoNote via API.",
    "totpEnabled": false,
    "featureFlags": {
      "templatesMarketplaceVisible": true,
      "callsEnabled": true, "mailboxEnabled": true
    }
  }
}
TOOLupdate_profile

Met à jour le profil (name, bio, avatarColor, avatarUrl). Les champs omis restent inchangés.

Scope profile:writemutatingSensitive false
Input schema
{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "bio": { "type": "string" },
    "avatarColor": { "type": "string" },
    "avatarUrl": { "type": "string" }
  }
}
tools/call
{
  "jsonrpc": "2.0", "id": 3, "method": "tools/call",
  "params": {
    "name": "update_profile",
    "arguments": {
      "name": "Ada Lovelace",
      "bio": "Développeuse — pilote NoNote via API.",
      "avatarColor": "#0B40C7"
    }
  }
}
Résultat (texte JSON)
{
  "user": {
    "id": "caa35a21-d7b7-4599-812c-35080160b6fe",
    "name": "Ada Lovelace",
    "avatarColor": "#0B40C7",
    "bio": "Développeuse — pilote NoNote via API.",
    "plan": "free", "role": "user"
  },
  "message": "Profil mis a jour."
}

Tâches

TOOLlist_tasks

Liste les tâches de l'utilisateur (Kanban / todo).

Scope tasks:readmutatingSensitive false
Input schema
{ "type": "object", "properties": {} }
tools/call
{
  "jsonrpc": "2.0", "id": 4, "method": "tools/call",
  "params": { "name": "list_tasks", "arguments": {} }
}
Résultat (texte JSON)
{
  "tasks": [
    {
      "id": "2367d366-d66a-40d0-a086-5523f6a953b7",
      "mode": "quick",
      "title": "Préparer la démo API",
      "done": false,
      "dueDate": "2026-07-20",
      "createdAt": "2026-07-16T13:57:18.570Z",
      "updatedAt": "2026-07-16T13:57:18.570Z"
    }
  ],
  "total": 1, "limit": 50, "offset": 0
}
TOOLcreate_task

Crée une tâche. Champs : title (obligatoire), description, status, dueDate.

Scope tasks:writemutatingSensitive false
Input schema
{
  "type": "object",
  "properties": {
    "title": { "type": "string" },
    "description": { "type": "string" },
    "status": { "type": "string" },
    "dueDate": { "type": "string" }
  },
  "required": ["title"]
}
tools/call
{
  "jsonrpc": "2.0", "id": 5, "method": "tools/call",
  "params": {
    "name": "create_task",
    "arguments": {
      "title": "Préparer la démo API",
      "description": "Rédiger le script de démonstration",
      "status": "todo",
      "dueDate": "2026-07-20"
    }
  }
}
Résultat (texte JSON)
{
  "id": "2367d366-d66a-40d0-a086-5523f6a953b7",
  "key": null,
  "mode": "quick",
  "title": "Préparer la démo API",
  "done": false,
  "dueDate": "2026-07-20",
  "canvasId": null,
  "postitId": null,
  "createdAt": "2026-07-16T13:57:18.570Z",
  "updatedAt": "2026-07-16T13:57:18.570Z"
}
TOOLupdate_task

Met à jour une tâche existante par id.

Scope tasks:writemutatingSensitive false
Input schema
{
  "type": "object",
  "properties": {
    "id": { "type": "string" },
    "title": { "type": "string" },
    "description": { "type": "string" },
    "status": { "type": "string" }
  },
  "required": ["id"]
}
tools/call
{
  "jsonrpc": "2.0", "id": 6, "method": "tools/call",
  "params": {
    "name": "update_task",
    "arguments": {
      "id": "2367d366-d66a-40d0-a086-5523f6a953b7",
      "status": "in_progress",
      "description": "Script rédigé, relecture en cours"
    }
  }
}
Résultat (texte JSON)
{
  "id": "2367d366-d66a-40d0-a086-5523f6a953b7",
  "mode": "quick",
  "title": "Préparer la démo API",
  "done": false,
  "dueDate": "2026-07-20",
  "createdAt": "2026-07-16T13:57:18.570Z",
  "updatedAt": "2026-07-16T13:57:18.612Z"
}
TOOLdelete_task

Supprime définitivement une tâche par id. Action irréversible.

Scope tasks:writemutatingSensitive true
Input schema
{
  "type": "object",
  "properties": { "id": { "type": "string" } },
  "required": ["id"]
}
1ᵉʳ appel — demande de confirmation
// requête
{
  "jsonrpc": "2.0", "id": 7, "method": "tools/call",
  "params": {
    "name": "delete_task",
    "arguments": { "id": "2367d366-…-5523f6a953b7" }
  }
}

// résultat (texte JSON) — RIEN n'est supprimé
{
  "needsConfirmation": true,
  "message": "Confirmation requise pour delete_task. Rappeler ce tool avec { actionId: \"a1b2c3…\" } pour executer.",
  "actionId": "a1b2c3d4e5f6"
}
2ᵉ appel — exécution
// requête
{
  "jsonrpc": "2.0", "id": 8, "method": "tools/call",
  "params": {
    "name": "delete_task",
    "arguments": { "actionId": "a1b2c3d4e5f6" }
  }
}

// résultat (texte JSON)
{ "ok": true }

Canvas

TOOLlist_canvases

Liste les canvas (tableaux blancs infinis) de l'utilisateur.

Scope canvas:readmutatingSensitive false
Input schema
{ "type": "object", "properties": {} }
tools/call
{
  "jsonrpc": "2.0", "id": 9, "method": "tools/call",
  "params": { "name": "list_canvases", "arguments": {} }
}
Résultat (texte JSON)
{
  "data": [
    {
      "id": "007819e6-fad3-4bdc-a8c8-1ccc5820b3b0",
      "name": "Feuille de route API",
      "ownerId": "caa35a21-…-35080160b6fe",
      "ownerName": "Ada Lovelace",
      "folderId": null,
      "postits": [],
      "collaborators": [],
      "createdAt": "2026-07-16T13:57:18.640Z",
      "updatedAt": "2026-07-16T13:57:18.640Z"
    }
  ],
  "folders": [],
  "pagination": { "page": 1, "limit": 20, "total": 1, "totalPages": 1 }
}
TOOLcreate_canvas

Crée un nouveau canvas. Champ : name (obligatoire).

Scope canvas:writemutatingSensitive false
Input schema
{
  "type": "object",
  "properties": { "name": { "type": "string" } },
  "required": ["name"]
}
tools/call
{
  "jsonrpc": "2.0", "id": 10, "method": "tools/call",
  "params": {
    "name": "create_canvas",
    "arguments": { "name": "Feuille de route API" }
  }
}
Résultat (texte JSON)
{
  "id": "007819e6-fad3-4bdc-a8c8-1ccc5820b3b0",
  "name": "Feuille de route API",
  "ownerId": "caa35a21-…-35080160b6fe",
  "folderId": null,
  "postits": [],
  "collaborators": [],
  "createdAt": "2026-07-16T13:57:18.640Z",
  "updatedAt": "2026-07-16T13:57:18.640Z"
}
TOOLcreate_postit

Crée un bloc dans un canvas. Types : sticky, page, todo, kanban, table… Champs : canvasId, type, data (obligatoires), x, y (optionnels, défaut 0 ; les dimensions w/h par défaut dépendent du type).

Scope canvas:writemutatingSensitive false
Input schema
{
  "type": "object",
  "properties": {
    "canvasId": { "type": "string" },
    "type": { "type": "string" },
    "data": { "type": "object" },
    "x": { "type": "number" },
    "y": { "type": "number" }
  },
  "required": ["canvasId", "type", "data"]
}
tools/call
{
  "jsonrpc": "2.0", "id": 11, "method": "tools/call",
  "params": {
    "name": "create_postit",
    "arguments": {
      "canvasId": "007819e6-…-1ccc5820b3b0",
      "type": "sticky",
      "data": { "text": "Publier la doc développeur", "color": "#E8EEFC" },
      "x": 120, "y": 80
    }
  }
}
Résultat (texte JSON)
{
  "id": "621bd876-c479-445b-9fbc-d653ccb655a9",
  "canvas_id": "007819e6-fad3-4bdc-a8c8-1ccc5820b3b0"
}
TOOLdelete_postit

Supprime définitivement un bloc d'un canvas. Action irréversible (confirmation en deux temps).

Scope canvas:writemutatingSensitive true
Input schema
{
  "type": "object",
  "properties": {
    "canvasId": { "type": "string" },
    "postitId": { "type": "string" }
  },
  "required": ["canvasId", "postitId"]
}
2ᵉ appel — avec actionId
{
  "jsonrpc": "2.0", "id": 12, "method": "tools/call",
  "params": {
    "name": "delete_postit",
    "arguments": { "actionId": "b7c8d9…" }
  }
}
Résultat (texte JSON)
{ "ok": true }

Drive

TOOLlist_drive_files

Liste les fichiers et dossiers du Drive personnel.

Scope drive:readmutatingSensitive false
Input schema
{ "type": "object", "properties": {} }
tools/call
{
  "jsonrpc": "2.0", "id": 13, "method": "tools/call",
  "params": { "name": "list_drive_files", "arguments": {} }
}
Résultat (texte JSON)
[
  {
    "id": "982a5c77-c673-4d08-b6a3-c79b655f3e5d",
    "parentId": null,
    "canvasId": null,
    "name": "Exports API",
    "type": "folder",
    "mimeType": null,
    "size": 0,
    "createdAt": "2026-07-16T13:57:18.924Z",
    "childFileCount": 0,
    "childTotalSize": 0
  }
]
TOOLcreate_drive_folder

Crée un dossier dans le Drive personnel. Champ : name (obligatoire), parentId (optionnel).

Scope drive:writemutatingSensitive false
Input schema
{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "parentId": { "type": "string" }
  },
  "required": ["name"]
}
tools/call
{
  "jsonrpc": "2.0", "id": 14, "method": "tools/call",
  "params": {
    "name": "create_drive_folder",
    "arguments": { "name": "Exports API" }
  }
}
Résultat (texte JSON)
{
  "id": "982a5c77-c673-4d08-b6a3-c79b655f3e5d",
  "parentId": null,
  "canvasId": null,
  "name": "Exports API",
  "type": "folder",
  "mimeType": null,
  "size": 0,
  "createdAt": "2026-07-16T13:57:18.924Z"
}
TOOLdelete_drive_file

Supprime définitivement un fichier ou dossier du Drive. Action irréversible (confirmation en deux temps).

Scope drive:writemutatingSensitive true
Input schema
{
  "type": "object",
  "properties": { "fileId": { "type": "string" } },
  "required": ["fileId"]
}
2ᵉ appel — avec actionId
{
  "jsonrpc": "2.0", "id": 15, "method": "tools/call",
  "params": {
    "name": "delete_drive_file",
    "arguments": { "actionId": "c9d0e1…" }
  }
}
Résultat (texte JSON)
{ "ok": true }

Connecter un agent IA

Tout client compatible MCP (Claude Desktop, Claude.ai, ChatGPT, etc.) peut se connecter au serveur /mcp en suivant le flux d'autorisation standard MCP : le client détecte que la ressource exige un jeton, découvre le serveur d'autorisation, obtient le consentement de l'utilisateur, puis appelle les outils.

Concrètement, le client réutilise exactement la brique OAuth2 décrite plus haut :

  1. La ressource protégée /mcp annonce, via les métadonnées de ressource protégée (/.well-known/oauth-protected-resource, RFC 9728), l'emplacement de son serveur d'autorisation.
  2. Le client lit les métadonnées du serveur d'autorisation à /oauth/.well-known/oauth-authorization-server pour trouver les endpoints (autorisation, jeton, enregistrement).
  3. Il s'enregistre dynamiquement (POST /oauth/register), puis lance Authorization Code + PKCE — l'utilisateur choisit les scopes sur l'écran de consentement de NoNote.
  4. Muni du jeton, le client appelle tools/list (qui ne renvoie que les outils autorisés par les scopes) puis tools/call.

Aucune configuration propriétaire n'est nécessaire : l'utilisateur colle l'URL du serveur MCP (https://www.nonote.fr/mcp) dans son client, s'authentifie via l'écran NoNote, et les 13 outils deviennent disponibles dans la limite des scopes accordés. La révocation se fait comme n'importe quel jeton OAuth2 (POST /oauth/revoke ou depuis les applications connectées du compte).