Skip to content

Commit 56b2de3

Browse files
monshriTeryl Taylorcrivetimihaimadhav165araujof
authored
feat: add LLMGuard security guardrails plugin (#1018)
* making cryptography version compatible with llmguard Signed-off-by: Shriti Priya <[email protected]> * lower bound Signed-off-by: Shriti Priya <[email protected]> * Initial plugin implementation using llmguard Signed-off-by: Shriti Priya <[email protected]> * changes for input and output filters Signed-off-by: Shriti Priya <[email protected]> * documentation on functions of llmguard.py Signed-off-by: Shriti Priya <[email protected]> * Adding documentation and minor bug fixes Signed-off-by: Shriti Priya <[email protected]> * linting changes Signed-off-by: Shriti Priya <[email protected]> * Updating cryptogrpahy dependency in conatinerfile for llmguard Signed-off-by: Shriti Priya <[email protected]> * Reverting the cryptogrpahy package version in root pyproject.toml Signed-off-by: Shriti Priya <[email protected]> * Updating manifest.in file Signed-off-by: Shriti Priya <[email protected]> * adding make test in container Signed-off-by: Shriti Priya <[email protected]> * fix: fixed retry on client plugin connection. Signed-off-by: Teryl Taylor <[email protected]> * Changing port for llmguard Signed-off-by: Shriti Priya <[email protected]> * Pre-caching the scanners during container build Signed-off-by: Shriti Priya <[email protected]> * test cases Signed-off-by: Shriti Priya <[email protected]> * filters and sanitizers Signed-off-by: Shriti Priya <[email protected]> * Vault caching for anonymize and deanoymize, examples Signed-off-by: Shriti Priya <[email protected]> * vault caching and expiry ttl, vault leak detection and redis caching Signed-off-by: Shriti Priya <[email protected]> * adding test cases Signed-off-by: Shriti Priya <[email protected]> * Adding test cases for vault and sanitizers Signed-off-by: Shriti Priya <[email protected]> * Documentation and test cases for LLMGuardPlugin Signed-off-by: Shriti Priya <[email protected]> * Updating readme for plugin Signed-off-by: Shriti Priya <[email protected]> * Updating readme for plugin Signed-off-by: Shriti Priya <[email protected]> * Updating readme for plugin Signed-off-by: Shriti Priya <[email protected]> * Updating readme for plugin Signed-off-by: Shriti Priya <[email protected]> * Updating yaml formatting in documentation Signed-off-by: Shriti Priya <[email protected]> * Adding some examples, test cases for complex policiies and documentation update Signed-off-by: Shriti Priya <[email protected]> * Pandoc MCP Server (#1044) Signed-off-by: Mihai Criveti <[email protected]> * Massive mcp server and plugin update (#1051) * MCP Servers and Plugins Signed-off-by: Mihai Criveti <[email protected]> * Formatting Signed-off-by: Mihai Criveti <[email protected]> * Update Readme Signed-off-by: Mihai Criveti <[email protected]> * Update plugin Signed-off-by: Mihai Criveti <[email protected]> * Update plugins Signed-off-by: Mihai Criveti <[email protected]> * Update docs Signed-off-by: Mihai Criveti <[email protected]> * Update chmod Signed-off-by: Mihai Criveti <[email protected]> * Update headers Signed-off-by: Mihai Criveti <[email protected]> * Update headers Signed-off-by: Mihai Criveti <[email protected]> --------- Signed-off-by: Mihai Criveti <[email protected]> * OAuth token multitenancy closes #1078 (user-scoped tokens) and #1023 (token refresh) (#1084) * Fix oauth token multitenancy Signed-off-by: Mihai Criveti <[email protected]> * Fix oauth token multitenancy Signed-off-by: Mihai Criveti <[email protected]> * Fix oauth token multitenancy Signed-off-by: Mihai Criveti <[email protected]> * Fix oauth token multitenancy Signed-off-by: Mihai Criveti <[email protected]> * Fix oauth token multitenancy Signed-off-by: Mihai Criveti <[email protected]> * Update alembic migration - fix 0.7.0 upgrade Signed-off-by: Mihai Criveti <[email protected]> * Closes #1023 - implement token refresh Signed-off-by: Mihai Criveti <[email protected]> * Closes #1023 - implement token refresh Signed-off-by: Mihai Criveti <[email protected]> --------- Signed-off-by: Mihai Criveti <[email protected]> * Documentation update readmes (#1087) * Documentation updates Signed-off-by: Mihai Criveti <[email protected]> * Documentation updates Signed-off-by: Mihai Criveti <[email protected]> --------- Signed-off-by: Mihai Criveti <[email protected]> * Documentation updates (#1088) Signed-off-by: Mihai Criveti <[email protected]> * Documentation updates (#1089) Signed-off-by: Mihai Criveti <[email protected]> * Test tokens (#1090) * Test tokens Signed-off-by: Mihai Criveti <[email protected]> * llms-mcp-server-python Signed-off-by: Mihai Criveti <[email protected]> --------- Signed-off-by: Mihai Criveti <[email protected]> * Update mcp servers (#1091) * Update MCP Servers Signed-off-by: Mihai Criveti <[email protected]> * Update MCP Servers Signed-off-by: Mihai Criveti <[email protected]> * Update MCP Servers Signed-off-by: Mihai Criveti <[email protected]> * Update MCP Servers Signed-off-by: Mihai Criveti <[email protected]> * Update MCP Servers Signed-off-by: Mihai Criveti <[email protected]> * Update MCP Servers Signed-off-by: Mihai Criveti <[email protected]> * Update MCP Servers Signed-off-by: Mihai Criveti <[email protected]> --------- Signed-off-by: Mihai Criveti <[email protected]> * PM MCP Server Signed-off-by: Mihai Criveti <[email protected]> * PM MCP Server Signed-off-by: Mihai Criveti <[email protected]> * PM MCP Server Signed-off-by: Mihai Criveti <[email protected]> * Fixes OAuth after addition of signature to state (#1097) * copied from main Signed-off-by: Madhav Kandukuri <[email protected]> * testing changes Signed-off-by: Madhav Kandukuri <[email protected]> * Fix oauth code Signed-off-by: Madhav Kandukuri <[email protected]> * Fix tests in test_oauth_router Signed-off-by: Madhav Kandukuri <[email protected]> * Linting fixes Signed-off-by: Madhav Kandukuri <[email protected]> * remove debug_team_dropdown.md Signed-off-by: Madhav Kandukuri <[email protected]> * String issue fixed Signed-off-by: Madhav Kandukuri <[email protected]> --------- Signed-off-by: Madhav Kandukuri <[email protected]> * feat: add opa policy input data mapping support (#1102) * feat: add opa policy input data mapping support Signed-off-by: Frederico Araujo <[email protected]> * chore: drop debugging print statement Signed-off-by: Frederico Araujo <[email protected]> --------- Signed-off-by: Frederico Araujo <[email protected]> * fix: multi-arch support for opa server (#1106) Signed-off-by: Frederico Araujo <[email protected]> * docs: add Terraform MCP Server and Gateway integration guide (#1083) This commit adds documentation explaining the Terraform MCP Server, its key features, and how to integrate it with the MCP Gateway. The content is based on the official documentation and adapted for usage and reference. Signed-off-by: Alexander Cobas Rodríguez <[email protected]> * copied from main Signed-off-by: Madhav Kandukuri <[email protected]> * testing changes Signed-off-by: Madhav Kandukuri <[email protected]> * Linting fixes Signed-off-by: Madhav Kandukuri <[email protected]> * remove debug_team_dropdown.md Signed-off-by: Madhav Kandukuri <[email protected]> * copied from fix-oauth Signed-off-by: Madhav Kandukuri <[email protected]> * OAuth for test gateway Signed-off-by: Madhav Kandukuri <[email protected]> * testing Signed-off-by: Madhav Kandukuri <[email protected]> * testing Signed-off-by: Madhav Kandukuri <[email protected]> * Fix tests Signed-off-by: Madhav Kandukuri <[email protected]> * Update doctest for check_health_for_gatways Signed-off-by: Madhav Kandukuri <[email protected]> * Linting fixes Signed-off-by: Madhav Kandukuri <[email protected]> * Fix pylint issues Signed-off-by: Madhav Kandukuri <[email protected]> * UI multi tenancy gaps (#1040) * visibility fix, team id in consistency fix, other minor fixes * fixed test cases * lint web fixes Signed-off-by: Satya <[email protected]> * updated tools view metadata * metadata visibility check Tools, A2A Signed-off-by: Satya <[email protected]> * rebase Signed-off-by: Satya <[email protected]> * lint-web fix Signed-off-by: Satya <[email protected]> * fix for private visibility to user specific Signed-off-by: Satya <[email protected]> --------- Signed-off-by: Satya <[email protected]> * The system executed 5 runs with a 0% success rate, an average response time of 0.393 ms, and an error rate of 0%. (#1103) Signed-off-by: NAYANAR <[email protected]> Co-authored-by: NAYANAR <[email protected]> * Pass auth headers when gateway auth is None (#1115) * code change as in issue Signed-off-by: Madhav Kandukuri <[email protected]> * Update tests Signed-off-by: Madhav Kandukuri <[email protected]> * Update README.md * Update README.md Signed-off-by: Shriti Priya <[email protected]> * Update README.md Signed-off-by: Shriti Priya <[email protected]> * WIP: Plugin Framework Specification Document (#1118) * docs: initial revision plugins spec Signed-off-by: Teryl Taylor <[email protected]> * docs(spec): moved plugin spec and broke into subpages. Signed-off-by: Teryl Taylor <[email protected]> * docs(spec): added some administrative hooks to spec Signed-off-by: Teryl Taylor <[email protected]> * (feat): Markdown fixes and added future hooks. Signed-off-by: Ian Molloy <[email protected]> --------- Signed-off-by: Teryl Taylor <[email protected]> Signed-off-by: Ian Molloy <[email protected]> Co-authored-by: Teryl Taylor <[email protected]> Co-authored-by: Ian Molloy <[email protected]> * plugins spec update Signed-off-by: Mihai Criveti <[email protected]> * Removing files Signed-off-by: Shriti Priya <[email protected]> * Removing files Signed-off-by: Shriti Priya <[email protected]> * Adding default allow response Signed-off-by: Shriti Priya <[email protected]> * Linting fixes, caching regex and toxicity filter, docker-compose edits Signed-off-by: Shriti Priya <[email protected]> * Update README.md Signed-off-by: Shriti Priya <[email protected]> * Update README.md Signed-off-by: Shriti Priya <[email protected]> * Update README.md Signed-off-by: Shriti Priya <[email protected]> * fix: solve linting issues Signed-off-by: Shriti Priya <[email protected]> --------- Signed-off-by: Shriti Priya <[email protected]> Signed-off-by: Teryl Taylor <[email protected]> Signed-off-by: Mihai Criveti <[email protected]> Signed-off-by: Madhav Kandukuri <[email protected]> Signed-off-by: Frederico Araujo <[email protected]> Signed-off-by: Alexander Cobas Rodríguez <[email protected]> Signed-off-by: Satya <[email protected]> Signed-off-by: NAYANAR <[email protected]> Signed-off-by: Ian Molloy <[email protected]> Co-authored-by: Teryl Taylor <[email protected]> Co-authored-by: Mihai Criveti <[email protected]> Co-authored-by: Madhav Kandukuri <[email protected]> Co-authored-by: Frederico Araujo <[email protected]> Co-authored-by: alex-cobas <[email protected]> Co-authored-by: Madhav Kandukuri <[email protected]> Co-authored-by: Satya <[email protected]> Co-authored-by: Nayana R Gowda <[email protected]> Co-authored-by: NAYANAR <[email protected]> Co-authored-by: terylt <[email protected]> Co-authored-by: Ian Molloy <[email protected]>
1 parent 00cd520 commit 56b2de3

32 files changed

+3917
-19
lines changed

MANIFEST.in

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,3 +172,13 @@ exclude plugins/external/opa/MANIFEST.in
172172
exclude plugins/external/opa/opaserver/rego/example.rego
173173
exclude plugins/external/opa/pyproject.toml
174174
exclude plugins/external/opa/run-server.sh
175+
176+
# Exclude llmguard
177+
exclude plugins/external/llmguard/.dockerignore
178+
exclude plugins/external/llmguard/.env.template
179+
exclude plugins/external/llmguard/.ruff.toml
180+
exclude plugins/external/llmguard/Containerfile
181+
exclude plugins/external/llmguard/MANIFEST.in
182+
exclude plugins/external/llmguard/opaserver/rego/example.rego
183+
exclude plugins/external/llmguard/pyproject.toml
184+
exclude plugins/external/llmguard/run-server.sh

mcpgateway/plugins/framework/external/mcp/client.py

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -135,29 +135,54 @@ async def __connect_to_stdio_server(self, server_script_path: str) -> None:
135135
raise PluginError(error=convert_exception_to_error(e, plugin_name=self.name))
136136

137137
async def __connect_to_http_server(self, uri: str) -> None:
138-
"""Connect to an MCP plugin server via streamable http.
138+
"""Connect to an MCP plugin server via streamable http with retry logic.
139139
140140
Args:
141141
uri: the URI of the mcp plugin server.
142142
143143
Raises:
144-
PluginError: if there is an external connection error.
144+
PluginError: if there is an external connection error after all retries.
145145
"""
146-
147-
try:
148-
http_transport = await self._exit_stack.enter_async_context(streamablehttp_client(uri))
149-
self._http, self._write, _ = http_transport
150-
self._session = await self._exit_stack.enter_async_context(ClientSession(self._http, self._write))
151-
152-
await self._session.initialize()
153-
154-
# List available tools
155-
response = await self._session.list_tools()
156-
tools = response.tools
157-
logger.info("\nConnected to plugin MCP (http) server with tools: %s", " ".join([tool.name for tool in tools]))
158-
except Exception as e:
159-
logger.exception(e)
160-
raise PluginError(error=convert_exception_to_error(e, plugin_name=self.name))
146+
max_retries = 3
147+
base_delay = 1.0
148+
149+
for attempt in range(max_retries):
150+
logger.info(f"Connecting to external plugin server: {uri} (attempt {attempt + 1}/{max_retries})")
151+
152+
try:
153+
# Create a fresh exit stack for each attempt
154+
async with AsyncExitStack() as temp_stack:
155+
http_transport = await temp_stack.enter_async_context(streamablehttp_client(uri))
156+
http_client, write_func, _ = http_transport
157+
session = await temp_stack.enter_async_context(ClientSession(http_client, write_func))
158+
159+
await session.initialize()
160+
161+
# List available tools
162+
response = await session.list_tools()
163+
tools = response.tools
164+
logger.info("Successfully connected to plugin MCP server with tools: %s", " ".join([tool.name for tool in tools]))
165+
166+
# Success! Now move to the main exit stack
167+
self._http = await self._exit_stack.enter_async_context(streamablehttp_client(uri))
168+
self._http, self._write, _ = self._http
169+
self._session = await self._exit_stack.enter_async_context(ClientSession(self._http, self._write))
170+
await self._session.initialize()
171+
return
172+
173+
except Exception as e:
174+
logger.warning(f"Connection attempt {attempt + 1}/{max_retries} failed: {e}")
175+
176+
if attempt == max_retries - 1:
177+
# Final attempt failed
178+
error_msg = f"External plugin '{self.name}' connection failed after {max_retries} attempts: {uri} is not reachable. Please ensure the MCP server is running."
179+
logger.error(error_msg)
180+
raise PluginError(error=PluginErrorModel(message=error_msg, plugin_name=self.name))
181+
await self.shutdown()
182+
# Wait before retry
183+
delay = base_delay * (2**attempt)
184+
logger.info(f"Retrying in {delay}s...")
185+
await asyncio.sleep(delay)
161186

162187
async def __invoke_hook(self, payload_result_model: Type[P], hook_type: HookType, payload: BaseModel, context: PluginContext) -> P:
163188
"""Invoke an external plugin hook using the MCP protocol.
@@ -296,4 +321,5 @@ async def __get_plugin_config(self) -> PluginConfig | None:
296321

297322
async def shutdown(self) -> None:
298323
"""Plugin cleanup code."""
299-
await self._exit_stack.aclose()
324+
if self._exit_stack:
325+
await self._exit_stack.aclose()

plugins/external/config.yaml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
# plugins/config.yaml - Main plugin configuration file
2-
32
plugins:
43
- name: "DenyListPlugin"
54
kind: "external"
@@ -14,6 +13,13 @@ plugins:
1413
proto: STREAMABLEHTTP
1514
url: http://127.0.0.1:8000/mcp
1615

16+
- name: "LLMGuardPlugin"
17+
kind: "external"
18+
priority: 20 # adjust the priority
19+
mcp:
20+
proto: STREAMABLEHTTP
21+
url: http://127.0.0.1:8001/mcp
22+
1723
# Plugin directories to scan
1824
plugin_dirs:
1925
- "plugins/native" # Built-in plugins

0 commit comments

Comments
 (0)