Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions airbyte/mcp/_datadog.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,20 @@
MCP_SESSION_ID_HEADER = "mcp-session-id"
_MAX_INTENT_LENGTH = 4096
INTENT_INSTRUCTIONS_SENTENCE = (
" Tools may accept an optional `intent` string; if present, "
"state in one sentence why you are calling the tool "
"(never credentials, identifiers or data values)."
" Tools may accept an optional `intent` string. This is internal metadata, "
"not a user-facing reply. Always write `intent` in English. "
"Describe the wider task and why you chose this tool in one English sentence, "
"regardless of the conversation's language. "
"Continue responding to the user in their preferred language. "
"Omit argument values, personal information, and secrets from `intent`."
)
_INTENT_SCHEMA = {
"type": "string",
"description": (
"Briefly describe the wider task and why you chose this tool, in English. "
"Internal metadata, not a user-facing reply. Always write `intent` in English. "
"Describe the wider task and why you chose this tool in one English sentence, "
"regardless of the conversation's language. "
"Continue responding to the user in their preferred language. "
"Omit argument values, personal information, and secrets."
),
}
Expand Down
18 changes: 16 additions & 2 deletions airbyte/mcp/cloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -1654,7 +1654,14 @@ def execute_external_api_query( # noqa: PLR0913 # Explicit args mirror the con
intent: Annotated[
str | None,
Field(
description="Optional free-text intent recorded with the request.",
description=(
"Optional intent recorded with the request. "
"Internal metadata, not a user-facing reply. Always write `intent` in English. "
"Describe the wider task and why you chose this tool in one English sentence, "
"regardless of the conversation's language. "
"Continue responding to the user in their preferred language. "
"Omit argument values, personal information, and secrets."
),
default=None,
),
TraceArg.OMIT,
Expand Down Expand Up @@ -1750,7 +1757,14 @@ def _execute_external_api_action( # noqa: PLR0913 # Explicit args mirror the c
intent: Annotated[
str | None,
Field(
description="Optional free-text intent recorded with the request.",
description=(
"Optional intent recorded with the request. "
"Internal metadata, not a user-facing reply. Always write `intent` in English. "
"Describe the wider task and why you chose this tool in one English sentence, "
"regardless of the conversation's language. "
"Continue responding to the user in their preferred language. "
"Omit argument values, personal information, and secrets."
),
default=None,
),
] = None,
Expand Down
29 changes: 28 additions & 1 deletion tests/unit_tests/test_mcp_cloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
AirbyteMissingResourceError,
AirbyteLibInputError,
)
from fastmcp import Context
from fastmcp import Context, FastMCP


@dataclass
Expand Down Expand Up @@ -1866,6 +1866,33 @@ def test_execute_external_api_action_uses_write_path(
assert kwargs["api_args"] == {"title": "Bug"}


@pytest.mark.parametrize(
"tool_fn",
[cloud_mcp.execute_external_api_query, cloud_mcp._execute_external_api_action],
)
def test_external_api_intent_guidance(tool_fn: Callable[..., Any]) -> None:
"""Explicit intents request English metadata, not English user-facing replies."""
app = FastMCP("intent-guidance-test")
app.tool(tool_fn)
(tool,) = asyncio.run(app.list_tools())
schema = tool.parameters
intent = schema["properties"]["intent"]

assert "Always write `intent` in English" in intent["description"]
assert "one English sentence" in intent["description"]
assert "regardless of the conversation's language" in intent["description"]
assert (
"Continue responding to the user in their preferred language"
in intent["description"]
)
assert (
"Omit argument values, personal information, and secrets"
in intent["description"]
)
assert "intent" not in schema.get("required", [])
assert intent["default"] is None


def test_execute_external_api_action_is_not_advertised() -> None:
"""The write tool stays hidden until the backend supports write actions."""
from airbyte.mcp import server
Expand Down
28 changes: 28 additions & 0 deletions tests/unit_tests/test_mcp_datadog.py
Original file line number Diff line number Diff line change
Expand Up @@ -1360,6 +1360,34 @@ async def run():
)
assert response.status_code == 200
responses.append((method, params, response.json()))
instructions = responses[0][2]["result"]["instructions"]
assert "optional `intent`" in instructions
assert "Always write `intent` in English" in instructions
assert "one English sentence" in instructions
assert "regardless of the conversation's language" in instructions
assert (
"Continue responding to the user in their preferred language"
in instructions
)
assert (
"Omit argument values, personal information, and secrets"
in instructions
)
for tool in responses[1][2]["result"]["tools"]:
schema = tool["inputSchema"]
description = schema["properties"]["intent"]["description"]
assert "Always write `intent` in English" in description
assert "one English sentence" in description
assert "regardless of the conversation's language" in description
assert (
"Continue responding to the user in their preferred language"
in description
)
assert (
"Omit argument values, personal information, and secrets"
in description
)
assert "intent" not in schema.get("required", [])
lifecycle_spans = [
span
for span in spans
Expand Down
Loading