Paperclip CEO Model Context Protocol Server & Alerting Bridge
A secure, narrow MCP interface to the private paperclip-ceo-bridge plus an outbound webhook loop that pushes blockers and decisions straight to Poke.
We need to implement a Model Context Protocol (MCP) server that acts as a secure, narrow interface to our private paperclip-ceo-bridge container (running on http://127.0.0.1:3200). This will allow Poke to securely converse with the CEO agent and manage tasks.
We also need to implement an outbound webhook alerting loop so the bridge can push unsolicited alerts (such as blockers or decision points requiring Connor) directly to a Poke ingestion endpoint.
Inbound traffic flows down through the tunnel and MCP server into the locked-down bridge. The bridge fires proactive alerts back up to Poke's webhook independently.
- You (iMessage / Poke)
- Poke MCP tool calls
- Secure tunnel
- paperclip-ceo-mcp
- paperclip-ceo-bridge
- Paperclip
Configure a new service paperclip-ceo-mcp to run alongside paperclip-ceo-bridge. Network them together so the MCP server can access the bridge over the local Docker bridge network, while keeping the bridge itself strictly closed to external traffic.
version: '3.8'
services:
paperclip-ceo-bridge:
image: paperclip-ceo-bridge:latest
container_name: paperclip-ceo-bridge
build:
context: ./paperclip-ceo-bridge
ports:
- "127.0.0.1:3200:3200" # Explicitly bound to localhost only
environment:
- PORT=3200
- PAPERCLIP_API_TOKEN=${PAPERCLIP_API_TOKEN}
- BRIDGE_SECRET=${BRIDGE_SECRET}
- POKE_WEBHOOK_URL=${POKE_WEBHOOK_URL} # Target for outbound alerts
restart: unless-stopped
paperclip-ceo-mcp:
image: paperclip-ceo-mcp:latest
container_name: paperclip-ceo-mcp
build:
context: ./paperclip-ceo-mcp
ports:
- "3300:3300" # Exposed internally on the host; will be funneled via Tailscale
environment:
- PORT=3300
- BRIDGE_URL=http://paperclip-ceo-bridge:3200
- BRIDGE_SECRET=${BRIDGE_SECRET}
depends_on:
- paperclip-ceo-bridge
restart: unless-stoppedCreate a clean TypeScript / Node.js project using @modelcontextprotocol/sdk. It must expose an SSE (Server-Sent Events) transport or standard HTTP POST endpoint matching the MCP spec so Poke can reach it remotely over a web tunnel.
Tool schemas to expose
send_ceo_messageget_ceo_updatesget_open_decisionsanswer_decisionget_task_statusTypeScript Express implementation draft (SSE)
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import express from "express";
const app = express();
const server = new Server({
name: "paperclip-ceo-mcp",
version: "1.0.0"
}, {
capabilities: {
tools: {}
}
});
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "send_ceo_message",
description: "Send a message or directive to the Paperclip CEO agent to kick off tasks",
inputSchema: {
type: "object",
properties: {
message: { type: "string" }
},
required: ["message"]
}
},
// Register remaining tools...
]
};
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
const bridgeUrl = process.env.BRIDGE_URL || "http://paperclip-ceo-bridge:3200";
const secret = process.env.BRIDGE_SECRET;
// Execute calls to paperclip-ceo-bridge with AUTH headers
});
let transport: SSEServerTransport;
app.get("/sse", (req, res) => {
transport = new SSEServerTransport("/messages", res);
server.connect(transport);
});
app.post("/messages", (req, res) => {
transport.handleMessage(req, res);
});
app.listen(process.env.PORT || 3300, () => {
console.log("MCP Server running on port 3300");
});When the Paperclip CEO agent writes a new update, flags a blocker, or hits a decision point:
- The
paperclip-ceo-bridgemust capture this event. - If
POKE_WEBHOOK_URLis set, the bridge must fire a POST request with a payload containing:
typemessageissueIdchoicesPlease perform the following actions:
- Write the Dockerfile and TypeScript code for the new paperclip-ceo-mcp service.
- Update the existing paperclip-ceo-bridge service to support sending outbound HTTP POST requests to POKE_WEBHOOK_URL.
- Provide a simple docker-compose.yml that pulls both of these services together on Connor's local docker host.
- Ensure the system builds successfully and output test curl commands Connor can run to verify health checks on both ports (3200 and 3300).
Suggested health-check commands
# Bridge (localhost only) - run on the docker host
curl -s http://127.0.0.1:3200/health
# MCP server (host-exposed, later funneled via Tailscale)
curl -s http://127.0.0.1:3300/health
# Confirm the MCP can reach the bridge over the internal docker network
docker compose exec paperclip-ceo-mcp \
curl -s http://paperclip-ceo-bridge:3200/health