universal-mcp 0.1.1rc1__tar.gz → 0.1.2__tar.gz
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.
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/PKG-INFO +2 -1
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/pyproject.toml +2 -1
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/playground/agents/react.py +2 -2
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/tests/test_applications.py +1 -0
- universal_mcp-0.1.2/src/universal_mcp/applications/notion/README.md +32 -0
- universal_mcp-0.1.2/src/universal_mcp/applications/notion/app.py +415 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/cli.py +1 -1
- universal_mcp-0.1.2/src/universal_mcp/utils/bridge.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/utils/openapi.py +26 -19
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/uv.lock +17 -1
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/.github/workflows/publish-pypi.yml +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/.github/workflows/pull-request-checks.yml +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/.github/workflows/shared.yml +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/.gitignore +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/.pre-commit-config.yaml +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/.python-version +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/CONTRIBUTING.md +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/README.md +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/local_config.json.example +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/playground/README.md +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/playground/__init__.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/playground/__main__.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/playground/client.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/playground/memory/__init__.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/playground/memory/sqlite.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/playground/schema.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/playground/service.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/playground/settings.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/playground/streamlit.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/playground/utils.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/tests/__init__.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/tests/conftest.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/tests/test_api_generator.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/tests/test_localserver.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/tests/test_zenquotes.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/__init__.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/applications/__init__.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/applications/application.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/applications/e2b/app.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/applications/firecrawl/app.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/applications/github/README.md +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/applications/github/app.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/applications/google_calendar/app.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/applications/google_mail/app.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/applications/markitdown/app.py +0 -0
- /universal_mcp-0.1.1rc1/src/universal_mcp/py.typed → /universal_mcp-0.1.2/src/universal_mcp/applications/notion/__init__.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/applications/reddit/app.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/applications/resend/app.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/applications/serp/app.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/applications/tavily/app.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/applications/zenquotes/app.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/config.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/exceptions.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/integrations/README.md +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/integrations/__init__.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/integrations/agentr.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/integrations/integration.py +0 -0
- /universal_mcp-0.1.1rc1/src/universal_mcp/utils/bridge.py → /universal_mcp-0.1.2/src/universal_mcp/py.typed +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/servers/__init__.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/servers/server.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/stores/__init__.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/stores/store.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/utils/__init__.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/utils/api_generator.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/utils/docgen.py +0 -0
- {universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/utils/installation.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: universal-mcp
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.2
|
4
4
|
Summary: Universal MCP acts as a middle ware for your API applications. It can store your credentials, authorize, enable disable apps on the fly and much more.
|
5
5
|
Author-email: Manoj Bajaj <manojbajaj95@gmail.com>
|
6
6
|
Requires-Python: >=3.11
|
@@ -27,6 +27,7 @@ Provides-Extra: playground
|
|
27
27
|
Requires-Dist: fastapi[standard]>=0.115.12; extra == 'playground'
|
28
28
|
Requires-Dist: langchain-anthropic>=0.3.10; extra == 'playground'
|
29
29
|
Requires-Dist: langchain-mcp-adapters>=0.0.3; extra == 'playground'
|
30
|
+
Requires-Dist: langchain-openai>=0.3.12; extra == 'playground'
|
30
31
|
Requires-Dist: langgraph-checkpoint-sqlite>=2.0.6; extra == 'playground'
|
31
32
|
Requires-Dist: langgraph>=0.3.24; extra == 'playground'
|
32
33
|
Requires-Dist: python-dotenv>=1.0.1; extra == 'playground'
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[project]
|
2
2
|
name = "universal-mcp"
|
3
|
-
version = "0.1.
|
3
|
+
version = "0.1.2"
|
4
4
|
description = "Universal MCP acts as a middle ware for your API applications. It can store your credentials, authorize, enable disable apps on the fly and much more."
|
5
5
|
readme = "README.md"
|
6
6
|
authors = [
|
@@ -28,6 +28,7 @@ playground = [
|
|
28
28
|
"langgraph-checkpoint-sqlite>=2.0.6",
|
29
29
|
"streamlit>=1.44.1",
|
30
30
|
"python-dotenv>=1.0.1",
|
31
|
+
"langchain-openai>=0.3.12",
|
31
32
|
]
|
32
33
|
dev = [
|
33
34
|
"ruff>=0.11.4",
|
@@ -1,9 +1,9 @@
|
|
1
1
|
import asyncio
|
2
2
|
from contextlib import asynccontextmanager
|
3
3
|
|
4
|
-
from langchain_anthropic import ChatAnthropic
|
5
4
|
from langchain_core.messages import HumanMessage
|
6
5
|
from langchain_mcp_adapters.client import MultiServerMCPClient
|
6
|
+
from langchain_openai import ChatOpenAI
|
7
7
|
from langgraph.prebuilt import create_react_agent
|
8
8
|
|
9
9
|
|
@@ -23,7 +23,7 @@ async def load_tools():
|
|
23
23
|
|
24
24
|
@asynccontextmanager
|
25
25
|
async def create_agent():
|
26
|
-
llm =
|
26
|
+
llm = ChatOpenAI(model="gpt-4o")
|
27
27
|
async with load_tools() as tools:
|
28
28
|
yield create_react_agent(
|
29
29
|
model=llm,
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# Notion Tool
|
2
|
+
|
3
|
+
This is automatically generated from OpenAPI schema for the Notion API.
|
4
|
+
|
5
|
+
## Supported Integrations
|
6
|
+
|
7
|
+
This tool can be integrated with any service that supports HTTP requests.
|
8
|
+
|
9
|
+
## Tool List
|
10
|
+
|
11
|
+
| Tool | Description |
|
12
|
+
|------|-------------|
|
13
|
+
| notion_retrieve_auser | Retrieves user information from the Notion API by user ID. |
|
14
|
+
| notion_list_all_users | Fetches and returns a list of all users from the Notion API. |
|
15
|
+
| notion_retrieve_your_token_sbot_user | Retrieves the current user's token data from the Notion API. |
|
16
|
+
| notion_retrieve_adatabase | Retrieves a Notion database by its unique identifier. |
|
17
|
+
| notion_update_adatabase | Updates a Notion database with the given ID and request body data. |
|
18
|
+
| notion_query_adatabase | Executes a query on a Notion database using the Notion API. |
|
19
|
+
| notion_create_adatabase | Creates a new database in Notion using the provided request body. |
|
20
|
+
| notion_create_apage | Creates a new page in Notion by sending a POST request with the specified request body. |
|
21
|
+
| notion_retrieve_apage | Retrieves a page from the Notion API using a given page ID. |
|
22
|
+
| notion_update_page_properties | Updates the properties of a Notion page identified by a given ID. |
|
23
|
+
| notion_retrieve_apage_property_item | Retrieves a specific property item from a page in Notion using the page and property IDs. |
|
24
|
+
| notion_retrieve_block_children | Retrieves the child blocks of a specified Notion block. |
|
25
|
+
| notion_append_block_children | Appends child blocks to a block in Notion using its API. |
|
26
|
+
| notion_retrieve_ablock | Retrieves a block from the Notion API using the specified block ID. |
|
27
|
+
| notion_delete_ablock | Deletes a block from the Notion database using the specified block ID. |
|
28
|
+
| notion_update_ablock | Updates a block in Notion with the given ID and request body. |
|
29
|
+
| notion_search | Executes a search request to the Notion API and returns the response in JSON format. |
|
30
|
+
| notion_retrieve_comments | Retrieves comments from a Notion block using the Notion API. |
|
31
|
+
| notion_add_comment_to_page | Adds a comment to a specified Notion page using the provided request body. |
|
32
|
+
|
@@ -0,0 +1,415 @@
|
|
1
|
+
from typing import Any
|
2
|
+
|
3
|
+
from universal_mcp.applications import APIApplication
|
4
|
+
from universal_mcp.integrations import Integration
|
5
|
+
|
6
|
+
|
7
|
+
class NotionApp(APIApplication):
|
8
|
+
def __init__(self, integration: Integration = None, **kwargs) -> None:
|
9
|
+
"""
|
10
|
+
Initializes a new instance of the class with given integration and additional options.
|
11
|
+
|
12
|
+
Args:
|
13
|
+
integration: An optional Integration instance to configure the connection. Defaults to None.
|
14
|
+
**kwargs: Additional keyword arguments for configuration.
|
15
|
+
|
16
|
+
Returns:
|
17
|
+
None
|
18
|
+
"""
|
19
|
+
super().__init__(name='notion', integration=integration, **kwargs)
|
20
|
+
self.base_url = "https://api.notion.com"
|
21
|
+
|
22
|
+
def _get_headers(self):
|
23
|
+
if not self.integration:
|
24
|
+
raise ValueError("Integration not configured for NotionApp")
|
25
|
+
credentials = self.integration.get_credentials()
|
26
|
+
if "headers" in credentials:
|
27
|
+
return credentials["headers"]
|
28
|
+
return {
|
29
|
+
"Authorization": f"Bearer {credentials['access_token']}",
|
30
|
+
"Accept": "application/json",
|
31
|
+
"Notion-Version": "2022-06-28",
|
32
|
+
}
|
33
|
+
|
34
|
+
def notion_retrieve_auser(self, id, request_body=None) -> dict[str, Any]:
|
35
|
+
"""
|
36
|
+
Retrieves user information from the Notion API by user ID.
|
37
|
+
|
38
|
+
Args:
|
39
|
+
id: The unique identifier of the user whose information is to be retrieved.
|
40
|
+
request_body: A dictionary representing the request body, optional, default is None.
|
41
|
+
|
42
|
+
Returns:
|
43
|
+
A dictionary containing the user's information from the Notion API.
|
44
|
+
"""
|
45
|
+
if id is None:
|
46
|
+
raise ValueError("Missing required parameter 'id'")
|
47
|
+
url = f"{self.base_url}/v1/users/{id}"
|
48
|
+
query_params = {}
|
49
|
+
response = self._get(url, params=query_params)
|
50
|
+
response.raise_for_status()
|
51
|
+
return response.json()
|
52
|
+
|
53
|
+
def notion_list_all_users(self, ) -> dict[str, Any]:
|
54
|
+
"""
|
55
|
+
Fetches and returns a list of all users from the Notion API.
|
56
|
+
|
57
|
+
Args:
|
58
|
+
None: This method does not take any parameters.
|
59
|
+
|
60
|
+
Returns:
|
61
|
+
A dictionary containing the JSON response from the Notion API, representing all users data.
|
62
|
+
"""
|
63
|
+
url = f"{self.base_url}/v1/users"
|
64
|
+
query_params = {}
|
65
|
+
response = self._get(url, params=query_params)
|
66
|
+
response.raise_for_status()
|
67
|
+
return response.json()
|
68
|
+
|
69
|
+
def notion_retrieve_your_token_sbot_user(self, ) -> dict[str, Any]:
|
70
|
+
"""
|
71
|
+
Retrieves the current user's token data from the Notion API.
|
72
|
+
|
73
|
+
Args:
|
74
|
+
self: Instance of the class containing the necessary configuration and authentication details for accessing the Notion API.
|
75
|
+
|
76
|
+
Returns:
|
77
|
+
A dictionary containing the current user's token information as retrieved from the Notion API.
|
78
|
+
"""
|
79
|
+
url = f"{self.base_url}/v1/users/me"
|
80
|
+
query_params = {}
|
81
|
+
response = self._get(url, params=query_params)
|
82
|
+
response.raise_for_status()
|
83
|
+
return response.json()
|
84
|
+
|
85
|
+
def notion_retrieve_adatabase(self, id) -> dict[str, Any]:
|
86
|
+
"""
|
87
|
+
Retrieves a Notion database by its unique identifier.
|
88
|
+
|
89
|
+
Args:
|
90
|
+
id: A string representing the unique identifier of the Notion database to be retrieved.
|
91
|
+
|
92
|
+
Returns:
|
93
|
+
A dictionary containing the details of the retrieved Notion database.
|
94
|
+
"""
|
95
|
+
if id is None:
|
96
|
+
raise ValueError("Missing required parameter 'id'")
|
97
|
+
url = f"{self.base_url}/v1/databases/{id}"
|
98
|
+
query_params = {}
|
99
|
+
response = self._get(url, params=query_params)
|
100
|
+
response.raise_for_status()
|
101
|
+
return response.json()
|
102
|
+
|
103
|
+
def notion_update_adatabase(self, id, request_body=None) -> dict[str, Any]:
|
104
|
+
"""
|
105
|
+
Updates a Notion database with the given ID and request body data.
|
106
|
+
|
107
|
+
Args:
|
108
|
+
self: An instance of the class containing configuration and methods for HTTP requests.
|
109
|
+
id: A string representing the unique identifier of the Notion database to be updated.
|
110
|
+
request_body: An optional dictionary containing the fields and values to update in the database.
|
111
|
+
|
112
|
+
Returns:
|
113
|
+
A dictionary representing the JSON response from the Notion API after updating the database.
|
114
|
+
"""
|
115
|
+
if id is None:
|
116
|
+
raise ValueError("Missing required parameter 'id'")
|
117
|
+
url = f"{self.base_url}/v1/databases/{id}"
|
118
|
+
query_params = {}
|
119
|
+
response = self._patch(url, data={}, params=query_params)
|
120
|
+
response.raise_for_status()
|
121
|
+
return response.json()
|
122
|
+
|
123
|
+
def notion_query_adatabase(self, id, request_body=None) -> dict[str, Any]:
|
124
|
+
"""
|
125
|
+
Executes a query on a Notion database using the Notion API.
|
126
|
+
|
127
|
+
Args:
|
128
|
+
self: Instance of the class which should contain 'base_url' and '_post' method.
|
129
|
+
id: A string representing the unique identifier of the Notion database to query.
|
130
|
+
request_body: Optional. A dictionary representing the request body for the query. Defaults to None.
|
131
|
+
|
132
|
+
Returns:
|
133
|
+
A dictionary containing the JSON response from the Notion API after querying the specified database.
|
134
|
+
"""
|
135
|
+
if id is None:
|
136
|
+
raise ValueError("Missing required parameter 'id'")
|
137
|
+
url = f"{self.base_url}/v1/databases/{id}/query"
|
138
|
+
query_params = {}
|
139
|
+
json_body = request_body if request_body is not None else None
|
140
|
+
response = self._post(url, data=json_body, params=query_params)
|
141
|
+
response.raise_for_status()
|
142
|
+
return response.json()
|
143
|
+
|
144
|
+
def notion_create_adatabase(self, request_body=None) -> dict[str, Any]:
|
145
|
+
"""
|
146
|
+
Creates a new database in Notion using the provided request body.
|
147
|
+
|
148
|
+
Args:
|
149
|
+
self: Reference to the current instance of the class.
|
150
|
+
request_body: Optional dictionary containing the specifications for creating the Notion database. If None, a default empty request body is used.
|
151
|
+
|
152
|
+
Returns:
|
153
|
+
A dictionary representing the JSON response from the Notion API, containing data about the newly created database.
|
154
|
+
"""
|
155
|
+
url = f"{self.base_url}/v1/databases/"
|
156
|
+
query_params = {}
|
157
|
+
json_body = request_body if request_body is not None else None
|
158
|
+
response = self._post(url, data=json_body, params=query_params)
|
159
|
+
response.raise_for_status()
|
160
|
+
return response.json()
|
161
|
+
|
162
|
+
def notion_create_apage(self, request_body=None) -> dict[str, Any]:
|
163
|
+
"""
|
164
|
+
Creates a new page in Notion by sending a POST request with the specified request body.
|
165
|
+
|
166
|
+
Args:
|
167
|
+
request_body: Optional; A dictionary containing the data to create a new page in Notion. Defaults to None.
|
168
|
+
|
169
|
+
Returns:
|
170
|
+
A dictionary containing the JSON response from the Notion API with the details of the newly created page.
|
171
|
+
"""
|
172
|
+
url = f"{self.base_url}/v1/pages/"
|
173
|
+
query_params = {}
|
174
|
+
json_body = request_body if request_body is not None else None
|
175
|
+
response = self._post(url, data=json_body, params=query_params)
|
176
|
+
response.raise_for_status()
|
177
|
+
return response.json()
|
178
|
+
|
179
|
+
def notion_retrieve_apage(self, id) -> dict[str, Any]:
|
180
|
+
"""
|
181
|
+
Retrieves a page from the Notion API using a given page ID.
|
182
|
+
|
183
|
+
Args:
|
184
|
+
id: The unique identifier of the Notion page to be retrieved.
|
185
|
+
|
186
|
+
Returns:
|
187
|
+
A dictionary containing the JSON response from the Notion API, representing the page data.
|
188
|
+
"""
|
189
|
+
if id is None:
|
190
|
+
raise ValueError("Missing required parameter 'id'")
|
191
|
+
url = f"{self.base_url}/v1/pages/{id}"
|
192
|
+
query_params = {}
|
193
|
+
response = self._get(url, params=query_params)
|
194
|
+
response.raise_for_status()
|
195
|
+
return response.json()
|
196
|
+
|
197
|
+
def notion_update_page_properties(self, id, request_body=None) -> dict[str, Any]:
|
198
|
+
"""
|
199
|
+
Updates the properties of a Notion page identified by a given ID.
|
200
|
+
|
201
|
+
Args:
|
202
|
+
self: Instance of the class containing the Notion API credentials and methods.
|
203
|
+
id: The unique identifier of the Notion page to update. Must not be None.
|
204
|
+
request_body: An optional dictionary representing the request body to be sent with the update request. Defaults to None, indicating no additional properties to update.
|
205
|
+
|
206
|
+
Returns:
|
207
|
+
A dictionary containing the JSON response from the Notion API after the page update request.
|
208
|
+
"""
|
209
|
+
if id is None:
|
210
|
+
raise ValueError("Missing required parameter 'id'")
|
211
|
+
url = f"{self.base_url}/v1/pages/{id}"
|
212
|
+
query_params = {}
|
213
|
+
response = self._patch(url, data={}, params=query_params)
|
214
|
+
response.raise_for_status()
|
215
|
+
return response.json()
|
216
|
+
|
217
|
+
def notion_retrieve_apage_property_item(self, page_id, property_id) -> dict[str, Any]:
|
218
|
+
"""
|
219
|
+
Retrieves a specific property item from a page in Notion using the page and property IDs.
|
220
|
+
|
221
|
+
Args:
|
222
|
+
page_id: The unique identifier for the Notion page from which the property item should be retrieved.
|
223
|
+
property_id: The unique identifier for the property item within the specified page that should be retrieved.
|
224
|
+
|
225
|
+
Returns:
|
226
|
+
A dictionary containing the JSON response from the Notion API representing the requested property item.
|
227
|
+
"""
|
228
|
+
if page_id is None:
|
229
|
+
raise ValueError("Missing required parameter 'page_id'")
|
230
|
+
if property_id is None:
|
231
|
+
raise ValueError("Missing required parameter 'property_id'")
|
232
|
+
url = f"{self.base_url}/v1/pages/{page_id}/properties/{property_id}"
|
233
|
+
query_params = {}
|
234
|
+
response = self._get(url, params=query_params)
|
235
|
+
response.raise_for_status()
|
236
|
+
return response.json()
|
237
|
+
|
238
|
+
def notion_retrieve_block_children(self, id, page_size=None) -> dict[str, Any]:
|
239
|
+
"""
|
240
|
+
Retrieves the child blocks of a specified Notion block.
|
241
|
+
|
242
|
+
Args:
|
243
|
+
self: The instance of the class this method belongs to.
|
244
|
+
id: The unique identifier of the parent block whose children are to be retrieved.
|
245
|
+
page_size: Optional; the number of child blocks to retrieve per request.
|
246
|
+
|
247
|
+
Returns:
|
248
|
+
A dictionary containing the JSON response with details about the child blocks.
|
249
|
+
"""
|
250
|
+
if id is None:
|
251
|
+
raise ValueError("Missing required parameter 'id'")
|
252
|
+
url = f"{self.base_url}/v1/blocks/{id}/children"
|
253
|
+
query_params = {k: v for k, v in [('page_size', page_size)] if v is not None}
|
254
|
+
response = self._get(url, params=query_params)
|
255
|
+
response.raise_for_status()
|
256
|
+
return response.json()
|
257
|
+
|
258
|
+
def notion_append_block_children(self, id, request_body=None) -> dict[str, Any]:
|
259
|
+
"""
|
260
|
+
Appends child blocks to a block in Notion using its API.
|
261
|
+
|
262
|
+
Args:
|
263
|
+
self: Instance of the class containing Notion API credentials and configuration.
|
264
|
+
id: The unique identifier of the parent block to which child blocks are to be appended.
|
265
|
+
request_body: An optional dictionary containing the block data to append. Defaults to None.
|
266
|
+
|
267
|
+
Returns:
|
268
|
+
A dictionary representing the response from the Notion API, containing the result of the append operation.
|
269
|
+
"""
|
270
|
+
if id is None:
|
271
|
+
raise ValueError("Missing required parameter 'id'")
|
272
|
+
url = f"{self.base_url}/v1/blocks/{id}/children"
|
273
|
+
query_params = {}
|
274
|
+
response = self._patch(url, data={}, params=query_params)
|
275
|
+
response.raise_for_status()
|
276
|
+
return response.json()
|
277
|
+
|
278
|
+
def notion_retrieve_ablock(self, id) -> dict[str, Any]:
|
279
|
+
"""
|
280
|
+
Retrieves a block from the Notion API using the specified block ID.
|
281
|
+
|
282
|
+
Args:
|
283
|
+
id: The unique identifier of the block to retrieve from the Notion API. Must be a non-null string.
|
284
|
+
|
285
|
+
Returns:
|
286
|
+
A dictionary containing the block data in JSON format as retrieved from the Notion API.
|
287
|
+
"""
|
288
|
+
if id is None:
|
289
|
+
raise ValueError("Missing required parameter 'id'")
|
290
|
+
url = f"{self.base_url}/v1/blocks/{id}"
|
291
|
+
query_params = {}
|
292
|
+
response = self._get(url, params=query_params)
|
293
|
+
response.raise_for_status()
|
294
|
+
return response.json()
|
295
|
+
|
296
|
+
def notion_delete_ablock(self, id) -> dict[str, Any]:
|
297
|
+
"""
|
298
|
+
Deletes a block from the Notion database using the specified block ID.
|
299
|
+
|
300
|
+
Args:
|
301
|
+
id: The unique identifier of the block to be deleted. Must not be None.
|
302
|
+
|
303
|
+
Returns:
|
304
|
+
A dictionary containing the JSON response from the Notion API after attempting to delete the block.
|
305
|
+
"""
|
306
|
+
if id is None:
|
307
|
+
raise ValueError("Missing required parameter 'id'")
|
308
|
+
url = f"{self.base_url}/v1/blocks/{id}"
|
309
|
+
query_params = {}
|
310
|
+
response = self._delete(url, params=query_params)
|
311
|
+
response.raise_for_status()
|
312
|
+
return response.json()
|
313
|
+
|
314
|
+
def notion_update_ablock(self, id, request_body=None) -> dict[str, Any]:
|
315
|
+
"""
|
316
|
+
Updates a block in Notion with the given ID and request body.
|
317
|
+
|
318
|
+
Args:
|
319
|
+
id: The unique identifier of the Notion block to update.
|
320
|
+
request_body: The request body containing the updates to be made to the block. Defaults to None if not provided.
|
321
|
+
|
322
|
+
Returns:
|
323
|
+
A dictionary containing the JSON response from the Notion API after the block has been updated.
|
324
|
+
"""
|
325
|
+
if id is None:
|
326
|
+
raise ValueError("Missing required parameter 'id'")
|
327
|
+
url = f"{self.base_url}/v1/blocks/{id}"
|
328
|
+
query_params = {}
|
329
|
+
response = self._patch(url, data={}, params=query_params)
|
330
|
+
response.raise_for_status()
|
331
|
+
return response.json()
|
332
|
+
|
333
|
+
def notion_search(self, request_body=None) -> dict[str, Any]:
|
334
|
+
"""
|
335
|
+
Executes a search request to the Notion API and returns the response in JSON format.
|
336
|
+
|
337
|
+
Args:
|
338
|
+
request_body: An optional dictionary containing the search parameters for the API request. Defaults to None if not provided.
|
339
|
+
|
340
|
+
Returns:
|
341
|
+
A dictionary containing the response from the Notion API in JSON format.
|
342
|
+
"""
|
343
|
+
url = f"{self.base_url}/v1/search"
|
344
|
+
query_params = {}
|
345
|
+
json_body = request_body if request_body is not None else None
|
346
|
+
response = self._post(url, data=json_body, params=query_params)
|
347
|
+
response.raise_for_status()
|
348
|
+
return response.json()
|
349
|
+
|
350
|
+
def notion_retrieve_comments(self, block_id=None, page_size=None, request_body=None) -> dict[str, Any]:
|
351
|
+
"""
|
352
|
+
Retrieves comments from a Notion block using the Notion API.
|
353
|
+
|
354
|
+
Args:
|
355
|
+
block_id: Optional; The ID of the block for which to retrieve comments. If None, it retrieves comments for all blocks available to the user.
|
356
|
+
page_size: Optional; The maximum number of comments to retrieve in one request. If None, the default page size will be used.
|
357
|
+
request_body: Optional; A dictionary to include additional parameters in the request body. If None, no extra parameters are added.
|
358
|
+
|
359
|
+
Returns:
|
360
|
+
A dictionary containing the JSON response from the Notion API with the comments retrieved.
|
361
|
+
"""
|
362
|
+
url = f"{self.base_url}/v1/comments"
|
363
|
+
query_params = {k: v for k, v in [('block_id', block_id), ('page_size', page_size)] if v is not None}
|
364
|
+
response = self._get(url, params=query_params)
|
365
|
+
response.raise_for_status()
|
366
|
+
return response.json()
|
367
|
+
|
368
|
+
def notion_add_comment_to_page(self, request_body=None) -> dict[str, Any]:
|
369
|
+
"""
|
370
|
+
Adds a comment to a specified Notion page using the provided request body.
|
371
|
+
|
372
|
+
Args:
|
373
|
+
request_body: An optional dictionary containing the details of the comment to be added to the Notion page. If None, no data is sent in the request's body.
|
374
|
+
|
375
|
+
Returns:
|
376
|
+
A dictionary containing the response data from the Notion API, parsed from JSON format.
|
377
|
+
"""
|
378
|
+
url = f"{self.base_url}/v1/comments"
|
379
|
+
query_params = {}
|
380
|
+
json_body = request_body if request_body is not None else None
|
381
|
+
response = self._post(url, data=json_body, params=query_params)
|
382
|
+
response.raise_for_status()
|
383
|
+
return response.json()
|
384
|
+
|
385
|
+
def list_tools(self):
|
386
|
+
"""
|
387
|
+
Returns a list of functions that interact with Notion's API for various operations.
|
388
|
+
|
389
|
+
Args:
|
390
|
+
None: This method does not take any parameters.
|
391
|
+
|
392
|
+
Returns:
|
393
|
+
A list of functions that perform specific operations with Notion's API, such as retrieving or updating users, databases, pages, blocks, and comments.
|
394
|
+
"""
|
395
|
+
return [
|
396
|
+
self.notion_retrieve_auser,
|
397
|
+
self.notion_list_all_users,
|
398
|
+
self.notion_retrieve_your_token_sbot_user,
|
399
|
+
self.notion_retrieve_adatabase,
|
400
|
+
self.notion_update_adatabase,
|
401
|
+
self.notion_query_adatabase,
|
402
|
+
self.notion_create_adatabase,
|
403
|
+
self.notion_create_apage,
|
404
|
+
self.notion_retrieve_apage,
|
405
|
+
self.notion_update_page_properties,
|
406
|
+
self.notion_retrieve_apage_property_item,
|
407
|
+
self.notion_retrieve_block_children,
|
408
|
+
self.notion_append_block_children,
|
409
|
+
self.notion_retrieve_ablock,
|
410
|
+
self.notion_delete_ablock,
|
411
|
+
self.notion_update_ablock,
|
412
|
+
self.notion_search,
|
413
|
+
self.notion_retrieve_comments,
|
414
|
+
self.notion_add_comment_to_page
|
415
|
+
]
|
@@ -66,7 +66,7 @@ def generate(
|
|
66
66
|
def docgen(
|
67
67
|
file_path: Path = typer.Argument(..., help="Path to the Python file to process"),
|
68
68
|
model: str = typer.Option(
|
69
|
-
"anthropic/claude-3-sonnet-
|
69
|
+
"anthropic/claude-3-5-sonnet-20241022",
|
70
70
|
"--model",
|
71
71
|
"-m",
|
72
72
|
help="Model to use for generating docstrings",
|
File without changes
|
@@ -177,6 +177,9 @@ def generate_method_code(path, method, operation, tool_name=None):
|
|
177
177
|
Returns:
|
178
178
|
tuple: (method_code, func_name) - The Python code for the method and its name.
|
179
179
|
"""
|
180
|
+
# Extract path parameters from the URL path
|
181
|
+
path_params_in_url = re.findall(r'{([^}]+)}', path)
|
182
|
+
|
180
183
|
# Determine function name
|
181
184
|
if "operationId" in operation:
|
182
185
|
raw_name = operation["operationId"]
|
@@ -198,18 +201,28 @@ def generate_method_code(path, method, operation, tool_name=None):
|
|
198
201
|
func_name = f"{tool_name}_{func_name}"
|
199
202
|
|
200
203
|
# Get parameters and request body
|
201
|
-
|
204
|
+
# Filter out header parameters
|
205
|
+
parameters = [param for param in operation.get("parameters", []) if param.get("in") != "header"]
|
202
206
|
has_body = "requestBody" in operation
|
203
207
|
body_required = has_body and operation["requestBody"].get("required", False)
|
204
208
|
|
205
209
|
# Build function arguments
|
206
210
|
required_args = []
|
207
211
|
optional_args = []
|
212
|
+
|
213
|
+
|
214
|
+
for param_name in path_params_in_url:
|
215
|
+
if param_name not in required_args:
|
216
|
+
required_args.append(param_name)
|
217
|
+
|
218
|
+
|
208
219
|
for param in parameters:
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
220
|
+
param_name = param["name"]
|
221
|
+
if param_name not in required_args:
|
222
|
+
if param.get("required", False):
|
223
|
+
required_args.append(param_name)
|
224
|
+
else:
|
225
|
+
optional_args.append(f"{param_name}=None")
|
213
226
|
|
214
227
|
# Add request body parameter
|
215
228
|
if has_body:
|
@@ -229,12 +242,12 @@ def generate_method_code(path, method, operation, tool_name=None):
|
|
229
242
|
# Build method body
|
230
243
|
body_lines = []
|
231
244
|
|
232
|
-
# Validate required parameters
|
233
|
-
for
|
234
|
-
if
|
235
|
-
body_lines.append(f" if {
|
245
|
+
# Validate required parameters including path parameters
|
246
|
+
for param_name in required_args:
|
247
|
+
if param_name != "request_body": # Skip validation for request body as it's handled separately
|
248
|
+
body_lines.append(f" if {param_name} is None:")
|
236
249
|
body_lines.append(
|
237
|
-
f" raise ValueError(\"Missing required parameter '{
|
250
|
+
f" raise ValueError(\"Missing required parameter '{param_name}'\")"
|
238
251
|
)
|
239
252
|
|
240
253
|
# Validate required body
|
@@ -244,15 +257,9 @@ def generate_method_code(path, method, operation, tool_name=None):
|
|
244
257
|
' raise ValueError("Missing required request body")'
|
245
258
|
)
|
246
259
|
|
247
|
-
#
|
248
|
-
|
249
|
-
|
250
|
-
body_lines.append(f" path_params = {{{path_params_dict}}}")
|
251
|
-
|
252
|
-
# Format URL
|
253
|
-
body_lines.append(
|
254
|
-
f' url = f"{{self.base_url}}{path}".format_map(path_params)'
|
255
|
-
)
|
260
|
+
# Format URL directly with path parameters
|
261
|
+
url_line = f' url = f"{{self.base_url}}{path}"'
|
262
|
+
body_lines.append(url_line)
|
256
263
|
|
257
264
|
# Query parameters
|
258
265
|
query_params = [p for p in parameters if p["in"] == "query"]
|
@@ -1092,6 +1092,20 @@ wheels = [
|
|
1092
1092
|
{ url = "https://files.pythonhosted.org/packages/a6/32/b09799c5b6ce8c6842536116118664dd7ec5964e229b7cd449c8d598c68d/langchain_mcp_adapters-0.0.7-py3-none-any.whl", hash = "sha256:1e37ec79fc6afb58d1dea17733e08cc111ebc1992aed4b22c67de5e2bdcdb5c6", size = 8610 },
|
1093
1093
|
]
|
1094
1094
|
|
1095
|
+
[[package]]
|
1096
|
+
name = "langchain-openai"
|
1097
|
+
version = "0.3.12"
|
1098
|
+
source = { registry = "https://pypi.org/simple" }
|
1099
|
+
dependencies = [
|
1100
|
+
{ name = "langchain-core" },
|
1101
|
+
{ name = "openai" },
|
1102
|
+
{ name = "tiktoken" },
|
1103
|
+
]
|
1104
|
+
sdist = { url = "https://files.pythonhosted.org/packages/32/01/94d861be321df40f104324d3c64115917c7e774bb5d6af45d4af967c863c/langchain_openai-0.3.12.tar.gz", hash = "sha256:c9dbff63551f6bd91913bca9f99a2d057fd95dc58d4778657d67e5baa1737f61", size = 269015 }
|
1105
|
+
wheels = [
|
1106
|
+
{ url = "https://files.pythonhosted.org/packages/07/7e/0d8838972ffead497b40cd42a1676f9ad90427d422c92dff2fb5461c4308/langchain_openai-0.3.12-py3-none-any.whl", hash = "sha256:0fab64d58ec95e65ffbaf659470cd362e815685e15edbcb171641e90eca4eb86", size = 61320 },
|
1107
|
+
]
|
1108
|
+
|
1095
1109
|
[[package]]
|
1096
1110
|
name = "langgraph"
|
1097
1111
|
version = "0.3.25"
|
@@ -2834,7 +2848,7 @@ wheels = [
|
|
2834
2848
|
|
2835
2849
|
[[package]]
|
2836
2850
|
name = "universal-mcp"
|
2837
|
-
version = "0.1.
|
2851
|
+
version = "0.1.2rc1"
|
2838
2852
|
source = { editable = "." }
|
2839
2853
|
dependencies = [
|
2840
2854
|
{ name = "keyring" },
|
@@ -2866,6 +2880,7 @@ playground = [
|
|
2866
2880
|
{ name = "fastapi", extra = ["standard"] },
|
2867
2881
|
{ name = "langchain-anthropic" },
|
2868
2882
|
{ name = "langchain-mcp-adapters" },
|
2883
|
+
{ name = "langchain-openai" },
|
2869
2884
|
{ name = "langgraph" },
|
2870
2885
|
{ name = "langgraph-checkpoint-sqlite" },
|
2871
2886
|
{ name = "python-dotenv" },
|
@@ -2884,6 +2899,7 @@ requires-dist = [
|
|
2884
2899
|
{ name = "keyring", specifier = ">=25.6.0" },
|
2885
2900
|
{ name = "langchain-anthropic", marker = "extra == 'playground'", specifier = ">=0.3.10" },
|
2886
2901
|
{ name = "langchain-mcp-adapters", marker = "extra == 'playground'", specifier = ">=0.0.3" },
|
2902
|
+
{ name = "langchain-openai", marker = "extra == 'playground'", specifier = ">=0.3.12" },
|
2887
2903
|
{ name = "langgraph", marker = "extra == 'playground'", specifier = ">=0.3.24" },
|
2888
2904
|
{ name = "langgraph-checkpoint-sqlite", marker = "extra == 'playground'", specifier = ">=2.0.6" },
|
2889
2905
|
{ name = "litellm", specifier = ">=1.30.7" },
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/applications/application.py
RENAMED
File without changes
|
File without changes
|
{universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/applications/firecrawl/app.py
RENAMED
File without changes
|
{universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/applications/github/README.md
RENAMED
File without changes
|
File without changes
|
{universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/applications/google_calendar/app.py
RENAMED
File without changes
|
{universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/applications/google_mail/app.py
RENAMED
File without changes
|
{universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/applications/markitdown/app.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/applications/zenquotes/app.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{universal_mcp-0.1.1rc1 → universal_mcp-0.1.2}/src/universal_mcp/integrations/integration.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|