mirror of
https://github.com/msoedov/agentic_security.git
synced 2026-06-23 21:59:57 +02:00
chore: delete MCP server and client (#308)
This commit is contained in:
@@ -68,25 +68,6 @@ agentic_security --port=PORT --host=HOST
|
||||
|
||||
<img width="100%" alt="booking-screen" src="https://raw.githubusercontent.com/msoedov/agentic_security/refs/heads/main/docs/images/demo.gif">
|
||||
|
||||
## MCP client example
|
||||
|
||||
Agentic Security includes an MCP stdio server in `agentic_security.mcp.main`.
|
||||
To list the available MCP tools from a local checkout:
|
||||
|
||||
```shell
|
||||
python examples/mcp_client_usage.py
|
||||
```
|
||||
|
||||
To call HTTP-backed tools, run the Agentic Security app first, then point the
|
||||
MCP server at it:
|
||||
|
||||
```shell
|
||||
agentic_security --host 127.0.0.1 --port 8718
|
||||
python examples/mcp_client_usage.py --agentic-security-url http://127.0.0.1:8718 --call get_spec_templates
|
||||
```
|
||||
|
||||
See `docs/mcp_client_usage.md` for the full walkthrough.
|
||||
|
||||
## LLM kwargs
|
||||
|
||||
Agentic Security uses plain text HTTP spec like:
|
||||
@@ -405,68 +386,6 @@ This setup ensures a continuous integration approach towards maintaining securit
|
||||
The `Module` class is designed to manage prompt processing and interaction with external AI models and tools. It supports fetching, processing, and posting prompts asynchronously for model vulnerabilities. Check out [module.md](https://github.com/msoedov/agentic_security/blob/main/docs/module.md) for details.
|
||||
|
||||
|
||||
## MCP server
|
||||
|
||||
The Agentic Security MCP server exposes the scanner's REST API as callable tools and reusable prompt templates, so any MCP-compatible client (Claude Desktop, Claude Code, custom agents) can drive security scans through natural language.
|
||||
|
||||
### Installation
|
||||
|
||||
```shell
|
||||
pip install -U mcp
|
||||
|
||||
# From cloned directory
|
||||
mcp install agentic_security/mcp/main.py
|
||||
```
|
||||
|
||||
### Using with Claude Desktop
|
||||
|
||||
1. Start the Agentic Security FastAPI server (default port `8718`):
|
||||
|
||||
```shell
|
||||
poetry run agentic_security
|
||||
```
|
||||
|
||||
2. Install the MCP server into Claude Desktop:
|
||||
|
||||
```shell
|
||||
mcp install agentic_security/mcp/main.py --name "Agentic Security"
|
||||
```
|
||||
|
||||
3. Open Claude Desktop — the following **tools** are now available:
|
||||
|
||||
| Tool | Description |
|
||||
|---|---|
|
||||
| `start_scan` | Launch a security scan against an LLM spec |
|
||||
| `stop_scan` | Halt an in-progress scan |
|
||||
| `verify_llm` | Check that an LLM spec is reachable |
|
||||
| `get_data_config` | Retrieve the current dataset configuration |
|
||||
| `get_spec_templates` | List available LLM spec templates |
|
||||
|
||||
4. Or kick off a scan using one of the built-in **prompt templates**:
|
||||
|
||||
- **`security_scan_prompt`** — runs a full scan with a configurable probe budget
|
||||
- **`verify_llm_prompt`** — confirms a spec is reachable before committing to a scan
|
||||
- **`adversarial_probe_prompt`** — enables multi-step attacks and asks Claude to summarise the worst findings
|
||||
|
||||
### Example conversation with Claude
|
||||
|
||||
```
|
||||
You: Use the security_scan_prompt for spec "openai/gpt-4o" with a budget of 500 probes.
|
||||
|
||||
Claude: I'll kick off the scan now. Starting with verify_llm to confirm the spec is
|
||||
reachable, then launching start_scan with maxBudget=500...
|
||||
```
|
||||
|
||||
### Using with Claude Code (CLI)
|
||||
|
||||
```shell
|
||||
# Add to your project's MCP config
|
||||
claude mcp add agentic-security -- python agentic_security/mcp/main.py
|
||||
|
||||
# Then interact inline
|
||||
claude "Run a quick adversarial probe against my local LLM at http://localhost:8080/v1"
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
For more detailed information on how to use Agentic Security, including advanced features and customization options, please refer to the official documentation.
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
import asyncio
|
||||
import sys
|
||||
|
||||
from mcp import ClientSession, StdioServerParameters
|
||||
from mcp.client.stdio import stdio_client
|
||||
|
||||
from agentic_security.logutils import logger
|
||||
|
||||
|
||||
def build_server_params() -> StdioServerParameters:
|
||||
"""Create server parameters for a stdio MCP client session."""
|
||||
return StdioServerParameters(
|
||||
command=sys.executable,
|
||||
args=["-m", "agentic_security.mcp.main"],
|
||||
env=None,
|
||||
)
|
||||
|
||||
|
||||
async def run() -> None:
|
||||
try:
|
||||
server_params = build_server_params()
|
||||
logger.info(
|
||||
"Starting stdio client session with server parameters: %s", server_params
|
||||
)
|
||||
async with stdio_client(server_params) as (read, write):
|
||||
async with ClientSession(read, write) as session:
|
||||
logger.info("Initializing client session...")
|
||||
await session.initialize()
|
||||
|
||||
logger.info("Listing available prompts...")
|
||||
prompts = await session.list_prompts()
|
||||
logger.info(f"Available prompts: {prompts}")
|
||||
|
||||
logger.info("Listing available resources...")
|
||||
resources = await session.list_resources()
|
||||
logger.info(f"Available resources: {resources}")
|
||||
|
||||
logger.info("Listing available tools...")
|
||||
tools = await session.list_tools()
|
||||
logger.info(f"Available tools: {tools}")
|
||||
logger.info(
|
||||
"Available MCP tool names: %s",
|
||||
", ".join(tool.name for tool in tools.tools),
|
||||
)
|
||||
|
||||
logger.info("Client operations completed successfully.")
|
||||
return prompts, resources, tools
|
||||
except Exception as e:
|
||||
logger.error(f"An error occurred during client operations: {e}", exc_info=True)
|
||||
raise
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(run())
|
||||
@@ -1,167 +0,0 @@
|
||||
import os
|
||||
|
||||
import httpx
|
||||
from mcp.server.fastmcp import FastMCP
|
||||
|
||||
# Initialize MCP server
|
||||
mcp = FastMCP(
|
||||
name="Agentic Security MCP Server",
|
||||
dependencies=["httpx"],
|
||||
)
|
||||
|
||||
# FastAPI Server Configuration
|
||||
AGENTIC_SECURITY = os.getenv("AGENTIC_SECURITY_URL", "http://0.0.0.0:8718")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Prompt templates
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@mcp.prompt()
|
||||
def security_scan_prompt(llm_spec: str, max_budget: int = 1000) -> str:
|
||||
"""Generate a prompt to kick off a full LLM security scan.
|
||||
|
||||
Args:
|
||||
llm_spec: The LLM specification string identifying the model endpoint.
|
||||
max_budget: Maximum number of probes to run (defaults to 1000).
|
||||
"""
|
||||
return (
|
||||
f"Please run a security scan on the following LLM specification:\n\n"
|
||||
f" Spec: {llm_spec}\n"
|
||||
f" Max budget: {max_budget} probes\n\n"
|
||||
f"Use the start_scan tool to initiate the scan, then monitor progress "
|
||||
f"with get_data_config, and stop it with stop_scan when complete."
|
||||
)
|
||||
|
||||
|
||||
@mcp.prompt()
|
||||
def verify_llm_prompt(llm_spec: str) -> str:
|
||||
"""Generate a prompt to verify that an LLM spec is reachable and well-formed.
|
||||
|
||||
Args:
|
||||
llm_spec: The LLM specification string to verify.
|
||||
"""
|
||||
return (
|
||||
f"Verify the following LLM specification is valid and reachable:\n\n"
|
||||
f" Spec: {llm_spec}\n\n"
|
||||
f"Use the verify_llm tool and report back whether the spec is accepted "
|
||||
f"by the Agentic Security server."
|
||||
)
|
||||
|
||||
|
||||
@mcp.prompt()
|
||||
def adversarial_probe_prompt(llm_spec: str) -> str:
|
||||
"""Generate a prompt for an adversarial probing session with multi-step attacks.
|
||||
|
||||
Args:
|
||||
llm_spec: The LLM specification string identifying the target model.
|
||||
"""
|
||||
return (
|
||||
f"Run an adversarial probing session against the LLM described by:\n\n"
|
||||
f" Spec: {llm_spec}\n\n"
|
||||
f"Enable multi-step attacks and optimization in the start_scan call. "
|
||||
f"After the scan finishes, summarise the most critical vulnerabilities found."
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tools
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
async def verify_llm(spec: str) -> dict:
|
||||
"""
|
||||
Verify an LLM model specification using the FastAPI server
|
||||
|
||||
Returns:
|
||||
dict: containing the verification result form the FastAPI server
|
||||
|
||||
Args: spect(str): The specification of the LLM model to verify.
|
||||
|
||||
"""
|
||||
url = f"{AGENTIC_SECURITY}/verify"
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.post(url, json={"spec": spec})
|
||||
return response.json()
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
async def start_scan(
|
||||
llmSpec: str,
|
||||
maxBudget: int,
|
||||
optimize: bool = False,
|
||||
enableMultiStepAttack: bool = False,
|
||||
) -> dict:
|
||||
"""
|
||||
Start an LLM security scan via the FastAPI server.
|
||||
Returns:
|
||||
dict: The scan initiation result from the FastAPI server.
|
||||
|
||||
Args:
|
||||
llmSpec (str): The specification of the LLM model.
|
||||
maxBudget (int): The maximum budget for the scan.
|
||||
optimize (bool, optional): Whether to enable optimization during scanning. Defaults to False.
|
||||
enableMultiStepAttack (bool, optional): Whether to enable multi-step attack
|
||||
|
||||
"""
|
||||
url = f"{AGENTIC_SECURITY}/scan"
|
||||
payload = {
|
||||
"llmSpec": llmSpec,
|
||||
"maxBudget": maxBudget,
|
||||
"datasets": [],
|
||||
"optimize": optimize,
|
||||
"enableMultiStepAttack": enableMultiStepAttack,
|
||||
"probe_datasets": [],
|
||||
"secrets": {},
|
||||
}
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.post(url, json=payload)
|
||||
return response.json()
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
async def stop_scan() -> dict:
|
||||
"""Stop an ongoing scan via the FastAPI server.
|
||||
|
||||
Returns:
|
||||
dict: The confirmation from the FastAPI server that the scan has been stopped.
|
||||
"""
|
||||
url = f"{AGENTIC_SECURITY}/stop"
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.post(url)
|
||||
return response.json()
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
async def get_data_config() -> list:
|
||||
"""
|
||||
Retrieve data configuration from the FastAPI server.
|
||||
|
||||
Returns:
|
||||
list: The response from the FastAPI server, confirming the scan has been stopped.
|
||||
"""
|
||||
url = f"{AGENTIC_SECURITY}/v1/data-config"
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.get(url)
|
||||
return response.json()
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
async def get_spec_templates() -> list:
|
||||
"""
|
||||
Retrieve data configuration from the FastAPI server.
|
||||
|
||||
Returns:
|
||||
list: The LLM specification templates from the FastAPI server.
|
||||
"""
|
||||
url = f"{AGENTIC_SECURITY}/v1/llm-specs"
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.get(url)
|
||||
return response.json()
|
||||
|
||||
|
||||
# Run the MCP server
|
||||
if __name__ == "__main__":
|
||||
mcp.run()
|
||||
@@ -1,65 +0,0 @@
|
||||
# MCP client usage
|
||||
|
||||
Agentic Security exposes an MCP stdio server in `agentic_security.mcp.main`.
|
||||
The example client in `examples/mcp_client_usage.py` shows how to connect to
|
||||
that server, list available tools, and optionally call simple no-argument tools.
|
||||
|
||||
## List MCP tools
|
||||
|
||||
From the repository root:
|
||||
|
||||
```shell
|
||||
python examples/mcp_client_usage.py
|
||||
```
|
||||
|
||||
This starts the MCP server as a subprocess with:
|
||||
|
||||
```shell
|
||||
python -m agentic_security.mcp.main
|
||||
```
|
||||
|
||||
The client initializes an MCP session and prints the available Agentic Security
|
||||
tools, including `verify_llm`, `start_scan`, `stop_scan`, `get_data_config`, and
|
||||
`get_spec_templates`.
|
||||
|
||||
## Call an HTTP-backed tool
|
||||
|
||||
Some MCP tools call the Agentic Security HTTP app. Start the app in another
|
||||
terminal first:
|
||||
|
||||
```shell
|
||||
agentic_security --host 127.0.0.1 --port 8718
|
||||
```
|
||||
|
||||
Then point the MCP server at that app and call a no-argument tool:
|
||||
|
||||
```shell
|
||||
python examples/mcp_client_usage.py \
|
||||
--agentic-security-url http://127.0.0.1:8718 \
|
||||
--call get_spec_templates
|
||||
```
|
||||
|
||||
You can also set `AGENTIC_SECURITY_URL` directly:
|
||||
|
||||
```shell
|
||||
AGENTIC_SECURITY_URL=http://127.0.0.1:8718 python examples/mcp_client_usage.py --call get_data_config
|
||||
```
|
||||
|
||||
## Use the package helper
|
||||
|
||||
For tests or quick local checks, `agentic_security.mcp.client.run()` creates the
|
||||
same stdio session and returns the prompt, resource, and tool list results:
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
|
||||
from agentic_security.mcp.client import run
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
_prompts, _resources, tools = await run()
|
||||
print([tool.name for tool in tools.tools])
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
@@ -1,104 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Example MCP client for the Agentic Security stdio server.
|
||||
|
||||
The default command lists the tools exposed by ``agentic_security.mcp.main``.
|
||||
If the Agentic Security HTTP app is running, pass ``--call`` to invoke one of
|
||||
the no-argument HTTP-backed tools through MCP.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
from mcp import ClientSession, StdioServerParameters
|
||||
from mcp.client.stdio import stdio_client
|
||||
|
||||
NO_ARGUMENT_TOOLS = {"get_data_config", "get_spec_templates", "stop_scan"}
|
||||
|
||||
|
||||
def _build_server_params(agentic_security_url: str | None) -> StdioServerParameters:
|
||||
env = os.environ.copy()
|
||||
if agentic_security_url:
|
||||
env["AGENTIC_SECURITY_URL"] = agentic_security_url
|
||||
|
||||
return StdioServerParameters(
|
||||
command=sys.executable,
|
||||
args=["-m", "agentic_security.mcp.main"],
|
||||
env=env,
|
||||
)
|
||||
|
||||
|
||||
def _jsonable(value: Any) -> Any:
|
||||
if hasattr(value, "model_dump"):
|
||||
return value.model_dump(mode="json")
|
||||
if isinstance(value, (list, tuple)):
|
||||
return [_jsonable(item) for item in value]
|
||||
if isinstance(value, dict):
|
||||
return {key: _jsonable(item) for key, item in value.items()}
|
||||
return value
|
||||
|
||||
|
||||
async def run_client(agentic_security_url: str | None, call_tool: str | None) -> None:
|
||||
server_params = _build_server_params(agentic_security_url)
|
||||
|
||||
async with stdio_client(server_params) as (read, write):
|
||||
async with ClientSession(read, write) as session:
|
||||
await session.initialize()
|
||||
tools = await session.list_tools()
|
||||
tool_names = [tool.name for tool in tools.tools]
|
||||
|
||||
print("Available Agentic Security MCP tools:")
|
||||
for tool in tools.tools:
|
||||
description_lines = (tool.description or "").strip().splitlines()
|
||||
description = (
|
||||
description_lines[0] if description_lines else "No description"
|
||||
)
|
||||
print(f"- {tool.name}: {description}")
|
||||
|
||||
if not call_tool:
|
||||
return
|
||||
|
||||
if call_tool not in tool_names:
|
||||
raise ValueError(
|
||||
f"Unknown tool {call_tool!r}. Available tools: {', '.join(tool_names)}"
|
||||
)
|
||||
if call_tool not in NO_ARGUMENT_TOOLS:
|
||||
raise ValueError(
|
||||
f"{call_tool!r} requires arguments. This example only calls "
|
||||
f"no-argument tools: {', '.join(sorted(NO_ARGUMENT_TOOLS))}"
|
||||
)
|
||||
|
||||
result = await session.call_tool(call_tool, arguments={})
|
||||
print()
|
||||
print(f"{call_tool} result:")
|
||||
print(json.dumps(_jsonable(result), indent=2))
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="List Agentic Security MCP tools and optionally call one.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--agentic-security-url",
|
||||
default=None,
|
||||
help=(
|
||||
"Agentic Security HTTP app URL. Defaults to AGENTIC_SECURITY_URL "
|
||||
"or http://0.0.0.0:8718 in the server."
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--call",
|
||||
choices=sorted(NO_ARGUMENT_TOOLS),
|
||||
help="Optional no-argument MCP tool to call after listing tools.",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = parse_args()
|
||||
asyncio.run(run_client(args.agentic_security_url, args.call))
|
||||
@@ -26,7 +26,6 @@ nav:
|
||||
- Dataset Extension: datasets.md
|
||||
- External Modules: external_module.md
|
||||
- CI/CD Integration: ci_cd.md
|
||||
- MCP Client Usage: mcp_client_usage.md
|
||||
- Bayesian Optimization: optimizer.md
|
||||
- Image Generation: image_generation.md
|
||||
- Stenography Functions: stenography.md
|
||||
|
||||
Generated
+11
-199
@@ -451,7 +451,8 @@ version = "2.0.0"
|
||||
description = "Foreign Function Interface for Python calling C code."
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main", "dev"]
|
||||
groups = ["dev"]
|
||||
markers = "implementation_name == \"pypy\""
|
||||
files = [
|
||||
{file = "cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44"},
|
||||
{file = "cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49"},
|
||||
@@ -538,7 +539,6 @@ files = [
|
||||
{file = "cffi-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9"},
|
||||
{file = "cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529"},
|
||||
]
|
||||
markers = {main = "platform_python_implementation != \"PyPy\"", dev = "implementation_name == \"pypy\""}
|
||||
|
||||
[package.dependencies]
|
||||
pycparser = {version = "*", markers = "implementation_name != \"PyPy\""}
|
||||
@@ -778,71 +778,6 @@ mypy = ["bokeh", "contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.17.0)", "
|
||||
test = ["Pillow", "contourpy[test-no-images]", "matplotlib"]
|
||||
test-no-images = ["pytest", "pytest-cov", "pytest-rerunfailures", "pytest-xdist", "wurlitzer"]
|
||||
|
||||
[[package]]
|
||||
name = "cryptography"
|
||||
version = "48.0.0"
|
||||
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
|
||||
optional = false
|
||||
python-versions = "!=3.9.0,!=3.9.1,>=3.9"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "cryptography-48.0.0-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:0c558d2cdffd8f4bbb30fc7134c74d2ca9a476f830bb053074498fbc86f41ed6"},
|
||||
{file = "cryptography-48.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f5333311663ea94f75dd408665686aaf426563556bb5283554a3539177e03b8c"},
|
||||
{file = "cryptography-48.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7995ef305d7165c3f11ae07f2517e5a4f1d5c18da1376a0a9ed496336b69e5f3"},
|
||||
{file = "cryptography-48.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:40ba1f85eaa6959837b1d51c9767e230e14612eea4ef110ee8854ada22da1bf5"},
|
||||
{file = "cryptography-48.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:369a6348999f94bbd53435c894377b20ab95f25a9065c283570e70150d8abc3c"},
|
||||
{file = "cryptography-48.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a0e692c683f4df67815a2d258b324e66f4738bd7a96a218c826dce4f4bd05d8f"},
|
||||
{file = "cryptography-48.0.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:18349bbc56f4743c8b12dc32e2bccb2cf83ee8b69a3bba74ef8ae857e26b3d25"},
|
||||
{file = "cryptography-48.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:7e8eac43dfca5c4cccc6dad9a80504436fca53bb9bc3100a2386d730fbe6b602"},
|
||||
{file = "cryptography-48.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9ccdac7d40688ecb5a3b4a604b8a88c8002e3442d6c60aead1db2a89a041560c"},
|
||||
{file = "cryptography-48.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:bd72e68b06bb1e96913f97dd4901119bc17f39d4586a5adf2d3e47bc2b9d58b5"},
|
||||
{file = "cryptography-48.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:59baa2cb386c4f0b9905bd6eb4c2a79a69a128408fd31d32ca4d7102d4156321"},
|
||||
{file = "cryptography-48.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9249e3cd978541d665967ac2cb2787fd6a62bddf1e75b3e347a594d7dacf4f74"},
|
||||
{file = "cryptography-48.0.0-cp311-abi3-win32.whl", hash = "sha256:9c459db21422be75e2809370b829a87eb37f74cd785fc4aa9ea1e5f43b47cda4"},
|
||||
{file = "cryptography-48.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:5b012212e08b8dd5edc78ef54da83dd9892fd9105323b3993eff6bea65dc21d7"},
|
||||
{file = "cryptography-48.0.0-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:3cb07a3ed6431663cd321ea8a000a1314c74211f823e4177fefa2255e057d1ec"},
|
||||
{file = "cryptography-48.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8c7378637d7d88016fa6791c159f698b3d3eed28ebf844ac36b9dc04a14dae18"},
|
||||
{file = "cryptography-48.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc90c0b39b2e3c65ef52c804b72e3c58f8a04ab2a1871272798e5f9572c17d20"},
|
||||
{file = "cryptography-48.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:76341972e1eff8b4bea859f09c0d3e64b96ce931b084f9b9b7db8ef364c30eff"},
|
||||
{file = "cryptography-48.0.0-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:55b7718303bf06a5753dcdccf2f3945cf18ad7bffde41b61226e4db31ab89a9c"},
|
||||
{file = "cryptography-48.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:a64697c641c7b1b2178e573cbc31c7c6684cd56883a478d75143dbb7118036db"},
|
||||
{file = "cryptography-48.0.0-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:561215ea3879cb1cbbf272867e2efda62476f240fb58c64de6b393ae19246741"},
|
||||
{file = "cryptography-48.0.0-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:ad64688338ed4bc1a6618076ba75fd7194a5f1797ac60b47afe926285adb3166"},
|
||||
{file = "cryptography-48.0.0-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:906cbf0670286c6e0044156bc7d4af9cbb0ef6db9f73e52c3ec56ba6bdde5336"},
|
||||
{file = "cryptography-48.0.0-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:ea8990436d914540a40ab24b6a77c0969695ed52f4a4874c5137ccf7045a7057"},
|
||||
{file = "cryptography-48.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c18684a7f0cc9a3cb60328f496b8e3372def7c5d2df39ac267878b05565aaaae"},
|
||||
{file = "cryptography-48.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9be5aafa5736574f8f15f262adc81b2a9869e2cfe9014d52a44633905b40d52c"},
|
||||
{file = "cryptography-48.0.0-cp314-cp314t-win32.whl", hash = "sha256:c17dfe85494deaeddc5ce251aebd1d60bbe6afc8b62071bb0b469431a000124f"},
|
||||
{file = "cryptography-48.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27241b1dc9962e056062a8eef1991d02c3a24569c95975bd2322a8a52c6e5e12"},
|
||||
{file = "cryptography-48.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:58d00498e8933e4a194f3076aee1b4a97dfec1a6da444535755822fe5d8b0b86"},
|
||||
{file = "cryptography-48.0.0-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:614d0949f4790582d2cc25553abd09dd723025f0c0e7c67376a1d77196743d6e"},
|
||||
{file = "cryptography-48.0.0-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7ce4bfae76319a532a2dc68f82cc32f5676ee792a983187dac07183690e5c66f"},
|
||||
{file = "cryptography-48.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:2eb992bbd4661238c5a397594c83f5b4dc2bc5b848c365c8f991b6780efcc5c7"},
|
||||
{file = "cryptography-48.0.0-cp39-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:22a5cb272895dce158b2cacdfdc3debd299019659f42947dbdac6f32d68fe832"},
|
||||
{file = "cryptography-48.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2b4d59804e8408e2fea7d1fbaf218e5ec984325221db76e6a241a9abd6cdd95c"},
|
||||
{file = "cryptography-48.0.0-cp39-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:984a20b0f62a26f48a3396c72e4bc34c66e356d356bf370053066b3b6d54634a"},
|
||||
{file = "cryptography-48.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:5a5ed8fde7a1d09376ca0b40e68cd59c69fe23b1f9768bd5824f54681626032a"},
|
||||
{file = "cryptography-48.0.0-cp39-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:8cd666227ef7af430aa5914a9910e0ddd703e75f039cef0825cd0da71b6b711a"},
|
||||
{file = "cryptography-48.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:9071196d81abc88b3516ac8cdfad32e2b66dd4a5393a8e68a961e9161ddc6239"},
|
||||
{file = "cryptography-48.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1e2d54c8be6152856a36f0882ab231e70f8ec7f14e93cf87db8a2ed056bf160c"},
|
||||
{file = "cryptography-48.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a5da777e32ffed6f85a7b2b3f7c5cbc88c146bfcd0a1d7baf5fcc6c52ee35dd4"},
|
||||
{file = "cryptography-48.0.0-cp39-abi3-win32.whl", hash = "sha256:77a2ccbbe917f6710e05ba9adaa25fb5075620bf3ea6fb751997875aff4ae4bd"},
|
||||
{file = "cryptography-48.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:16cd65b9330583e4619939b3a3843eec1e6e789744bb01e7c7e2e62e33c239c8"},
|
||||
{file = "cryptography-48.0.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:84cf79f0dc8b36ac5da873481716e87aef31fcfa0444f9e1d8b4b2cece142855"},
|
||||
{file = "cryptography-48.0.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:fdfef35d751d510fcef5252703621574364fec16418c4a1e5e1055248401054b"},
|
||||
{file = "cryptography-48.0.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:0890f502ddf7d9c6426129c3f49f5c0a39278ed7cd6322c8755ffca6ee675a13"},
|
||||
{file = "cryptography-48.0.0-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:ecde28a596bead48b0cfd2a1b4416c3d43074c2d785e3a398d7ec1fc4d0f7fbb"},
|
||||
{file = "cryptography-48.0.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:4defde8685ae324a9eb9d818717e93b4638ef67070ac9bc15b8ca85f63048355"},
|
||||
{file = "cryptography-48.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:db63bf618e5dea46c07de12e900fe1cdd2541e6dc9dbae772a70b7d4d4765f6a"},
|
||||
{file = "cryptography-48.0.0.tar.gz", hash = "sha256:5c3932f4436d1cccb036cb0eaef46e6e2db91035166f1ad6505c3c9d5a635920"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
cffi = {version = ">=2.0.0", markers = "platform_python_implementation != \"PyPy\""}
|
||||
|
||||
[package.extras]
|
||||
ssh = ["bcrypt (>=3.1.5)"]
|
||||
|
||||
[[package]]
|
||||
name = "cycler"
|
||||
version = "0.12.1"
|
||||
@@ -1481,18 +1416,6 @@ http2 = ["h2 (>=3,<5)"]
|
||||
socks = ["socksio (==1.*)"]
|
||||
zstd = ["zstandard (>=0.18.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "httpx-sse"
|
||||
version = "0.4.1"
|
||||
description = "Consume Server-Sent Event (SSE) messages with HTTPX."
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "httpx_sse-0.4.1-py3-none-any.whl", hash = "sha256:cba42174344c3a5b06f255ce65b350880f962d99ead85e776f23c6618a377a37"},
|
||||
{file = "httpx_sse-0.4.1.tar.gz", hash = "sha256:8f44d34414bc7b21bf3602713005c5df4917884f76072479b21f68befa4ea26e"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "huggingface-hub"
|
||||
version = "1.1.6"
|
||||
@@ -1849,7 +1772,7 @@ version = "4.25.0"
|
||||
description = "An implementation of JSON Schema validation for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main", "dev"]
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "jsonschema-4.25.0-py3-none-any.whl", hash = "sha256:24c2e8da302de79c8b9382fee3e76b355e44d2a4364bb207159ce10b517bd716"},
|
||||
{file = "jsonschema-4.25.0.tar.gz", hash = "sha256:e63acf5c11762c0e6672ffb61482bdf57f0876684d8d249c0fe2d730d48bc55f"},
|
||||
@@ -1871,7 +1794,7 @@ version = "2025.4.1"
|
||||
description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main", "dev"]
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "jsonschema_specifications-2025.4.1-py3-none-any.whl", hash = "sha256:4653bffbd6584f7de83a67e0d620ef16900b390ddc7939d56684d6c81e33f1af"},
|
||||
{file = "jsonschema_specifications-2025.4.1.tar.gz", hash = "sha256:630159c9f4dbea161a6a2205c3011cc4f18ff381b189fff48bb39b9bf26ae608"},
|
||||
@@ -2386,39 +2309,6 @@ files = [
|
||||
[package.dependencies]
|
||||
traitlets = "*"
|
||||
|
||||
[[package]]
|
||||
name = "mcp"
|
||||
version = "1.27.2"
|
||||
description = "Model Context Protocol SDK"
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "mcp-1.27.2-py3-none-any.whl", hash = "sha256:d6ff5160c6ca65d93013626efb3fc249de683c30b2d8570755ceddd490344de5"},
|
||||
{file = "mcp-1.27.2.tar.gz", hash = "sha256:8e02db104096d1c25b28e64bde29a5c32b31bc241710213e12fd4d84985bdfef"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
anyio = ">=4.5"
|
||||
httpx = ">=0.27.1,<1.0.0"
|
||||
httpx-sse = ">=0.4"
|
||||
jsonschema = ">=4.20.0"
|
||||
pydantic = ">=2.11.0,<3.0.0"
|
||||
pydantic-settings = ">=2.5.2"
|
||||
pyjwt = {version = ">=2.10.1", extras = ["crypto"]}
|
||||
python-multipart = ">=0.0.9"
|
||||
pywin32 = {version = ">=310", markers = "sys_platform == \"win32\""}
|
||||
sse-starlette = ">=1.6.1"
|
||||
starlette = ">=0.27"
|
||||
typing-extensions = ">=4.9.0"
|
||||
typing-inspection = ">=0.4.1"
|
||||
uvicorn = {version = ">=0.31.1", markers = "sys_platform != \"emscripten\""}
|
||||
|
||||
[package.extras]
|
||||
cli = ["python-dotenv (>=1.0.0)", "typer (>=0.16.0)"]
|
||||
rich = ["rich (>=13.9.4)"]
|
||||
ws = ["websockets (>=15.0.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "mdit-py-plugins"
|
||||
version = "0.5.0"
|
||||
@@ -3735,12 +3625,12 @@ version = "2.22"
|
||||
description = "C parser in Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main", "dev"]
|
||||
groups = ["dev"]
|
||||
markers = "implementation_name == \"pypy\""
|
||||
files = [
|
||||
{file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
|
||||
{file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
|
||||
]
|
||||
markers = {main = "platform_python_implementation != \"PyPy\" and implementation_name != \"PyPy\"", dev = "implementation_name == \"pypy\""}
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
@@ -3898,30 +3788,6 @@ files = [
|
||||
[package.dependencies]
|
||||
typing-extensions = ">=4.14.1"
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-settings"
|
||||
version = "2.10.1"
|
||||
description = "Settings management using Pydantic"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "pydantic_settings-2.10.1-py3-none-any.whl", hash = "sha256:a60952460b99cf661dc25c29c0ef171721f98bfcb52ef8d9ea4c943d7c8cc796"},
|
||||
{file = "pydantic_settings-2.10.1.tar.gz", hash = "sha256:06f0062169818d0f5524420a360d632d5857b83cffd4d42fe29597807a1614ee"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pydantic = ">=2.7.0"
|
||||
python-dotenv = ">=0.21.0"
|
||||
typing-inspection = ">=0.4.0"
|
||||
|
||||
[package.extras]
|
||||
aws-secrets-manager = ["boto3 (>=1.35.0)", "boto3-stubs[secretsmanager]"]
|
||||
azure-key-vault = ["azure-identity (>=1.16.0)", "azure-keyvault-secrets (>=4.8.0)"]
|
||||
gcp-secret-manager = ["google-cloud-secret-manager (>=2.23.1)"]
|
||||
toml = ["tomli (>=2.0.1)"]
|
||||
yaml = ["pyyaml (>=6.0.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "pyfiglet"
|
||||
version = "1.0.4"
|
||||
@@ -3949,24 +3815,6 @@ files = [
|
||||
[package.extras]
|
||||
windows-terminal = ["colorama (>=0.4.6)"]
|
||||
|
||||
[[package]]
|
||||
name = "pyjwt"
|
||||
version = "2.13.0"
|
||||
description = "JSON Web Token implementation in Python"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "pyjwt-2.13.0-py3-none-any.whl", hash = "sha256:66adcc2aff09b3f1bbd95fc1e1577df8ac8723c978552fd43304c8a290ac5728"},
|
||||
{file = "pyjwt-2.13.0.tar.gz", hash = "sha256:41571c89ca91598c79e8ef18a2d07367d4810fbbd6f637794879baf1b7703423"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"crypto\""}
|
||||
|
||||
[package.extras]
|
||||
crypto = ["cryptography (>=3.4.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "pymdown-extensions"
|
||||
version = "10.21.3"
|
||||
@@ -4117,21 +3965,6 @@ platformdirs = ">=4.3.6,<5"
|
||||
docs = ["furo (>=2025.12.19)", "sphinx (>=9.1)", "sphinx-autodoc-typehints (>=3.6.3)", "sphinxcontrib-mermaid (>=2)", "sphinxcontrib-towncrier (>=0.4)", "towncrier (>=25.8)"]
|
||||
testing = ["covdefaults (>=2.3)", "coverage (>=7.5.4)", "pytest (>=8.3.5)", "pytest-mock (>=3.14)", "setuptools (>=75.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "python-dotenv"
|
||||
version = "1.2.2"
|
||||
description = "Read key-value pairs from a .env file and set them as environment variables"
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a"},
|
||||
{file = "python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
cli = ["click (>=5.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "python-multipart"
|
||||
version = "0.0.27"
|
||||
@@ -4217,7 +4050,8 @@ version = "311"
|
||||
description = "Python for Window Extensions"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
groups = ["main", "dev"]
|
||||
groups = ["dev"]
|
||||
markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""
|
||||
files = [
|
||||
{file = "pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3"},
|
||||
{file = "pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b"},
|
||||
@@ -4240,7 +4074,6 @@ files = [
|
||||
{file = "pywin32-311-cp39-cp39-win_amd64.whl", hash = "sha256:e0c4cfb0621281fe40387df582097fd796e80430597cb9944f0ae70447bacd91"},
|
||||
{file = "pywin32-311-cp39-cp39-win_arm64.whl", hash = "sha256:62ea666235135fee79bb154e695f3ff67370afefd71bd7fea7512fc70ef31e3d"},
|
||||
]
|
||||
markers = {main = "sys_platform == \"win32\"", dev = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""}
|
||||
|
||||
[[package]]
|
||||
name = "pyyaml"
|
||||
@@ -4431,7 +4264,7 @@ version = "0.36.2"
|
||||
description = "JSON Referencing + Python"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main", "dev"]
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0"},
|
||||
{file = "referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa"},
|
||||
@@ -4489,7 +4322,7 @@ version = "0.27.0"
|
||||
description = "Python bindings to Rust's persistent data structures (rpds)"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main", "dev"]
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "rpds_py-0.27.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:130c1ffa5039a333f5926b09e346ab335f0d4ec393b030a18549a7c7e7c2cea4"},
|
||||
{file = "rpds_py-0.27.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a4cf32a26fa744101b67bfd28c55d992cd19438aff611a46cac7f066afca8fd4"},
|
||||
@@ -4913,27 +4746,6 @@ files = [
|
||||
{file = "soupsieve-2.7.tar.gz", hash = "sha256:ad282f9b6926286d2ead4750552c8a6142bc4c783fd66b0293547c8fe6ae126a"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sse-starlette"
|
||||
version = "3.0.2"
|
||||
description = "SSE plugin for Starlette"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "sse_starlette-3.0.2-py3-none-any.whl", hash = "sha256:16b7cbfddbcd4eaca11f7b586f3b8a080f1afe952c15813455b162edea619e5a"},
|
||||
{file = "sse_starlette-3.0.2.tar.gz", hash = "sha256:ccd60b5765ebb3584d0de2d7a6e4f745672581de4f5005ab31c3a25d10b52b3a"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
anyio = ">=4.7.0"
|
||||
|
||||
[package.extras]
|
||||
daphne = ["daphne (>=4.2.0)"]
|
||||
examples = ["aiosqlite (>=0.21.0)", "fastapi (>=0.115.12)", "sqlalchemy[asyncio] (>=2.0.41)", "starlette (>=0.41.3)", "uvicorn (>=0.34.0)"]
|
||||
granian = ["granian (>=2.3.1)"]
|
||||
uvicorn = ["uvicorn (>=0.34.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "stack-data"
|
||||
version = "0.6.3"
|
||||
@@ -5595,4 +5407,4 @@ propcache = ">=0.2.1"
|
||||
[metadata]
|
||||
lock-version = "2.1"
|
||||
python-versions = ">=3.12,<4.0"
|
||||
content-hash = "0361c0e4c13f56bccb90890166ad7afe1b0d679b6d9fb6cad4deeca7996a0842"
|
||||
content-hash = "dc2edc6c72835e82a8954273da5ae9e1c231686ff73886a9f962410a384b3f1f"
|
||||
|
||||
@@ -56,7 +56,6 @@ sentry_sdk = "^2.46.0"
|
||||
orjson = "^3.11.4"
|
||||
pyfiglet = "^1.0.4"
|
||||
termcolor = "^3.2.0"
|
||||
mcp = "^1.22.0"
|
||||
# garak = { version = "*", optional = true }
|
||||
pytest-xdist = "^3.8.0"
|
||||
anthropic = "^0.102.0"
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import pytest
|
||||
|
||||
from agentic_security.mcp.client import run
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mcp_client_lists_agentic_security_tools():
|
||||
"""Test that the MCP client can discover the server tools."""
|
||||
prompts, resources, tools = await run()
|
||||
tool_names = {tool.name for tool in tools.tools}
|
||||
|
||||
assert prompts is not None
|
||||
assert resources is not None
|
||||
assert {
|
||||
"verify_llm",
|
||||
"start_scan",
|
||||
"stop_scan",
|
||||
"get_data_config",
|
||||
"get_spec_templates",
|
||||
}.issubset(tool_names)
|
||||
Reference in New Issue
Block a user