c3023d2cc3
Applied @instrument_tool decorator to all 86 remaining tools across 8 server files. Instrumented files: - calendar.py: 16 tools - contacts.py: 7 tools - deck.py: 25 tools - webdav.py: 11 tools - tables.py: 6 tools - sharing.py: 5 tools - cookbook.py: 13 tools - semantic.py: 3 tools Total: 93 tools instrumented (7 in notes.py + 86 in other files) These metrics populate: - MCP Tool Calls panel (by tool name and status) - MCP Tool Duration panel (histogram) - MCP Tool Errors panel (by tool name and error type) This completes PR #295 - All 5 phases of metrics instrumentation done: ✅ Phase 1: Queue size metrics (2 locations) ✅ Phase 2: Health checks (1 location) ✅ Phase 3: Database operations (3 methods) ✅ Phase 4: OAuth token metrics (3 locations) ✅ Phase 5: MCP tool metrics (93 tools) All 34 dashboard panels now have data sources.
72 lines
2.4 KiB
Python
72 lines
2.4 KiB
Python
import logging
|
|
|
|
from mcp.server.fastmcp import Context, FastMCP
|
|
|
|
from nextcloud_mcp_server.auth import require_scopes
|
|
from nextcloud_mcp_server.context import get_client
|
|
from nextcloud_mcp_server.observability.metrics import instrument_tool
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def configure_tables_tools(mcp: FastMCP):
|
|
# Tables tools
|
|
@mcp.tool()
|
|
@require_scopes("tables:read")
|
|
@instrument_tool
|
|
async def nc_tables_list_tables(ctx: Context):
|
|
"""List all tables available to the user"""
|
|
client = await get_client(ctx)
|
|
return await client.tables.list_tables()
|
|
|
|
@mcp.tool()
|
|
@require_scopes("tables:read")
|
|
@instrument_tool
|
|
async def nc_tables_get_schema(table_id: int, ctx: Context):
|
|
"""Get the schema/structure of a specific table including columns and views"""
|
|
client = await get_client(ctx)
|
|
return await client.tables.get_table_schema(table_id)
|
|
|
|
@mcp.tool()
|
|
@require_scopes("tables:read")
|
|
@instrument_tool
|
|
async def nc_tables_read_table(
|
|
table_id: int,
|
|
ctx: Context,
|
|
limit: int | None = None,
|
|
offset: int | None = None,
|
|
):
|
|
"""Read rows from a table with optional pagination"""
|
|
client = await get_client(ctx)
|
|
return await client.tables.get_table_rows(table_id, limit, offset)
|
|
|
|
@mcp.tool()
|
|
@require_scopes("tables:write")
|
|
@instrument_tool
|
|
async def nc_tables_insert_row(table_id: int, data: dict, ctx: Context):
|
|
"""Insert a new row into a table.
|
|
|
|
Data should be a dictionary mapping column IDs to values, e.g. {1: "text", 2: 42}
|
|
"""
|
|
client = await get_client(ctx)
|
|
return await client.tables.create_row(table_id, data)
|
|
|
|
@mcp.tool()
|
|
@require_scopes("tables:write")
|
|
@instrument_tool
|
|
async def nc_tables_update_row(row_id: int, data: dict, ctx: Context):
|
|
"""Update an existing row in a table.
|
|
|
|
Data should be a dictionary mapping column IDs to new values, e.g. {1: "new text", 2: 99}
|
|
"""
|
|
client = await get_client(ctx)
|
|
return await client.tables.update_row(row_id, data)
|
|
|
|
@mcp.tool()
|
|
@require_scopes("tables:write")
|
|
@instrument_tool
|
|
async def nc_tables_delete_row(row_id: int, ctx: Context):
|
|
"""Delete a row from a table"""
|
|
client = await get_client(ctx)
|
|
return await client.tables.delete_row(row_id)
|