@macaw-ai/client 0.0.0-stage → 0.9.10

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.
Files changed (142) hide show
  1. package/LICENSE.md +339 -0
  2. package/bin/install.js +278 -0
  3. package/package.json +37 -4
  4. package/payload/README.md +56 -0
  5. package/payload/secureAI/LICENSE +190 -0
  6. package/payload/secureAI/NOTICE +5 -0
  7. package/payload/secureAI/demos/policy-controls/1_uncontrolled.py +139 -0
  8. package/payload/secureAI/demos/policy-controls/2_with_macaw.py +139 -0
  9. package/payload/secureAI/demos/policy-controls/3_with_user_policies.py +162 -0
  10. package/payload/secureAI/demos/policy-controls/credentials.txt +12 -0
  11. package/payload/secureAI/demos/policy-controls/malicious_report.txt +21 -0
  12. package/payload/secureAI/demos/policy-controls/sales_report.txt +20 -0
  13. package/payload/secureAI/demos/tutorial-1-rbac/README.md +143 -0
  14. package/payload/secureAI/demos/tutorial-1-rbac/app.py +147 -0
  15. package/payload/secureAI/demos/tutorial-1-rbac/authprompts_demo.py +306 -0
  16. package/payload/secureAI/demos/tutorial-1-rbac/config/claims-config.yaml +152 -0
  17. package/payload/secureAI/demos/tutorial-1-rbac/demo_secureopenai_with_policies.py +150 -0
  18. package/payload/secureAI/demos/tutorial-1-rbac/policies/bu_Analytics.json +8 -0
  19. package/payload/secureAI/demos/tutorial-1-rbac/policies/company_FinTech_Corp.json +70 -0
  20. package/payload/secureAI/demos/tutorial-1-rbac/policies/llm-base.json +69 -0
  21. package/payload/secureAI/demos/tutorial-1-rbac/policies/team_Reporting.json +8 -0
  22. package/payload/secureAI/demos/tutorial-1-rbac/policies/user_alice.json +32 -0
  23. package/payload/secureAI/demos/tutorial-1-rbac/policies/user_bob.json +28 -0
  24. package/payload/secureAI/demos/tutorial-1-rbac/policies/user_carol.json +34 -0
  25. package/payload/secureAI/demos/tutorial-1-rbac/requirements.txt +6 -0
  26. package/payload/secureAI/demos/tutorial-1-rbac/setup/auth0_complete_setup.sh +392 -0
  27. package/payload/secureAI/demos/tutorial-1-rbac/setup/keycloak_complete_setup.sh +320 -0
  28. package/payload/secureAI/demos/tutorial-2-intent/Policies/alation-remote-proxy.json +155 -0
  29. package/payload/secureAI/demos/tutorial-2-intent/Policies/bu.json +22 -0
  30. package/payload/secureAI/demos/tutorial-2-intent/Policies/company.json +17 -0
  31. package/payload/secureAI/demos/tutorial-2-intent/Policies/user_alice.json +48 -0
  32. package/payload/secureAI/demos/tutorial-2-intent/Policies/user_bob.json +83 -0
  33. package/payload/secureAI/demos/tutorial-2-intent/README.md +213 -0
  34. package/payload/secureAI/demos/tutorial-2-intent/script.py +188 -0
  35. package/payload/secureAI/demos/tutorial-2-intent/setup/alation_verifier.py +177 -0
  36. package/payload/secureAI/demos/tutorial-2-intent/setup/get_alation_user_token.py +180 -0
  37. package/payload/secureAI/examples/README.md +244 -0
  38. package/payload/secureAI/examples/anthropic/anthropic_1a_dropin_simple.py +103 -0
  39. package/payload/secureAI/examples/anthropic/anthropic_1b_multiuser_bind.py +190 -0
  40. package/payload/secureAI/examples/anthropic/anthropic_1b_multiuser_bind_streaming.py +190 -0
  41. package/payload/secureAI/examples/anthropic/anthropic_1c_a2a_invoke.py +156 -0
  42. package/payload/secureAI/examples/attestations/1a_trade_alice.py +215 -0
  43. package/payload/secureAI/examples/attestations/1a_trade_bob.py +164 -0
  44. package/payload/secureAI/examples/attestations/1b_grant_admin.py +170 -0
  45. package/payload/secureAI/examples/attestations/1b_grant_researcher.py +231 -0
  46. package/payload/secureAI/examples/attestations/README.md +128 -0
  47. package/payload/secureAI/examples/langchain/langchain_1a_dropin_simple.py +199 -0
  48. package/payload/secureAI/examples/langchain/langchain_1b_multiuser.py +262 -0
  49. package/payload/secureAI/examples/langchain/langchain_1c_orchestration.py +332 -0
  50. package/payload/secureAI/examples/langchain/langchain_1d_llm_openai.py +130 -0
  51. package/payload/secureAI/examples/langchain/langchain_1e_llm_anthropic.py +130 -0
  52. package/payload/secureAI/examples/langchain/langchain_1f_memory.py +214 -0
  53. package/payload/secureAI/examples/litellm/litellm_1a_dropin_simple.py +131 -0
  54. package/payload/secureAI/examples/mcp/1a_simple_invocation.py +115 -0
  55. package/payload/secureAI/examples/mcp/1b_discovery_and_resources.py +142 -0
  56. package/payload/secureAI/examples/mcp/1c_logging_client.py +100 -0
  57. package/payload/secureAI/examples/mcp/1d_progress_client.py +100 -0
  58. package/payload/secureAI/examples/mcp/1e_sampling_client.py +150 -0
  59. package/payload/secureAI/examples/mcp/1e_sampling_server.py +90 -0
  60. package/payload/secureAI/examples/mcp/1f_elicitation_client.py +127 -0
  61. package/payload/secureAI/examples/mcp/1f_elicitation_server.py +73 -0
  62. package/payload/secureAI/examples/mcp/1g_roots_client.py +122 -0
  63. package/payload/secureAI/examples/mcp/1g_roots_server.py +85 -0
  64. package/payload/secureAI/examples/mcp/2a_proxy_snowflake.py +212 -0
  65. package/payload/secureAI/examples/mcp/2b_proxy_databricks.py +299 -0
  66. package/payload/secureAI/examples/mcp/2c_proxy_stdio_fetch.py +91 -0
  67. package/payload/secureAI/examples/mcp/2d_proxy_stdio_salesforce.py +119 -0
  68. package/payload/secureAI/examples/mcp/2e_proxy_multiuser.py +136 -0
  69. package/payload/secureAI/examples/mcp/2f_proxy_stdio_databricks.py +144 -0
  70. package/payload/secureAI/examples/mcp/3a_native_mcp_client.py +104 -0
  71. package/payload/secureAI/examples/mcp/3b_native_mcp_proxy.py +114 -0
  72. package/payload/secureAI/examples/mcp/3c_native_mcp_sampling.py +180 -0
  73. package/payload/secureAI/examples/mcp/3d_native_mcp_2026.py +135 -0
  74. package/payload/secureAI/examples/mcp/securemcp_calculator.py +248 -0
  75. package/payload/secureAI/examples/mcp/securemcp_server.py +75 -0
  76. package/payload/secureAI/examples/openai/openai_1a_dropin_simple.py +102 -0
  77. package/payload/secureAI/examples/openai/openai_1b_multiuser_bind.py +193 -0
  78. package/payload/secureAI/examples/openai/openai_1b_multiuser_bind_streaming.py +199 -0
  79. package/payload/secureAI/examples/openai/openai_1c_a2a_invoke.py +156 -0
  80. package/payload/secureAI/examples/openai/openai_1d_invocation_patterns.py +337 -0
  81. package/payload/secureAI/examples/phishing-resistance/1a_login_alice.py +180 -0
  82. package/payload/secureAI/examples/phishing-resistance/1b_trade_alice.py +241 -0
  83. package/payload/secureAI/examples/phishing-resistance/1b_trade_bob.py +164 -0
  84. package/payload/secureAI/examples/phishing-resistance/README.md +124 -0
  85. package/payload/secureAI/examples/phishing-resistance/get_token.py +114 -0
  86. package/payload/secureAI/examples/pydantic_ai/README.md +88 -0
  87. package/payload/secureAI/examples/pydantic_ai/policies/app_pydantic-agent.json +10 -0
  88. package/payload/secureAI/examples/pydantic_ai/pydanticai_1a_dropin_simple.py +90 -0
  89. package/payload/secureAI/examples/pydantic_ai/pydanticai_1b_model_routing.py +85 -0
  90. package/payload/secureAI/examples/pydantic_ai/pydanticai_1c_native_tools.py +83 -0
  91. package/payload/secureAI/examples/pydantic_ai/pydanticai_1d_multiuser_bind.py +104 -0
  92. package/payload/secureAI/examples/pydantic_ai/pydanticai_1e_mcp_compose.py +92 -0
  93. package/payload/secureAI/macaw_adapters/__init__.py +55 -0
  94. package/payload/secureAI/macaw_adapters/anthropic/REFERENCE.md +374 -0
  95. package/payload/secureAI/macaw_adapters/anthropic/__init__.py +22 -0
  96. package/payload/secureAI/macaw_adapters/anthropic/secure_anthropic.py +792 -0
  97. package/payload/secureAI/macaw_adapters/anthropic_ext_tools/__init__.py +25 -0
  98. package/payload/secureAI/macaw_adapters/anthropic_ext_tools/secure_anthropic.py +840 -0
  99. package/payload/secureAI/macaw_adapters/langchain/REFERENCE.md +234 -0
  100. package/payload/secureAI/macaw_adapters/langchain/__init__.py +100 -0
  101. package/payload/secureAI/macaw_adapters/langchain/_utils.py +83 -0
  102. package/payload/secureAI/macaw_adapters/langchain/agents.py +296 -0
  103. package/payload/secureAI/macaw_adapters/langchain/anthropic.py +456 -0
  104. package/payload/secureAI/macaw_adapters/langchain/callbacks.py +306 -0
  105. package/payload/secureAI/macaw_adapters/langchain/memory.py +352 -0
  106. package/payload/secureAI/macaw_adapters/langchain/openai.py +410 -0
  107. package/payload/secureAI/macaw_adapters/langchain/tools.py +174 -0
  108. package/payload/secureAI/macaw_adapters/litellm/README.md +216 -0
  109. package/payload/secureAI/macaw_adapters/litellm/__init__.py +143 -0
  110. package/payload/secureAI/macaw_adapters/litellm/secure_litellm.py +686 -0
  111. package/payload/secureAI/macaw_adapters/mcp/REFERENCE.md +460 -0
  112. package/payload/secureAI/macaw_adapters/mcp/__init__.py +65 -0
  113. package/payload/secureAI/macaw_adapters/mcp/_endpoint.py +193 -0
  114. package/payload/secureAI/macaw_adapters/mcp/_endpoint2.py +225 -0
  115. package/payload/secureAI/macaw_adapters/mcp/_serve.py +25 -0
  116. package/payload/secureAI/macaw_adapters/mcp/client.py +721 -0
  117. package/payload/secureAI/macaw_adapters/mcp/decorators.py +228 -0
  118. package/payload/secureAI/macaw_adapters/mcp/fastmcp_compat.py +353 -0
  119. package/payload/secureAI/macaw_adapters/mcp/mcp.py +785 -0
  120. package/payload/secureAI/macaw_adapters/mcp/proxy.py +626 -0
  121. package/payload/secureAI/macaw_adapters/mcp/server.py +317 -0
  122. package/payload/secureAI/macaw_adapters/mcp/subscriptions.py +450 -0
  123. package/payload/secureAI/macaw_adapters/openai/REFERENCE.md +368 -0
  124. package/payload/secureAI/macaw_adapters/openai/__init__.py +22 -0
  125. package/payload/secureAI/macaw_adapters/openai/secure_openai.py +833 -0
  126. package/payload/secureAI/macaw_adapters/openai_ext_tools/REFERENCE.md +368 -0
  127. package/payload/secureAI/macaw_adapters/openai_ext_tools/__init__.py +25 -0
  128. package/payload/secureAI/macaw_adapters/openai_ext_tools/secure_openai.py +876 -0
  129. package/payload/secureAI/macaw_adapters/pydantic_ai/__init__.py +36 -0
  130. package/payload/secureAI/macaw_adapters/pydantic_ai/_core.py +257 -0
  131. package/payload/secureAI/macaw_adapters/pydantic_ai/agent.py +218 -0
  132. package/payload/secureAI/macaw_adapters/pydantic_ai/model.py +99 -0
  133. package/payload/secureAI/macaw_adapters/pydantic_ai/toolset.py +86 -0
  134. package/payload/secureAI/test_harness_quick.py +296 -0
  135. package/wheels/macaw_adapters-0.9.10.1-py3-none-any.whl +0 -0
  136. package/wheels/macaw_client-0.9.10.1-cp312-cp312-macosx_11_0_arm64.whl +0 -0
  137. package/wheels/macaw_client-0.9.10.1-cp312-cp312-manylinux_2_17_x86_64.whl +0 -0
  138. package/wheels/macaw_client-0.9.10.1-cp314-cp314-macosx_11_0_arm64.whl +0 -0
  139. package/wheels/macaw_client-0.9.10.1-cp314-cp314-manylinux_2_17_x86_64.whl +0 -0
  140. package/wheels/macaw_client-0.9.10.1-cp314-cp314-win_amd64.whl +0 -0
  141. package/wheels/macaw_client-0.9.10.1-cp39-cp39-macosx_11_0_arm64.whl +0 -0
  142. package/README.md +0 -3
@@ -0,0 +1,317 @@
1
+ """
2
+ SecureMCP Server: Integrated with MACAW Local Agent
3
+
4
+ This provides a developer-friendly MCP API while leveraging MACAW Local Agent's
5
+ security infrastructure. All security is delegated to MACAWClient.
6
+
7
+ Simplified Architecture:
8
+ - SecureMCP provides MCP-style decorators (@tool, @resource, @prompt)
9
+ - All security handled by MACAWClient -> LocalAgent -> ToolAgent
10
+ - No duplicate permission checks - trust the MACAW protocol
11
+ """
12
+
13
+ import asyncio
14
+ import logging
15
+ import time
16
+ from typing import Optional, Dict, Any, Callable, List
17
+ from functools import wraps
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+
22
+ class Server:
23
+ """
24
+ SecureMCP Server with MACAW Local Agent integration.
25
+
26
+ - Requires MACAW Local Agent running
27
+ - All security via Unix socket to Local Agent
28
+ - No direct MACAW SDK imports
29
+ """
30
+
31
+ def __init__(
32
+ self,
33
+ name: str,
34
+ version: str = "1.0.0",
35
+ port: int = 8080,
36
+ host: str = "localhost",
37
+ **kwargs
38
+ ):
39
+ """
40
+ Initialize SecureMCP server.
41
+
42
+ Args:
43
+ name: Server name
44
+ version: Server version
45
+ port: Port to listen on
46
+ host: Host to bind to
47
+ **kwargs: Additional configuration
48
+ """
49
+ self.name = name
50
+ self.version = version
51
+ self.port = port
52
+ self.host = host
53
+ self.config = kwargs
54
+
55
+ # Registries for MCP components
56
+ self.tools = {}
57
+ self.resources = {}
58
+ self.prompts = {}
59
+
60
+ # MACAW client (initialized in start() after tools are registered)
61
+ self.macaw_client = None
62
+ self.server_id = None
63
+
64
+ def _init_with_macaw(self):
65
+ """Initialize with MACAW Local Agent using agent-per-app model."""
66
+ try:
67
+ from macaw_client import MACAWClient
68
+
69
+ # Create this SecureMCP server's own agent with unique identity
70
+ # Following the agent-per-app model - each service is an autonomous agent
71
+ server_app_name = f"securemcp-{self.name}"
72
+
73
+ # Collect unified tools config (handler + metadata together)
74
+ tools_config = {}
75
+ tool_names = []
76
+
77
+ for tool_name, tool_info in self.tools.items():
78
+ tool_names.append(tool_name) # Collect tool names for intent_policy
79
+
80
+ # Create handler wrapper for this tool
81
+ func = tool_info['function']
82
+ def create_handler(tool_func):
83
+ def handler(params):
84
+ try:
85
+ if asyncio.iscoroutinefunction(tool_func):
86
+ # Return coroutine for async functions - MACAWClient will await it
87
+ return tool_func(**params)
88
+ else:
89
+ return tool_func(**params)
90
+ except Exception as e:
91
+ logger.error(f"Tool execution error in {tool_func.__name__}: {e}")
92
+ raise
93
+ return handler
94
+
95
+ # Unified format: handler + metadata together
96
+ tools_config[tool_name] = {
97
+ 'handler': create_handler(func),
98
+ 'description': tool_info.get('description', ''),
99
+ 'metadata': tool_info.get('metadata', {})
100
+ }
101
+
102
+ # Define the intent policy with the actual tools this server provides
103
+ intent_policy = {
104
+ "provided_capabilities": [
105
+ {
106
+ "type": "tools",
107
+ "tools": tool_names, # Populated with actual tool names
108
+ "description": f"Tools provided by SecureMCP server {self.name}"
109
+ }
110
+ ],
111
+ "required_resources": [],
112
+ "data_access": ["none"],
113
+ "description": f"SecureMCP server: {self.name}"
114
+ }
115
+
116
+ # Create MACAWClient with unified tools config
117
+ self.macaw_client = MACAWClient(
118
+ app_name=server_app_name,
119
+ app_version=self.version,
120
+ intent_policy=intent_policy,
121
+ tools=tools_config, # Unified: {name: {handler, description, ...}}
122
+ )
123
+
124
+ # Register this server's agent with the Local Agent
125
+ success = self.macaw_client.register()
126
+
127
+ if success:
128
+ self.server_id = self.macaw_client.agent_id
129
+ logger.info(f"✅ SecureMCP server registered as agent: {self.server_id}")
130
+ logger.info("All security handled by MACAWClient -> LocalAgent -> ToolAgent")
131
+ else:
132
+ raise RuntimeError("Failed to register SecureMCP server agent with MACAW Local Agent")
133
+
134
+ except ImportError as e:
135
+ logger.error(f"MACAW Local Agent client not available: {e}")
136
+ raise RuntimeError("MACAW Local Agent required. Ensure macaw_client is installed.")
137
+ except ConnectionError as e:
138
+ logger.error(f"Cannot connect to MACAW Local Agent: {e}")
139
+ raise RuntimeError("MACAW Local Agent service not running. Start with: sudo systemctl start macaw-local")
140
+ except Exception as e:
141
+ logger.error(f"Error initializing with MACAW: {e}")
142
+ raise
143
+
144
+ # ============================================
145
+ # Tool Registration and Execution
146
+ # ============================================
147
+
148
+ def tool(self, name: str = None, description: str = "", **kwargs):
149
+ """
150
+ Decorator to register a tool.
151
+
152
+ Security is handled by MACAWClient -> LocalAgent -> ToolAgent.
153
+ No duplicate permission checks here - trust the MACAW protocol.
154
+
155
+ Args:
156
+ name: Tool name (uses function name if not provided)
157
+ description: Tool description
158
+ **kwargs: Additional metadata
159
+ """
160
+ def decorator(func):
161
+ tool_name = name or func.__name__
162
+
163
+ # Store the tool - MACAWClient will handle security when invoked
164
+ self.tools[tool_name] = {
165
+ 'function': func,
166
+ 'description': description or func.__doc__ or "",
167
+ 'metadata': kwargs
168
+ }
169
+
170
+ # Return original function - all security via MACAW protocol
171
+ # When invoked via LocalAgent, ToolAgent.verify_and_execute() handles:
172
+ # - Signature verification
173
+ # - Policy enforcement
174
+ # - Audit logging
175
+ return func
176
+ return decorator
177
+
178
+ # ============================================
179
+ # Resource Registration
180
+ # ============================================
181
+
182
+ def resource(self, pattern: str, description: str = "", **kwargs):
183
+ """
184
+ Decorator to register a resource (read-only tool semantics).
185
+
186
+ Resources are treated as read-only tools. Security is handled by
187
+ MACAWClient -> LocalAgent -> ToolAgent with read-only policy.
188
+
189
+ Args:
190
+ pattern: Resource URI pattern (e.g., "config/{name}")
191
+ description: Resource description
192
+ **kwargs: Additional metadata
193
+ """
194
+ def decorator(cls):
195
+ # Store the resource class - treated as read-only tool
196
+ self.resources[pattern] = {
197
+ 'class': cls,
198
+ 'description': description or cls.__doc__ or "",
199
+ 'metadata': kwargs
200
+ }
201
+
202
+ # Return original class - all security via MACAW protocol
203
+ return cls
204
+ return decorator
205
+
206
+ # ============================================
207
+ # Prompt Registration
208
+ # ============================================
209
+
210
+ def prompt(self, name: str = None, description: str = "", **kwargs):
211
+ """
212
+ Decorator to register a prompt template.
213
+
214
+ Prompts are starting points for AuthenticatedPrompt creation.
215
+ Use MACAWClient.create_authenticated_prompt() to create signed,
216
+ policy-bound prompts for LLM invocation.
217
+
218
+ Args:
219
+ name: Prompt name (uses function name if not provided)
220
+ description: Prompt description
221
+ **kwargs: Additional metadata
222
+ """
223
+ def decorator(func):
224
+ prompt_name = name or func.__name__
225
+
226
+ # Store the prompt template
227
+ self.prompts[prompt_name] = {
228
+ 'function': func,
229
+ 'description': description or func.__doc__ or "",
230
+ 'metadata': kwargs
231
+ }
232
+
233
+ # Return original function - prompt templates are just starting points
234
+ # Security comes from AuthenticatedPrompt when actually used
235
+ return func
236
+ return decorator
237
+
238
+ # ============================================
239
+ # Server Lifecycle
240
+ # ============================================
241
+
242
+ async def start(self):
243
+ """Start the SecureMCP server"""
244
+ logger.info(f"Starting SecureMCP server '{self.name}' on {self.host}:{self.port}")
245
+
246
+ # Initialize MACAW now that all tools are registered
247
+ # MACAWClient handles connection - raises clear error if LocalAgent unavailable
248
+ self._init_with_macaw()
249
+
250
+ logger.info(f"Server '{self.name}' is ready")
251
+ logger.info(f" Tools: {list(self.tools.keys())}")
252
+ logger.info(f" Resources: {list(self.resources.keys())}")
253
+ logger.info(f" Prompts: {list(self.prompts.keys())}")
254
+
255
+ # Keep running
256
+ try:
257
+ while True:
258
+ await asyncio.sleep(1)
259
+ except KeyboardInterrupt:
260
+ await self.stop()
261
+
262
+ async def stop(self):
263
+ """Stop the SecureMCP server"""
264
+ logger.info(f"Stopping SecureMCP server '{self.name}'")
265
+
266
+ # Unregister from Local Agent
267
+ if self.macaw_client:
268
+ try:
269
+ self.macaw_client.unregister()
270
+ logger.info(f"✅ Unregistered agent {self.server_id} from Local Agent")
271
+ except Exception as e:
272
+ logger.error(f"Error unregistering from Local Agent: {e}")
273
+
274
+ logger.info(f"Server '{self.name}' stopped")
275
+
276
+ def run(self):
277
+ """Run the server (blocking)"""
278
+ asyncio.run(self.start())
279
+
280
+ # ============================================
281
+ # Helper Methods
282
+ # ============================================
283
+
284
+ def _extract_parameters(self, func: Callable) -> Dict[str, Any]:
285
+ """Extract parameter information from function signature"""
286
+ import inspect
287
+
288
+ sig = inspect.signature(func)
289
+ params = {}
290
+
291
+ for param_name, param in sig.parameters.items():
292
+ if param_name == "self":
293
+ continue
294
+
295
+ param_info = {
296
+ "type": "string", # Default type
297
+ "required": param.default == inspect.Parameter.empty
298
+ }
299
+
300
+ # Try to extract type from annotation
301
+ if param.annotation != inspect.Parameter.empty:
302
+ if param.annotation == str:
303
+ param_info["type"] = "string"
304
+ elif param.annotation == int:
305
+ param_info["type"] = "integer"
306
+ elif param.annotation == float:
307
+ param_info["type"] = "number"
308
+ elif param.annotation == bool:
309
+ param_info["type"] = "boolean"
310
+ elif param.annotation == dict:
311
+ param_info["type"] = "object"
312
+ elif param.annotation == list:
313
+ param_info["type"] = "array"
314
+
315
+ params[param_name] = param_info
316
+
317
+ return params