Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
1badaba
making cryptography version compatible with llmguard
monshri Sep 11, 2025
a08f322
lower bound
monshri Sep 11, 2025
d295f62
Initial plugin implementation using llmguard
monshri Sep 11, 2025
c53ca74
changes for input and output filters
monshri Sep 15, 2025
84ebb4f
documentation on functions of llmguard.py
monshri Sep 15, 2025
5e21ab6
Adding documentation and minor bug fixes
monshri Sep 15, 2025
5fae48c
linting changes
monshri Sep 15, 2025
75cc1ef
Updating cryptogrpahy dependency in conatinerfile for llmguard
monshri Sep 15, 2025
be34c88
Reverting the cryptogrpahy package version in root pyproject.toml
monshri Sep 15, 2025
efed00d
Updating manifest.in file
monshri Sep 15, 2025
74ee428
adding make test in container
monshri Sep 16, 2025
6000074
Merge remote-tracking branch 'origin' into feat/229-llmguard-plugin-dev
monshri Sep 16, 2025
30aca45
fix: fixed retry on client plugin connection.
Sep 16, 2025
2f4e3ce
Changing port for llmguard
monshri Sep 16, 2025
f16aa41
Merge branch 'IBM:main' into fix/plugin_mcp_http_client_retry
monshri Sep 16, 2025
979beb2
Merge remote-tracking branch 'remotes/teryl/fix/plugin_mcp_http_clien…
monshri Sep 16, 2025
e89d9b6
Pre-caching the scanners during container build
monshri Sep 18, 2025
58f584f
Merge remote-tracking branch 'origin' into feat/229-llmguard-plugin-dev
monshri Sep 18, 2025
c7a8da3
test cases
monshri Sep 18, 2025
253bc94
filters and sanitizers
monshri Sep 18, 2025
cacec70
Vault caching for anonymize and deanoymize, examples
monshri Sep 19, 2025
8ce6cab
vault caching and expiry ttl, vault leak detection and redis caching
monshri Sep 22, 2025
8bd61a5
adding test cases
monshri Sep 22, 2025
8c0866d
Adding test cases for vault and sanitizers
monshri Sep 24, 2025
0ffcd65
Documentation and test cases for LLMGuardPlugin
monshri Sep 25, 2025
ed9a98a
Updating readme for plugin
monshri Sep 25, 2025
587d32d
Updating readme for plugin
monshri Sep 25, 2025
cea9171
Updating readme for plugin
monshri Sep 25, 2025
a5556f5
Updating readme for plugin
monshri Sep 25, 2025
046daac
Updating yaml formatting in documentation
monshri Sep 26, 2025
a558aa6
Adding some examples, test cases for complex policiies and documentat…
monshri Sep 26, 2025
1c333ac
Pandoc MCP Server (#1044)
crivetimihai Sep 18, 2025
27019fa
Massive mcp server and plugin update (#1051)
crivetimihai Sep 19, 2025
b57bacd
OAuth token multitenancy closes #1078 (user-scoped tokens) and #1023 …
crivetimihai Sep 20, 2025
b3f8604
Documentation update readmes (#1087)
crivetimihai Sep 21, 2025
e9f8b82
Documentation updates (#1088)
crivetimihai Sep 21, 2025
dd4553e
Documentation updates (#1089)
crivetimihai Sep 21, 2025
1f8f60e
Test tokens (#1090)
crivetimihai Sep 21, 2025
c632108
Update mcp servers (#1091)
crivetimihai Sep 21, 2025
d7ff1a8
PM MCP Server
crivetimihai Sep 21, 2025
b28faab
PM MCP Server
crivetimihai Sep 21, 2025
b8c1444
PM MCP Server
crivetimihai Sep 21, 2025
02ea00b
Fixes OAuth after addition of signature to state (#1097)
madhav165 Sep 22, 2025
df9b703
feat: add opa policy input data mapping support (#1102)
araujof Sep 23, 2025
c8404b1
fix: multi-arch support for opa server (#1106)
araujof Sep 24, 2025
cfd42db
docs: add Terraform MCP Server and Gateway integration guide (#1083)
alex-cobas Sep 24, 2025
4c2ff16
copied from main
madhav165 Sep 22, 2025
55d8b69
testing changes
madhav165 Sep 22, 2025
71ed6f9
Linting fixes
madhav165 Sep 22, 2025
ed814a0
remove debug_team_dropdown.md
madhav165 Sep 22, 2025
b462b22
copied from fix-oauth
madhav165 Sep 22, 2025
c348d7b
OAuth for test gateway
madhav165 Sep 22, 2025
010f4ca
testing
madhav165 Sep 23, 2025
573ed14
testing
madhav165 Sep 23, 2025
fe06366
Fix tests
madhav165 Sep 24, 2025
7cc77e2
Update doctest for check_health_for_gatways
madhav165 Sep 24, 2025
b742980
Linting fixes
madhav165 Sep 24, 2025
c81aa3b
Fix pylint issues
madhav165 Sep 24, 2025
8d4e598
UI multi tenancy gaps (#1040)
TS0713 Sep 25, 2025
64361b3
The system executed 5 runs with a 0% success rate, an average respons…
Nayana-R-Gowda Sep 25, 2025
30e9cd8
Pass auth headers when gateway auth is None (#1115)
madhav165 Sep 25, 2025
d34d0b9
Update README.md
crivetimihai Sep 26, 2025
0c3596e
Update README.md
monshri Sep 26, 2025
e0b9958
Update README.md
monshri Sep 26, 2025
c4a83d0
WIP: Plugin Framework Specification Document (#1118)
terylt Sep 26, 2025
9e378ff
plugins spec update
crivetimihai Sep 26, 2025
852328e
Removing files
monshri Sep 26, 2025
2d39fa1
Removing files
monshri Sep 26, 2025
06ffb73
Adding default allow response
monshri Sep 26, 2025
f533e9f
Linting fixes, caching regex and toxicity filter, docker-compose edits
monshri Sep 26, 2025
dc35cd6
Update README.md
monshri Sep 26, 2025
85fe3c5
Update README.md
monshri Sep 26, 2025
996d275
Update README.md
monshri Sep 26, 2025
32175d1
fix: solve linting issues
monshri Sep 27, 2025
9b0b3b2
Merge main into feature branch
monshri Sep 27, 2025
c638ad0
Merge branch 'IBM:main' into feat/229-llmguard-plugin-dev
monshri Sep 27, 2025
26989a9
Merge remote-tracking branch 'origin/main' into feat/229-llmguard-plu…
monshri Sep 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,13 @@ exclude plugins/external/opa/MANIFEST.in
exclude plugins/external/opa/opaserver/rego/example.rego
exclude plugins/external/opa/pyproject.toml
exclude plugins/external/opa/run-server.sh

# Exclude llmguard
exclude plugins/external/llmguard/.dockerignore
exclude plugins/external/llmguard/.env.template
exclude plugins/external/llmguard/.ruff.toml
exclude plugins/external/llmguard/Containerfile
exclude plugins/external/llmguard/MANIFEST.in
exclude plugins/external/llmguard/opaserver/rego/example.rego
exclude plugins/external/llmguard/pyproject.toml
exclude plugins/external/llmguard/run-server.sh
62 changes: 44 additions & 18 deletions mcpgateway/plugins/framework/external/mcp/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,29 +135,54 @@ async def __connect_to_stdio_server(self, server_script_path: str) -> None:
raise PluginError(error=convert_exception_to_error(e, plugin_name=self.name))

async def __connect_to_http_server(self, uri: str) -> None:
"""Connect to an MCP plugin server via streamable http.
"""Connect to an MCP plugin server via streamable http with retry logic.

Args:
uri: the URI of the mcp plugin server.

Raises:
PluginError: if there is an external connection error.
PluginError: if there is an external connection error after all retries.
"""

try:
http_transport = await self._exit_stack.enter_async_context(streamablehttp_client(uri))
self._http, self._write, _ = http_transport
self._session = await self._exit_stack.enter_async_context(ClientSession(self._http, self._write))

await self._session.initialize()

# List available tools
response = await self._session.list_tools()
tools = response.tools
logger.info("\nConnected to plugin MCP (http) server with tools: %s", " ".join([tool.name for tool in tools]))
except Exception as e:
logger.exception(e)
raise PluginError(error=convert_exception_to_error(e, plugin_name=self.name))
max_retries = 3
base_delay = 1.0

for attempt in range(max_retries):
logger.info(f"Connecting to external plugin server: {uri} (attempt {attempt + 1}/{max_retries})")

try:
# Create a fresh exit stack for each attempt
async with AsyncExitStack() as temp_stack:
http_transport = await temp_stack.enter_async_context(streamablehttp_client(uri))
http_client, write_func, _ = http_transport
session = await temp_stack.enter_async_context(ClientSession(http_client, write_func))

await session.initialize()

# List available tools
response = await session.list_tools()
tools = response.tools
logger.info("Successfully connected to plugin MCP server with tools: %s", " ".join([tool.name for tool in tools]))

# Success! Now move to the main exit stack
self._http = await self._exit_stack.enter_async_context(streamablehttp_client(uri))
self._http, self._write, _ = self._http
self._session = await self._exit_stack.enter_async_context(ClientSession(self._http, self._write))
await self._session.initialize()
return

except Exception as e:
logger.warning(f"Connection attempt {attempt + 1}/{max_retries} failed: {e}")

if attempt == max_retries - 1:
# Final attempt failed
error_msg = f"External plugin '{self.name}' connection failed after {max_retries} attempts: {uri} is not reachable. Please ensure the MCP server is running."
logger.error(error_msg)
raise PluginError(error=PluginErrorModel(message=error_msg, plugin_name=self.name))
await self.shutdown()
# Wait before retry
delay = base_delay * (2**attempt)
logger.info(f"Retrying in {delay}s...")
await asyncio.sleep(delay)

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

async def shutdown(self) -> None:
"""Plugin cleanup code."""
await self._exit_stack.aclose()
if self._exit_stack:
await self._exit_stack.aclose()
8 changes: 7 additions & 1 deletion plugins/external/config.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# plugins/config.yaml - Main plugin configuration file

plugins:
- name: "DenyListPlugin"
kind: "external"
Expand All @@ -14,6 +13,13 @@ plugins:
proto: STREAMABLEHTTP
url: http://127.0.0.1:8000/mcp

- name: "LLMGuardPlugin"
kind: "external"
priority: 20 # adjust the priority
mcp:
proto: STREAMABLEHTTP
url: http://127.0.0.1:8001/mcp

# Plugin directories to scan
plugin_dirs:
- "plugins/native" # Built-in plugins
Expand Down
Loading
Loading