universal-mcp-applications 0.1.22__py3-none-any.whl → 0.1.39rc8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of universal-mcp-applications might be problematic. Click here for more details.
- universal_mcp/applications/ahrefs/app.py +92 -238
- universal_mcp/applications/airtable/app.py +23 -122
- universal_mcp/applications/apollo/app.py +122 -475
- universal_mcp/applications/asana/app.py +605 -1755
- universal_mcp/applications/aws_s3/app.py +36 -103
- universal_mcp/applications/bill/app.py +644 -2055
- universal_mcp/applications/box/app.py +1246 -4159
- universal_mcp/applications/braze/app.py +410 -1476
- universal_mcp/applications/browser_use/README.md +15 -1
- universal_mcp/applications/browser_use/__init__.py +1 -0
- universal_mcp/applications/browser_use/app.py +94 -37
- universal_mcp/applications/cal_com_v2/app.py +207 -625
- universal_mcp/applications/calendly/app.py +103 -242
- universal_mcp/applications/canva/app.py +75 -140
- universal_mcp/applications/clickup/app.py +331 -798
- universal_mcp/applications/coda/app.py +240 -520
- universal_mcp/applications/confluence/app.py +497 -1285
- universal_mcp/applications/contentful/app.py +36 -151
- universal_mcp/applications/crustdata/app.py +42 -121
- universal_mcp/applications/dialpad/app.py +451 -924
- universal_mcp/applications/digitalocean/app.py +2071 -6082
- universal_mcp/applications/domain_checker/app.py +3 -54
- universal_mcp/applications/e2b/app.py +14 -64
- universal_mcp/applications/elevenlabs/app.py +9 -47
- universal_mcp/applications/exa/README.md +8 -4
- universal_mcp/applications/exa/app.py +408 -186
- universal_mcp/applications/falai/app.py +24 -101
- universal_mcp/applications/figma/app.py +91 -175
- universal_mcp/applications/file_system/app.py +2 -13
- universal_mcp/applications/firecrawl/app.py +186 -163
- universal_mcp/applications/fireflies/app.py +59 -281
- universal_mcp/applications/fpl/app.py +92 -529
- universal_mcp/applications/fpl/utils/fixtures.py +15 -49
- universal_mcp/applications/fpl/utils/helper.py +25 -89
- universal_mcp/applications/fpl/utils/league_utils.py +20 -64
- universal_mcp/applications/ghost_content/app.py +66 -175
- universal_mcp/applications/github/app.py +28 -65
- universal_mcp/applications/gong/app.py +140 -300
- universal_mcp/applications/google_calendar/app.py +26 -78
- universal_mcp/applications/google_docs/app.py +324 -354
- universal_mcp/applications/google_drive/app.py +194 -793
- universal_mcp/applications/google_gemini/app.py +29 -64
- universal_mcp/applications/google_mail/README.md +1 -0
- universal_mcp/applications/google_mail/app.py +93 -214
- universal_mcp/applications/google_searchconsole/app.py +25 -58
- universal_mcp/applications/google_sheet/app.py +174 -623
- universal_mcp/applications/google_sheet/helper.py +26 -53
- universal_mcp/applications/hashnode/app.py +57 -269
- universal_mcp/applications/heygen/app.py +77 -155
- universal_mcp/applications/http_tools/app.py +10 -32
- universal_mcp/applications/hubspot/README.md +1 -1
- universal_mcp/applications/hubspot/app.py +7508 -99
- universal_mcp/applications/jira/app.py +2419 -8334
- universal_mcp/applications/klaviyo/app.py +737 -1619
- universal_mcp/applications/linkedin/README.md +23 -4
- universal_mcp/applications/linkedin/app.py +861 -155
- universal_mcp/applications/mailchimp/app.py +696 -1851
- universal_mcp/applications/markitdown/app.py +8 -20
- universal_mcp/applications/miro/app.py +333 -815
- universal_mcp/applications/ms_teams/app.py +85 -207
- universal_mcp/applications/neon/app.py +144 -250
- universal_mcp/applications/notion/app.py +36 -51
- universal_mcp/applications/onedrive/README.md +24 -0
- universal_mcp/applications/onedrive/__init__.py +1 -0
- universal_mcp/applications/onedrive/app.py +316 -0
- universal_mcp/applications/openai/app.py +42 -165
- universal_mcp/applications/outlook/README.md +22 -9
- universal_mcp/applications/outlook/app.py +606 -262
- universal_mcp/applications/perplexity/README.md +2 -1
- universal_mcp/applications/perplexity/app.py +162 -20
- universal_mcp/applications/pipedrive/app.py +1021 -3331
- universal_mcp/applications/posthog/app.py +272 -541
- universal_mcp/applications/reddit/app.py +88 -204
- universal_mcp/applications/resend/app.py +41 -107
- universal_mcp/applications/retell/app.py +23 -50
- universal_mcp/applications/rocketlane/app.py +250 -963
- universal_mcp/applications/scraper/README.md +7 -4
- universal_mcp/applications/scraper/app.py +245 -283
- universal_mcp/applications/semanticscholar/app.py +36 -78
- universal_mcp/applications/semrush/app.py +43 -77
- universal_mcp/applications/sendgrid/app.py +826 -1576
- universal_mcp/applications/sentry/app.py +444 -1079
- universal_mcp/applications/serpapi/app.py +40 -143
- universal_mcp/applications/sharepoint/README.md +16 -14
- universal_mcp/applications/sharepoint/app.py +245 -154
- universal_mcp/applications/shopify/app.py +1743 -4479
- universal_mcp/applications/shortcut/app.py +272 -534
- universal_mcp/applications/slack/app.py +58 -109
- universal_mcp/applications/spotify/app.py +206 -405
- universal_mcp/applications/supabase/app.py +174 -283
- universal_mcp/applications/tavily/app.py +2 -2
- universal_mcp/applications/trello/app.py +853 -2816
- universal_mcp/applications/twilio/app.py +14 -50
- universal_mcp/applications/twitter/api_segments/compliance_api.py +4 -14
- universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +6 -18
- universal_mcp/applications/twitter/api_segments/likes_api.py +1 -3
- universal_mcp/applications/twitter/api_segments/lists_api.py +5 -15
- universal_mcp/applications/twitter/api_segments/trends_api.py +1 -3
- universal_mcp/applications/twitter/api_segments/tweets_api.py +9 -31
- universal_mcp/applications/twitter/api_segments/usage_api.py +1 -5
- universal_mcp/applications/twitter/api_segments/users_api.py +14 -42
- universal_mcp/applications/whatsapp/app.py +35 -186
- universal_mcp/applications/whatsapp/audio.py +2 -6
- universal_mcp/applications/whatsapp/whatsapp.py +17 -51
- universal_mcp/applications/whatsapp_business/app.py +86 -299
- universal_mcp/applications/wrike/app.py +80 -153
- universal_mcp/applications/yahoo_finance/app.py +19 -65
- universal_mcp/applications/youtube/app.py +120 -306
- universal_mcp/applications/zenquotes/app.py +4 -4
- {universal_mcp_applications-0.1.22.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/METADATA +4 -2
- {universal_mcp_applications-0.1.22.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/RECORD +113 -117
- {universal_mcp_applications-0.1.22.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/WHEEL +1 -1
- universal_mcp/applications/hubspot/api_segments/__init__.py +0 -0
- universal_mcp/applications/hubspot/api_segments/api_segment_base.py +0 -54
- universal_mcp/applications/hubspot/api_segments/crm_api.py +0 -7337
- universal_mcp/applications/hubspot/api_segments/marketing_api.py +0 -1467
- universal_mcp/applications/unipile/README.md +0 -28
- universal_mcp/applications/unipile/__init__.py +0 -1
- universal_mcp/applications/unipile/app.py +0 -1077
- {universal_mcp_applications-0.1.22.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from collections.abc import Callable
|
|
2
2
|
from typing import Any
|
|
3
|
-
|
|
4
3
|
from loguru import logger
|
|
5
4
|
from universal_mcp.applications.application import GraphQLApplication
|
|
6
5
|
from universal_mcp.exceptions import NotAuthorizedError
|
|
@@ -8,24 +7,14 @@ from universal_mcp.integrations import Integration
|
|
|
8
7
|
|
|
9
8
|
|
|
10
9
|
class ContentfulApp(GraphQLApplication):
|
|
11
|
-
def __init__(
|
|
12
|
-
self,
|
|
13
|
-
integration: Integration | None = None,
|
|
14
|
-
**kwargs: Any,
|
|
15
|
-
) -> None:
|
|
10
|
+
def __init__(self, integration: Integration | None = None, **kwargs: Any) -> None:
|
|
16
11
|
self.space_id: str | None = None
|
|
17
12
|
self.environment_id: str = "master"
|
|
18
13
|
self._access_token: str | None = None
|
|
19
14
|
self._is_eu_customer: bool = False
|
|
20
15
|
self._credentials_loaded: bool = False
|
|
21
16
|
default_base_url = "https://graphql.contentful.com"
|
|
22
|
-
|
|
23
|
-
super().__init__(
|
|
24
|
-
name="contentful",
|
|
25
|
-
base_url=default_base_url,
|
|
26
|
-
integration=integration,
|
|
27
|
-
**kwargs,
|
|
28
|
-
)
|
|
17
|
+
super().__init__(name="contentful", base_url=default_base_url, integration=integration, **kwargs)
|
|
29
18
|
|
|
30
19
|
def _load_credentials_and_construct_url(self) -> bool:
|
|
31
20
|
"""
|
|
@@ -37,70 +26,39 @@ class ContentfulApp(GraphQLApplication):
|
|
|
37
26
|
"""
|
|
38
27
|
if self._credentials_loaded:
|
|
39
28
|
return True
|
|
40
|
-
|
|
41
29
|
logger.debug("Attempting to load Contentful credentials and construct URL...")
|
|
42
|
-
|
|
43
30
|
if not self.integration:
|
|
44
|
-
logger.error(
|
|
45
|
-
"Contentful integration not configured. Cannot load credentials or construct URL."
|
|
46
|
-
)
|
|
47
|
-
# Mark as 'loaded' to prevent retries, even though it failed.
|
|
31
|
+
logger.error("Contentful integration not configured. Cannot load credentials or construct URL.")
|
|
48
32
|
self._credentials_loaded = True
|
|
49
33
|
return False
|
|
50
|
-
|
|
51
34
|
try:
|
|
52
35
|
credentials = self.integration.get_credentials()
|
|
53
36
|
except NotAuthorizedError as e:
|
|
54
|
-
logger.error(
|
|
55
|
-
|
|
56
|
-
)
|
|
57
|
-
self._credentials_loaded = True # Prevent retries
|
|
37
|
+
logger.error(f"Authorization required or credentials unavailable for Contentful: {e.message}")
|
|
38
|
+
self._credentials_loaded = True
|
|
58
39
|
return False
|
|
59
40
|
except Exception as e:
|
|
60
|
-
logger.error(
|
|
61
|
-
|
|
62
|
-
)
|
|
63
|
-
self._credentials_loaded = True # Prevent retries
|
|
41
|
+
logger.error(f"Failed to get credentials from integration: {e}", exc_info=True)
|
|
42
|
+
self._credentials_loaded = True
|
|
64
43
|
return False
|
|
65
|
-
|
|
66
44
|
self.space_id = credentials.get("space_id")
|
|
67
|
-
self._access_token = credentials.get("access_token") or credentials.get(
|
|
68
|
-
|
|
69
|
-
)
|
|
70
|
-
self.environment_id = credentials.get(
|
|
71
|
-
"environment_id", "master"
|
|
72
|
-
) # Use default if not specified
|
|
73
|
-
self._is_eu_customer = credentials.get(
|
|
74
|
-
"is_eu_customer", False
|
|
75
|
-
) # Use default if not specified
|
|
76
|
-
|
|
45
|
+
self._access_token = credentials.get("access_token") or credentials.get("api_key")
|
|
46
|
+
self.environment_id = credentials.get("environment_id", "master")
|
|
47
|
+
self._is_eu_customer = credentials.get("is_eu_customer", False)
|
|
77
48
|
missing_creds = []
|
|
78
49
|
if not self.space_id:
|
|
79
50
|
missing_creds.append("'space_id'")
|
|
80
51
|
if not self._access_token:
|
|
81
52
|
missing_creds.append("'access_token' or 'api_key'")
|
|
82
|
-
|
|
83
53
|
if missing_creds:
|
|
84
|
-
logger.error(
|
|
85
|
-
|
|
86
|
-
"API calls will fail."
|
|
87
|
-
)
|
|
88
|
-
self._credentials_loaded = True # Prevent retries
|
|
54
|
+
logger.error(f"Missing required Contentful credentials in integration: {', '.join(missing_creds)}. API calls will fail.")
|
|
55
|
+
self._credentials_loaded = True
|
|
89
56
|
return False
|
|
90
|
-
|
|
91
|
-
contentful_api_domain = (
|
|
92
|
-
"graphql.eu.contentful.com"
|
|
93
|
-
if self._is_eu_customer
|
|
94
|
-
else "graphql.contentful.com"
|
|
95
|
-
)
|
|
57
|
+
contentful_api_domain = "graphql.eu.contentful.com" if self._is_eu_customer else "graphql.contentful.com"
|
|
96
58
|
self.base_url = f"https://{contentful_api_domain}/content/v1/spaces/{self.space_id}/environments/{self.environment_id}"
|
|
97
|
-
|
|
98
59
|
self._client = None
|
|
99
|
-
|
|
100
60
|
logger.info(
|
|
101
|
-
f"Contentful credentials loaded and URL constructed successfully. "
|
|
102
|
-
f"Space: '{self.space_id}', Environment: '{self.environment_id}'. "
|
|
103
|
-
f"Base URL: {self.base_url}"
|
|
61
|
+
f"Contentful credentials loaded and URL constructed successfully. Space: '{self.space_id}', Environment: '{self.environment_id}'. Base URL: {self.base_url}"
|
|
104
62
|
)
|
|
105
63
|
self._credentials_loaded = True
|
|
106
64
|
return True
|
|
@@ -114,7 +72,7 @@ class ContentfulApp(GraphQLApplication):
|
|
|
114
72
|
return ""
|
|
115
73
|
if len(parts) == 1 and parts[0] == s and s:
|
|
116
74
|
return s[0].lower() + s[1:] if len(s) > 1 else s.lower()
|
|
117
|
-
return parts[0].lower() + "".join(word.capitalize() for word in parts[1:])
|
|
75
|
+
return parts[0].lower() + "".join((word.capitalize() for word in parts[1:]))
|
|
118
76
|
|
|
119
77
|
@staticmethod
|
|
120
78
|
def _to_pascal_case(s: str) -> str:
|
|
@@ -125,57 +83,36 @@ class ContentfulApp(GraphQLApplication):
|
|
|
125
83
|
return ""
|
|
126
84
|
if len(parts) == 1 and parts[0] == s and s:
|
|
127
85
|
return s[0].upper() + s[1:] if len(s) > 1 else s.upper()
|
|
128
|
-
return "".join(word.capitalize() for word in parts)
|
|
86
|
+
return "".join((word.capitalize() for word in parts))
|
|
129
87
|
|
|
130
88
|
def _ensure_loaded(self) -> bool:
|
|
131
89
|
"""Internal helper to trigger lazy loading and check status."""
|
|
132
90
|
if not self._credentials_loaded:
|
|
133
91
|
return self._load_credentials_and_construct_url()
|
|
134
|
-
# If already marked as loaded, check if essential parts are actually set (robustness check)
|
|
135
92
|
return bool(self.base_url and self.space_id and self._access_token)
|
|
136
93
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
def get_entry(
|
|
140
|
-
self,
|
|
141
|
-
content_type_id: str,
|
|
142
|
-
entry_id: str,
|
|
143
|
-
fields_to_select: str,
|
|
144
|
-
locale: str | None = None,
|
|
145
|
-
preview: bool = False,
|
|
94
|
+
async def get_entry(
|
|
95
|
+
self, content_type_id: str, entry_id: str, fields_to_select: str, locale: str | None = None, preview: bool = False
|
|
146
96
|
) -> dict[str, Any]:
|
|
147
97
|
"""
|
|
148
98
|
Fetches a single entry of a specified content type by its ID.
|
|
149
99
|
(See original docstring for details)
|
|
150
100
|
"""
|
|
151
101
|
if not self._ensure_loaded():
|
|
152
|
-
return {
|
|
153
|
-
"error": "Failed to initialize ContentfulApp. Check credentials and configuration."
|
|
154
|
-
}
|
|
155
|
-
|
|
102
|
+
return {"error": "Failed to initialize ContentfulApp. Check credentials and configuration."}
|
|
156
103
|
query_field = self._to_camel_case(content_type_id)
|
|
157
|
-
logger.debug(
|
|
158
|
-
|
|
159
|
-
)
|
|
160
|
-
query_gql = f"""
|
|
161
|
-
query GetEntryById($id: String!, $locale: String, $preview: Boolean) {{
|
|
162
|
-
{query_field}(id: $id, locale: $locale, preview: $preview) {{
|
|
163
|
-
{fields_to_select}
|
|
164
|
-
}}
|
|
165
|
-
}}
|
|
166
|
-
"""
|
|
104
|
+
logger.debug(f"Fetching entry for content_type_id='{content_type_id}' (query field='{query_field}'), entry_id='{entry_id}'")
|
|
105
|
+
query_gql = f"\n query GetEntryById($id: String!, $locale: String, $preview: Boolean) {{\n {query_field}(id: $id, locale: $locale, preview: $preview) {{\n {fields_to_select}\n }}\n }}\n "
|
|
167
106
|
variables: dict[str, Any] = {"id": entry_id, "preview": preview}
|
|
168
107
|
if locale:
|
|
169
108
|
variables["locale"] = locale
|
|
170
|
-
|
|
171
|
-
# Call the base class query method which uses the configured client
|
|
172
109
|
try:
|
|
173
110
|
return self.query(query_gql, variables=variables)
|
|
174
111
|
except Exception as e:
|
|
175
112
|
logger.error(f"Error executing get_entry query: {e}", exc_info=True)
|
|
176
113
|
return {"error": f"Failed to get entry: {e}"}
|
|
177
114
|
|
|
178
|
-
def get_entries_collection(
|
|
115
|
+
async def get_entries_collection(
|
|
179
116
|
self,
|
|
180
117
|
content_type_id: str,
|
|
181
118
|
fields_to_select_for_item: str,
|
|
@@ -191,28 +128,14 @@ class ContentfulApp(GraphQLApplication):
|
|
|
191
128
|
(See original docstring for details)
|
|
192
129
|
"""
|
|
193
130
|
if not self._ensure_loaded():
|
|
194
|
-
return {
|
|
195
|
-
"error": "Failed to initialize ContentfulApp. Check credentials and configuration."
|
|
196
|
-
}
|
|
197
|
-
|
|
131
|
+
return {"error": "Failed to initialize ContentfulApp. Check credentials and configuration."}
|
|
198
132
|
collection_field = self._to_camel_case(content_type_id) + "Collection"
|
|
199
133
|
filter_type = self._to_pascal_case(content_type_id) + "Filter"
|
|
200
134
|
order_enum_type = self._to_pascal_case(content_type_id) + "Order"
|
|
201
135
|
logger.debug(
|
|
202
|
-
f"Fetching collection for content_type_id='{content_type_id}' "
|
|
203
|
-
f"(collection field='{collection_field}', filter type='{filter_type}', order enum='{order_enum_type}')"
|
|
136
|
+
f"Fetching collection for content_type_id='{content_type_id}' (collection field='{collection_field}', filter type='{filter_type}', order enum='{order_enum_type}')"
|
|
204
137
|
)
|
|
205
|
-
query_gql = f""
|
|
206
|
-
query GetEntries(
|
|
207
|
-
$limit: Int, $skip: Int, $where: {filter_type}, $order: [{order_enum_type}!], $locale: String, $preview: Boolean
|
|
208
|
-
) {{
|
|
209
|
-
{collection_field}(
|
|
210
|
-
limit: $limit, skip: $skip, where: $where, order: $order, locale: $locale, preview: $preview
|
|
211
|
-
) {{
|
|
212
|
-
total skip limit items {{ {fields_to_select_for_item} }}
|
|
213
|
-
}}
|
|
214
|
-
}}
|
|
215
|
-
"""
|
|
138
|
+
query_gql = f"\n query GetEntries(\n $limit: Int, $skip: Int, $where: {filter_type}, $order: [{order_enum_type}!], $locale: String, $preview: Boolean\n ) {{\n {collection_field}(\n limit: $limit, skip: $skip, where: $where, order: $order, locale: $locale, preview: $preview\n ) {{\n total skip limit items {{ {fields_to_select_for_item} }}\n }}\n }}\n "
|
|
216
139
|
variables: dict[str, Any] = {"preview": preview}
|
|
217
140
|
if limit is not None:
|
|
218
141
|
variables["limit"] = limit
|
|
@@ -224,16 +147,13 @@ class ContentfulApp(GraphQLApplication):
|
|
|
224
147
|
variables["order"] = order
|
|
225
148
|
if locale:
|
|
226
149
|
variables["locale"] = locale
|
|
227
|
-
|
|
228
150
|
try:
|
|
229
151
|
return self.query(query_gql, variables=variables)
|
|
230
152
|
except Exception as e:
|
|
231
|
-
logger.error(
|
|
232
|
-
f"Error executing get_entries_collection query: {e}", exc_info=True
|
|
233
|
-
)
|
|
153
|
+
logger.error(f"Error executing get_entries_collection query: {e}", exc_info=True)
|
|
234
154
|
return {"error": f"Failed to get entries collection: {e}"}
|
|
235
155
|
|
|
236
|
-
def get_asset(
|
|
156
|
+
async def get_asset(
|
|
237
157
|
self,
|
|
238
158
|
asset_id: str,
|
|
239
159
|
fields_to_select: str = "sys { id } url title description fileName contentType size width height",
|
|
@@ -244,25 +164,17 @@ class ContentfulApp(GraphQLApplication):
|
|
|
244
164
|
(See original docstring for details)
|
|
245
165
|
"""
|
|
246
166
|
if not self._ensure_loaded():
|
|
247
|
-
return {
|
|
248
|
-
"error": "Failed to initialize ContentfulApp. Check credentials and configuration."
|
|
249
|
-
}
|
|
250
|
-
|
|
167
|
+
return {"error": "Failed to initialize ContentfulApp. Check credentials and configuration."}
|
|
251
168
|
logger.debug(f"Fetching asset_id='{asset_id}'")
|
|
252
|
-
query_gql = f""
|
|
253
|
-
query GetAssetById($id: String!, $preview: Boolean) {{
|
|
254
|
-
asset(id: $id, preview: $preview) {{ {fields_to_select} }}
|
|
255
|
-
}}
|
|
256
|
-
"""
|
|
169
|
+
query_gql = f"\n query GetAssetById($id: String!, $preview: Boolean) {{\n asset(id: $id, preview: $preview) {{ {fields_to_select} }}\n }}\n "
|
|
257
170
|
variables: dict[str, Any] = {"id": asset_id, "preview": preview}
|
|
258
|
-
|
|
259
171
|
try:
|
|
260
172
|
return self.query(query_gql, variables=variables)
|
|
261
173
|
except Exception as e:
|
|
262
174
|
logger.error(f"Error executing get_asset query: {e}", exc_info=True)
|
|
263
175
|
return {"error": f"Failed to get asset: {e}"}
|
|
264
176
|
|
|
265
|
-
def get_assets_collection(
|
|
177
|
+
async def get_assets_collection(
|
|
266
178
|
self,
|
|
267
179
|
fields_to_select_for_item: str = "sys { id } url title description fileName contentType size width height",
|
|
268
180
|
limit: int | None = None,
|
|
@@ -277,22 +189,9 @@ class ContentfulApp(GraphQLApplication):
|
|
|
277
189
|
(See original docstring for details)
|
|
278
190
|
"""
|
|
279
191
|
if not self._ensure_loaded():
|
|
280
|
-
return {
|
|
281
|
-
"error": "Failed to initialize ContentfulApp. Check credentials and configuration."
|
|
282
|
-
}
|
|
283
|
-
|
|
192
|
+
return {"error": "Failed to initialize ContentfulApp. Check credentials and configuration."}
|
|
284
193
|
logger.debug("Fetching assets collection")
|
|
285
|
-
query_gql = f""
|
|
286
|
-
query GetAssets(
|
|
287
|
-
$limit: Int, $skip: Int, $where: AssetFilter, $order: [AssetOrder!], $locale: String, $preview: Boolean
|
|
288
|
-
) {{
|
|
289
|
-
assetCollection(
|
|
290
|
-
limit: $limit, skip: $skip, where: $where, order: $order, locale: $locale, preview: $preview
|
|
291
|
-
) {{
|
|
292
|
-
total skip limit items {{ {fields_to_select_for_item} }}
|
|
293
|
-
}}
|
|
294
|
-
}}
|
|
295
|
-
"""
|
|
194
|
+
query_gql = f"\n query GetAssets(\n $limit: Int, $skip: Int, $where: AssetFilter, $order: [AssetOrder!], $locale: String, $preview: Boolean\n ) {{\n assetCollection(\n limit: $limit, skip: $skip, where: $where, order: $order, locale: $locale, preview: $preview\n ) {{\n total skip limit items {{ {fields_to_select_for_item} }}\n }}\n }}\n "
|
|
296
195
|
variables: dict[str, Any] = {"preview": preview}
|
|
297
196
|
if limit is not None:
|
|
298
197
|
variables["limit"] = limit
|
|
@@ -304,18 +203,13 @@ class ContentfulApp(GraphQLApplication):
|
|
|
304
203
|
variables["order"] = order
|
|
305
204
|
if locale:
|
|
306
205
|
variables["locale"] = locale
|
|
307
|
-
|
|
308
206
|
try:
|
|
309
207
|
return self.query(query_gql, variables=variables)
|
|
310
208
|
except Exception as e:
|
|
311
|
-
logger.error(
|
|
312
|
-
f"Error executing get_assets_collection query: {e}", exc_info=True
|
|
313
|
-
)
|
|
209
|
+
logger.error(f"Error executing get_assets_collection query: {e}", exc_info=True)
|
|
314
210
|
return {"error": f"Failed to get assets collection: {e}"}
|
|
315
211
|
|
|
316
|
-
def execute_graphql_query(
|
|
317
|
-
self, query_string: str, variables: dict[str, Any] | None = None
|
|
318
|
-
) -> dict[str, Any]:
|
|
212
|
+
async def execute_graphql_query(self, query_string: str, variables: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
319
213
|
"""
|
|
320
214
|
Executes an arbitrary GraphQL query against the configured Contentful space/environment.
|
|
321
215
|
|
|
@@ -330,10 +224,7 @@ class ContentfulApp(GraphQLApplication):
|
|
|
330
224
|
important
|
|
331
225
|
"""
|
|
332
226
|
if not self._ensure_loaded():
|
|
333
|
-
return {
|
|
334
|
-
"error": "Failed to initialize ContentfulApp. Check credentials and configuration."
|
|
335
|
-
}
|
|
336
|
-
|
|
227
|
+
return {"error": "Failed to initialize ContentfulApp. Check credentials and configuration."}
|
|
337
228
|
logger.debug(f"Executing custom GraphQL query with variables: {variables}")
|
|
338
229
|
try:
|
|
339
230
|
return self.query(query_string, variables=variables)
|
|
@@ -343,10 +234,4 @@ class ContentfulApp(GraphQLApplication):
|
|
|
343
234
|
|
|
344
235
|
def list_tools(self) -> list[Callable]:
|
|
345
236
|
"""Returns a list of methods exposed as tools."""
|
|
346
|
-
return [
|
|
347
|
-
self.get_entry,
|
|
348
|
-
self.get_entries_collection,
|
|
349
|
-
self.get_asset,
|
|
350
|
-
self.get_assets_collection,
|
|
351
|
-
self.execute_graphql_query,
|
|
352
|
-
]
|
|
237
|
+
return [self.get_entry, self.get_entries_collection, self.get_asset, self.get_assets_collection, self.execute_graphql_query]
|