Skip to content
Open
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
5 changes: 4 additions & 1 deletion mcpgateway/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@
from mcpgateway.services.cancellation_service import cancellation_service
from mcpgateway.services.completion_service import CompletionError, CompletionService
from mcpgateway.services.content_security import ContentPatternError, ContentSizeError, ContentTypeError, TemplateValidationError
from mcpgateway.services.dataplane_publisher import DataplanePublisherService
from mcpgateway.services.email_auth_service import EmailAuthService
from mcpgateway.services.export_service import ExportError, ExportService
from mcpgateway.services.gateway_service import GatewayConnectionError, GatewayDuplicateConflictError, GatewayError, GatewayNameConflictError, GatewayNotFoundError
Expand All @@ -178,7 +179,6 @@
from mcpgateway.services.resource_service import ResourceError, ResourceLockConflictError, ResourceNotFoundError, ResourceURIConflictError
from mcpgateway.services.server_service import ServerError, ServerLockConflictError, ServerNameConflictError, ServerNotFoundError
from mcpgateway.services.tag_service import TagService
from mcpgateway.services.dataplane_publisher import DataplanePublisherService
from mcpgateway.services.tool_service import ToolError, ToolLockConflictError, ToolNameConflictError, ToolNotFoundError
from mcpgateway.transports.sse_transport import SSETransport
from mcpgateway.transports.streamablehttp_transport import (
Expand Down Expand Up @@ -5423,6 +5423,7 @@ async def get_tool(
request: Request,
db: Session = Depends(get_db),
user=Depends(get_current_user_with_permissions),
include_metrics: bool = Query(True, description="Include metrics (execution count, success rate, etc.) in the response"),
apijsonpath: Optional[str] = Query(None, max_length=1000, description="Optional JSONPath modifier as JSON string"),
) -> ToolResponse:
"""
Expand All @@ -5433,6 +5434,7 @@ async def get_tool(
request: The incoming HTTP request.
db: Active SQLAlchemy session (dependency).
user: Authenticated username (dependency).
include_metrics: Whether to include metrics in the response. Defaults to True for detail view.
apijsonpath: Optional JSON-Path modifier supplied as URL-encoded query parameter.
Example: ?apijsonpath=%7B%22jsonpath%22%3A%22%24.name%22%7D
(decoded: {"jsonpath":"$.name","mapping":null})
Expand Down Expand Up @@ -5460,6 +5462,7 @@ async def get_tool(
requesting_user_is_admin=_req_is_admin,
requesting_user_team_roles=_req_team_roles,
token_teams=auth_token_teams,
include_metrics=include_metrics,
)
_enforce_scoped_resource_access(request, db, user, f"/tools/{tool_id}")

Expand Down
13 changes: 11 additions & 2 deletions mcpgateway/services/tool_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -1235,8 +1235,13 @@ def convert_tool_to_read(
# Compute metrics in a single pass (matches server/resource/prompt service pattern)
if include_metrics:
metrics = tool.metrics_summary # Single-pass computation
tool_dict["metrics"] = metrics
tool_dict["execution_count"] = metrics["total_executions"]
# Return None if there's no actual metrics data (total_executions is 0)
if metrics.get("total_executions", 0) == 0:
tool_dict["metrics"] = None
tool_dict["execution_count"] = None
else:
tool_dict["metrics"] = metrics
tool_dict["execution_count"] = metrics["total_executions"]
else:
tool_dict["metrics"] = None
tool_dict["execution_count"] = None
Expand Down Expand Up @@ -3124,6 +3129,7 @@ async def get_tool(
requesting_user_is_admin: bool = False,
requesting_user_team_roles: Optional[Dict[str, str]] = None,
token_teams: Optional[List[str]] = None,
include_metrics: bool = True,
) -> ToolRead:
"""
Retrieve a tool by its ID with access control.
Expand All @@ -3140,6 +3146,7 @@ async def get_tool(
``[]`` means public-only scope. ``[...]`` means team-scoped.
This is kept separate from ``requesting_user_team_roles`` to avoid the Layer 1
visibility check silently widening a scoped token to full DB team membership.
include_metrics (bool): Whether to include metrics in the response. Defaults to True.

Returns:
ToolRead: The tool object.
Expand Down Expand Up @@ -3193,6 +3200,7 @@ async def get_tool(

tool_read = self.convert_tool_to_read(
tool,
include_metrics=include_metrics,
requesting_user_email=requesting_user_email,
requesting_user_is_admin=requesting_user_is_admin,
requesting_user_team_roles=requesting_user_team_roles,
Expand Down Expand Up @@ -4371,6 +4379,7 @@ async def invoke_tool(
# ═══════════════════════════════════════════════════════════════════════════
# First-Party
from mcpgateway.transports.context import request_headers_var # pylint: disable=import-outside-toplevel

if request_headers:
request_headers_var.set(request_headers)
# ═══════════════════════════════════════════════════════════════════════════
Expand Down
12 changes: 6 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ build-backend = "setuptools.build_meta"
exclude-newer = "10 days"

[tool.uv.exclude-newer-package]
cpex = "2026-05-11T23:59:59Z"
cpex = "2026-05-29T23:59:59Z"
cpex-url-reputation = "2026-05-25T23:59:59Z"
cpex-rate-limiter = "2026-05-25T23:59:59Z"
cpex-encoded-exfil-detection = "2026-05-25T23:59:59Z"
cpex-encoded-exfil-detection = "2026-05-29T23:59:59Z"
cpex-pii-filter = "2026-05-25T23:59:59Z"
cpex-retry-with-backoff = "2026-05-25T23:59:59Z"
cpex-secrets-detection = "2026-05-25T23:59:59Z"
cpex-secrets-detection = "2026-05-29T23:59:59Z"
langchain-core = "2026-05-06T23:59:59Z"
langsmith = "2026-05-25T23:59:59Z"
opentelemetry-api = "2026-05-25T23:59:59Z"
Expand Down Expand Up @@ -76,7 +76,7 @@ dependencies = [
"base58>=2.1.1",
"brotli>=1.2.0",
"click<=8.3.3", # Transitive pin
"cpex>=0.1.0",
"cpex==0.1.1.dev1",
"cryptography>=48.0.0",
"fastapi<=0.136.1",
"filelock>=3.29.0",
Expand Down Expand Up @@ -276,11 +276,11 @@ templating = [
# External plugin packages (optional)
# Install with: pip install mcp-contextforge-gateway[plugins]
plugins = [
"cpex-encoded-exfil-detection>=0.3.2",
"cpex-encoded-exfil-detection>=0.3.3",
"cpex-pii-filter>=0.3.3",
"cpex-rate-limiter>=0.1.3",
"cpex-retry-with-backoff>=0.3.3",
"cpex-secrets-detection>=0.3.3",
"cpex-secrets-detection>=0.3.4",
"cpex-url-reputation>=0.3.2",
]

Expand Down
52 changes: 26 additions & 26 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.