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>
This commit is contained in:
94
confluence-collab/src/confluence_collab/proxy.py
Normal file
94
confluence-collab/src/confluence_collab/proxy.py
Normal file
@@ -0,0 +1,94 @@
|
||||
"""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()
|
||||
Reference in New Issue
Block a user