Skip to content

feat: Add MCP tool annotations for read-only, destructive, and idempotent hints#839

Merged
Aaron ("AJ") Steers (aaronsteers) merged 3 commits intomainfrom
devin/1761253837-add-mcp-tool-annotations
Oct 23, 2025
Merged

feat: Add MCP tool annotations for read-only, destructive, and idempotent hints#839
Aaron ("AJ") Steers (aaronsteers) merged 3 commits intomainfrom
devin/1761253837-add-mcp-tool-annotations

Conversation

@aaronsteers
Copy link
Copy Markdown
Member

@aaronsteers Aaron ("AJ") Steers (aaronsteers) commented Oct 23, 2025

feat: Add MCP tool annotations for read-only, destructive, and idempotent hints

Summary

This PR adds comprehensive MCP annotations to all 27 tools in the PyAirbyte MCP server, classifying each tool's behavior according to the FastMCP 2.2.7+ specification. These annotations enable AI assistants and future safe mode implementations to understand tool behavior patterns.

Annotations added:

  • readOnlyHint: Indicates if tool only reads without making changes
  • destructiveHint: Signals if changes are destructive (updates/deletes)
  • idempotentHint: Indicates if repeated calls have the same effect
  • openWorldHint: Specifies if tool interacts with external systems

Tool breakdown:

  • Local ops (11 tools): All read-only except sync_source_to_cache (non-destructive write)
  • Cloud ops (14 tools): Two destructive tools (update_custom_source_definition, permanently_delete_custom_source_definition)
  • Connector registry (2 tools): Both read-only

This is groundwork for future safe mode implementation - no enforcement logic is included in this PR.

Review & Testing Checklist for Human

Note: This PR only adds metadata annotations and does not implement any enforcement logic. Classification accuracy is critical for future safe mode PRs.

  • Verify sync_source_to_cache classification: Currently marked as destructiveHint: False (non-destructive), but this depends on write strategy. REPLACE strategy could be destructive - does this need to be True?
  • Test annotations are exposed correctly: Run poetry run poe mcp-inspect to verify annotations appear in the MCP tool list and are properly formatted
  • Review idempotent classifications: Check tools marked idempotentHint: False (like get_stream_previews, read_source_stream_records) - these return potentially different data on each call. Confirm this is the intended behavior for idempotency classification.
  • Spot check openWorldHint accuracy: Tools marked openWorldHint: True interact with external systems (connectors, cloud APIs). Verify this makes sense for each tool.

Test Plan

# Verify annotations are properly exposed
poetry run poe mcp-inspect

# Look for the annotations field in each tool's output
# Should see: "readOnlyHint", "destructiveHint", "idempotentHint", "openWorldHint"

Notes

  • This PR follows FastMCP 2.2.7+ annotation specification
  • Future PR will implement safe mode enforcement using these annotations
  • All lint checks and type checks pass

Requested by: AJ Steers (Aaron ("AJ") Steers (@aaronsteers))
Devin Session: https://app.devin.ai/sessions/026dbd2898474bc2a3ce21aec839533e

Summary by CodeRabbit

  • New Features

    • Added standardized per-tool safety and behavior annotations and applied them across cloud, connector, and local operations.
  • Documentation

    • Improved tool descriptions and metadata to clarify read-only, idempotent, destructive, and openness semantics.
  • Chores

    • Centralized annotation constants for consistent metadata usage across tooling.

Important

Auto-merge enabled.

This PR is set to merge automatically when all requirements are met.

…tent hints

Add comprehensive MCP annotations to all tools in the PyAirbyte MCP server:
- readOnlyHint: Indicates if tool only reads without making changes
- destructiveHint: Signals if changes are destructive (updates/deletes)
- idempotentHint: Indicates if repeated calls have the same effect
- openWorldHint: Specifies if tool interacts with external systems

This classification enables future safe mode implementations and helps
AI assistants understand tool behavior patterns.

Tool classifications:
- Local ops: All read-only except sync_source_to_cache (non-destructive write)
- Cloud ops: Two destructive tools (update/delete custom definitions)
- Connector registry: All read-only

Annotations follow FastMCP 2.2.7+ specification.

Co-Authored-By: AJ Steers <aj@airbyte.io>
@devin-ai-integration
Copy link
Copy Markdown
Contributor

Original prompt from AJ Steers
@Devin - Let's add a general "safe mode" to PyAirbyte MCP, driven by an env var AIRBYTE_CLOUD_MCP_SAFE_MODE with values 1 (all destructive tools disabled), "session" (all tools available but only objects created in the session can be edited in the session), and 0 or "" (default), which means no extra restrictions.

In safe mode all destructive actions are disabled:
• Changing config.
• Deleting objects.
• Renaming objects.
• Modifying objects.
The agent can list objects, run syncs, read logs, and all sorts of things. They can also create connections and other objects. They just shouldn't be able to "break" anything.

We don't implement the 'session' level safe mode yet, but that mode would only allow destructive actions on objects created in this session. Presumably that implementation would be more difficult, as it requires us to cache all object IDs created in the session - and gate other tool actions with that list as a filter.
Thread URL: https://airbytehq-team.slack.com/archives/D089P0UPVT4/p1761251475655129?thread_ts=1761251475.655129

@devin-ai-integration
Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@github-actions
Copy link
Copy Markdown

👋 Greetings, Airbyte Team Member!

Here are some helpful tips and reminders for your convenience.

Testing This PyAirbyte Version

You can test this version of PyAirbyte using the following:

# Run PyAirbyte CLI from this branch:
uvx --from 'git+https://github.com/airbytehq/PyAirbyte.git@devin/1761253837-add-mcp-tool-annotations' pyairbyte --help

# Install PyAirbyte from this branch for development:
pip install 'git+https://github.com/airbytehq/PyAirbyte.git@devin/1761253837-add-mcp-tool-annotations'

Helpful Resources

PR Slash Commands

Airbyte Maintainers can execute the following slash commands on your PR:

  • /fix-pr - Fixes most formatting and linting issues
  • /poetry-lock - Updates poetry.lock file
  • /test-pr - Runs tests with the updated PyAirbyte

Community Support

Questions? Join the #pyairbyte channel in our Slack workspace.

📝 Edit this welcome message.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Oct 23, 2025

📝 Walkthrough

Walkthrough

Adds a new annotations module and updates MCP tool registrations in cloud_ops, connector_registry, and local_ops to supply per-tool annotation metadata (READ_ONLY_HINT, DESTRUCTIVE_HINT, IDEMPOTENT_HINT, OPEN_WORLD_HINT) and more explicit per-tool descriptions; local_ops registration was refactored from a loop to explicit registrations.

Changes

Cohort / File(s) Summary
New annotations constants
airbyte/mcp/_annotations.py
Adds four annotation constants: READ_ONLY_HINT, DESTRUCTIVE_HINT, IDEMPOTENT_HINT, OPEN_WORLD_HINT (string constants with docstrings) to standardize per-tool metadata.
Cloud operations tool registrations
airbyte/mcp/cloud_ops.py
Replaces prior tool registration calls with per-tool app.tool calls that include annotations (read-only/idempotent/destructive hints) for each cloud operation; imports new annotation constants.
Connector registry tool registrations
airbyte/mcp/connector_registry.py
Adds per-tool annotations to connector registry tools (e.g., list_connectors, get_connector_info) and imports annotation constants.
Local operations tool registrations
airbyte/mcp/local_ops.py
Refactors registration from a loop into explicit app.tool calls with descriptions (docstrings + shared _CONFIG_HELP) and per-tool annotations (READ_ONLY_HINT, IDEMPOTENT_HINT, OPEN_WORLD_HINT, DESTRUCTIVE_HINT as applicable).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Would you like me to re-evaluate any specific tool annotations (e.g., DESTRUCTIVE vs. IDEMPOTENT choices) before you merge? Wdyt?

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "feat: Add MCP tool annotations for read-only, destructive, and idempotent hints" is directly aligned with the changeset. The raw summary confirms that the PR introduces a new _annotations.py module containing annotation constants and applies these annotations across three tool registration files (cloud_ops.py, connector_registry.py, and local_ops.py). The title accurately captures the main objective: adding MCP tool annotations for behavior classification. While the PR also adds an OPEN_WORLD_HINT that isn't mentioned in the title, the title remains concise and covers the primary annotations without being overly comprehensive, which aligns with the guidance that titles don't need to cover every detail.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch devin/1761253837-add-mcp-tool-annotations

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

@github-actions
Copy link
Copy Markdown

github-actions bot commented Oct 23, 2025

PyTest Results (Fast Tests Only, No Creds)

304 tests  ±0   304 ✅ ±0   5m 42s ⏱️ -14s
  1 suites ±0     0 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit 56787f8. ± Comparison against base commit 01ffecc.

♻️ This comment has been updated with latest results.

…dHint usage

- Create _annotations.py with documented constants for all MCP hints
- Add FastMCP default values to each constant's docstring
- Replace string literals with constants across all MCP tool registrations
- Clarify openWorldHint usage with inline comments:
  - True for tools requiring Cloud auth or connecting to source connectors
  - False for local-only operations (cache, .env files, registry cache)
- Link to FastMCP docs in annotations module header

Co-Authored-By: AJ Steers <aj@airbyte.io>
Copy link
Copy Markdown
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: 0

🧹 Nitpick comments (9)
airbyte/mcp/cloud_ops.py (4)

756-763: Make time-varying reads non-idempotent.

These two tools return status/logs that can legitimately change between identical invocations (even with same params), which contradicts your docstring definition of idempotency (“same result and side effects”). Shall we mark them non-idempotent, wdyt?

Apply:

 app.tool(
     get_cloud_sync_status,
     annotations={
         READ_ONLY_HINT: True,
         DESTRUCTIVE_HINT: False,
-        IDEMPOTENT_HINT: True,
+        IDEMPOTENT_HINT: False,
         OPEN_WORLD_HINT: True,  # Requires Cloud auth
     },
 )

 app.tool(
     get_cloud_sync_logs,
     annotations={
         READ_ONLY_HINT: True,
         DESTRUCTIVE_HINT: False,
-        IDEMPOTENT_HINT: True,
+        IDEMPOTENT_HINT: False,
         OPEN_WORLD_HINT: True,  # Requires Cloud auth
     },
 )

Also applies to: 766-773


746-753: Re-evaluate destructiveHint for run_cloud_sync.

Connections configured for full-refresh/overwrite or resets can drop/replace tables, which is “destructive” per your hint docs. Should we set DESTRUCTIVE_HINT=True here, or at least document that it depends on the connection’s sync mode so safe mode can treat it cautiously, wdyt?

Example change:

 app.tool(
     run_cloud_sync,
     annotations={
         READ_ONLY_HINT: False,
-        DESTRUCTIVE_HINT: False,
+        DESTRUCTIVE_HINT: True,  # May overwrite/replace depending on sync mode
         IDEMPOTENT_HINT: False,
         OPEN_WORLD_HINT: True,  # Requires Cloud auth
     },
 )

776-783: Optional: consider non-idempotent for list calls in open world.*

list_deployed_* and list_custom_source_definitions can change between calls due to external drift. It’s reasonable to keep them idempotent=True if you define idempotency as “no side effects,” but your docs say “same result and side effects.” Do you want to flip these to False for consistency with that definition, wdyt?

Also applies to: 786-793, 796-803, 816-824


837-844: Delete idempotency semantics: True or False?

permanently_delete_custom_source_definition is marked idempotent, but repeated calls will likely error on the second run (not “same result”). Two options:

  • Keep True and swallow “not found” with a stable “already deleted or not found” message to maintain idempotent behavior; or
  • Set IDEMPOTENT_HINT=False.

Which approach do you prefer, wdyt?

Example if keeping True (pseudocode only; not required in this PR):

-    definition.permanently_delete(
+    try:
+        definition.permanently_delete(
         safe_mode=True,
-    )
+        )
+    except NotFoundError:
+        pass
airbyte/mcp/_annotations.py (1)

14-52: Polish: mark as constants and export explicitly?

Would you like to add typing.Final and an all to make the export surface explicit and help linters/types, wdyt?

Suggested tweak:

+from typing import Final
+
-READ_ONLY_HINT = "readOnlyHint"
+READ_ONLY_HINT: Final = "readOnlyHint"
-DESTRUCTIVE_HINT = "destructiveHint"
+DESTRUCTIVE_HINT: Final = "destructiveHint"
-IDEMPOTENT_HINT = "idempotentHint"
+IDEMPOTENT_HINT: Final = "idempotentHint"
-OPEN_WORLD_HINT = "openWorldHint"
+OPEN_WORLD_HINT: Final = "openWorldHint"
+
+__all__ = [
+    "READ_ONLY_HINT",
+    "DESTRUCTIVE_HINT",
+    "IDEMPOTENT_HINT",
+    "OPEN_WORLD_HINT",
+]
airbyte/mcp/local_ops.py (4)

787-795: Trim _CONFIG_HELP from tools that don’t take config inputs.

describe_default_cache, list_cached_streams, list_dotenv_secrets, and run_sql_query don’t accept config-related params. Removing _CONFIG_HELP from their descriptions could reduce noise. Shall we drop it for these four tools, wdyt?

- description=(describe_default_cache.__doc__ or "").rstrip() + "\n" + _CONFIG_HELP,
+ description=(describe_default_cache.__doc__ or "").rstrip(),
@@
- description=(list_cached_streams.__doc__ or "").rstrip() + "\n" + _CONFIG_HELP,
+ description=(list_cached_streams.__doc__ or "").rstrip(),
@@
- description=(list_dotenv_secrets.__doc__ or "").rstrip() + "\n" + _CONFIG_HELP,
+ description=(list_dotenv_secrets.__doc__ or "").rstrip(),
@@
- description=(run_sql_query.__doc__ or "").rstrip() + "\n" + _CONFIG_HELP,
+ description=(run_sql_query.__doc__ or "").rstrip(),

Also applies to: 821-829, 833-840, 865-872


776-784: Consistency: add explicit description for list_connector_config_secrets?

Most tools here set a description explicitly. Do you want to set description=(list_connector_config_secrets.doc or "").rstrip() for consistency in tool metadata, wdyt?


427-429: Prefer structured logging over stderr print.

Printing to stderr inside MCP tools can be noisy for clients. Would you switch to a logger (or app.log) at INFO/DEBUG, wdyt?

-        print(f"Retrieved {len(records)} records from stream '{stream_name}'", sys.stderr)
+        # logger.debug(...)  # or use FastMCP's logging if available

878-883: Classification check for sync_source_to_cache (non-destructive).

You marked destructiveHint=False with a comment “additive/merge operations”. If any cache implementation performs overwrite/replace, should we flip to True or keep False but clarify in the description that behavior is cache-dependent, wdyt?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a830fd3 and 8333543.

📒 Files selected for processing (4)
  • airbyte/mcp/_annotations.py (1 hunks)
  • airbyte/mcp/cloud_ops.py (2 hunks)
  • airbyte/mcp/connector_registry.py (2 hunks)
  • airbyte/mcp/local_ops.py (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • airbyte/mcp/connector_registry.py
🧰 Additional context used
🧬 Code graph analysis (2)
airbyte/mcp/local_ops.py (1)
airbyte/caches/base.py (1)
  • run_sql_query (195-241)
airbyte/mcp/cloud_ops.py (1)
airbyte/cloud/workspaces.py (2)
  • publish_custom_source_definition (461-552)
  • list_custom_source_definitions (554-582)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Pytest (All, Python 3.11, Ubuntu)
  • GitHub Check: Pytest (All, Python 3.11, Windows)
  • GitHub Check: Pytest (All, Python 3.10, Ubuntu)
  • GitHub Check: Pytest (All, Python 3.10, Windows)
  • GitHub Check: Pytest (Fast)
  • GitHub Check: Pytest (No Creds)
🔇 Additional comments (2)
airbyte/mcp/_annotations.py (1)

20-21: Docstring defaults verified against FastMCP 2.2.7 specification.

All four tool annotation defaults in the docstrings match the FastMCP 2.2.7 spec:

  • readOnlyHint: False ✓
  • destructiveHint: True ✓
  • idempotentHint: False ✓
  • openWorldHint: True ✓

No drift detected. The code is good to go!

airbyte/mcp/local_ops.py (1)

771-894: Verification complete—all app.tool registrations are properly configured.

The scan across airbyte/mcp/local_ops.py, airbyte/mcp/cloud_ops.py, and airbyte/mcp/connector_registry.py confirms that every app.tool() registration includes all four required hint keys (READ_ONLY_HINT, DESTRUCTIVE_HINT, IDEMPOTENT_HINT, OPEN_WORLD_HINT) with no typos detected. The code snippet you provided (lines 771–894) accurately reflects this consistency.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Oct 23, 2025

PyTest Results (Full)

373 tests  ±0   357 ✅ ±0   24m 37s ⏱️ -38s
  1 suites ±0    16 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit 56787f8. ± Comparison against base commit 01ffecc.

♻️ This comment has been updated with latest results.

- Remove hints that match FastMCP documented defaults:
  - READ_ONLY_HINT: False (default)
  - DESTRUCTIVE_HINT: True (default)
  - IDEMPOTENT_HINT: False (default)
  - OPEN_WORLD_HINT: True (default)
- Only specify non-default values to reduce noise
- Keep inline comments for OPEN_WORLD_HINT: False to clarify local-only operations

Co-Authored-By: AJ Steers <aj@airbyte.io>
Copy link
Copy Markdown
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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
airbyte/mcp/local_ops.py (1)

657-667: Avoid NameError from runtime-evaluated local type annotations.

DuckDBCache is only imported under TYPE_CHECKING, but it’s referenced in local variable annotations inside functions. In Python without from __future__ import annotations, those annotations are evaluated at runtime when the line executes, leading to NameError: name 'DuckDBCache' is not defined. Two lightweight fixes:

  • Quote the local annotations, or
  • Enable postponed evaluation via a module-level future import.

Here’s an in-place, minimal diff using quoted annotations:

@@
-    cache: DuckDBCache = get_default_cache()
+    cache: "DuckDBCache" = get_default_cache()
@@
-    cache: DuckDBCache = get_default_cache()
+    cache: "DuckDBCache" = get_default_cache()

Alternatively, add the future import near the top (after the module docstring, before other imports):

@@
-"""Local MCP operations."""
+"""Local MCP operations."""
+from __future__ import annotations

Either approach prevents runtime evaluation of the forward reference. Prefer the future import if this pattern appears elsewhere in the module, wdyt?

Also applies to: 752-769, 30-32

🧹 Nitpick comments (3)
airbyte/mcp/local_ops.py (3)

682-715: Permit common read-only SQL forms (WITH CTEs, PRAGMA) and trim leading comments?

currently _is_safe_sql blocks:

  • CTEs starting with WITH (valid read-only SELECTs).
  • DuckDB PRAGMA reads (e.g., PRAGMA show_tables).
  • Queries prefixed by comments or whitespace lines.

Would you consider expanding the allowlist and normalizing the first token before checks, e.g.?

@@
-    normalized_query = sql_query.strip().upper()
+    # Strip leading comments and whitespace before checking the first keyword
+    q = sql_query.lstrip()
+    while q.startswith("--") or q.startswith("/*"):
+        # drop single-line or block comments
+        if q.startswith("--"):
+            q = q.splitlines()[1:]  # remove first line
+            q = ("\n".join(q)).lstrip()
+        else:
+            end = q.find("*/")
+            q = q[end+2:].lstrip() if end != -1 else ""
+    normalized_query = q.upper()
@@
-    allowed_prefixes = (
+    allowed_prefixes = (
         "SELECT",
         "DESCRIBE",
         "DESC",
         "SHOW",
         "EXPLAIN",
+        "WITH",    # Allow read-only CTE queries
+        "PRAGMA",  # DuckDB pragma reads
     )

Keeps the safety posture but avoids false negatives for common read-only queries. Optional, wdyt?


785-787: Suggestion verified and accurate—remove _CONFIG_HELP from the 4 tools without config parameters.

I've confirmed your observation. The four tools you identified—describe_default_cache, list_cached_streams, list_dotenv_secrets, and run_sql_query—genuinely lack config, config_file, or config_secret_name parameters.

In contrast, the other six tools using _CONFIG_HELP (get_source_stream_json_schema, get_stream_previews, list_source_streams, read_source_stream_records, sync_source_to_cache, validate_connector_config) do accept config parameters, so keeping _CONFIG_HELP for them makes sense.

Removing it from the non-config tools will indeed improve clarity for users, since they won't see configuration guidance for tools that don't actually need it. The suggested diffs accurately capture all four cases. Wdyt—should we apply these changes?


776-783: Add explicit OPEN_WORLD_HINT and IDEMPOTENT_HINT annotations to tools with external dependencies.

Your suggestions are spot-on. I've verified each tool against its implementation:

  • list_connector_config_secrets calls GoogleGSMSecretManager.fetch_connector_secrets() → needs OPEN_WORLD_HINT: True
  • get_stream_previews calls source.get_samples() with variable results → needs IDEMPOTENT_HINT: False, OPEN_WORLD_HINT: True
  • list_source_streams calls source.get_available_streams() → needs OPEN_WORLD_HINT: True
  • read_source_stream_records returns variable record slices → needs IDEMPOTENT_HINT: False, OPEN_WORLD_HINT: True
  • sync_source_to_cache reads from external source + writes to cache → needs READ_ONLY_HINT: False, IDEMPOTENT_HINT: False, OPEN_WORLD_HINT: True
  • validate_connector_config calls source.check() with remote APIs → needs OPEN_WORLD_HINT: True
  • get_source_stream_json_schema (not fully visible but context-clear) → needs OPEN_WORLD_HINT: True

The pattern you've established (local-only tools already have OPEN_WORLD_HINT: False) makes the distinction explicit for safe-mode behavior. The diff you provided aligns perfectly with what each function actually does.

Does this match your intended semantics for distinguishing local-only vs. external-dependent tools?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8333543 and 56787f8.

📒 Files selected for processing (3)
  • airbyte/mcp/cloud_ops.py (2 hunks)
  • airbyte/mcp/connector_registry.py (2 hunks)
  • airbyte/mcp/local_ops.py (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • airbyte/mcp/cloud_ops.py
  • airbyte/mcp/connector_registry.py
🧰 Additional context used
🧬 Code graph analysis (1)
airbyte/mcp/local_ops.py (1)
airbyte/caches/base.py (1)
  • run_sql_query (195-241)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Pytest (All, Python 3.11, Windows)
  • GitHub Check: Pytest (All, Python 3.11, Ubuntu)
  • GitHub Check: Pytest (All, Python 3.10, Ubuntu)
  • GitHub Check: Pytest (All, Python 3.10, Windows)
  • GitHub Check: Pytest (Fast)
  • GitHub Check: Pytest (No Creds)
🔇 Additional comments (2)
airbyte/mcp/local_ops.py (2)

16-21: Nice: centralizing annotation keys via constants.

Importing DESTRUCTIVE_HINT/READ_ONLY_HINT/IDEMPOTENT_HINT/OPEN_WORLD_HINT keeps registrations consistent and avoids typos. LGTM, wdyt?


776-873: Manual verification of MCP annotations required—sandbox cannot run poetry.

I've confirmed that all annotations are present in the code and structurally consistent. However, since poetry isn't available in the sandbox, I can't execute poetry run poe mcp-inspect to validate the JSON output and runtime exposure.

I did notice a few annotation patterns worth double-checking when you run the inspection:

  • get_stream_previews and read_source_stream_records only have READ_ONLY_HINT: True (missing IDEMPOTENT_HINT)—is this intentional for streaming operations?
  • sync_source_to_cache uses only DESTRUCTIVE_HINT: False without READ_ONLY_HINT, which makes sense for a cache mutation, but worth confirming the inspection output reflects this correctly.

Could you run the following when you have poetry available?

poetry run poe mcp-inspect --tools | grep -A 10 "local_ops"

This will show the actual runtime hints and confirm they match your expectations. Would that work for you?

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.

1 participant