mcpscraper-memory-sdk 0.13.0__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.
- mcpscraper_memory/__init__.py +9 -0
- mcpscraper_memory/_generated_client.py +588 -0
- mcpscraper_memory/_mcp_generated_client.py +1111 -0
- mcpscraper_memory/client.py +115 -0
- mcpscraper_memory/errors.py +17 -0
- mcpscraper_memory/mcp_client.py +136 -0
- mcpscraper_memory/mcp_models/__init__.py +0 -0
- mcpscraper_memory/mcp_models/access_accept_share.py +17 -0
- mcpscraper_memory/mcp_models/access_approve_sender.py +16 -0
- mcpscraper_memory/mcp_models/access_decline_share.py +16 -0
- mcpscraper_memory/mcp_models/access_inbox_settings.py +16 -0
- mcpscraper_memory/mcp_models/access_invite_account.py +21 -0
- mcpscraper_memory/mcp_models/access_issue_key.py +26 -0
- mcpscraper_memory/mcp_models/access_list_approved_senders.py +15 -0
- mcpscraper_memory/mcp_models/access_list_keys.py +17 -0
- mcpscraper_memory/mcp_models/access_note_inbox.py +14 -0
- mcpscraper_memory/mcp_models/access_remove_approved_sender.py +17 -0
- mcpscraper_memory/mcp_models/access_revoke_key.py +17 -0
- mcpscraper_memory/mcp_models/access_revoke_share.py +16 -0
- mcpscraper_memory/mcp_models/access_set_scope.py +19 -0
- mcpscraper_memory/mcp_models/access_share_note.py +26 -0
- mcpscraper_memory/mcp_models/access_share_vault.py +20 -0
- mcpscraper_memory/mcp_models/access_swap_vault.py +17 -0
- mcpscraper_memory/mcp_models/access_switch_account.py +18 -0
- mcpscraper_memory/mcp_models/access_unlink_share.py +16 -0
- mcpscraper_memory/mcp_models/add_vault.py +18 -0
- mcpscraper_memory/mcp_models/audit_site.py +17 -0
- mcpscraper_memory/mcp_models/browser_click.py +16 -0
- mcpscraper_memory/mcp_models/browser_close.py +12 -0
- mcpscraper_memory/mcp_models/browser_extension_delete.py +12 -0
- mcpscraper_memory/mcp_models/browser_extension_import.py +13 -0
- mcpscraper_memory/mcp_models/browser_extension_list.py +10 -0
- mcpscraper_memory/mcp_models/browser_goto.py +13 -0
- mcpscraper_memory/mcp_models/browser_list_replays.py +12 -0
- mcpscraper_memory/mcp_models/browser_list_sessions.py +12 -0
- mcpscraper_memory/mcp_models/browser_locate.py +13 -0
- mcpscraper_memory/mcp_models/browser_open.py +17 -0
- mcpscraper_memory/mcp_models/browser_press.py +13 -0
- mcpscraper_memory/mcp_models/browser_profile_connect.py +19 -0
- mcpscraper_memory/mcp_models/browser_profile_list.py +15 -0
- mcpscraper_memory/mcp_models/browser_read.py +12 -0
- mcpscraper_memory/mcp_models/browser_replay_annotate.py +19 -0
- mcpscraper_memory/mcp_models/browser_replay_download.py +14 -0
- mcpscraper_memory/mcp_models/browser_replay_mark.py +20 -0
- mcpscraper_memory/mcp_models/browser_replay_start.py +12 -0
- mcpscraper_memory/mcp_models/browser_replay_stop.py +13 -0
- mcpscraper_memory/mcp_models/browser_screenshot.py +12 -0
- mcpscraper_memory/mcp_models/browser_scroll.py +16 -0
- mcpscraper_memory/mcp_models/browser_type.py +14 -0
- mcpscraper_memory/mcp_models/bulk_delete_notes.py +24 -0
- mcpscraper_memory/mcp_models/call_service_connection_action.py +14 -0
- mcpscraper_memory/mcp_models/capture_serp_page_snapshots.py +16 -0
- mcpscraper_memory/mcp_models/capture_serp_snapshot.py +22 -0
- mcpscraper_memory/mcp_models/check_site_export.py +12 -0
- mcpscraper_memory/mcp_models/cost_usage.py +28 -0
- mcpscraper_memory/mcp_models/create_channel.py +19 -0
- mcpscraper_memory/mcp_models/create_scheduled_action.py +25 -0
- mcpscraper_memory/mcp_models/create_secure_vault.py +17 -0
- mcpscraper_memory/mcp_models/create_webhook.py +19 -0
- mcpscraper_memory/mcp_models/credits_info.py +13 -0
- mcpscraper_memory/mcp_models/delete_note.py +23 -0
- mcpscraper_memory/mcp_models/delete_scheduled_action.py +16 -0
- mcpscraper_memory/mcp_models/delete_vault.py +18 -0
- mcpscraper_memory/mcp_models/describe_service_connection_tool.py +14 -0
- mcpscraper_memory/mcp_models/diff_page.py +14 -0
- mcpscraper_memory/mcp_models/directory_workflow.py +24 -0
- mcpscraper_memory/mcp_models/export_connected_service_data.py +20 -0
- mcpscraper_memory/mcp_models/export_search_console_table_data.py +15 -0
- mcpscraper_memory/mcp_models/extract_site.py +18 -0
- mcpscraper_memory/mcp_models/extract_url.py +20 -0
- mcpscraper_memory/mcp_models/facebook_ad_search.py +14 -0
- mcpscraper_memory/mcp_models/facebook_ad_transcribe.py +12 -0
- mcpscraper_memory/mcp_models/facebook_page_intel.py +16 -0
- mcpscraper_memory/mcp_models/facebook_video_transcribe.py +13 -0
- mcpscraper_memory/mcp_models/fact_history.py +18 -0
- mcpscraper_memory/mcp_models/g2_reviews.py +13 -0
- mcpscraper_memory/mcp_models/get_chat_link.py +15 -0
- mcpscraper_memory/mcp_models/get_message_note.py +17 -0
- mcpscraper_memory/mcp_models/get_schedule_link.py +16 -0
- mcpscraper_memory/mcp_models/get_schedule_status.py +22 -0
- mcpscraper_memory/mcp_models/get_vault_app_link.py +15 -0
- mcpscraper_memory/mcp_models/get_vault_contract.py +17 -0
- mcpscraper_memory/mcp_models/gmail_send_message.py +15 -0
- mcpscraper_memory/mcp_models/google_ads_page_intel.py +15 -0
- mcpscraper_memory/mcp_models/google_ads_search.py +14 -0
- mcpscraper_memory/mcp_models/google_ads_transcribe.py +12 -0
- mcpscraper_memory/mcp_models/google_calendar_create_event.py +20 -0
- mcpscraper_memory/mcp_models/harvest_paa.py +20 -0
- mcpscraper_memory/mcp_models/import_service_connection_to_memory.py +17 -0
- mcpscraper_memory/mcp_models/instagram_media_download.py +19 -0
- mcpscraper_memory/mcp_models/instagram_profile_content.py +19 -0
- mcpscraper_memory/mcp_models/library_ingest.py +31 -0
- mcpscraper_memory/mcp_models/list_channel_members.py +18 -0
- mcpscraper_memory/mcp_models/list_channel_messages.py +17 -0
- mcpscraper_memory/mcp_models/list_memory_tags.py +16 -0
- mcpscraper_memory/mcp_models/list_scheduled_actions.py +14 -0
- mcpscraper_memory/mcp_models/list_service_connections.py +10 -0
- mcpscraper_memory/mcp_models/list_shared_with_me.py +14 -0
- mcpscraper_memory/mcp_models/list_vaults.py +16 -0
- mcpscraper_memory/mcp_models/list_webhooks.py +14 -0
- mcpscraper_memory/mcp_models/map_site_urls.py +13 -0
- mcpscraper_memory/mcp_models/maps_place_intel.py +18 -0
- mcpscraper_memory/mcp_models/maps_search.py +20 -0
- mcpscraper_memory/mcp_models/memory_backlinks.py +18 -0
- mcpscraper_memory/mcp_models/memory_capture.py +31 -0
- mcpscraper_memory/mcp_models/memory_export.py +18 -0
- mcpscraper_memory/mcp_models/memory_get.py +18 -0
- mcpscraper_memory/mcp_models/memory_graph_path.py +21 -0
- mcpscraper_memory/mcp_models/memory_graph_universe.py +23 -0
- mcpscraper_memory/mcp_models/memory_list.py +20 -0
- mcpscraper_memory/mcp_models/memory_put.py +26 -0
- mcpscraper_memory/mcp_models/memory_questions.py +18 -0
- mcpscraper_memory/mcp_models/memory_search.py +39 -0
- mcpscraper_memory/mcp_models/memory_suggest.py +17 -0
- mcpscraper_memory/mcp_models/memory_upload.py +22 -0
- mcpscraper_memory/mcp_models/meta_ad_creative_media.py +15 -0
- mcpscraper_memory/mcp_models/my_mentions.py +16 -0
- mcpscraper_memory/mcp_models/pause_scheduled_action.py +15 -0
- mcpscraper_memory/mcp_models/poll_channel.py +21 -0
- mcpscraper_memory/mcp_models/post_message.py +20 -0
- mcpscraper_memory/mcp_models/prepare_memory_write.py +26 -0
- mcpscraper_memory/mcp_models/propose_scheduled_action.py +21 -0
- mcpscraper_memory/mcp_models/provision_defaults.py +23 -0
- mcpscraper_memory/mcp_models/query_fanout_workflow.py +17 -0
- mcpscraper_memory/mcp_models/rank_tracker_workflow.py +26 -0
- mcpscraper_memory/mcp_models/react_message.py +21 -0
- mcpscraper_memory/mcp_models/read_service_connection.py +14 -0
- mcpscraper_memory/mcp_models/record_fact.py +22 -0
- mcpscraper_memory/mcp_models/reddit_thread.py +13 -0
- mcpscraper_memory/mcp_models/remove_channel_member.py +17 -0
- mcpscraper_memory/mcp_models/renew_connected_data_download.py +12 -0
- mcpscraper_memory/mcp_models/reply_message.py +21 -0
- mcpscraper_memory/mcp_models/report_artifact_read.py +14 -0
- mcpscraper_memory/mcp_models/resolve_memory_tags.py +16 -0
- mcpscraper_memory/mcp_models/resume_scheduled_action.py +17 -0
- mcpscraper_memory/mcp_models/revoke_chat_link.py +14 -0
- mcpscraper_memory/mcp_models/revoke_schedule_link.py +14 -0
- mcpscraper_memory/mcp_models/revoke_vault_app_link.py +14 -0
- mcpscraper_memory/mcp_models/revoke_webhook.py +16 -0
- mcpscraper_memory/mcp_models/route_memory.py +22 -0
- mcpscraper_memory/mcp_models/search_serp.py +20 -0
- mcpscraper_memory/mcp_models/set_agent_identity.py +16 -0
- mcpscraper_memory/mcp_models/set_schedule_defaults.py +16 -0
- mcpscraper_memory/mcp_models/set_schedule_entitlement.py +18 -0
- mcpscraper_memory/mcp_models/set_scheduled_action_connections.py +13 -0
- mcpscraper_memory/mcp_models/slack_send_message.py +14 -0
- mcpscraper_memory/mcp_models/storage_usage.py +19 -0
- mcpscraper_memory/mcp_models/table_create.py +19 -0
- mcpscraper_memory/mcp_models/table_delete_rows.py +17 -0
- mcpscraper_memory/mcp_models/table_describe.py +17 -0
- mcpscraper_memory/mcp_models/table_drop.py +16 -0
- mcpscraper_memory/mcp_models/table_insert_rows.py +17 -0
- mcpscraper_memory/mcp_models/table_list.py +14 -0
- mcpscraper_memory/mcp_models/table_query.py +22 -0
- mcpscraper_memory/mcp_models/temporal_recall.py +22 -0
- mcpscraper_memory/mcp_models/test_service_connection.py +13 -0
- mcpscraper_memory/mcp_models/trustpilot_reviews.py +13 -0
- mcpscraper_memory/mcp_models/upsert_memory_tag.py +19 -0
- mcpscraper_memory/mcp_models/validate_memory_write.py +22 -0
- mcpscraper_memory/mcp_models/video_analyze_start.py +21 -0
- mcpscraper_memory/mcp_models/video_analyze_status.py +22 -0
- mcpscraper_memory/mcp_models/video_frame_analysis.py +16 -0
- mcpscraper_memory/mcp_models/video_frame_analysis_status.py +12 -0
- mcpscraper_memory/mcp_models/workflow_artifact_read.py +14 -0
- mcpscraper_memory/mcp_models/workflow_list.py +12 -0
- mcpscraper_memory/mcp_models/workflow_run.py +14 -0
- mcpscraper_memory/mcp_models/workflow_status.py +12 -0
- mcpscraper_memory/mcp_models/workflow_step.py +12 -0
- mcpscraper_memory/mcp_models/workflow_suggest.py +19 -0
- mcpscraper_memory/mcp_models/youtube_harvest.py +15 -0
- mcpscraper_memory/mcp_models/youtube_transcribe.py +13 -0
- mcpscraper_memory/mcp_models/zoom_create_meeting.py +17 -0
- mcpscraper_memory/models/__init__.py +0 -0
- mcpscraper_memory/models/access_accept_share.py +19 -0
- mcpscraper_memory/models/access_approve_sender.py +18 -0
- mcpscraper_memory/models/access_decline_share.py +18 -0
- mcpscraper_memory/models/access_inbox_settings.py +18 -0
- mcpscraper_memory/models/access_invite_account.py +23 -0
- mcpscraper_memory/models/access_issue_key.py +28 -0
- mcpscraper_memory/models/access_list_approved_senders.py +18 -0
- mcpscraper_memory/models/access_list_keys.py +19 -0
- mcpscraper_memory/models/access_note_inbox.py +17 -0
- mcpscraper_memory/models/access_remove_approved_sender.py +19 -0
- mcpscraper_memory/models/access_revoke_key.py +19 -0
- mcpscraper_memory/models/access_revoke_share.py +18 -0
- mcpscraper_memory/models/access_set_scope.py +21 -0
- mcpscraper_memory/models/access_share_note.py +28 -0
- mcpscraper_memory/models/access_share_vault.py +22 -0
- mcpscraper_memory/models/access_swap_vault.py +19 -0
- mcpscraper_memory/models/access_switch_account.py +20 -0
- mcpscraper_memory/models/access_unlink_share.py +18 -0
- mcpscraper_memory/models/add_vault.py +20 -0
- mcpscraper_memory/models/cost_usage.py +30 -0
- mcpscraper_memory/models/create_channel.py +21 -0
- mcpscraper_memory/models/create_scheduled_action.py +27 -0
- mcpscraper_memory/models/create_secure_vault.py +19 -0
- mcpscraper_memory/models/create_webhook.py +21 -0
- mcpscraper_memory/models/delete_note.py +25 -0
- mcpscraper_memory/models/delete_scheduled_action.py +18 -0
- mcpscraper_memory/models/delete_vault.py +20 -0
- mcpscraper_memory/models/fact_history.py +20 -0
- mcpscraper_memory/models/get_chat_link.py +18 -0
- mcpscraper_memory/models/get_message_note.py +19 -0
- mcpscraper_memory/models/get_schedule_link.py +19 -0
- mcpscraper_memory/models/get_schedule_status.py +25 -0
- mcpscraper_memory/models/get_vault_contract.py +19 -0
- mcpscraper_memory/models/library_ingest.py +33 -0
- mcpscraper_memory/models/list_channel_members.py +20 -0
- mcpscraper_memory/models/list_channel_messages.py +19 -0
- mcpscraper_memory/models/list_memory_tags.py +18 -0
- mcpscraper_memory/models/list_scheduled_actions.py +17 -0
- mcpscraper_memory/models/list_shared_with_me.py +17 -0
- mcpscraper_memory/models/list_vaults.py +19 -0
- mcpscraper_memory/models/list_webhooks.py +17 -0
- mcpscraper_memory/models/memory_backlinks.py +20 -0
- mcpscraper_memory/models/memory_capture.py +33 -0
- mcpscraper_memory/models/memory_export.py +20 -0
- mcpscraper_memory/models/memory_get.py +20 -0
- mcpscraper_memory/models/memory_graph_path.py +23 -0
- mcpscraper_memory/models/memory_graph_universe.py +25 -0
- mcpscraper_memory/models/memory_list.py +22 -0
- mcpscraper_memory/models/memory_put.py +28 -0
- mcpscraper_memory/models/memory_questions.py +20 -0
- mcpscraper_memory/models/memory_search.py +24 -0
- mcpscraper_memory/models/memory_suggest.py +19 -0
- mcpscraper_memory/models/memory_upload.py +24 -0
- mcpscraper_memory/models/my_mentions.py +18 -0
- mcpscraper_memory/models/pause_scheduled_action.py +17 -0
- mcpscraper_memory/models/poll_channel.py +23 -0
- mcpscraper_memory/models/post_message.py +22 -0
- mcpscraper_memory/models/prepare_memory_write.py +28 -0
- mcpscraper_memory/models/propose_scheduled_action.py +21 -0
- mcpscraper_memory/models/provision_defaults.py +25 -0
- mcpscraper_memory/models/react_message.py +23 -0
- mcpscraper_memory/models/record_fact.py +24 -0
- mcpscraper_memory/models/remove_channel_member.py +19 -0
- mcpscraper_memory/models/reply_message.py +23 -0
- mcpscraper_memory/models/resolve_memory_tags.py +18 -0
- mcpscraper_memory/models/resume_scheduled_action.py +19 -0
- mcpscraper_memory/models/revoke_chat_link.py +17 -0
- mcpscraper_memory/models/revoke_schedule_link.py +17 -0
- mcpscraper_memory/models/revoke_webhook.py +18 -0
- mcpscraper_memory/models/route_memory.py +24 -0
- mcpscraper_memory/models/set_agent_identity.py +18 -0
- mcpscraper_memory/models/set_schedule_entitlement.py +20 -0
- mcpscraper_memory/models/storage_usage.py +22 -0
- mcpscraper_memory/models/table_create.py +21 -0
- mcpscraper_memory/models/table_delete_rows.py +19 -0
- mcpscraper_memory/models/table_describe.py +19 -0
- mcpscraper_memory/models/table_drop.py +18 -0
- mcpscraper_memory/models/table_insert_rows.py +19 -0
- mcpscraper_memory/models/table_list.py +17 -0
- mcpscraper_memory/models/table_query.py +24 -0
- mcpscraper_memory/models/temporal_recall.py +24 -0
- mcpscraper_memory/models/upsert_memory_tag.py +21 -0
- mcpscraper_memory/models/validate_memory_write.py +24 -0
- mcpscraper_memory/models/video_analyze_start.py +23 -0
- mcpscraper_memory/models/video_analyze_status.py +24 -0
- mcpscraper_memory_sdk-0.13.0.dist-info/METADATA +61 -0
- mcpscraper_memory_sdk-0.13.0.dist-info/RECORD +261 -0
- mcpscraper_memory_sdk-0.13.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import itertools
|
|
2
|
+
import json
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
import requests
|
|
6
|
+
|
|
7
|
+
from .errors import MemoryApiError
|
|
8
|
+
from ._generated_client import (
|
|
9
|
+
AccessNamespace,
|
|
10
|
+
CaptureNamespace,
|
|
11
|
+
ChannelsNamespace,
|
|
12
|
+
FactsNamespace,
|
|
13
|
+
GraphNamespace,
|
|
14
|
+
LibraryNamespace,
|
|
15
|
+
MemoryNamespace,
|
|
16
|
+
RecallNamespace,
|
|
17
|
+
ScheduleNamespace,
|
|
18
|
+
StorageNamespace,
|
|
19
|
+
TablesNamespace,
|
|
20
|
+
TagsNamespace,
|
|
21
|
+
VaultsNamespace,
|
|
22
|
+
VideoNamespace,
|
|
23
|
+
WebhooksNamespace,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
DEFAULT_BASE_URL = "https://memory.mcpscraper.dev"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class MemoryClient:
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
api_key: str,
|
|
33
|
+
base_url: str = DEFAULT_BASE_URL,
|
|
34
|
+
session: requests.Session | None = None,
|
|
35
|
+
) -> None:
|
|
36
|
+
self._api_key = api_key
|
|
37
|
+
self._base_url = base_url.rstrip("/")
|
|
38
|
+
self._session = session or requests.Session()
|
|
39
|
+
self._rpc_id = itertools.count(1)
|
|
40
|
+
|
|
41
|
+
self.access = AccessNamespace(self._call_tool)
|
|
42
|
+
self.capture = CaptureNamespace(self._call_tool)
|
|
43
|
+
self.channels = ChannelsNamespace(self._call_tool)
|
|
44
|
+
self.facts = FactsNamespace(self._call_tool)
|
|
45
|
+
self.graph = GraphNamespace(self._call_tool)
|
|
46
|
+
self.library = LibraryNamespace(self._call_tool)
|
|
47
|
+
self.memory = MemoryNamespace(self._call_tool)
|
|
48
|
+
self.recall = RecallNamespace(self._call_tool)
|
|
49
|
+
self.schedule = ScheduleNamespace(self._call_tool)
|
|
50
|
+
self.storage = StorageNamespace(self._call_tool)
|
|
51
|
+
self.tables = TablesNamespace(self._call_tool)
|
|
52
|
+
self.tags = TagsNamespace(self._call_tool)
|
|
53
|
+
self.vaults = VaultsNamespace(self._call_tool)
|
|
54
|
+
self.video = VideoNamespace(self._call_tool)
|
|
55
|
+
self.webhooks = WebhooksNamespace(self._call_tool)
|
|
56
|
+
|
|
57
|
+
def _call_tool(self, name: str, arguments: dict[str, Any]) -> Any:
|
|
58
|
+
response = self._session.post(
|
|
59
|
+
f"{self._base_url}/mcp",
|
|
60
|
+
headers={
|
|
61
|
+
"content-type": "application/json",
|
|
62
|
+
"accept": "application/json, text/event-stream",
|
|
63
|
+
"authorization": f"Bearer {self._api_key}",
|
|
64
|
+
},
|
|
65
|
+
json={
|
|
66
|
+
"jsonrpc": "2.0",
|
|
67
|
+
"id": next(self._rpc_id),
|
|
68
|
+
"method": "tools/call",
|
|
69
|
+
"params": {"name": name, "arguments": arguments},
|
|
70
|
+
},
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
if not response.ok:
|
|
74
|
+
raise MemoryApiError(
|
|
75
|
+
f'HTTP {response.status_code} calling tool "{name}"',
|
|
76
|
+
http_status=response.status_code,
|
|
77
|
+
data=response.text,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
payload = response.json()
|
|
81
|
+
|
|
82
|
+
if payload.get("error"):
|
|
83
|
+
error = payload["error"]
|
|
84
|
+
raise MemoryApiError(
|
|
85
|
+
error.get("message", f'tool "{name}" failed'),
|
|
86
|
+
rpc_code=error.get("code"),
|
|
87
|
+
data=error.get("data"),
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
result = payload.get("result") or {}
|
|
91
|
+
text_block = next(
|
|
92
|
+
(block.get("text") for block in result.get("content", []) if block.get("type") == "text"),
|
|
93
|
+
None,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
parsed: Any = text_block
|
|
97
|
+
if isinstance(text_block, str):
|
|
98
|
+
try:
|
|
99
|
+
parsed = json.loads(text_block)
|
|
100
|
+
except ValueError:
|
|
101
|
+
parsed = text_block
|
|
102
|
+
if "structuredContent" in result:
|
|
103
|
+
parsed = result["structuredContent"]
|
|
104
|
+
|
|
105
|
+
if result.get("isError"):
|
|
106
|
+
message = (
|
|
107
|
+
parsed.get("message")
|
|
108
|
+
if isinstance(parsed, dict) and "message" in parsed
|
|
109
|
+
else parsed
|
|
110
|
+
if isinstance(parsed, str)
|
|
111
|
+
else f'Tool "{name}" failed'
|
|
112
|
+
)
|
|
113
|
+
raise MemoryApiError(str(message), tool_error=parsed)
|
|
114
|
+
|
|
115
|
+
return parsed
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class MemoryApiError(Exception):
|
|
5
|
+
def __init__(
|
|
6
|
+
self,
|
|
7
|
+
message: str,
|
|
8
|
+
http_status: int | None = None,
|
|
9
|
+
rpc_code: int | None = None,
|
|
10
|
+
data: Any = None,
|
|
11
|
+
tool_error: Any = None,
|
|
12
|
+
) -> None:
|
|
13
|
+
super().__init__(message)
|
|
14
|
+
self.http_status = http_status
|
|
15
|
+
self.rpc_code = rpc_code
|
|
16
|
+
self.data = data
|
|
17
|
+
self.tool_error = tool_error
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import itertools
|
|
4
|
+
import json
|
|
5
|
+
import time
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
import requests
|
|
9
|
+
|
|
10
|
+
from ._mcp_generated_client import GeneratedMcpToolsClient
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class McpToolError(RuntimeError):
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
message: str,
|
|
17
|
+
*,
|
|
18
|
+
http_status: int | None = None,
|
|
19
|
+
rpc_code: int | None = None,
|
|
20
|
+
data: Any = None,
|
|
21
|
+
tool_error: Any = None,
|
|
22
|
+
) -> None:
|
|
23
|
+
super().__init__(message)
|
|
24
|
+
self.http_status = http_status
|
|
25
|
+
self.rpc_code = rpc_code
|
|
26
|
+
self.data = data
|
|
27
|
+
self.tool_error = tool_error
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class McpToolsClient(GeneratedMcpToolsClient):
|
|
31
|
+
"""Typed access to every tool exposed by https://mcpscraper.dev/mcp."""
|
|
32
|
+
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
api_key: str,
|
|
36
|
+
base_url: str = "https://mcpscraper.dev",
|
|
37
|
+
session: requests.Session | None = None,
|
|
38
|
+
list_retries: int = 2,
|
|
39
|
+
retry_delay_s: float = 0.25,
|
|
40
|
+
) -> None:
|
|
41
|
+
self._api_key = api_key
|
|
42
|
+
self._base_url = base_url.rstrip("/")
|
|
43
|
+
self._session = session or requests.Session()
|
|
44
|
+
self._rpc_id = itertools.count(1)
|
|
45
|
+
self._list_retries = list_retries
|
|
46
|
+
self._retry_delay_s = retry_delay_s
|
|
47
|
+
super().__init__(self._call_tool)
|
|
48
|
+
|
|
49
|
+
def _request(self, method: str, params: dict[str, Any] | None = None) -> Any:
|
|
50
|
+
payload: dict[str, Any] = {
|
|
51
|
+
"jsonrpc": "2.0",
|
|
52
|
+
"id": next(self._rpc_id),
|
|
53
|
+
"method": method,
|
|
54
|
+
}
|
|
55
|
+
if params is not None:
|
|
56
|
+
payload["params"] = params
|
|
57
|
+
attempts = self._list_retries + 1 if method == "tools/list" else 1
|
|
58
|
+
response = None
|
|
59
|
+
for attempt in range(attempts):
|
|
60
|
+
response = self._session.post(
|
|
61
|
+
f"{self._base_url}/mcp",
|
|
62
|
+
headers={
|
|
63
|
+
"x-api-key": self._api_key,
|
|
64
|
+
"content-type": "application/json",
|
|
65
|
+
"accept": "application/json, text/event-stream",
|
|
66
|
+
},
|
|
67
|
+
json=payload,
|
|
68
|
+
)
|
|
69
|
+
transient_discovery_failure = method == "tools/list" and response.status_code in (502, 503, 504)
|
|
70
|
+
if not transient_discovery_failure or attempt == attempts - 1:
|
|
71
|
+
break
|
|
72
|
+
time.sleep(self._retry_delay_s * (attempt + 1))
|
|
73
|
+
assert response is not None
|
|
74
|
+
if not response.ok:
|
|
75
|
+
raise McpToolError(
|
|
76
|
+
f'HTTP {response.status_code} calling MCP method "{method}"',
|
|
77
|
+
http_status=response.status_code,
|
|
78
|
+
data=response.text,
|
|
79
|
+
)
|
|
80
|
+
body = response.json()
|
|
81
|
+
if body.get("error"):
|
|
82
|
+
error = body["error"]
|
|
83
|
+
raise McpToolError(
|
|
84
|
+
error.get("message", f'MCP method "{method}" failed'),
|
|
85
|
+
rpc_code=error.get("code"),
|
|
86
|
+
data=error.get("data"),
|
|
87
|
+
)
|
|
88
|
+
if "result" not in body:
|
|
89
|
+
raise McpToolError(f'MCP method "{method}" returned no result')
|
|
90
|
+
return body["result"]
|
|
91
|
+
|
|
92
|
+
def list_tools(self) -> list[dict[str, Any]]:
|
|
93
|
+
result = self._request("tools/list")
|
|
94
|
+
return result.get("tools", [])
|
|
95
|
+
|
|
96
|
+
def describe_tool(self, name: str) -> dict[str, Any] | None:
|
|
97
|
+
return next((tool for tool in self.list_tools() if tool.get("name") == name), None)
|
|
98
|
+
|
|
99
|
+
def call_tool(self, name: str, args: dict[str, Any] | None = None) -> Any:
|
|
100
|
+
return self._call_tool(name, args or {})
|
|
101
|
+
|
|
102
|
+
@staticmethod
|
|
103
|
+
def _parsed_tool_value(result: dict[str, Any]) -> Any:
|
|
104
|
+
text_block = next(
|
|
105
|
+
(block.get("text") for block in result.get("content", []) if block.get("type") == "text"),
|
|
106
|
+
None,
|
|
107
|
+
)
|
|
108
|
+
parsed: Any = text_block
|
|
109
|
+
if isinstance(text_block, str):
|
|
110
|
+
try:
|
|
111
|
+
parsed = json.loads(text_block)
|
|
112
|
+
except ValueError:
|
|
113
|
+
parsed = text_block
|
|
114
|
+
if "structuredContent" in result:
|
|
115
|
+
parsed = result["structuredContent"]
|
|
116
|
+
return parsed
|
|
117
|
+
|
|
118
|
+
def call_tool_result(self, name: str, args: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
119
|
+
"""Return the complete MCP tool result, preserving image/audio/resource content blocks."""
|
|
120
|
+
result = self._request("tools/call", {"name": name, "arguments": args or {}})
|
|
121
|
+
parsed = self._parsed_tool_value(result)
|
|
122
|
+
if result.get("isError"):
|
|
123
|
+
message = (
|
|
124
|
+
parsed.get("message")
|
|
125
|
+
if isinstance(parsed, dict) and "message" in parsed
|
|
126
|
+
else parsed
|
|
127
|
+
if isinstance(parsed, str)
|
|
128
|
+
else f'Tool "{name}" failed'
|
|
129
|
+
)
|
|
130
|
+
raise McpToolError(str(message), tool_error=parsed)
|
|
131
|
+
return result
|
|
132
|
+
|
|
133
|
+
def _call_tool(self, name: str, arguments: dict[str, Any]) -> Any:
|
|
134
|
+
result = self.call_tool_result(name, arguments)
|
|
135
|
+
parsed = self._parsed_tool_value(result)
|
|
136
|
+
return parsed
|
|
File without changes
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from typing import Any, Literal
|
|
2
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AccessAcceptShareInput(BaseModel):
|
|
6
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
7
|
+
|
|
8
|
+
share_id: str = Field(..., alias="shareId", description="The shareId from note-inbox to accept.")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AccessAcceptShareOutput(BaseModel):
|
|
12
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
13
|
+
|
|
14
|
+
ok: bool = Field(..., alias="ok", description="True on success; false on auth/scope/lookup error.")
|
|
15
|
+
share_id: str | None = Field(None, alias="shareId", description="The accepted share.")
|
|
16
|
+
owner: str | None = Field(None, alias="owner", description="Identity who shared the note.")
|
|
17
|
+
error: str | None = Field(None, alias="error", description="Human-readable failure reason when ok is false.")
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from typing import Any, Literal
|
|
2
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AccessApproveSenderInput(BaseModel):
|
|
6
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
7
|
+
|
|
8
|
+
sender_identity: str = Field(..., alias="senderIdentity", description="Identity (email or user id) to approve as a sender.")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AccessApproveSenderOutput(BaseModel):
|
|
12
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
13
|
+
|
|
14
|
+
ok: bool = Field(..., alias="ok", description="True on success; false on auth error.")
|
|
15
|
+
sender: str | None = Field(None, alias="sender", description="The identity that was approved.")
|
|
16
|
+
error: str | None = Field(None, alias="error", description="Human-readable failure reason when ok is false.")
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from typing import Any, Literal
|
|
2
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AccessDeclineShareInput(BaseModel):
|
|
6
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
7
|
+
|
|
8
|
+
share_id: str = Field(..., alias="shareId", description="The shareId from note-inbox to decline.")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AccessDeclineShareOutput(BaseModel):
|
|
12
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
13
|
+
|
|
14
|
+
ok: bool = Field(..., alias="ok", description="True on success; false on auth/scope/lookup error.")
|
|
15
|
+
share_id: str | None = Field(None, alias="shareId", description="The declined share.")
|
|
16
|
+
error: str | None = Field(None, alias="error", description="Human-readable failure reason when ok is false.")
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from typing import Any, Literal
|
|
2
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AccessInboxSettingsInput(BaseModel):
|
|
6
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
7
|
+
|
|
8
|
+
allow_unapproved_senders: bool = Field(..., alias="allowUnapprovedSenders", description="Set true to accept invites/shares from anyone; false to require approval.")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AccessInboxSettingsOutput(BaseModel):
|
|
12
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
13
|
+
|
|
14
|
+
ok: bool = Field(..., alias="ok", description="True on success; false on auth error.")
|
|
15
|
+
allow_unapproved_senders: bool | None = Field(None, alias="allowUnapprovedSenders", description="The setting now in effect.")
|
|
16
|
+
error: str | None = Field(None, alias="error", description="Human-readable failure reason when ok is false.")
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from typing import Any, Literal
|
|
2
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AccessInviteAccountInput(BaseModel):
|
|
6
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
7
|
+
|
|
8
|
+
grantee_identity: str = Field(..., alias="granteeIdentity", description="Identity (email or user id) to invite into your full account.")
|
|
9
|
+
scope: dict[str, Any] | None = Field(None, alias="scope", description="Permissions to grant across your account. Optional; defaults to read+write (read, write, export, index, swap).")
|
|
10
|
+
revoke: bool | None = Field(None, alias="revoke", description="Set true to revoke an existing account invite for this grantee instead of granting one.")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AccessInviteAccountOutput(BaseModel):
|
|
14
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
15
|
+
|
|
16
|
+
ok: bool = Field(..., alias="ok", description="True on success; false on auth/scope error.")
|
|
17
|
+
grantee: str | None = Field(None, alias="grantee", description="The identity that was invited or revoked.")
|
|
18
|
+
granted: dict[str, Any] | None = Field(None, alias="granted", description="The permissions now in effect for the grantee. Absent on revoke.")
|
|
19
|
+
revoked: bool | None = Field(None, alias="revoked", description="True when an existing invite was removed.")
|
|
20
|
+
note: str | None = Field(None, alias="note", description="Guidance on next steps for the grantee.")
|
|
21
|
+
error: str | None = Field(None, alias="error", description="Human-readable failure reason when ok is false.")
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from typing import Any, Literal
|
|
2
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AccessIssueKeyInput(BaseModel):
|
|
6
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
7
|
+
|
|
8
|
+
grantee_identity: str = Field(..., alias="granteeIdentity", description="Identity that will own the newly issued key (e.g. an email or user id).")
|
|
9
|
+
vaults: list[str] = Field(..., alias="vaults", description="Vaults the new key is entitled to; the caller must already hold each. At least one required.")
|
|
10
|
+
scope: dict[str, Any] | None = Field(None, alias="scope", description="Scope grant (read/write/export/index/admin/swap). Optional; omit for least-privilege read-only.")
|
|
11
|
+
plan: Literal["free", "pro", "team", "enterprise"] | None = Field(None, alias="plan", description="Subscription plan carried by the key. Optional; defaults to free.")
|
|
12
|
+
expires_in_days: int | None = Field(None, alias="expiresInDays", description="Days until the key expires (1-3650). Optional; omit for a non-expiring key.")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class AccessIssueKeyOutput(BaseModel):
|
|
16
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
17
|
+
|
|
18
|
+
ok: bool = Field(..., alias="ok", description="True when the key was issued; false on auth/scope error.")
|
|
19
|
+
key_id: str | None = Field(None, alias="keyId", description="Stable identifier of the issued key (safe to store/log).")
|
|
20
|
+
secret: str | None = Field(None, alias="secret", description="The key secret — RETURNED ONCE and never retrievable again. Capture it immediately.")
|
|
21
|
+
grantee: str | None = Field(None, alias="grantee", description="Identity the key was issued to.")
|
|
22
|
+
vaults: list[str] | None = Field(None, alias="vaults", description="Vaults the issued key is entitled to.")
|
|
23
|
+
scope: dict[str, Any] | None = Field(None, alias="scope", description="Normalized scope actually granted on the key.")
|
|
24
|
+
plan: str | None = Field(None, alias="plan", description="Subscription plan assigned to the key.")
|
|
25
|
+
expires_at: Any | None = Field(None, alias="expiresAt", description="ISO-8601 expiry timestamp, or null when the key does not expire.")
|
|
26
|
+
error: str | None = Field(None, alias="error", description="Human-readable failure reason when ok is false.")
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from typing import Any, Literal
|
|
2
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AccessListApprovedSendersInput(BaseModel):
|
|
6
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AccessListApprovedSendersOutput(BaseModel):
|
|
10
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
11
|
+
|
|
12
|
+
ok: bool = Field(..., alias="ok", description="True on success; false on auth error.")
|
|
13
|
+
approved_senders: list[str] | None = Field(None, alias="approvedSenders", description="Identities approved to reach you.")
|
|
14
|
+
allow_unapproved_senders: bool | None = Field(None, alias="allowUnapprovedSenders", description="True if your inbox is open to anyone regardless of this list.")
|
|
15
|
+
error: str | None = Field(None, alias="error", description="Human-readable failure reason when ok is false.")
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from typing import Any, Literal
|
|
2
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AccessListKeysInput(BaseModel):
|
|
6
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
7
|
+
|
|
8
|
+
vault: str | None = Field(None, alias="vault", description="Filter to keys entitled to this vault. Optional; omit to list across all vaults.")
|
|
9
|
+
plan: str | None = Field(None, alias="plan", description="Filter to keys on this plan (free/pro/team/enterprise). Optional; omit to list all plans.")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AccessListKeysOutput(BaseModel):
|
|
13
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
14
|
+
|
|
15
|
+
ok: bool = Field(..., alias="ok", description="True when the listing succeeded; false on auth/scope error.")
|
|
16
|
+
keys: list[dict[str, Any]] | None = Field(None, alias="keys", description="Key metadata for the caller identity. NEVER includes secrets. Present when ok is true.")
|
|
17
|
+
error: str | None = Field(None, alias="error", description="Human-readable failure reason when ok is false.")
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from typing import Any, Literal
|
|
2
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AccessNoteInboxInput(BaseModel):
|
|
6
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AccessNoteInboxOutput(BaseModel):
|
|
10
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
11
|
+
|
|
12
|
+
ok: bool = Field(..., alias="ok", description="True on success; false on auth error.")
|
|
13
|
+
pending: list[dict[str, Any]] | None = Field(None, alias="pending", description="Pending offers, oldest first. Present when ok is true.")
|
|
14
|
+
error: str | None = Field(None, alias="error", description="Human-readable failure reason when ok is false.")
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from typing import Any, Literal
|
|
2
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AccessRemoveApprovedSenderInput(BaseModel):
|
|
6
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
7
|
+
|
|
8
|
+
sender_identity: str = Field(..., alias="senderIdentity", description="Identity to remove from your approved-senders list.")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AccessRemoveApprovedSenderOutput(BaseModel):
|
|
12
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
13
|
+
|
|
14
|
+
ok: bool = Field(..., alias="ok", description="True on success; false on auth error.")
|
|
15
|
+
sender: str | None = Field(None, alias="sender", description="The identity that was removed.")
|
|
16
|
+
removed: bool | None = Field(None, alias="removed", description="True when an existing approval was found and removed.")
|
|
17
|
+
error: str | None = Field(None, alias="error", description="Human-readable failure reason when ok is false.")
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from typing import Any, Literal
|
|
2
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AccessRevokeKeyInput(BaseModel):
|
|
6
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
7
|
+
|
|
8
|
+
key_id: str = Field(..., alias="keyId", description="Identifier of the key to revoke (from access-list-keys). Must be a key the caller owns or fully covers.")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AccessRevokeKeyOutput(BaseModel):
|
|
12
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
13
|
+
|
|
14
|
+
ok: bool = Field(..., alias="ok", description="True when the revoke operation completed; false on auth/scope error or not-found.")
|
|
15
|
+
key_id: str | None = Field(None, alias="keyId", description="The key that was targeted for revocation.")
|
|
16
|
+
revoked: bool | None = Field(None, alias="revoked", description="True if the key is now revoked.")
|
|
17
|
+
error: str | None = Field(None, alias="error", description="Human-readable failure reason when ok is false (e.g. \"key not found\").")
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from typing import Any, Literal
|
|
2
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AccessRevokeShareInput(BaseModel):
|
|
6
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
7
|
+
|
|
8
|
+
share_id: str = Field(..., alias="shareId", description="The shareId to revoke.")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AccessRevokeShareOutput(BaseModel):
|
|
12
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
13
|
+
|
|
14
|
+
ok: bool = Field(..., alias="ok", description="True on success; false on auth/scope/lookup error.")
|
|
15
|
+
share_id: str | None = Field(None, alias="shareId", description="The revoked share.")
|
|
16
|
+
error: str | None = Field(None, alias="error", description="Human-readable failure reason when ok is false.")
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from typing import Any, Literal
|
|
2
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AccessSetScopeInput(BaseModel):
|
|
6
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
7
|
+
|
|
8
|
+
key_id: str = Field(..., alias="keyId", description="Identifier of the key to modify (from access-list-keys). Must be a key the caller owns.")
|
|
9
|
+
scope: dict[str, Any] | None = Field(None, alias="scope", description="New scope set. Partial; the provided keys are normalized and REPLACE the full existing scope. Optional, but supply scope and/or plan.")
|
|
10
|
+
plan: Literal["free", "pro", "team", "enterprise"] | None = Field(None, alias="plan", description="New subscription plan. Optional, but supply scope and/or plan.")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AccessSetScopeOutput(BaseModel):
|
|
14
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
15
|
+
|
|
16
|
+
ok: bool = Field(..., alias="ok", description="True when the change applied; false on auth/scope error, not-found, or nothing-to-change.")
|
|
17
|
+
key_id: str | None = Field(None, alias="keyId", description="The key that was targeted.")
|
|
18
|
+
updated: bool | None = Field(None, alias="updated", description="True if a row was actually updated.")
|
|
19
|
+
error: str | None = Field(None, alias="error", description="Human-readable failure reason when ok is false.")
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from typing import Any, Literal
|
|
2
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AccessShareNoteInput(BaseModel):
|
|
6
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
7
|
+
|
|
8
|
+
vault: str | None = Field(None, alias="vault", description="Vault containing the note to share. Required (with path) unless shareId is given. Must be a vault you own.")
|
|
9
|
+
path: str | None = Field(None, alias="path", description="Vault-relative path of the note to share. Required (with vault) unless shareId is given.")
|
|
10
|
+
share_id: str | None = Field(None, alias="shareId", description="Instead of vault+path, re-share a note already shared to you by this shareId. Requires reshare permission on that share.")
|
|
11
|
+
grantee_identity: str = Field(..., alias="granteeIdentity", description="Identity to offer the note to.")
|
|
12
|
+
permissions: dict[str, Any] | None = Field(None, alias="permissions", description="Permissions to grant beyond read (always granted): edit (write back to the canonical note), delete (destroy the canonical note — dangerous), reshare (grantee may re-share onward). All default false.")
|
|
13
|
+
bundle_links: Any | None = Field(None, alias="bundleLinks", description="true to also share every detected linked note (same permissions as this share); an array of specific link refs (path or title, from a prior call's linkCandidates) to share only those. Omit or false to share none — default, and the safest choice when unsure.")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class AccessShareNoteOutput(BaseModel):
|
|
17
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
18
|
+
|
|
19
|
+
ok: bool = Field(..., alias="ok", description="True when the offer was created; false on auth/scope/lookup error.")
|
|
20
|
+
share_id: str | None = Field(None, alias="shareId", description="Identifier the grantee will use to accept-share, then address the note on get/put/delete.")
|
|
21
|
+
grantee: str | None = Field(None, alias="grantee", description="The identity the note was offered to.")
|
|
22
|
+
permissions: dict[str, Any] | None = Field(None, alias="permissions", description="The permissions in effect for this share.")
|
|
23
|
+
note: str | None = Field(None, alias="note", description="Guidance: the offer is pending until the grantee calls accept-share.")
|
|
24
|
+
link_candidates: list[dict[str, Any]] | None = Field(None, alias="linkCandidates", description="Notes this one links to (same vault) that were NOT bundled into this share. Relay these to the human and ask before calling share-note again with bundleLinks if they want them included — otherwise they render as [[private note]] to this grantee.")
|
|
25
|
+
bundled: list[dict[str, Any]] | None = Field(None, alias="bundled", description="Linked notes that WERE bundled into this share as their own pending offers (per bundleLinks).")
|
|
26
|
+
error: str | None = Field(None, alias="error", description="Human-readable failure reason when ok is false.")
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from typing import Any, Literal
|
|
2
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AccessShareVaultInput(BaseModel):
|
|
6
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
7
|
+
|
|
8
|
+
vault: str = Field(..., alias="vault", description="Vault to share. The caller must control (be entitled to) this vault and hold write scope.")
|
|
9
|
+
grantee_identity: str = Field(..., alias="granteeIdentity", description="Identity to grant access to (e.g. an email or user id).")
|
|
10
|
+
scope: dict[str, Any] | None = Field(None, alias="scope", description="Entitlement scope to grant (read/write/export/index/admin/swap). Optional; omit for least-privilege read-only.")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AccessShareVaultOutput(BaseModel):
|
|
14
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
15
|
+
|
|
16
|
+
ok: bool = Field(..., alias="ok", description="True when the entitlement was written; false on auth/scope error.")
|
|
17
|
+
vault: str | None = Field(None, alias="vault", description="The vault that was shared.")
|
|
18
|
+
grantee: str | None = Field(None, alias="grantee", description="The identity that was granted access.")
|
|
19
|
+
note: str | None = Field(None, alias="note", description="Guidance on next steps (e.g. the grantee still needs a key tied to this vault).")
|
|
20
|
+
error: str | None = Field(None, alias="error", description="Human-readable failure reason when ok is false.")
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from typing import Any, Literal
|
|
2
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AccessSwapVaultInput(BaseModel):
|
|
6
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
7
|
+
|
|
8
|
+
vault: str = Field(..., alias="vault", description="Vault to make active for the session. Must be an entitled vault and the key must hold \"swap\" scope.")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AccessSwapVaultOutput(BaseModel):
|
|
12
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
13
|
+
|
|
14
|
+
ok: bool = Field(..., alias="ok", description="True when the active vault was set; false on auth/scope error.")
|
|
15
|
+
active_vault: str | None = Field(None, alias="activeVault", description="The vault now active for the session.")
|
|
16
|
+
session: str | None = Field(None, alias="session", description="The session the active vault was set for.")
|
|
17
|
+
error: str | None = Field(None, alias="error", description="Human-readable failure reason when ok is false.")
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from typing import Any, Literal
|
|
2
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AccessSwitchAccountInput(BaseModel):
|
|
6
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
7
|
+
|
|
8
|
+
owner: str | None = Field(None, alias="owner", description="Identity whose account to make active. Must be your own identity (switch back) or one that has invited you. Omit to just list available accounts.")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AccessSwitchAccountOutput(BaseModel):
|
|
12
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
13
|
+
|
|
14
|
+
ok: bool = Field(..., alias="ok", description="True on success; false on auth/scope error.")
|
|
15
|
+
active_owner: str | None = Field(None, alias="activeOwner", description="The account now active for your identity (your own identity means your own account).")
|
|
16
|
+
is_own_account: bool | None = Field(None, alias="isOwnAccount", description="True when the active account is your own.")
|
|
17
|
+
available: list[str] | None = Field(None, alias="available", description="Identities whose accounts you can switch into (you have been invited).")
|
|
18
|
+
error: str | None = Field(None, alias="error", description="Human-readable failure reason when ok is false.")
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from typing import Any, Literal
|
|
2
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AccessUnlinkShareInput(BaseModel):
|
|
6
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
7
|
+
|
|
8
|
+
share_id: str = Field(..., alias="shareId", description="The shareId to unlink from your \"Shared with me\" notes.")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AccessUnlinkShareOutput(BaseModel):
|
|
12
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
13
|
+
|
|
14
|
+
ok: bool = Field(..., alias="ok", description="True on success; false on auth/scope/lookup error.")
|
|
15
|
+
share_id: str | None = Field(None, alias="shareId", description="The unlinked share.")
|
|
16
|
+
error: str | None = Field(None, alias="error", description="Human-readable failure reason when ok is false.")
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from typing import Any, Literal
|
|
2
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AddVaultInput(BaseModel):
|
|
6
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
7
|
+
|
|
8
|
+
vault: str = Field(..., alias="vault", description="Name of the vault to create. Must match ^[A-Za-z0-9 _-]{1,48}$ (letters, digits, space, _ or -, 1-48 chars).")
|
|
9
|
+
owner: str | None = Field(None, alias="owner", description="Identity that should OWN the new vault (becomes the owner entitlement, so list-vaults reports role \"owner\" for them). Optional; defaults to the caller. Used when an admin bootstraps a personal vault on a user's behalf so the user owns it rather than receiving it as a share.")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AddVaultOutput(BaseModel):
|
|
13
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
14
|
+
|
|
15
|
+
ok: bool = Field(..., alias="ok", description="True when the request succeeded (whether or not a new vault was created); false on auth/scope/validation error.")
|
|
16
|
+
vault: str | None = Field(None, alias="vault", description="The vault name. Present when ok is true.")
|
|
17
|
+
created: bool | None = Field(None, alias="created", description="True if a new vault was created; false if it already existed (idempotent no-op). Present when ok is true.")
|
|
18
|
+
error: str | None = Field(None, alias="error", description="Human-readable failure reason when ok is false.")
|