Skip to content

Conversation

@ZmeiGorynych
Copy link
Member

@ZmeiGorynych ZmeiGorynych commented Jan 20, 2026

Summary by CodeRabbit

  • New Features

    • Added an MCP Server for Google Slides: presentation/slide/element retrieval, thumbnails, read/write/replace, copy/move/delete, and multi-format outputs (raw, domain, outline)
  • Documentation

    • Added comprehensive MCP Server docs: installation, credentials, CLI/config, tool reference, examples, error schemas, and troubleshooting
  • Chores

    • Bumped package version to 0.3.3 and added a console entry point for the MCP server
  • Tests

    • Added unit and concurrency tests for MCP models, utils, and client child behavior

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 20, 2026

📝 Walkthrough

Walkthrough

Adds a new MCP server for Google Slides with Pydantic models, utilities, CLI entry, tests, docs, and client credential/child-client lifecycle changes to support per-request clients and MCP tool execution (presentation/slide/element operations, thumbnails, read/write, copy/move/delete).

Changes

Cohort / File(s) Summary
Documentation
README.md, docs/MCP_SERVER.md
Updated credential reference in README; added docs/MCP_SERVER.md documenting MCP Server installation, configuration, CLI, tools, formats, errors, and troubleshooting.
Credential & Client lifecycle
gslides_api/client.py
Moved credential loading into GoogleAPIClient.initialize_credentials(credential_location); added create_child_client(...), per-instance batch state, _shared_services support; module-level initialize_credentials now delegates to instance.
MCP package surface
gslides_api/mcp/__init__.py
New package initializer exporting MCP entry points (mcp, main, initialize_server), models, and utility helpers.
MCP Data Models
gslides_api/mcp/models.py
New Pydantic models and enums: OutputFormat, ThumbnailSizeOption, ErrorResponse, SuccessResponse, ElementOutline, SlideOutline, PresentationOutline.
MCP Utilities
gslides_api/mcp/utils.py
New utilities: parse_presentation_id, regex for Slides URLs, slide/element naming & search helpers, outline builders, markdown extraction, and standardized error factories.
MCP Server Implementation
gslides_api/mcp/server.py
New MCP server exposing tools (get_presentation, get_slide, get_element, get_slide_thumbnail, read/write markdown, replace image, copy/move/delete slide), per-request child clients, response formatting, CLI main(), and structured error handling.
Packaging / CLI
pyproject.toml
Version bumped to 0.3.3; added dependency mcp = "^1.0.0"; added console script gslides-mcp = "gslides_api.mcp.server:main".
Tests
tests/mcp_tests/*
tests/mcp_tests/__init__.py, tests/mcp_tests/test_models.py, tests/mcp_tests/test_utils.py, tests/mcp_tests/test_concurrency.py
Added tests for models, utils (URL parsing, error builders), and concurrency/child-client behavior (shared services, isolated batch state, initialization checks).

Sequence Diagram(s)

sequenceDiagram
    participant User as AI Assistant / User
    participant MCP as MCP Server (gslides_api.mcp.server)
    participant Client as GoogleAPIClient
    participant SlidesAPI as Google Slides API

    User->>MCP: invoke tool (e.g., get_slide)
    activate MCP

    MCP->>MCP: parse_presentation_id()
    MCP->>Client: get_api_client() (create child from factory)
    activate Client
    Client-->>MCP: authenticated per-request client
    deactivate Client

    MCP->>SlidesAPI: fetch_presentation(presentation_id)
    activate SlidesAPI
    SlidesAPI-->>MCP: presentation JSON
    deactivate SlidesAPI

    MCP->>MCP: find_slide_by_name()
    MCP->>MCP: _get_effective_format(how)
    alt format == OUTLINE
        MCP->>MCP: build_slide_outline()
    else format == DOMAIN
        MCP->>MCP: convert_to_domain_model()
    else format == RAW
        MCP->>MCP: return raw JSON
    end

    MCP->>MCP: _format_response()
    deactivate MCP
    MCP-->>User: JSON/metadata (or error)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • PR #50: Modifies gslides_api/client.py credential initialization/OAuth flow; strongly related due to overlapping credential/client lifecycle changes.
  • PR #43: Changes gslides_api/client.py concerning client initialization and batch-update behavior; related because both touch GoogleAPIClient internals and child-client semantics.

Poem

🐰 I hop through slides both wide and deep,
New tools awake from their quiet sleep,
Credentials in place, thumbnails gleam,
Outlines and copies — a rabbit's dream,
Hooray for MCP — let's leap! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main objective of the pull request—adding an MCP server to the gslides-api library. It directly summarizes the primary change across multiple new files and modules.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Fix all issues with AI agents
In `@docs/MCP_SERVER.md`:
- Line 12: The Table of Contents entry linking to "#configuration" is broken
because there is no corresponding "## Configuration" heading; either remove or
update the TOC link, or add a "## Configuration" section to the document (create
a heading titled "## Configuration" and include the intended configuration
details), then ensure the TOC entry text matches that exact heading text
("Configuration") so the anchor works.

In `@gslides_api/mcp/models.py`:
- Around line 25-33: The ErrorResponse Pydantic model uses a Dict[str, Any] for
the details field which violates repo guidelines; change ErrorResponse.details
to a typed list of structured items (e.g., List[DetailItem]) and add a new
DetailItem model describing key, value, and optional meta fields; update any
corresponding models (e.g., SuccessResponse) that use Dict to use the same
DetailItem list, and update utils/server emitters to produce and return a list
of DetailItem instances instead of raw dicts so schemas remain explicit and
validated (search for class ErrorResponse and its details field and the
analogous model around lines 64-71 to locate all usages).

In `@gslides_api/mcp/server.py`:
- Around line 376-386: The code writes thumbnails to a deterministic temp
filename (filename/file_path) which can collide under concurrent calls; update
the save logic in the block using thumbnail.payload/image_data and
safe_slide_name to create a unique temp file (e.g., use
tempfile.NamedTemporaryFile or mkstemp with a unique suffix or include a
uuid4/timestamp) and write the image to that unique path, then return that
unique file path instead of a fixed filename to avoid overwrites.
- Around line 64-100: Add an asyncio.Lock named api_client_lock alongside the
global api_client and initialize it in initialize_server so concurrent handlers
can serialize access; specifically, declare api_client_lock:
Optional[asyncio.Lock] = None at module scope, set api_client_lock =
asyncio.Lock() inside initialize_server after creating the GoogleAPIClient, and
update docs/comments to instruct handlers to use "async with api_client_lock:
client = get_api_client()" before calling client methods (or refactor to
per-request GoogleAPIClient instances). Ensure references to api_client,
get_api_client, initialize_server, and GoogleAPIClient are preserved so callers
can adopt the lock-based access pattern.

In `@pyproject.toml`:
- Around line 22-30: The entrypoint gslides-mcp imports mcp.server.FastMCP
unconditionally so invoking the CLI without the optional mcp extra raises
ImportError; either make mcp a required dependency in pyproject by moving mcp =
{version = "^1.0.0"} out of optional extras, or modify gslides_api.mcp.server
(the module that defines FastMCP and the CLI main) to guard the import: wrap the
import of mcp.server.FastMCP in a try/except ImportError and raise a clear
runtime error from main (or when importing) that tells the user to install the
[mcp] extra (e.g., "install with poetry install --extras mcp" or similar),
ensuring the entrypoint fails with a helpful message instead of a raw
ImportError.

In `@tests/mcp_tests/test_utils.py`:
- Around line 14-15: Rename the test class to fix the typo: change the class
name TestParsePresenatationId to TestParsePresentationId in
tests/mcp_tests/test_utils.py so it correctly reflects the parse_presentation_id
function and follows naming conventions used by the test suite; update any
references to TestParsePresenatationId within that file if present.
🧹 Nitpick comments (1)
gslides_api/mcp/__init__.py (1)

30-49: Consider sorting __all__ alphabetically.

Static analysis (RUF022) flags that __all__ is not sorted. While the current categorical grouping (Server, Models, Utils) is readable, the coding guidelines specify using isort for import sorting. You can apply isort-style sorting to __all__ for consistency.

♻️ Suggested sorted __all__
 __all__ = [
-    # Server
-    "mcp",
-    "main",
-    "initialize_server",
-    # Models
-    "OutputFormat",
-    "ThumbnailSizeOption",
+    # Models
     "ElementOutline",
-    "SlideOutline",
-    "PresentationOutline",
     "ErrorResponse",
+    "OutputFormat",
+    "PresentationOutline",
+    "SlideOutline",
     "SuccessResponse",
+    "ThumbnailSizeOption",
+    # Server
+    "initialize_server",
+    "main",
+    "mcp",
     # Utils
-    "parse_presentation_id",
-    "get_slide_name",
-    "get_element_name",
+    "find_element_by_name",
     "find_slide_by_name",
-    "find_element_by_name",
+    "get_element_name",
+    "get_slide_name",
+    "parse_presentation_id",
 ]

- [Server Startup](#server-startup)
- [Tool Reference](#tool-reference)
- [Output Formats](#output-formats)
- [Configuration](#configuration)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Broken TOC link: #configuration section does not exist.

The Table of Contents references [Configuration](#configuration) but there is no ## Configuration heading in the document. Either add the missing section or update the TOC entry.

🔧 Suggested fix - remove or rename the link
 - [Output Formats](`#output-formats`)
-- [Configuration](`#configuration`)
 - [Troubleshooting](`#troubleshooting`)

Or add a ## Configuration section if intended.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- [Configuration](#configuration)
- [Output Formats](`#output-formats`)
- [Troubleshooting](`#troubleshooting`)
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

12-12: Link fragments should be valid

(MD051, link-fragments)

🤖 Prompt for AI Agents
In `@docs/MCP_SERVER.md` at line 12, The Table of Contents entry linking to
"#configuration" is broken because there is no corresponding "## Configuration"
heading; either remove or update the TOC link, or add a "## Configuration"
section to the document (create a heading titled "## Configuration" and include
the intended configuration details), then ensure the TOC entry text matches that
exact heading text ("Configuration") so the anchor works.

ZmeiGorynych and others added 3 commits January 20, 2026 12:08
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants