gopher-mcp-python 0.1.23__tar.gz → 0.1.30__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/PKG-INFO +10 -2
  2. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/README.md +9 -1
  3. gopher_mcp_python-0.1.30/gopher_mcp_python/__init__.py +165 -0
  4. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/gopher_mcp_python/agent.py +98 -26
  5. gopher_mcp_python-0.1.30/gopher_mcp_python/auth/__init__.py +83 -0
  6. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/gopher_mcp_python/config.py +141 -1
  7. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/gopher_mcp_python/ffi/auth/__init__.py +38 -0
  8. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/gopher_mcp_python/ffi/auth/auth_client.py +0 -1
  9. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/gopher_mcp_python/ffi/auth/loader.py +43 -11
  10. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/gopher_mcp_python/ffi/library.py +381 -23
  11. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/gopher_mcp_python.egg-info/PKG-INFO +10 -2
  12. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/gopher_mcp_python.egg-info/SOURCES.txt +5 -0
  13. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/pyproject.toml +1 -1
  14. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/setup.py +1 -0
  15. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/tests/test_agent_create_by.py +2 -6
  16. gopher_mcp_python-0.1.30/tests/test_agent_error_message.py +124 -0
  17. gopher_mcp_python-0.1.30/tests/test_agent_runtime_options.py +200 -0
  18. gopher_mcp_python-0.1.30/tests/test_auth_exports.py +88 -0
  19. gopher_mcp_python-0.1.30/tests/test_config.py +173 -0
  20. gopher_mcp_python-0.1.30/tests/test_ffi_runtime_options.py +119 -0
  21. gopher_mcp_python-0.1.30/tests/test_library_search_paths.py +77 -0
  22. gopher_mcp_python-0.1.23/gopher_mcp_python/__init__.py +0 -84
  23. gopher_mcp_python-0.1.23/gopher_mcp_python/auth/__init__.py +0 -31
  24. gopher_mcp_python-0.1.23/tests/test_config.py +0 -79
  25. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/LICENSE +0 -0
  26. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/gopher_mcp_python/auth/errors.py +0 -0
  27. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/gopher_mcp_python/auth/gopher_auth.py +0 -0
  28. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/gopher_mcp_python/auth/scope_helpers.py +0 -0
  29. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/gopher_mcp_python/errors.py +0 -0
  30. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/gopher_mcp_python/ffi/__init__.py +0 -0
  31. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/gopher_mcp_python/ffi/auth/auto_refresh.py +0 -0
  32. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/gopher_mcp_python/ffi/auth/config_loader.py +0 -0
  33. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/gopher_mcp_python/ffi/auth/oauth_client.py +0 -0
  34. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/gopher_mcp_python/ffi/auth/session_manager.py +0 -0
  35. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/gopher_mcp_python/ffi/auth/types.py +0 -0
  36. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/gopher_mcp_python/ffi/auth/validation_options.py +0 -0
  37. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/gopher_mcp_python/result.py +0 -0
  38. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/gopher_mcp_python/server_config.py +0 -0
  39. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/gopher_mcp_python.egg-info/dependency_links.txt +0 -0
  40. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/gopher_mcp_python.egg-info/requires.txt +0 -0
  41. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/gopher_mcp_python.egg-info/top_level.txt +0 -0
  42. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/setup.cfg +0 -0
  43. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/tests/test_ffi.py +0 -0
  44. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/tests/test_gopher_auth.py +0 -0
  45. {gopher_mcp_python-0.1.23 → gopher_mcp_python-0.1.30}/tests/test_result.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gopher-mcp-python
3
- Version: 0.1.23
3
+ Version: 0.1.30
4
4
  Summary: Python SDK for Gopher MCP - AI Agent orchestration framework with native performance
5
5
  Author-email: Gopher Security <dev@gophersecurity.com>
6
6
  License: Apache-2.0
@@ -59,8 +59,16 @@ Python SDK for gopher-mcp-python, providing AI agent orchestration with native C
59
59
  ## Requirements
60
60
 
61
61
  - Python 3.8 or higher
62
+ - `venv` and `pip` for PyPI installation, examples, and development workflows
62
63
  - Native gopher-mcp-python library (built from source)
63
64
 
65
+ On Debian/Ubuntu, install the Python venv and pip packages before using the
66
+ PyPI install path, running examples, or setting up development dependencies:
67
+
68
+ ```bash
69
+ sudo apt-get install python3 python3-venv python3-pip
70
+ ```
71
+
64
72
  ## Installation
65
73
 
66
74
  ### From Source
@@ -78,7 +86,7 @@ cd gopher-mcp-python
78
86
 
79
87
  3. Install the Python package:
80
88
  ```bash
81
- pip install -e .
89
+ python3 -m pip install -e .
82
90
  ```
83
91
 
84
92
  ## Quick Start
@@ -15,8 +15,16 @@ Python SDK for gopher-mcp-python, providing AI agent orchestration with native C
15
15
  ## Requirements
16
16
 
17
17
  - Python 3.8 or higher
18
+ - `venv` and `pip` for PyPI installation, examples, and development workflows
18
19
  - Native gopher-mcp-python library (built from source)
19
20
 
21
+ On Debian/Ubuntu, install the Python venv and pip packages before using the
22
+ PyPI install path, running examples, or setting up development dependencies:
23
+
24
+ ```bash
25
+ sudo apt-get install python3 python3-venv python3-pip
26
+ ```
27
+
20
28
  ## Installation
21
29
 
22
30
  ### From Source
@@ -34,7 +42,7 @@ cd gopher-mcp-python
34
42
 
35
43
  3. Install the Python package:
36
44
  ```bash
37
- pip install -e .
45
+ python3 -m pip install -e .
38
46
  ```
39
47
 
40
48
  ## Quick Start
@@ -0,0 +1,165 @@
1
+ """
2
+ Gopher Orch Python SDK - AI Agent orchestration framework with native performance.
3
+
4
+ This module provides Python bindings to the gopher-mcp-python native library through ctypes FFI.
5
+
6
+ Example:
7
+ >>> from gopher_mcp_python import GopherAgent, GopherAgentConfig
8
+ >>>
9
+ >>> # Create an agent with API key
10
+ >>> config = (GopherAgentConfig.builder()
11
+ ... .provider("AnthropicProvider")
12
+ ... .model("claude-3-haiku-20240307")
13
+ ... .api_key("your-api-key")
14
+ ... .build())
15
+ >>> agent = GopherAgent.create(config)
16
+ >>>
17
+ >>> # Run a query
18
+ >>> answer = agent.run("What time is it in Tokyo?")
19
+ >>> print(answer)
20
+ >>>
21
+ >>> # Cleanup
22
+ >>> agent.dispose()
23
+ """
24
+
25
+ from gopher_mcp_python.agent import GopherAgent
26
+ from gopher_mcp_python.config import (
27
+ GopherAgentConfig,
28
+ GopherAgentConfigBuilder,
29
+ GopherAgentRuntimeOptions,
30
+ )
31
+ from gopher_mcp_python.result import AgentResult, AgentResultStatus, AgentResultBuilder
32
+ from gopher_mcp_python.errors import (
33
+ AgentError,
34
+ ApiKeyError,
35
+ ConnectionError,
36
+ TimeoutError,
37
+ )
38
+ from gopher_mcp_python.server_config import ServerConfig
39
+ from gopher_mcp_python.ffi import GopherOrchLibrary, GopherOrchHandle
40
+
41
+ # Auth module re-exports
42
+ from gopher_mcp_python.ffi.auth import (
43
+ # Types
44
+ GopherAuthError,
45
+ AutoRefreshResult,
46
+ RegistrationResponse,
47
+ TokenResponse,
48
+ ValidationResult,
49
+ TokenPayload,
50
+ GopherAuthContext,
51
+ ERROR_DESCRIPTIONS,
52
+ get_error_description,
53
+ gopher_create_empty_auth_context,
54
+ is_gopher_auth_error,
55
+ # Classes
56
+ GopherAuthClient,
57
+ GopherAuthConfig,
58
+ GopherOAuthClient,
59
+ GopherSessionManager,
60
+ GopherValidationOptions,
61
+ # Functions
62
+ gopher_auth_auto_refresh,
63
+ gopher_auth_build_oidc_discovery_metadata,
64
+ gopher_auth_build_oauth_server_metadata,
65
+ gopher_auth_build_protected_resource_metadata,
66
+ gopher_auth_extract_bearer_token,
67
+ gopher_auth_extract_method,
68
+ gopher_auth_extract_path,
69
+ gopher_auth_url_decode,
70
+ gopher_auth_url_encode,
71
+ gopher_auth_validate_all_scopes,
72
+ gopher_auth_validate_any_scopes,
73
+ gopher_auth_validate_idp,
74
+ gopher_create_validation_options,
75
+ gopher_generate_www_authenticate_header,
76
+ gopher_generate_www_authenticate_header_v2,
77
+ gopher_get_auth_library_version,
78
+ gopher_init_auth_library,
79
+ gopher_is_auth_library_initialized,
80
+ gopher_shutdown_auth_library,
81
+ is_auth_available,
82
+ )
83
+ from gopher_mcp_python.auth import (
84
+ GopherAuth,
85
+ GopherAuthError as GopherAuthBaseError,
86
+ ConfigurationError,
87
+ InsufficientScopesError,
88
+ JwksError,
89
+ TokenExchangeError,
90
+ TokenValidationError,
91
+ has_all_scopes,
92
+ has_any_scope,
93
+ has_scope,
94
+ )
95
+
96
+ __version__ = "0.1.30"
97
+
98
+ __all__ = [
99
+ # Main classes
100
+ "GopherAgent",
101
+ "GopherAgentConfig",
102
+ "GopherAgentConfigBuilder",
103
+ "GopherAgentRuntimeOptions",
104
+ "AgentResult",
105
+ "AgentResultStatus",
106
+ "AgentResultBuilder",
107
+ "ServerConfig",
108
+ # Errors
109
+ "AgentError",
110
+ "ApiKeyError",
111
+ "ConnectionError",
112
+ "TimeoutError",
113
+ # FFI
114
+ "GopherOrchLibrary",
115
+ "GopherOrchHandle",
116
+ # Auth
117
+ "GopherAuthError",
118
+ "AutoRefreshResult",
119
+ "RegistrationResponse",
120
+ "TokenResponse",
121
+ "ValidationResult",
122
+ "TokenPayload",
123
+ "GopherAuthContext",
124
+ "ERROR_DESCRIPTIONS",
125
+ "get_error_description",
126
+ "gopher_create_empty_auth_context",
127
+ "is_gopher_auth_error",
128
+ "GopherAuthClient",
129
+ "GopherAuthConfig",
130
+ "GopherOAuthClient",
131
+ "GopherSessionManager",
132
+ "GopherValidationOptions",
133
+ "gopher_auth_auto_refresh",
134
+ "gopher_auth_build_oidc_discovery_metadata",
135
+ "gopher_auth_build_oauth_server_metadata",
136
+ "gopher_auth_build_protected_resource_metadata",
137
+ "gopher_auth_extract_bearer_token",
138
+ "gopher_auth_extract_method",
139
+ "gopher_auth_extract_path",
140
+ "gopher_auth_url_decode",
141
+ "gopher_auth_url_encode",
142
+ "gopher_auth_validate_all_scopes",
143
+ "gopher_auth_validate_any_scopes",
144
+ "gopher_auth_validate_idp",
145
+ "gopher_create_validation_options",
146
+ "gopher_generate_www_authenticate_header",
147
+ "gopher_generate_www_authenticate_header_v2",
148
+ "gopher_get_auth_library_version",
149
+ "gopher_init_auth_library",
150
+ "gopher_is_auth_library_initialized",
151
+ "gopher_shutdown_auth_library",
152
+ "is_auth_available",
153
+ "GopherAuth",
154
+ "GopherAuthBaseError",
155
+ "ConfigurationError",
156
+ "InsufficientScopesError",
157
+ "JwksError",
158
+ "TokenExchangeError",
159
+ "TokenValidationError",
160
+ "has_all_scopes",
161
+ "has_any_scope",
162
+ "has_scope",
163
+ # Version
164
+ "__version__",
165
+ ]
@@ -34,7 +34,6 @@ from gopher_mcp_python.result import AgentResult, AgentResultStatus
34
34
  from gopher_mcp_python.errors import AgentError, TimeoutError
35
35
  from gopher_mcp_python.ffi import GopherOrchLibrary, GopherOrchHandle
36
36
 
37
-
38
37
  _initialized = False
39
38
  _cleanup_handler_registered = False
40
39
 
@@ -78,7 +77,10 @@ class GopherAgent:
78
77
 
79
78
  lib = GopherOrchLibrary.get_instance()
80
79
  if lib is None:
81
- raise AgentError("Failed to load gopher-mcp-python native library")
80
+ load_error = GopherOrchLibrary.get_load_error_message()
81
+ raise AgentError(
82
+ f"Failed to load gopher-mcp-python native library.\n{load_error}"
83
+ )
82
84
 
83
85
  _initialized = True
84
86
  _setup_cleanup_handler()
@@ -117,17 +119,24 @@ class GopherAgent:
117
119
 
118
120
  lib = GopherOrchLibrary.get_instance()
119
121
  if lib is None:
120
- raise AgentError("Native library not available")
122
+ load_error = GopherOrchLibrary.get_load_error_message()
123
+ raise AgentError(f"Native library not available.\n{load_error}")
121
124
 
122
125
  handle: Optional[GopherOrchHandle] = None
123
126
  try:
124
127
  if config.has_api_key():
125
128
  handle = lib.agent_create_by_api_key(
126
- config.provider, config.model, config.api_key
129
+ config.provider,
130
+ config.model,
131
+ config.api_key,
132
+ config.runtime_options,
127
133
  )
128
134
  else:
129
135
  handle = lib.agent_create_by_json(
130
- config.provider, config.model, config.server_config
136
+ config.provider,
137
+ config.model,
138
+ config.server_config,
139
+ config.runtime_options,
131
140
  )
132
141
  except Exception as e:
133
142
  raise AgentError(f"Failed to create agent: {e}")
@@ -135,12 +144,17 @@ class GopherAgent:
135
144
  if handle is None:
136
145
  error = lib.get_last_error_message()
137
146
  lib.clear_error()
138
- raise AgentError(error or "Failed to create agent")
147
+ raise AgentError(error or _build_create_error_message())
139
148
 
140
149
  return GopherAgent(handle)
141
150
 
142
151
  @staticmethod
143
- def create_with_api_key(provider: str, model: str, api_key: str) -> "GopherAgent":
152
+ def create_with_api_key(
153
+ provider: str,
154
+ model: str,
155
+ api_key: str,
156
+ runtime_options: Optional[object] = None,
157
+ ) -> "GopherAgent":
144
158
  """
145
159
  Create a new GopherAgent with API key.
146
160
 
@@ -148,21 +162,27 @@ class GopherAgent:
148
162
  provider: Provider name (e.g., "AnthropicProvider")
149
163
  model: Model name (e.g., "claude-3-haiku-20240307")
150
164
  api_key: API key for fetching remote server config
165
+ runtime_options: Dynamic MCP runtime headers/access token
151
166
 
152
167
  Returns:
153
168
  GopherAgent instance
154
169
  """
155
- return GopherAgent.create(
170
+ builder = (
156
171
  GopherAgentConfig.builder()
157
172
  .provider(provider)
158
173
  .model(model)
159
174
  .api_key(api_key)
160
- .build()
161
175
  )
176
+ if runtime_options is not None:
177
+ builder.runtime_options(runtime_options)
178
+ return GopherAgent.create(builder.build())
162
179
 
163
180
  @staticmethod
164
181
  def create_with_server_config(
165
- provider: str, model: str, server_config: str
182
+ provider: str,
183
+ model: str,
184
+ server_config: str,
185
+ runtime_options: Optional[object] = None,
166
186
  ) -> "GopherAgent":
167
187
  """
168
188
  Create a new GopherAgent with JSON server config.
@@ -171,21 +191,28 @@ class GopherAgent:
171
191
  provider: Provider name (e.g., "AnthropicProvider")
172
192
  model: Model name (e.g., "claude-3-haiku-20240307")
173
193
  server_config: JSON server configuration
194
+ runtime_options: Dynamic MCP runtime headers/access token
174
195
 
175
196
  Returns:
176
197
  GopherAgent instance
177
198
  """
178
- return GopherAgent.create(
199
+ builder = (
179
200
  GopherAgentConfig.builder()
180
201
  .provider(provider)
181
202
  .model(model)
182
203
  .server_config(server_config)
183
- .build()
184
204
  )
205
+ if runtime_options is not None:
206
+ builder.runtime_options(runtime_options)
207
+ return GopherAgent.create(builder.build())
185
208
 
186
209
  @staticmethod
187
210
  def create_with_server_id(
188
- provider: str, model: str, api_key: str, server_id: str
211
+ provider: str,
212
+ model: str,
213
+ api_key: str,
214
+ server_id: str,
215
+ runtime_options: Optional[object] = None,
189
216
  ) -> "GopherAgent":
190
217
  """
191
218
  Create a new GopherAgent scoped to a single MCP server by id.
@@ -199,19 +226,24 @@ class GopherAgent:
199
226
  model: Model identifier accepted by the chosen provider
200
227
  api_key: Gopher API key
201
228
  server_id: MCP server id to scope the agent to
229
+ runtime_options: Dynamic MCP runtime headers/access token
202
230
 
203
231
  Returns:
204
232
  GopherAgent instance
205
233
  """
206
234
  return GopherAgent._create_from_ffi(
207
235
  lambda lib: lib.agent_create_by_server_id(
208
- provider, model, api_key, server_id
236
+ provider, model, api_key, server_id, runtime_options
209
237
  )
210
238
  )
211
239
 
212
240
  @staticmethod
213
241
  def create_with_server_name(
214
- provider: str, model: str, api_key: str, server_name: str
242
+ provider: str,
243
+ model: str,
244
+ api_key: str,
245
+ server_name: str,
246
+ runtime_options: Optional[object] = None,
215
247
  ) -> "GopherAgent":
216
248
  """
217
249
  Create a new GopherAgent scoped to a single MCP server by name.
@@ -225,19 +257,24 @@ class GopherAgent:
225
257
  model: Model identifier accepted by the chosen provider
226
258
  api_key: Gopher API key
227
259
  server_name: MCP server name to scope the agent to
260
+ runtime_options: Dynamic MCP runtime headers/access token
228
261
 
229
262
  Returns:
230
263
  GopherAgent instance
231
264
  """
232
265
  return GopherAgent._create_from_ffi(
233
266
  lambda lib: lib.agent_create_by_server_name(
234
- provider, model, api_key, server_name
267
+ provider, model, api_key, server_name, runtime_options
235
268
  )
236
269
  )
237
270
 
238
271
  @staticmethod
239
272
  def create_with_gateway_id(
240
- provider: str, model: str, api_key: str, gateway_id: str
273
+ provider: str,
274
+ model: str,
275
+ api_key: str,
276
+ gateway_id: str,
277
+ runtime_options: Optional[object] = None,
241
278
  ) -> "GopherAgent":
242
279
  """
243
280
  Create a new GopherAgent scoped to a single MCP gateway by id.
@@ -251,19 +288,24 @@ class GopherAgent:
251
288
  model: Model identifier accepted by the chosen provider
252
289
  api_key: Gopher API key
253
290
  gateway_id: MCP gateway id to scope the agent to
291
+ runtime_options: Dynamic MCP runtime headers/access token
254
292
 
255
293
  Returns:
256
294
  GopherAgent instance
257
295
  """
258
296
  return GopherAgent._create_from_ffi(
259
297
  lambda lib: lib.agent_create_by_gateway_id(
260
- provider, model, api_key, gateway_id
298
+ provider, model, api_key, gateway_id, runtime_options
261
299
  )
262
300
  )
263
301
 
264
302
  @staticmethod
265
303
  def create_with_gateway_name(
266
- provider: str, model: str, api_key: str, gateway_name: str
304
+ provider: str,
305
+ model: str,
306
+ api_key: str,
307
+ gateway_name: str,
308
+ runtime_options: Optional[object] = None,
267
309
  ) -> "GopherAgent":
268
310
  """
269
311
  Create a new GopherAgent scoped to a single MCP gateway by name.
@@ -277,18 +319,24 @@ class GopherAgent:
277
319
  model: Model identifier accepted by the chosen provider
278
320
  api_key: Gopher API key
279
321
  gateway_name: MCP gateway name to scope the agent to
322
+ runtime_options: Dynamic MCP runtime headers/access token
280
323
 
281
324
  Returns:
282
325
  GopherAgent instance
283
326
  """
284
327
  return GopherAgent._create_from_ffi(
285
328
  lambda lib: lib.agent_create_by_gateway_name(
286
- provider, model, api_key, gateway_name
329
+ provider, model, api_key, gateway_name, runtime_options
287
330
  )
288
331
  )
289
332
 
290
333
  @staticmethod
291
- def create_with_url(provider: str, model: str, url: str) -> "GopherAgent":
334
+ def create_with_url(
335
+ provider: str,
336
+ model: str,
337
+ url: str,
338
+ runtime_options: Optional[object] = None,
339
+ ) -> "GopherAgent":
292
340
  """
293
341
  Create a new GopherAgent for a single MCP server reachable at a URL.
294
342
 
@@ -301,12 +349,13 @@ class GopherAgent:
301
349
  provider: Provider name (e.g., "AnthropicProvider")
302
350
  model: Model identifier accepted by the chosen provider
303
351
  url: Full URL of the MCP server (e.g., "http://127.0.0.1:8080/mcp")
352
+ runtime_options: Dynamic MCP runtime headers/access token
304
353
 
305
354
  Returns:
306
355
  GopherAgent instance
307
356
  """
308
357
  return GopherAgent._create_from_ffi(
309
- lambda lib: lib.agent_create_by_url(provider, model, url)
358
+ lambda lib: lib.agent_create_by_url(provider, model, url, runtime_options)
310
359
  )
311
360
 
312
361
  @staticmethod
@@ -325,7 +374,8 @@ class GopherAgent:
325
374
 
326
375
  lib = GopherOrchLibrary.get_instance()
327
376
  if lib is None:
328
- raise AgentError("Native library not available")
377
+ load_error = GopherOrchLibrary.get_load_error_message()
378
+ raise AgentError(f"Native library not available.\n{load_error}")
329
379
 
330
380
  try:
331
381
  handle = create_handle(lib)
@@ -335,7 +385,7 @@ class GopherAgent:
335
385
  if handle is None:
336
386
  error = lib.get_last_error_message()
337
387
  lib.clear_error()
338
- raise AgentError(error or "Failed to create agent")
388
+ raise AgentError(error or _build_create_error_message())
339
389
 
340
390
  return GopherAgent(handle)
341
391
 
@@ -357,13 +407,18 @@ class GopherAgent:
357
407
 
358
408
  lib = GopherOrchLibrary.get_instance()
359
409
  if lib is None:
360
- raise AgentError("Native library not available")
410
+ load_error = GopherOrchLibrary.get_load_error_message()
411
+ raise AgentError(f"Native library not available.\n{load_error}")
361
412
 
362
413
  try:
363
414
  response = lib.agent_run(self._handle, query, timeout_ms)
364
415
  if response is None:
365
- return f'No response for query: "{query}"'
416
+ error = lib.get_last_error_message()
417
+ lib.clear_error()
418
+ raise AgentError(error or f'No response for query: "{query}"')
366
419
  return response
420
+ except AgentError:
421
+ raise
367
422
  except Exception as e:
368
423
  raise AgentError(f"Query execution failed: {e}")
369
424
 
@@ -421,3 +476,20 @@ def _setup_cleanup_handler() -> None:
421
476
 
422
477
  _cleanup_handler_registered = True
423
478
  atexit.register(GopherAgent.shutdown)
479
+
480
+
481
+ def _build_create_error_message() -> str:
482
+ """
483
+ Build the AgentError message for a null native create*() result.
484
+
485
+ Native should usually populate gopher_orch_last_error, but a few
486
+ defensive paths can still return null without details. Keep that
487
+ fallback actionable instead of raising only "Failed to create agent".
488
+ """
489
+ return (
490
+ "Failed to create agent: native library returned null without a "
491
+ "specific error. Most often this means every configured MCP server "
492
+ "failed to connect or returned no tools (TLS / network / bad URL), "
493
+ "or the LLM provider could not be initialized. Set GOPHER_DEBUG=1 to "
494
+ "see native-side logs."
495
+ )
@@ -0,0 +1,83 @@
1
+ """
2
+ Auth Module - Reusable OAuth/JWT authentication for Python MCP servers.
3
+ """
4
+
5
+ from gopher_mcp_python.auth.gopher_auth import GopherAuth
6
+ from gopher_mcp_python.auth.errors import (
7
+ GopherAuthError,
8
+ TokenValidationError,
9
+ InsufficientScopesError,
10
+ JwksError,
11
+ ConfigurationError,
12
+ TokenExchangeError,
13
+ )
14
+ from gopher_mcp_python.auth.scope_helpers import (
15
+ has_scope,
16
+ has_all_scopes,
17
+ has_any_scope,
18
+ )
19
+ from gopher_mcp_python.ffi.auth import (
20
+ AutoRefreshResult,
21
+ GopherAuthClient,
22
+ GopherAuthConfig,
23
+ GopherOAuthClient,
24
+ GopherSessionManager,
25
+ GopherValidationOptions,
26
+ RegistrationResponse,
27
+ TokenPayload,
28
+ TokenResponse,
29
+ ValidationResult,
30
+ gopher_auth_auto_refresh,
31
+ gopher_auth_build_oidc_discovery_metadata,
32
+ gopher_auth_build_oauth_server_metadata,
33
+ gopher_auth_build_protected_resource_metadata,
34
+ gopher_auth_extract_bearer_token,
35
+ gopher_auth_extract_method,
36
+ gopher_auth_extract_path,
37
+ gopher_auth_url_decode,
38
+ gopher_auth_url_encode,
39
+ gopher_auth_validate_all_scopes,
40
+ gopher_auth_validate_any_scopes,
41
+ gopher_auth_validate_idp,
42
+ gopher_create_validation_options,
43
+ gopher_generate_www_authenticate_header,
44
+ gopher_generate_www_authenticate_header_v2,
45
+ )
46
+
47
+ __all__ = [
48
+ "GopherAuth",
49
+ "GopherAuthError",
50
+ "TokenValidationError",
51
+ "InsufficientScopesError",
52
+ "JwksError",
53
+ "ConfigurationError",
54
+ "TokenExchangeError",
55
+ "has_scope",
56
+ "has_all_scopes",
57
+ "has_any_scope",
58
+ "AutoRefreshResult",
59
+ "GopherAuthClient",
60
+ "GopherAuthConfig",
61
+ "GopherOAuthClient",
62
+ "GopherSessionManager",
63
+ "GopherValidationOptions",
64
+ "RegistrationResponse",
65
+ "TokenPayload",
66
+ "TokenResponse",
67
+ "ValidationResult",
68
+ "gopher_auth_auto_refresh",
69
+ "gopher_auth_build_oidc_discovery_metadata",
70
+ "gopher_auth_build_oauth_server_metadata",
71
+ "gopher_auth_build_protected_resource_metadata",
72
+ "gopher_auth_extract_bearer_token",
73
+ "gopher_auth_extract_method",
74
+ "gopher_auth_extract_path",
75
+ "gopher_auth_url_decode",
76
+ "gopher_auth_url_encode",
77
+ "gopher_auth_validate_all_scopes",
78
+ "gopher_auth_validate_any_scopes",
79
+ "gopher_auth_validate_idp",
80
+ "gopher_create_validation_options",
81
+ "gopher_generate_www_authenticate_header",
82
+ "gopher_generate_www_authenticate_header_v2",
83
+ ]