@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,460 @@
1
+ # SecureMCP Reference
2
+
3
+ SecureMCP provides enterprise-grade security for Model Context Protocol through integration with MACAW Control Plane.
4
+
5
+ **Two main components:**
6
+ 1. **SecureMCP** — For MCP servers YOU write (FastMCP-compatible decorators)
7
+ 2. **SecureMCPProxy** — For external MCP servers you DON'T control (inline gateway)
8
+
9
+ ---
10
+
11
+ ## SecureMCP (Your MCP Servers)
12
+
13
+ FastMCP-compatible decorator API with MACAW security. All tool invocations are cryptographically signed, policy-enforced, and audit-logged.
14
+
15
+ ```python
16
+ from macaw_adapters.mcp import SecureMCP, Context
17
+
18
+ mcp = SecureMCP("calculator")
19
+
20
+ @mcp.tool(description="Add two numbers")
21
+ def add(a: float, b: float) -> float:
22
+ return a + b
23
+
24
+ if __name__ == "__main__":
25
+ mcp.run()
26
+ ```
27
+
28
+ ### Constructor
29
+
30
+ ```python
31
+ SecureMCP(
32
+ name: str, # Server name (required)
33
+ version: str = "1.0.0", # Server version
34
+ intent_policy: dict = None, # MAPL policy declaration
35
+ roots: list[str] = None, # Filesystem paths server can access
36
+ **kwargs # Additional MACAWClient options
37
+ )
38
+ ```
39
+
40
+ | Parameter | Type | Default | Description |
41
+ |-----------|------|---------|-------------|
42
+ | `name` | str | required | Server name for MACAW registration |
43
+ | `version` | str | `"1.0.0"` | Server version |
44
+ | `intent_policy` | dict | `None` | MAPL policy (resources, denied_resources, etc.) |
45
+ | `roots` | list | `None` | Filesystem paths this server can access (MCP roots) |
46
+
47
+ ### Decorators
48
+
49
+ #### `@mcp.tool(name, description, prompts)`
50
+
51
+ Register a tool that can be invoked by clients.
52
+
53
+ ```python
54
+ @mcp.tool(description="Add two numbers")
55
+ def add(a: float, b: float) -> float:
56
+ return a + b
57
+
58
+ @mcp.tool(description="Calculate with history")
59
+ def calculate(ctx: Context, op: str, a: float, b: float) -> dict:
60
+ # ctx parameter gives access to context vault
61
+ history = ctx.get("calc_history") or []
62
+ result = a + b if op == "add" else a * b
63
+ history.append({"op": op, "result": result})
64
+ ctx.set("calc_history", history)
65
+ return {"result": result}
66
+ ```
67
+
68
+ | Parameter | Type | Description |
69
+ |-----------|------|-------------|
70
+ | `name` | str | Tool name (defaults to function name) |
71
+ | `description` | str | Tool description (defaults to docstring) |
72
+ | `prompts` | list | Parameter names to treat as AuthenticatedPrompts |
73
+
74
+ #### `@mcp.resource(uri_pattern, description)`
75
+
76
+ Register a read-only resource.
77
+
78
+ ```python
79
+ @mcp.resource("calc://history")
80
+ def get_history(ctx: Context) -> dict:
81
+ return {"history": ctx.get("calc_history") or []}
82
+
83
+ @mcp.resource("config://{key}")
84
+ def get_config(ctx: Context, key: str) -> dict:
85
+ return {"key": key, "value": "..."}
86
+ ```
87
+
88
+ #### `@mcp.prompt(name, description)`
89
+
90
+ Register a prompt template.
91
+
92
+ ```python
93
+ @mcp.prompt(description="Generate a greeting")
94
+ def greeting(name: str) -> str:
95
+ return f"Hello, {name}! How can I help?"
96
+ ```
97
+
98
+ ### Lifecycle
99
+
100
+ ```python
101
+ mcp.run(transport="stdio") # Blocking run (stdio or sse)
102
+ ```
103
+
104
+ ### Properties
105
+
106
+ | Property | Type | Description |
107
+ |----------|------|-------------|
108
+ | `mcp.name` | str | Server name |
109
+ | `mcp.version` | str | Server version |
110
+ | `mcp.agent_id` | str | MACAW agent ID (after run) |
111
+ | `mcp.roots` | list | Filesystem roots |
112
+
113
+ ---
114
+
115
+ ## Context
116
+
117
+ Request context passed to tool handlers. Provides access to context vault, progress reporting, sampling, and elicitation.
118
+
119
+ ```python
120
+ @mcp.tool()
121
+ def my_tool(ctx: Context, param: str) -> dict:
122
+ # Context vault (persistent storage)
123
+ ctx.set("key", "value")
124
+ data = ctx.get("key")
125
+
126
+ # Logging
127
+ ctx.info("Processing request")
128
+ ctx.audit("data_access", target="records", outcome="success")
129
+
130
+ return {"result": data}
131
+ ```
132
+
133
+ ### Methods
134
+
135
+ | Method | Description |
136
+ |--------|-------------|
137
+ | `ctx.get(key)` | Get value from context vault |
138
+ | `ctx.set(key, value)` | Set value in context vault |
139
+ | `await ctx.report_progress(progress, message)` | Report progress (0.0-1.0) |
140
+ | `await ctx.read_resource(uri)` | Read another resource |
141
+ | `await ctx.sample(prompt, ...)` | Request LLM completion from client |
142
+ | `await ctx.elicit(prompt, ...)` | Request user input from client |
143
+
144
+ ### Logging Methods
145
+
146
+ | Method | Description |
147
+ |--------|-------------|
148
+ | `ctx.debug(message)` | Log debug message |
149
+ | `ctx.info(message)` | Log info message |
150
+ | `ctx.warning(message)` | Log warning message |
151
+ | `ctx.error(message)` | Log error message |
152
+ | `ctx.audit(action, target, outcome, **metadata)` | Cryptographically signed audit entry |
153
+
154
+ ### Sampling (MCP Sampling)
155
+
156
+ Request LLM completion from the calling client:
157
+
158
+ ```python
159
+ @mcp.tool()
160
+ async def analyze(ctx: Context, text: str) -> dict:
161
+ summary = await ctx.sample(
162
+ prompt=f"Summarize: {text}",
163
+ system_prompt="You are a helpful assistant.",
164
+ max_tokens=500
165
+ )
166
+ return {"summary": summary}
167
+ ```
168
+
169
+ **Note on `temperature`:** it is unset by default and is not sent unless you pass
170
+ one. The server does not know which model the client will use, and current Claude
171
+ models reject sampling parameters. Pass a temperature only if you know the client's
172
+ model accepts it — and expect the client may ignore it regardless (MCP treats
173
+ sampling parameters as hints).
174
+
175
+ ### Elicitation (MCP Elicitation)
176
+
177
+ Request user input during tool execution:
178
+
179
+ ```python
180
+ @mcp.tool()
181
+ async def delete_file(ctx: Context, path: str) -> dict:
182
+ confirmed = await ctx.elicit(
183
+ prompt=f"Delete {path}?",
184
+ input_type="confirm",
185
+ default="no"
186
+ )
187
+ if confirmed:
188
+ # perform deletion
189
+ return {"deleted": path}
190
+ return {"cancelled": True}
191
+ ```
192
+
193
+ ---
194
+
195
+ ## SecureMCPProxy (External MCP Servers)
196
+
197
+ Inline gateway that wraps external MCP servers (Snowflake, Salesforce, Databricks, etc.) with MACAW security.
198
+
199
+ ```python
200
+ from macaw_adapters.mcp import SecureMCPProxy
201
+
202
+ # HTTP transport (remote MCP servers)
203
+ proxy = SecureMCPProxy(
204
+ app_name="snowflake-mcp",
205
+ upstream_url="http://localhost:9000/mcp"
206
+ )
207
+
208
+ # stdio transport (local MCP servers via subprocess)
209
+ proxy = SecureMCPProxy(
210
+ app_name="salesforce-dx",
211
+ command=["npx", "@salesforce/mcp", "--orgs", "DEFAULT"],
212
+ env={"HOME": os.environ["HOME"]}
213
+ )
214
+
215
+ # Use tools
216
+ tools = proxy.list_tools()
217
+ result = proxy.call_tool("run_snowflake_query", {"statement": "SELECT 1"})
218
+ ```
219
+
220
+ ### Constructor
221
+
222
+ ```python
223
+ SecureMCPProxy(
224
+ app_name: str, # Application name (required)
225
+ # HTTP transport
226
+ upstream_url: str = None, # URL of upstream MCP server
227
+ upstream_auth: dict = None, # Auth config (see below)
228
+ # stdio transport
229
+ command: list[str] = None, # Command to start MCP server
230
+ env: dict = None, # Environment variables
231
+ # Identity
232
+ iam_token: str = None, # IAM token for user identity
233
+ user_name: str = None, # User name
234
+ intent_policy: dict = None # MAPL intent policy
235
+ )
236
+ ```
237
+
238
+ | Parameter | Type | Description |
239
+ |-----------|------|-------------|
240
+ | `app_name` | str | Application name for MACAW registration |
241
+ | `upstream_url` | str | URL for HTTP transport |
242
+ | `upstream_auth` | dict | Auth: `{"type": "bearer", "token": "..."}` or `{"type": "api_key", "api_key": "...", "header_name": "X-API-Key"}` |
243
+ | `command` | list | Command for stdio transport |
244
+ | `env` | dict | Environment variables for stdio subprocess |
245
+ | `iam_token` | str | IAM token for authenticated identity |
246
+ | `user_name` | str | User name (used with local identity) |
247
+ | `intent_policy` | dict | MAPL policy for this proxy |
248
+
249
+ **Note:** Provide either `upstream_url` (HTTP) or `command` (stdio), not both.
250
+
251
+ ### Methods
252
+
253
+ #### `call_tool(tool_name, params) -> Any`
254
+
255
+ Call a tool through MACAW security.
256
+
257
+ ```python
258
+ result = proxy.call_tool("run_snowflake_query", {
259
+ "statement": "SELECT * FROM customers LIMIT 10"
260
+ })
261
+ ```
262
+
263
+ Flow:
264
+ 1. MACAWClient.invoke_tool() checks MAPL policy
265
+ 2. Signs the invocation cryptographically
266
+ 3. Logs to audit trail
267
+ 4. Proxy handler forwards to upstream MCP server
268
+
269
+ #### `list_tools() -> list[dict]`
270
+
271
+ List available tools discovered from upstream.
272
+
273
+ ```python
274
+ tools = proxy.list_tools()
275
+ # Returns: [{"name": "run_query", "description": "...", "schema": {...}}]
276
+ ```
277
+
278
+ #### `get_tool_schema(tool_name) -> dict`
279
+
280
+ Get schema for a specific tool.
281
+
282
+ ```python
283
+ schema = proxy.get_tool_schema("run_snowflake_query")
284
+ ```
285
+
286
+ #### `bind_to_user(user_client) -> BoundMCPProxy`
287
+
288
+ Bind proxy to a specific user's identity for multi-tenant applications.
289
+
290
+ ```python
291
+ from macaw_client import MACAWClient, RemoteIdentityProvider
292
+
293
+ # Authenticate user via Keycloak/Okta
294
+ jwt, _ = RemoteIdentityProvider().login("alice", "Alice123!")
295
+ alice = MACAWClient(user_name="alice", iam_token=jwt, app_name="my-app")
296
+ alice.register()
297
+
298
+ # Bind proxy to Alice's identity
299
+ alice_proxy = proxy.bind_to_user(alice)
300
+
301
+ # Calls now use Alice's identity and policy
302
+ result = alice_proxy.call_tool("run_snowflake_query", {...})
303
+ ```
304
+
305
+ #### `refresh_tools()`
306
+
307
+ Re-discover tools from upstream (if tools may have changed).
308
+
309
+ ```python
310
+ proxy.refresh_tools()
311
+ ```
312
+
313
+ ### Properties
314
+
315
+ | Property | Type | Description |
316
+ |----------|------|-------------|
317
+ | `proxy.app_name` | str | Application name |
318
+ | `proxy.upstream_url` | str | Upstream URL |
319
+ | `proxy.agent_id` | str | MACAW agent ID |
320
+ | `proxy.server_id` | str | Alias for agent_id |
321
+ | `proxy.tool_schemas` | dict | Discovered tool schemas |
322
+ | `proxy.is_connected` | bool | Connection status |
323
+
324
+ ---
325
+
326
+ ## BoundMCPProxy
327
+
328
+ MCP Proxy bound to a specific user's identity. All calls use the user's policy and audit trail.
329
+
330
+ ```python
331
+ bound_proxy = proxy.bind_to_user(user_client)
332
+
333
+ # Methods (same as SecureMCPProxy)
334
+ result = bound_proxy.call_tool("tool_name", params)
335
+ tools = bound_proxy.list_tools()
336
+ schema = bound_proxy.get_tool_schema("tool_name")
337
+ ```
338
+
339
+ ---
340
+
341
+ ## Examples
342
+
343
+ ### SecureMCP Calculator Server
344
+
345
+ ```python
346
+ from macaw_adapters.mcp import SecureMCP, Context
347
+
348
+ mcp = SecureMCP("calculator")
349
+
350
+ @mcp.tool(description="Add two numbers")
351
+ def add(a: float, b: float) -> float:
352
+ return a + b
353
+
354
+ @mcp.tool(description="Multiply two numbers")
355
+ def multiply(a: float, b: float) -> float:
356
+ return a * b
357
+
358
+ @mcp.tool(description="Calculate with history")
359
+ def calculate(ctx: Context, op: str, a: float, b: float) -> dict:
360
+ history = ctx.get("calc_history") or []
361
+ result = a + b if op == "add" else a * b
362
+ history.append({"op": op, "a": a, "b": b, "result": result})
363
+ ctx.set("calc_history", history)
364
+ return {"result": result, "history_count": len(history)}
365
+
366
+ @mcp.resource("calc://history")
367
+ def get_history(ctx: Context) -> dict:
368
+ return {"history": ctx.get("calc_history") or []}
369
+
370
+ if __name__ == "__main__":
371
+ mcp.run()
372
+ ```
373
+
374
+ ### SecureMCPProxy with Snowflake
375
+
376
+ ```python
377
+ from macaw_adapters.mcp import SecureMCPProxy
378
+
379
+ proxy = SecureMCPProxy(
380
+ app_name="snowflake-data",
381
+ upstream_url="http://localhost:9000/mcp"
382
+ )
383
+
384
+ # List available tools
385
+ for tool in proxy.list_tools():
386
+ print(f" {tool['name']}: {tool['description']}")
387
+
388
+ # Query data
389
+ result = proxy.call_tool("run_snowflake_query", {
390
+ "statement": "SELECT CURRENT_USER(), CURRENT_ROLE()"
391
+ })
392
+ print(result)
393
+ ```
394
+
395
+ ### Multi-User SecureMCPProxy
396
+
397
+ ```python
398
+ from macaw_adapters.mcp import SecureMCPProxy
399
+ from macaw_client import MACAWClient, RemoteIdentityProvider
400
+
401
+ # Service creates shared proxy
402
+ proxy = SecureMCPProxy(
403
+ app_name="data-platform",
404
+ upstream_url="http://localhost:9000/mcp"
405
+ )
406
+
407
+ # Authenticate users via Keycloak
408
+ alice_jwt, _ = RemoteIdentityProvider().login("alice", "Alice123!")
409
+ alice = MACAWClient(user_name="alice", iam_token=alice_jwt, app_name="data-platform")
410
+ alice.register()
411
+
412
+ bob_jwt, _ = RemoteIdentityProvider().login("bob", "Bob@123!")
413
+ bob = MACAWClient(user_name="bob", iam_token=bob_jwt, app_name="data-platform")
414
+ bob.register()
415
+
416
+ # Per-user proxies
417
+ alice_proxy = proxy.bind_to_user(alice)
418
+ bob_proxy = proxy.bind_to_user(bob)
419
+
420
+ # Each user's calls use their identity and policy
421
+ alice_result = alice_proxy.call_tool("list_objects", {"object_type": "database"})
422
+ bob_result = bob_proxy.call_tool("run_snowflake_query", {"statement": "SELECT 1"})
423
+ ```
424
+
425
+ ---
426
+
427
+ ## Security Model
428
+
429
+ All security is delegated to MACAW Control Plane:
430
+
431
+ 1. **Registration**: Server/proxy registers with LocalAgent on startup
432
+ 2. **Tool Invocation**: Requests routed through ToolAgent PEP
433
+ 3. **Policy Enforcement**: MAPL policies enforced on every request
434
+ 4. **Cryptographic Signing**: All invocations are signed per-request
435
+ 5. **Audit Logging**: Security events logged with cryptographic proof
436
+ 6. **Identity Propagation**: User identity flows through bind_to_user()
437
+
438
+ **Per-invocation security**: Even with persistent connections (stdio), MACAW creates fresh AuthenticatedContext for each call. This solves the "shared context" problem in standard MCP.
439
+
440
+ ---
441
+
442
+ ## Legacy API
443
+
444
+ The `Server` and `Client` classes are available for backwards compatibility:
445
+
446
+ ```python
447
+ from macaw_adapters.mcp import Server, Client
448
+ ```
449
+
450
+ For new projects, use `SecureMCP` (your servers) or `SecureMCPProxy` (external servers).
451
+
452
+ ---
453
+
454
+ ## Installation
455
+
456
+ ```bash
457
+ pip install macaw-adapters[mcp-proxy]
458
+ ```
459
+
460
+ For more information: https://macawsecurity.ai
@@ -0,0 +1,65 @@
1
+ """
2
+ MACAW MCP Adapter - FastMCP-compatible API with MACAW Security.
3
+
4
+ Two main components:
5
+ 1. SecureMCP - For MCP servers YOU write (wrap your tools with MACAW security)
6
+ 2. SecureMCPProxy - For MCP servers you DON'T control (inline gateway to external servers)
7
+
8
+ Usage - SecureMCP (your servers):
9
+ from macaw_adapters.mcp import SecureMCP, Context
10
+
11
+ mcp = SecureMCP("calculator")
12
+
13
+ @mcp.tool(description="Add two numbers")
14
+ def add(a: float, b: float) -> float:
15
+ return a + b
16
+
17
+ mcp.run()
18
+
19
+ Usage - SecureMCPProxy (external servers):
20
+ from macaw_adapters.mcp import SecureMCPProxy
21
+
22
+ # Connect to external MCP server (Salesforce, Google, etc.)
23
+ proxy = SecureMCPProxy(
24
+ app_name="salesforce-mcp",
25
+ upstream_url="https://mcp.salesforce.com",
26
+ upstream_auth={"type": "bearer", "token": SF_TOKEN}
27
+ )
28
+
29
+ # Call tools - MACAW security applied
30
+ result = proxy.call_tool("query_accounts", {"limit": 10})
31
+
32
+ Features:
33
+ - FastMCP-compatible decorator API (SecureMCP)
34
+ - Inline gateway for external MCP servers (SecureMCPProxy)
35
+ - Policy-enforced tool execution
36
+ - Cryptographic audit trail
37
+ - Multi-user identity via bind_to_user()
38
+
39
+ For more information: https://macawsecurity.ai
40
+ """
41
+
42
+ __version__ = "0.9.10.1"
43
+
44
+ # Primary FastMCP-compatible API (your MCP servers)
45
+ from .mcp import SecureMCP, Context
46
+
47
+ # Inline Gateway for external MCP servers
48
+ from .proxy import SecureMCPProxy, BoundMCPProxy
49
+
50
+ # Legacy API (backwards compatibility)
51
+ from .server import Server
52
+ from .client import Client
53
+
54
+ __all__ = [
55
+ # Your MCP servers
56
+ "SecureMCP",
57
+ "Context",
58
+ # External MCP servers (inline gateway)
59
+ "SecureMCPProxy",
60
+ "BoundMCPProxy",
61
+ # Legacy
62
+ "Server",
63
+ "Client",
64
+ "__version__"
65
+ ]