From 89ae702c08dd64667f544b4ceb2c5e883b9ba6ff Mon Sep 17 00:00:00 2001 From: Dyn Date: Sun, 15 Mar 2026 14:53:12 +0000 Subject: [PATCH] Add server-writbase: stdio proxy for WritBase MCP server Co-Authored-By: Claude Opus 4.6 (1M context) --- src/server-writbase/LICENSE | 21 +++++ src/server-writbase/README.md | 83 ++++++++++++++++++ src/server-writbase/package.json | 43 +++++++++ src/server-writbase/src/index.ts | 141 ++++++++++++++++++++++++++++++ src/server-writbase/tsconfig.json | 14 +++ 5 files changed, 302 insertions(+) create mode 100644 src/server-writbase/LICENSE create mode 100644 src/server-writbase/README.md create mode 100644 src/server-writbase/package.json create mode 100644 src/server-writbase/src/index.ts create mode 100644 src/server-writbase/tsconfig.json diff --git a/src/server-writbase/LICENSE b/src/server-writbase/LICENSE new file mode 100644 index 0000000..e30b978 --- /dev/null +++ b/src/server-writbase/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 WritBase + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/server-writbase/README.md b/src/server-writbase/README.md new file mode 100644 index 0000000..db52438 --- /dev/null +++ b/src/server-writbase/README.md @@ -0,0 +1,83 @@ +# @mcp-get-community/server-writbase + +An MCP stdio proxy for [WritBase](https://github.com/Writbase/writbase) — an MCP-native task management system for AI agent fleets. + +WritBase provides a Postgres-backed control plane with multi-agent permissions, full provenance, inter-agent delegation, and 11 MCP tools out of the box. This package bridges MCP stdio transport to WritBase's remote streamable-HTTP endpoint so any MCP client can connect. + +## Installation + +```bash +npx @michaellatman/mcp-get@latest install @mcp-get-community/server-writbase +``` + +## Configuration + +Two environment variables are required: + +| Variable | Description | +|---|---| +| `WRITBASE_URL` | Full MCP endpoint URL (e.g. `https://.supabase.co/functions/v1/mcp-server`) | +| `WRITBASE_AGENT_KEY` | Agent bearer token (`wb__`) | + +### Usage + +```json +{ + "mcpServers": { + "@mcp-get-community/server-writbase": { + "runtime": "node", + "command": "npx", + "args": [ + "-y", + "@mcp-get-community/server-writbase" + ], + "env": { + "WRITBASE_URL": "https://.supabase.co/functions/v1/mcp-server", + "WRITBASE_AGENT_KEY": "wb__" + } + } + } +} +``` + +## Available MCP Tools + +WritBase exposes 11 tools through this proxy: + +**Worker tools** — `info`, `get_tasks`, `add_task`, `update_task` + +**Manager tools** — `manage_agent_keys`, `manage_agent_permissions`, `get_provenance`, `manage_projects`, `manage_departments`, `subscribe`, `discover_agents` + +Tool availability depends on the permissions granted to your agent key. + +## How It Works + +This package is a lightweight stdio-to-HTTP proxy (~120 LOC). It: + +1. Connects to your WritBase instance via `StreamableHTTPClientTransport` +2. Exposes a local `StdioServerTransport` for MCP clients +3. Forwards all MCP messages (tool calls, resource/prompt listings) transparently + +No business logic runs locally — all task management happens on your WritBase server. + +## Development + +```bash +# Install dependencies +npm install + +# Build the project +npm run build + +# Run in development mode +npm run dev +``` + +## Links + +- [WritBase repository](https://github.com/Writbase/writbase) (Apache 2.0) +- [WritBase documentation](https://github.com/Writbase/writbase#readme) + +## License + +MIT diff --git a/src/server-writbase/package.json b/src/server-writbase/package.json new file mode 100644 index 0000000..3679d7f --- /dev/null +++ b/src/server-writbase/package.json @@ -0,0 +1,43 @@ +{ + "name": "@mcp-get-community/server-writbase", + "version": "0.1.0", + "description": "MCP stdio proxy for WritBase — task management for AI agent fleets", + "main": "dist/index.js", + "type": "module", + "private": false, + "bin": { + "@mcp-get-community/server-writbase": "./dist/index.js" + }, + "files": [ + "dist", + "README.md", + "LICENSE" + ], + "publishConfig": { + "access": "public" + }, + "license": "MIT", + "author": "WritBase ", + "homepage": "https://github.com/Writbase/writbase#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/mcp-get/community-servers.git" + }, + "bugs": { + "url": "https://github.com/mcp-get/community-servers/issues" + }, + "scripts": { + "build": "tsc", + "start": "node dist/index.js", + "dev": "ts-node src/index.ts", + "prepublishOnly": "npm run build" + }, + "dependencies": { + "@modelcontextprotocol/sdk": "^1.12.1" + }, + "devDependencies": { + "@types/node": "^20.10.0", + "typescript": "^5.3.0", + "ts-node": "^10.9.0" + } +} diff --git a/src/server-writbase/src/index.ts b/src/server-writbase/src/index.ts new file mode 100644 index 0000000..3524b5b --- /dev/null +++ b/src/server-writbase/src/index.ts @@ -0,0 +1,141 @@ +#!/usr/bin/env node + +/** + * WritBase MCP Stdio Proxy + * + * Bridges MCP stdio transport to a remote WritBase streamable-HTTP endpoint. + * All MCP messages are forwarded transparently — no business logic lives here. + * + * Required env vars: + * WRITBASE_URL – Full MCP endpoint URL (e.g. https://.supabase.co/functions/v1/mcp-server) + * WRITBASE_AGENT_KEY – Bearer token (wb__) + */ + +import { Client } from "@modelcontextprotocol/sdk/client/index.js"; +import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; +import { Server } from "@modelcontextprotocol/sdk/server/index.js"; +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { + CallToolRequestSchema, + ListToolsRequestSchema, + ListResourcesRequestSchema, + ListPromptsRequestSchema, + type CallToolRequest, + type ListToolsRequest, + type ListResourcesRequest, + type ListPromptsRequest, +} from "@modelcontextprotocol/sdk/types.js"; + +// --------------------------------------------------------------------------- +// Config +// --------------------------------------------------------------------------- + +const WRITBASE_URL = process.env.WRITBASE_URL; +const WRITBASE_AGENT_KEY = process.env.WRITBASE_AGENT_KEY; + +if (!WRITBASE_URL) { + console.error("Error: WRITBASE_URL environment variable is required."); + console.error("Set it to your WritBase MCP endpoint URL."); + process.exit(1); +} + +if (!WRITBASE_AGENT_KEY) { + console.error("Error: WRITBASE_AGENT_KEY environment variable is required."); + console.error("Set it to your WritBase agent key (wb__)."); + process.exit(1); +} + +// --------------------------------------------------------------------------- +// Remote client (stdio proxy → WritBase HTTP) +// --------------------------------------------------------------------------- + +const remoteTransport = new StreamableHTTPClientTransport( + new URL(WRITBASE_URL), + { + requestInit: { + headers: { + Authorization: `Bearer ${WRITBASE_AGENT_KEY}`, + }, + }, + } +); + +const remoteClient = new Client( + { name: "writbase-stdio-proxy", version: "0.1.0" }, + { capabilities: {} } +); + +// --------------------------------------------------------------------------- +// Local stdio server +// --------------------------------------------------------------------------- + +const localServer = new Server( + { + name: "@mcp-get-community/server-writbase", + version: "0.1.0", + }, + { + capabilities: { + tools: {}, + }, + } +); + +// --------------------------------------------------------------------------- +// Proxy handlers — forward every request to the remote server +// --------------------------------------------------------------------------- + +localServer.setRequestHandler(ListToolsRequestSchema, async (_req: ListToolsRequest) => { + const result = await remoteClient.listTools(); + return { tools: result.tools }; +}); + +localServer.setRequestHandler(CallToolRequestSchema, async (req: CallToolRequest) => { + const result = await remoteClient.callTool({ + name: req.params.name, + arguments: req.params.arguments, + }); + return { + content: result.content as Array<{ type: string; text: string }>, + isError: result.isError, + }; +}); + +// Forward resource/prompt listing if the remote supports them (graceful no-op) +localServer.setRequestHandler(ListResourcesRequestSchema, async (_req: ListResourcesRequest) => { + try { + const result = await remoteClient.listResources(); + return { resources: result.resources }; + } catch { + return { resources: [] }; + } +}); + +localServer.setRequestHandler(ListPromptsRequestSchema, async (_req: ListPromptsRequest) => { + try { + const result = await remoteClient.listPrompts(); + return { prompts: result.prompts }; + } catch { + return { prompts: [] }; + } +}); + +// --------------------------------------------------------------------------- +// Start +// --------------------------------------------------------------------------- + +async function main() { + // Connect to remote WritBase server first + await remoteClient.connect(remoteTransport); + console.error("Connected to WritBase at", WRITBASE_URL); + + // Then expose local stdio transport + const stdioTransport = new StdioServerTransport(); + await localServer.connect(stdioTransport); + console.error("WritBase MCP stdio proxy running"); +} + +main().catch((error) => { + console.error("Fatal error:", error); + process.exit(1); +}); diff --git a/src/server-writbase/tsconfig.json b/src/server-writbase/tsconfig.json new file mode 100644 index 0000000..9df80b2 --- /dev/null +++ b/src/server-writbase/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ES2020", + "moduleResolution": "node", + "esModuleInterop": true, + "strict": true, + "outDir": "./dist", + "rootDir": "./src", + "skipLibCheck": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +}