We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/nic01asFr/mcp-server-grist'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
"""
Outils de navigation pour l'API Grist.
Ce module contient des outils MCP pour naviguer dans la structure hiérarchique de Grist:
organisations, espaces de travail, documents, tables, colonnes et enregistrements.
"""
import logging
from typing import Any, Dict, List, Optional, Union
from fastmcp import Context
from ..client import get_client
from ..models import MCP_Response
# Configurer le logger
logger = logging.getLogger("grist_mcp_server")
def register_navigation_tools(mcp_server):
"""
Enregistre tous les outils de navigation sur le serveur MCP.
Args:
mcp_server: L'instance du serveur MCP sur laquelle enregistrer les outils.
"""
# Enregistrement des outils sur le serveur MCP
mcp_server.tool()(list_organizations)
mcp_server.tool()(describe_organization)
mcp_server.tool()(list_workspaces)
mcp_server.tool()(describe_workspace)
mcp_server.tool()(list_documents)
mcp_server.tool()(describe_document)
mcp_server.tool()(list_tables)
mcp_server.tool()(list_columns)
mcp_server.tool()(list_records)
mcp_server.tool()(get_table_schema)
async def list_organizations(ctx: Context) -> Dict[str, Any]:
"""
Liste toutes les organisations Grist accessibles.
Prérequis:
Aucun - ce tool est le point d'entrée principal pour la navigation.
Flux de travail typique:
1. list_organizations() → obtenir tous les org_id disponibles
2. list_workspaces(org_id) → explorer les espaces de travail
Returns:
Dict avec:
- success (bool): Indique si l'opération a réussi
- message (str): Message de succès ou d'erreur
- organizations (List): Liste des organisations disponibles
"""
logger.info("Tool called: list_organizations")
try:
client = get_client(ctx)
if not client:
return {
"success": False,
"message": "Client Grist non configuré",
"organizations": []
}
orgs = await client.list_orgs()
return {
"success": True,
"message": f"Found {len(orgs)} organizations",
"organizations": [org.model_dump() for org in orgs]
}
except Exception as e:
logger.error(f"Error listing organizations: {e}")
return {
"success": False,
"message": f"Error listing organizations: {str(e)}",
"organizations": []
}
async def describe_organization(org_id: Union[int, str], ctx: Context) -> Dict[str, Any]:
"""
Obtient des informations détaillées sur une organisation spécifique.
Prérequis:
- list_organizations: Pour obtenir un org_id valide
Flux de travail typique:
1. list_organizations() → identifier l'organisation
2. describe_organization(org_id) → obtenir les détails
Args:
org_id: L'ID de l'organisation à décrire
Returns:
Dict avec:
- success (bool): Indique si l'opération a réussi
- message (str): Message de succès ou d'erreur
- organization (Dict): Détails de l'organisation
"""
logger.info(f"Tool called: describe_organization with org_id: {org_id}")
try:
client = get_client(ctx)
if not client:
return {
"success": False,
"message": "Client Grist non configuré"
}
org_details = await client.describe_org(org_id)
return {
"success": True,
"message": f"Found organization details for {org_id}",
"organization": org_details
}
except Exception as e:
logger.error(f"Error describing organization: {e}")
return {
"success": False,
"message": f"Error describing organization {org_id}: {str(e)}"
}
async def list_workspaces(org_id: Union[int, str], ctx: Context) -> Dict[str, Any]:
"""
Liste tous les espaces de travail dans une organisation Grist.
Prérequis:
- list_organizations: Pour obtenir un org_id valide
Flux de travail typique:
1. list_organizations() → choisir org_id
2. list_workspaces(org_id) → obtenir workspace_id
3. list_documents(workspace_id) → naviguer dans les documents
Voir aussi:
- create_workspace: Pour créer un nouvel espace de travail
- describe_workspace: Pour obtenir les détails d'un workspace
- modify_workspace_access: Pour gérer les permissions
Args:
org_id: L'ID de l'organisation (entier ou sous-domaine string)
Returns:
Dict avec:
- success (bool): Indique si l'opération a réussi
- message (str): Message de succès ou d'erreur
- workspaces (List): Liste des espaces de travail
"""
logger.info(f"Tool called: list_workspaces with org_id: {org_id}")
try:
client = get_client(ctx)
if not client:
return {
"success": False,
"message": "Client Grist non configuré",
"workspaces": []
}
workspaces = await client.list_workspaces(org_id)
return {
"success": True,
"message": f"Found {len(workspaces)} workspaces in organization {org_id}",
"workspaces": [workspace.model_dump() for workspace in workspaces]
}
except Exception as e:
logger.error(f"Error listing workspaces: {e}")
return {
"success": False,
"message": f"Error listing workspaces for organization {org_id}: {str(e)}",
"workspaces": []
}
async def describe_workspace(workspace_id: int, ctx: Context) -> Dict[str, Any]:
"""
Obtient des informations détaillées sur un espace de travail spécifique.
Prérequis:
- list_workspaces: Pour obtenir un workspace_id valide
Flux de travail typique:
1. list_organizations() → identifier l'organisation
2. list_workspaces(org_id) → identifier l'espace de travail
3. describe_workspace(workspace_id) → obtenir les détails
Args:
workspace_id: L'ID de l'espace de travail à décrire
Returns:
Dict avec:
- success (bool): Indique si l'opération a réussi
- message (str): Message de succès ou d'erreur
- workspace (Dict): Détails de l'espace de travail
"""
logger.info(f"Tool called: describe_workspace with workspace_id: {workspace_id}")
try:
client = get_client(ctx)
if not client:
return {
"success": False,
"message": "Client Grist non configuré"
}
workspace_details = await client.describe_workspace(workspace_id)
return {
"success": True,
"message": f"Found workspace details for {workspace_id}",
"workspace": workspace_details
}
except Exception as e:
logger.error(f"Error describing workspace: {e}")
return {
"success": False,
"message": f"Error describing workspace {workspace_id}: {str(e)}"
}
async def list_documents(workspace_id: int, ctx: Context) -> Dict[str, Any]:
"""
Liste tous les documents dans un espace de travail Grist.
Prérequis:
- list_workspaces: Pour obtenir un workspace_id valide
Flux de travail typique:
1. list_workspaces(org_id) → obtenir workspace_id
2. list_documents(workspace_id) → obtenir doc_id
3. list_tables(doc_id) → explorer les tables du document
Voir aussi:
- create_document: Pour créer un nouveau document
- describe_document: Pour obtenir les détails d'un document
- modify_document_access: Pour gérer les permissions
Args:
workspace_id: L'ID de l'espace de travail
Returns:
Dict avec:
- success (bool): Indique si l'opération a réussi
- message (str): Message de succès ou d'erreur
- documents (List): Liste des documents
"""
logger.info(f"Tool called: list_documents with workspace_id: {workspace_id}")
try:
client = get_client(ctx)
if not client:
return {
"success": False,
"message": "Client Grist non configuré",
"documents": []
}
documents = await client.list_documents(workspace_id)
return {
"success": True,
"message": f"Found {len(documents)} documents in workspace {workspace_id}",
"documents": [document.model_dump() for document in documents]
}
except Exception as e:
logger.error(f"Error listing documents: {e}")
return {
"success": False,
"message": f"Error listing documents for workspace {workspace_id}: {str(e)}",
"documents": []
}
async def describe_document(doc_id: str, ctx: Context) -> Dict[str, Any]:
"""
Obtient des informations détaillées sur un document spécifique.
Prérequis:
- list_documents: Pour obtenir un doc_id valide
Flux de travail typique:
1. list_documents(workspace_id) → identifier le document
2. describe_document(doc_id) → obtenir les détails complets
Args:
doc_id: L'ID du document à décrire
Returns:
Dict avec:
- success (bool): Indique si l'opération a réussi
- message (str): Message de succès ou d'erreur
- document (Dict): Détails du document
"""
logger.info(f"Tool called: describe_document with doc_id: {doc_id}")
try:
client = get_client(ctx)
if not client:
return {
"success": False,
"message": "Client Grist non configuré"
}
document_details = await client.describe_doc(doc_id)
return {
"success": True,
"message": f"Found document details for {doc_id}",
"document": document_details
}
except Exception as e:
logger.error(f"Error describing document: {e}")
return {
"success": False,
"message": f"Error describing document {doc_id}: {str(e)}"
}
async def list_tables(doc_id: str, ctx: Context) -> Dict[str, Any]:
"""
Liste toutes les tables dans un document Grist.
Prérequis:
- list_documents: Pour obtenir un doc_id valide
Flux de travail typique:
1. list_documents(workspace_id) → obtenir doc_id
2. list_tables(doc_id) → obtenir table_id
3. list_columns(doc_id, table_id) → explorer la structure
Voir aussi:
- create_table: Pour créer une nouvelle table
- filter_sql_query: Pour requêter les données d'une table
Args:
doc_id: L'ID du document
Returns:
Dict avec:
- success (bool): Indique si l'opération a réussi
- message (str): Message de succès ou d'erreur
- tables (List): Liste des tables
"""
logger.info(f"Tool called: list_tables with doc_id: {doc_id}")
try:
client = get_client(ctx)
if not client:
return {
"success": False,
"message": "Client Grist non configuré",
"tables": []
}
tables = await client.list_tables(doc_id)
return {
"success": True,
"message": f"Found {len(tables)} tables in document {doc_id}",
"tables": [table.model_dump() for table in tables]
}
except Exception as e:
logger.error(f"Error listing tables: {e}")
return {
"success": False,
"message": f"Error listing tables for document {doc_id}: {str(e)}",
"tables": []
}
async def list_columns(doc_id: str, table_id: str, ctx: Context) -> Dict[str, Any]:
"""
Liste toutes les colonnes dans une table Grist.
Prérequis:
- list_tables: Pour obtenir un table_id valide
Flux de travail typique:
1. list_tables(doc_id) → obtenir table_id
2. list_columns(doc_id, table_id) → explorer la structure
3. list_records(doc_id, table_id) → obtenir les données
Voir aussi:
- create_column: Pour ajouter une nouvelle colonne
- modify_column: Pour modifier une colonne existante
Args:
doc_id: L'ID du document
table_id: L'ID de la table
Returns:
Dict avec:
- success (bool): Indique si l'opération a réussi
- message (str): Message de succès ou d'erreur
- columns (List): Liste des colonnes
"""
logger.info(f"Tool called: list_columns with doc_id: {doc_id}, table_id: {table_id}")
try:
client = get_client(ctx)
if not client:
return {
"success": False,
"message": "Client Grist non configuré",
"columns": []
}
columns = await client.list_columns(doc_id, table_id)
return {
"success": True,
"message": f"Found {len(columns)} columns in table {table_id}",
"columns": [column.model_dump() for column in columns]
}
except Exception as e:
logger.error(f"Error listing columns: {e}")
return {
"success": False,
"message": f"Error listing columns for table {table_id} in document {doc_id}: {str(e)}",
"columns": []
}
async def list_records(
doc_id: str,
table_id: str,
sort: Optional[str] = None,
limit: Optional[int] = None,
ctx: Context = None
) -> Dict[str, Any]:
"""
Liste les enregistrements dans une table Grist avec tri et limitation optionnels.
Prérequis:
- list_tables: Pour obtenir un table_id valide
Flux de travail typique:
1. list_tables(doc_id) → obtenir table_id
2. list_columns(doc_id, table_id) → comprendre la structure
3. list_records(doc_id, table_id, sort="nom", limit=10) → obtenir les données
Voir aussi:
- filter_sql_query: Alternative avec filtrage avancé
- add_grist_records: Pour ajouter des enregistrements
Args:
doc_id: L'ID du document Grist
table_id: L'ID de la table
sort: Colonne de tri (optionnel, format: "colonne" ou "colonne:asc/desc")
limit: Nombre maximum d'enregistrements à retourner (optionnel)
Returns:
Dict avec:
- success (bool): Indique si l'opération a réussi
- message (str): Message de succès ou d'erreur
- records (List): Liste des enregistrements
- record_count (int): Nombre total d'enregistrements retournés
"""
logger.info(f"Tool called: list_records with doc_id: {doc_id}, table_id: {table_id}")
try:
client = get_client(ctx)
if not client:
return {
"success": False,
"message": "Client Grist non configuré",
"records": [],
"record_count": 0
}
records = await client.list_records(doc_id, table_id, sort=sort, limit=limit)
limit_info = f" (limited to {limit})" if limit else ""
sort_info = f" sorted by {sort}" if sort else ""
return {
"success": True,
"message": f"Found {len(records)} records in table {table_id}{sort_info}{limit_info}",
"records": [record.model_dump() for record in records],
"record_count": len(records)
}
except Exception as e:
logger.error(f"Error listing records: {e}")
return {
"success": False,
"message": f"Error listing records for table {table_id} in document {doc_id}: {str(e)}",
"records": [],
"record_count": 0
}
async def get_table_schema(doc_id: str, table_id: str, ctx: Context) -> Dict[str, Any]:
"""
Obtient le schéma détaillé d'une table Grist.
Prérequis:
- list_tables: Pour obtenir un table_id valide
Flux de travail typique:
1. list_tables(doc_id) → obtenir table_id
2. get_table_schema(doc_id, table_id) → obtenir la structure détaillée
Voir aussi:
- list_columns: Pour une liste plus simple des colonnes
Args:
doc_id: L'ID du document
table_id: L'ID de la table
Returns:
Dict avec:
- success (bool): Indique si l'opération a réussi
- message (str): Message de succès ou d'erreur
- schema (Dict): Schéma détaillé de la table au format frictionless
"""
logger.info(f"Tool called: get_table_schema with doc_id: {doc_id}, table_id: {table_id}")
try:
client = get_client(ctx)
if not client:
return {
"success": False,
"message": "Client Grist non configuré"
}
schema = await client.download_table_schema(doc_id, table_id)
return {
"success": True,
"message": f"Retrieved schema for table {table_id}",
"schema": schema
}
except Exception as e:
logger.error(f"Error getting table schema: {e}")
return {
"success": False,
"message": f"Error getting schema for table {table_id} in document {doc_id}: {str(e)}"
}