feat: add file asset listing prompt

Expose list_file_assets so agents can browse allowed source files without relying on empty search queries.

Add a how_to_use_wiki_file_assets prompt to make the MCP purpose and workflow visible to clients that inspect prompts/resources before tools.
This commit is contained in:
Codex
2026-07-05 12:25:36 +00:00
parent a6ef696d84
commit 57b98f1979
2 changed files with 56 additions and 0 deletions
+42
View File
@@ -151,6 +151,32 @@ def create_server(
)
)
@server.tool()
def list_file_assets(
doc_type: str | None = None,
source_type: str | None = None,
product_line: str | None = None,
customer: str | None = None,
competitor: str | None = None,
limit: int = 10,
) -> list[dict[str, Any]]:
"""List safe source files matching optional filters. Use search_file_assets when the user gives keywords such as product codes, sizes, or drawing names."""
return _as_mcp_results(
core_search_file_assets(
vault,
"",
db_path=db,
limit=limit,
doc_type=doc_type,
source_type=source_type,
product_line=product_line,
customer=customer,
competitor=competitor,
profile_name=profile_name,
expose_paths=expose_paths,
)
)
@server.tool()
def get_file_asset_metadata(file_id: str) -> dict[str, Any]:
"""Return safe metadata and the resource URI for one indexed source file."""
@@ -176,6 +202,22 @@ def create_server(
)
return resource["bytes"]
@server.prompt(
"how_to_use_wiki_file_assets",
description="Explain how to search and retrieve original source files from the wiki-file-assets MCP server.",
)
def how_to_use_wiki_file_assets() -> str:
return (
"wiki-file-assets serves original source files archived from an Obsidian wiki vault. "
"Use search_file_assets for keyword searches such as product codes, drawing names, sizes, "
"or document types. Use list_file_assets to browse allowed engineering files with optional "
"filters. Use get_file_asset_metadata with a file_id from search/list results to get the "
"asset://source/sha256/... URI, then read that resource to fetch the original file bytes. "
"This MCP is intentionally limited to safe engineering files such as drawings, CAD/3D models, "
"specifications, product parameters, and test reports; it blocks raw orders, prices, email "
"correspondence, complaint evidence, claims, and personal data."
)
return server
+14
View File
@@ -100,12 +100,15 @@ class RemoteMcpServerTests(unittest.TestCase):
def test_create_server_uses_file_asset_service_name(self):
class FakeMCP:
names = []
tool_names = []
prompt_names = []
def __init__(self, name, **kwargs):
self.names.append(name)
def tool(self):
def decorator(func):
self.tool_names.append(func.__name__)
return func
return decorator
@@ -116,6 +119,13 @@ class RemoteMcpServerTests(unittest.TestCase):
return decorator
def prompt(self, name=None, **_kwargs):
def decorator(func):
self.prompt_names.append(name or func.__name__)
return func
return decorator
with (
tempfile.TemporaryDirectory() as tmp,
patch.dict("sys.modules", {"mcp.server.fastmcp": type("Mod", (), {"FastMCP": FakeMCP})()}),
@@ -124,6 +134,10 @@ class RemoteMcpServerTests(unittest.TestCase):
self.assertIsInstance(server, FakeMCP)
self.assertEqual(FakeMCP.names[-1], "wiki-file-assets")
self.assertIn("search_file_assets", FakeMCP.tool_names)
self.assertIn("list_file_assets", FakeMCP.tool_names)
self.assertIn("get_file_asset_metadata", FakeMCP.tool_names)
self.assertIn("how_to_use_wiki_file_assets", FakeMCP.prompt_names)
def test_run_http_server_fails_before_server_creation_without_token(self):
with tempfile.TemporaryDirectory() as tmp: