Files
matrix-ai-agent/confluence-collab/src/confluence_collab/proxy.py
Christian Gick b492abe0c9 fix: Copy confluence-collab package instead of symlink for Docker build
Symlinks dont resolve on remote VM during Docker build context.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 11:38:39 +02:00

95 lines
3.0 KiB
Python

"""Composite MCP server: proxies mcp-atlassian + adds section tools.
Spawns mcp-atlassian as a subprocess (stdio), proxies all its tools, and
registers the confluence_section_* tools from this package. Claude Code
sees a single MCP server with all tools under one prefix.
"""
from __future__ import annotations
import asyncio
import json
import logging
import os
import sys
from mcp.server.fastmcp import FastMCP
from mcp.client.session import ClientSession
from mcp.client.stdio import StdioServerParameters, stdio_client
from confluence_collab.server import (
confluence_section_list,
confluence_section_get,
confluence_section_update,
confluence_section_append,
confluence_section_delete,
)
logger = logging.getLogger("confluence-collab-proxy")
mcp = FastMCP("atlassian-with-sections")
# Register section tools directly (they're already decorated with @mcp.tool in server.py,
# but we need to re-register them on this new FastMCP instance)
mcp.tool()(confluence_section_list)
mcp.tool()(confluence_section_get)
mcp.tool()(confluence_section_update)
mcp.tool()(confluence_section_append)
mcp.tool()(confluence_section_delete)
async def _proxy_upstream_tools() -> None:
"""Connect to mcp-atlassian subprocess and proxy its tools."""
cmd = "uvx"
args = ["--python", "3.13", "mcp-atlassian"]
server_params = StdioServerParameters(command=cmd, args=args, env=dict(os.environ))
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
# List upstream tools
tools_result = await session.list_tools()
logger.info("Proxying %d upstream tools from mcp-atlassian", len(tools_result.tools))
# Register each upstream tool as a proxy on our server
for tool in tools_result.tools:
_register_proxy_tool(tool, session)
# Keep running until interrupted
await asyncio.Event().wait()
def _register_proxy_tool(tool, session: ClientSession) -> None:
"""Register a proxied tool from the upstream MCP server."""
async def proxy_handler(**kwargs):
result = await session.call_tool(tool.name, kwargs)
# Return concatenated text content
texts = []
for content in result.content:
if hasattr(content, "text"):
texts.append(content.text)
return "\n".join(texts) if texts else ""
proxy_handler.__name__ = tool.name
proxy_handler.__doc__ = tool.description or ""
# Build parameter annotations from tool schema
mcp.tool(name=tool.name, description=tool.description or "")(proxy_handler)
def main():
"""Run the composite MCP server.
Note: The proxy approach requires running the upstream mcp-atlassian
as a subprocess. For simpler deployment, use the standalone server.py
which only provides section tools, and keep mcp-atlassian separate.
"""
mcp.run(transport="stdio")
if __name__ == "__main__":
main()