feat(mcp): instructions OAuth Claude.ai/ChatGPT sur /compte/mcp (#114)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+38
-5
@@ -45,6 +45,26 @@ def client_instructions(url: str, token: str):
|
|||||||
title="Claude Code",
|
title="Claude Code",
|
||||||
children=html.Pre(html.Code(claude)),
|
children=html.Pre(html.Code(claude)),
|
||||||
),
|
),
|
||||||
|
dbc.AccordionItem(
|
||||||
|
title="Claude.ai / Claude Desktop / mobile",
|
||||||
|
children=[
|
||||||
|
html.P("Aucun jeton à copier : ces applications utilisent OAuth."),
|
||||||
|
html.Ol(
|
||||||
|
[
|
||||||
|
html.Li(
|
||||||
|
"Paramètres → Connecteurs → Ajouter un connecteur personnalisé."
|
||||||
|
),
|
||||||
|
html.Li(f"URL du serveur MCP : {url}"),
|
||||||
|
html.Li(
|
||||||
|
"Laissez le champ « Client Secret » vide (client public)."
|
||||||
|
),
|
||||||
|
html.Li(
|
||||||
|
"Connectez-vous avec votre compte colibre, puis « Autoriser »."
|
||||||
|
),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
dbc.AccordionItem(
|
dbc.AccordionItem(
|
||||||
title="Gemini CLI",
|
title="Gemini CLI",
|
||||||
children=[
|
children=[
|
||||||
@@ -68,8 +88,20 @@ def client_instructions(url: str, token: str):
|
|||||||
title="ChatGPT",
|
title="ChatGPT",
|
||||||
children=[
|
children=[
|
||||||
html.P(
|
html.P(
|
||||||
"""L'app ChatGPT grand public exige une technique d'authentification plus complexe
|
"ChatGPT utilise aussi OAuth (aucun jeton à copier). Dans les "
|
||||||
qu'un simple jeton. Votez pour cette fonctionnalité si elle peut vous être utile."""
|
"connecteurs, ajoutez un connecteur par URL :"
|
||||||
|
),
|
||||||
|
html.Ol(
|
||||||
|
[
|
||||||
|
html.Li(f"URL du serveur MCP : {url}"),
|
||||||
|
html.Li(
|
||||||
|
"Connectez-vous avec colibre, puis autorisez l'accès."
|
||||||
|
),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
html.P(
|
||||||
|
"La disponibilité des connecteurs dépend de votre plan ChatGPT.",
|
||||||
|
className="text-muted",
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -185,9 +217,10 @@ def layout(**_):
|
|||||||
[
|
[
|
||||||
html.H2("Connecteur MCP"),
|
html.H2("Connecteur MCP"),
|
||||||
html.P(
|
html.P(
|
||||||
"Générez un jeton pour connecter votre agent IA (Claude, Gemini, "
|
"Les clients en ligne de commande (Claude Code, Gemini, Mistral) se "
|
||||||
"Mistral…) aux données colibre via le protocole MCP. Le jeton vaut "
|
"connectent avec un jeton généré ci-dessous. Les applications grand "
|
||||||
"votre identité : gardez-le secret. Un abonnement actif est requis."
|
"public (Claude.ai, ChatGPT) se connectent par OAuth, sans jeton à "
|
||||||
|
"copier. Dans tous les cas, un abonnement actif est requis."
|
||||||
),
|
),
|
||||||
*alerts,
|
*alerts,
|
||||||
html.H4("Générer un jeton", className="mt-3"),
|
html.H4("Générer un jeton", className="mt-3"),
|
||||||
|
|||||||
@@ -22,3 +22,32 @@ def test_page_module_registers_and_builds_client_instructions():
|
|||||||
assert "https://colibre.fr/_mcp" in text
|
assert "https://colibre.fr/_mcp" in text
|
||||||
for client_name in ("Claude", "Gemini", "Mistral", "ChatGPT"):
|
for client_name in ("Claude", "Gemini", "Mistral", "ChatGPT"):
|
||||||
assert client_name in text
|
assert client_name in text
|
||||||
|
|
||||||
|
|
||||||
|
def test_client_instructions_include_oauth_apps():
|
||||||
|
from src.app import app # noqa: F401
|
||||||
|
from src.pages.compte.mcp import client_instructions
|
||||||
|
|
||||||
|
comp = client_instructions("https://colibre.fr/_mcp", "<VOTRE_JETON>")
|
||||||
|
titles = _collect_titles(comp)
|
||||||
|
assert any("Claude.ai" in t for t in titles)
|
||||||
|
assert any("ChatGPT" in t for t in titles)
|
||||||
|
|
||||||
|
|
||||||
|
def _collect_titles(component):
|
||||||
|
# Parcourt récursivement les AccordionItem pour collecter leurs `title`.
|
||||||
|
found = []
|
||||||
|
|
||||||
|
def walk(node):
|
||||||
|
title = getattr(node, "title", None)
|
||||||
|
if isinstance(title, str):
|
||||||
|
found.append(title)
|
||||||
|
children = getattr(node, "children", None)
|
||||||
|
if isinstance(children, (list, tuple)):
|
||||||
|
for c in children:
|
||||||
|
walk(c)
|
||||||
|
elif children is not None:
|
||||||
|
walk(children)
|
||||||
|
|
||||||
|
walk(component)
|
||||||
|
return found
|
||||||
|
|||||||
Reference in New Issue
Block a user