Merge remote-tracking branch 'gitea/mcps'
Some checks failed
CI / coverage (push) Has been cancelled
CI / check (push) Has been cancelled
CI / release (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / mypy (push) Has been cancelled
CI / test on 3.10 (push) Has been cancelled
CI / test on 3.11 (push) Has been cancelled
CI / test on 3.12 (push) Has been cancelled
CI / test on 3.13 (push) Has been cancelled
CI / test on 3.14 (push) Has been cancelled
CI / test on 3.14t (push) Has been cancelled
Some checks failed
CI / coverage (push) Has been cancelled
CI / check (push) Has been cancelled
CI / release (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / mypy (push) Has been cancelled
CI / test on 3.10 (push) Has been cancelled
CI / test on 3.11 (push) Has been cancelled
CI / test on 3.12 (push) Has been cancelled
CI / test on 3.13 (push) Has been cancelled
CI / test on 3.14 (push) Has been cancelled
CI / test on 3.14t (push) Has been cancelled
This commit is contained in:
@@ -27,6 +27,9 @@ RUN apk add --update --no-cache catatonit
|
||||
# Final stage with explicit platform specification
|
||||
FROM python:3.13-alpine
|
||||
|
||||
# Install Node.js and npm
|
||||
RUN apk add --no-cache nodejs npm
|
||||
|
||||
COPY --from=uv --chown=app:app /app/.venv /app/.venv
|
||||
COPY --from=uv /usr/bin/catatonit /usr/bin/
|
||||
COPY --from=uv /usr/libexec/podman/catatonit /usr/libexec/podman/
|
||||
|
||||
50
build-and-push.sh
Executable file
50
build-and-push.sh
Executable file
@@ -0,0 +1,50 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
REGISTRY="git.baked.rocks"
|
||||
OWNER="vasceannie"
|
||||
# Extract service names from docker-compose.yml
|
||||
SERVICES=($(docker compose config --services))
|
||||
|
||||
# Login to registry if not already authenticated
|
||||
echo "Logging in to ${REGISTRY}..."
|
||||
docker login "${REGISTRY}" || {
|
||||
echo "Error: Failed to login to ${REGISTRY}"
|
||||
echo "Please ensure you have valid credentials"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Build all services
|
||||
echo "Building all services..."
|
||||
docker compose build
|
||||
|
||||
# Tag and push each service
|
||||
for service in "${SERVICES[@]}"; do
|
||||
echo "Tagging and pushing $service..."
|
||||
# Get the image ID - try multiple methods
|
||||
IMAGE_ID=$(docker compose images -q "$service" 2>/dev/null | head -1)
|
||||
|
||||
if [ -z "$IMAGE_ID" ]; then
|
||||
# Fallback: find image by service name pattern
|
||||
IMAGE_ID=$(docker images --format "{{.ID}}" --filter "reference=*${service}*" | head -1)
|
||||
fi
|
||||
|
||||
if [ -z "$IMAGE_ID" ]; then
|
||||
echo "Error: Could not find image ID for $service"
|
||||
echo "Available images:"
|
||||
docker compose images
|
||||
docker images | grep -E "(${SERVICES[*]// /|})"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TARGET_IMAGE="${OWNER}/${service}:latest"
|
||||
REGISTRY_IMAGE="${REGISTRY}/${TARGET_IMAGE}"
|
||||
|
||||
# Tag using image ID directly
|
||||
docker tag "${IMAGE_ID}" "${REGISTRY_IMAGE}"
|
||||
docker push "${REGISTRY_IMAGE}"
|
||||
echo "$service pushed successfully"
|
||||
done
|
||||
|
||||
echo "All services built and pushed to ${REGISTRY}"
|
||||
|
||||
56
config.json
Normal file
56
config.json
Normal file
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"pieces": {
|
||||
"enabled": true,
|
||||
"timeout": 60,
|
||||
"url": "http://localhost:39300/model_context_protocol/2024-11-05/sse",
|
||||
"transportType": "sse",
|
||||
"command": "echo",
|
||||
"args": ["sse-placeholder"]
|
||||
},
|
||||
"firecrawl": {
|
||||
"enabled": true,
|
||||
"timeout": 60,
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"-y",
|
||||
"firecrawl-mcp"
|
||||
],
|
||||
"transportType": "stdio",
|
||||
"env": {
|
||||
"FIRECRAWL_API_URL": "http://crawl.lab:30002",
|
||||
"FIRECRAWL_API_KEY": "dummy-key"
|
||||
}
|
||||
},
|
||||
"context7": {
|
||||
"enabled": true,
|
||||
"timeout": 60,
|
||||
"url": "https://mcp.context7.com/mcp",
|
||||
"transportType": "http",
|
||||
"command": "echo",
|
||||
"args": ["http-placeholder"],
|
||||
"headers": {
|
||||
"CONTEXT7_API_KEY": "ctx7sk-f6f1b998-88a2-4e78-9d21-433545326e6c"
|
||||
}
|
||||
},
|
||||
"knowledge-graph": {
|
||||
"enabled": true,
|
||||
"timeout": 60,
|
||||
"url": "http://localhost:48000/sse",
|
||||
"transportType": "sse",
|
||||
"command": "echo",
|
||||
"args": ["sse-placeholder"]
|
||||
},
|
||||
"xpipe": {
|
||||
"enabled": true,
|
||||
"timeout": 60,
|
||||
"url": "http://localhost:21721/mcp",
|
||||
"transportType": "http",
|
||||
"command": "echo",
|
||||
"args": ["http-placeholder"],
|
||||
"headers": {
|
||||
"Authorization": "Bearer 27d1c4ca-dfec-4d38-adc1-1e0f4bcbaadc"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"fetch": {
|
||||
"enabled": true,
|
||||
"timeout": 60,
|
||||
"command": "uvx",
|
||||
"args": [
|
||||
"mcp-server-fetch"
|
||||
],
|
||||
"transportType": "stdio"
|
||||
},
|
||||
"github": {
|
||||
"enabled": false,
|
||||
"timeout": 60,
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"-y",
|
||||
"@modelcontextprotocol/server-github"
|
||||
],
|
||||
"transportType": "stdio"
|
||||
}
|
||||
}
|
||||
}
|
||||
147
docker-compose.yml
Normal file
147
docker-compose.yml
Normal file
@@ -0,0 +1,147 @@
|
||||
version: '3.8'
|
||||
|
||||
networks:
|
||||
traefik:
|
||||
external: true
|
||||
|
||||
services:
|
||||
pieces-mcp:
|
||||
image: git.baked.rocks/vasceannie/pieces-mcp:latest
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.hostname == wslbox
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.pieces-mcp.rule=Host(`mcp.box`) && PathPrefix(`/pieces-mcp`)"
|
||||
- "traefik.http.routers.pieces-mcp.entrypoints=web"
|
||||
- "traefik.http.services.pieces-mcp.loadbalancer.server.port=8096"
|
||||
- "traefik.http.middlewares.pieces-mcp-stripprefix.stripprefix.prefixes=/pieces-mcp"
|
||||
- "traefik.http.routers.pieces-mcp.middlewares=pieces-mcp-stripprefix"
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "netstat -tln | grep ':8096 ' || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
command: >
|
||||
--named-server pieces-os 'mcp-proxy --transport sse http://host.docker.internal:39300/model_context_protocol/2024-11-05/sse'
|
||||
--port=8096 --host=0.0.0.0 --allow-origin='*'
|
||||
networks:
|
||||
- traefik
|
||||
|
||||
firecrawl-mcp:
|
||||
image: git.baked.rocks/vasceannie/firecrawl-mcp:latest
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.hostname == wslbox
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.firecrawl-mcp.rule=Host(`mcp.box`) && PathPrefix(`/firecrawl-mcp`)"
|
||||
- "traefik.http.routers.firecrawl-mcp.entrypoints=web"
|
||||
- "traefik.http.services.firecrawl-mcp.loadbalancer.server.port=8097"
|
||||
- "traefik.http.middlewares.firecrawl-mcp-stripprefix.stripprefix.prefixes=/firecrawl-mcp"
|
||||
- "traefik.http.routers.firecrawl-mcp.middlewares=firecrawl-mcp-stripprefix"
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
environment:
|
||||
- FIRECRAWL_API_URL=http://crawl.toy
|
||||
- FIRECRAWL_API_KEY=dummy-key
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "netstat -tln | grep ':809[6-9]\\|:8100' || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
command: >
|
||||
--pass-environment
|
||||
--stateless
|
||||
--transport streamablehttp
|
||||
--port=8097 --host=0.0.0.0
|
||||
npx firecrawl-mcp
|
||||
networks:
|
||||
- traefik
|
||||
|
||||
context7-mcp:
|
||||
image: git.baked.rocks/vasceannie/context7-mcp:latest
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.hostname == wslbox
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.context7-mcp.rule=Host(`mcp.box`) && PathPrefix(`/context7-mcp`)"
|
||||
- "traefik.http.routers.context7-mcp.entrypoints=web"
|
||||
- "traefik.http.services.context7-mcp.loadbalancer.server.port=8098"
|
||||
- "traefik.http.middlewares.context7-mcp-stripprefix.stripprefix.prefixes=/context7-mcp"
|
||||
- "traefik.http.routers.context7-mcp.middlewares=context7-mcp-stripprefix"
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "netstat -tln | grep ':809[6-9]\\|:8100' || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
command: >
|
||||
--named-server context7 'mcp-proxy --stateless --transport streamablehttp --headers CONTEXT7_API_KEY ctx7sk-f6f1b998-88a2-4e78-9d21-433545326e6c https://mcp.context7.com/mcp'
|
||||
--port=8098 --host=0.0.0.0 --allow-origin='*'
|
||||
networks:
|
||||
- traefik
|
||||
|
||||
# knowledge-graph-mcp:
|
||||
# image: git.baked.rocks/vasceannie/knowledge-graph-mcp:latest
|
||||
# deploy:
|
||||
# placement:
|
||||
# constraints:
|
||||
# - node.hostname == wslbox
|
||||
# labels:
|
||||
# - "traefik.enable=true"
|
||||
# - "traefik.http.routers.knowledge-graph-mcp.rule=Host(`mcp.box`) && PathPrefix(`/knowledge-graph-mcp`)"
|
||||
# - "traefik.http.routers.knowledge-graph-mcp.entrypoints=web"
|
||||
# - "traefik.http.services.knowledge-graph-mcp.loadbalancer.server.port=8099"
|
||||
# - "traefik.http.middlewares.knowledge-graph-mcp-stripprefix.stripprefix.prefixes=/knowledge-graph-mcp"
|
||||
# - "traefik.http.routers.knowledge-graph-mcp.middlewares=knowledge-graph-mcp-stripprefix"
|
||||
# restart_policy:
|
||||
# condition: on-failure
|
||||
# healthcheck:
|
||||
# test: ["CMD", "sh", "-c", "netstat -tln | grep ':809[6-9]\\|:8100' || exit 1"]
|
||||
# interval: 30s
|
||||
# timeout: 10s
|
||||
# retries: 3
|
||||
# start_period: 40s
|
||||
# command: >
|
||||
# --named-server knowledge-graph 'mcp-proxy --transport sse http://host.docker.internal:48000/sse'
|
||||
# --port=8099 --host=0.0.0.0 --allow-origin='*'
|
||||
# networks:
|
||||
# - traefik
|
||||
|
||||
xpipe-mcp:
|
||||
image: git.baked.rocks/vasceannie/xpipe-mcp:latest
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.hostname == wslbox
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.xpipe-mcp.rule=Host(`mcp.box`) && PathPrefix(`/xpipe-mcp`)"
|
||||
- "traefik.http.routers.xpipe-mcp.entrypoints=web"
|
||||
- "traefik.http.services.xpipe-mcp.loadbalancer.server.port=8100"
|
||||
- "traefik.http.middlewares.xpipe-mcp-stripprefix.stripprefix.prefixes=/xpipe-mcp"
|
||||
- "traefik.http.routers.xpipe-mcp.middlewares=xpipe-mcp-stripprefix"
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "netstat -tln | grep ':809[6-9]\\|:8100' || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
command: >
|
||||
--named-server xpipe 'mcp-proxy --transport streamablehttp --headers Authorization "Bearer 27d1c4ca-dfec-4d38-adc1-1e0f4bcbaadc" http://host.docker.internal:21721/mcp'
|
||||
--port=8100 --host=0.0.0.0 --allow-origin='*'
|
||||
networks:
|
||||
- traefik
|
||||
@@ -124,6 +124,23 @@ def create_single_instance_routes(
|
||||
|
||||
await http_session_manager.handle_request(updated_scope, receive, send)
|
||||
|
||||
async def handle_sse_messages(scope: Scope, receive: Receive, send: Send) -> None:
|
||||
_update_global_activity()
|
||||
try:
|
||||
await sse_transport.handle_post_message(scope, receive, send)
|
||||
except Exception as e:
|
||||
# If session is not found or other SSE errors, return a proper HTTP response
|
||||
if "Could not find session" in str(e) or "session" in str(e).lower():
|
||||
logger.warning("Session not found for SSE message request, client should reconnect: %s", e)
|
||||
response = JSONResponse(
|
||||
{"error": "Session not found", "message": "Please reconnect to establish a new session"},
|
||||
status_code=410, # 410 Gone - indicates resource is no longer available
|
||||
)
|
||||
await response(scope, receive, send)
|
||||
else:
|
||||
# Re-raise other exceptions
|
||||
raise
|
||||
|
||||
routes = [
|
||||
Route(
|
||||
"/mcp",
|
||||
@@ -133,7 +150,8 @@ def create_single_instance_routes(
|
||||
),
|
||||
Mount("/mcp", app=handle_streamable_http_instance),
|
||||
Route("/sse", endpoint=handle_sse_instance),
|
||||
Mount("/messages/", app=sse_transport.handle_post_message),
|
||||
Mount("/messages/", app=handle_sse_messages),
|
||||
Mount("/", app=handle_streamable_http_instance),
|
||||
]
|
||||
return routes, http_session_manager
|
||||
|
||||
|
||||
Reference in New Issue
Block a user