paperclipai/paperclip · error
Paperclip API origin is unavailable
Error message
Paperclip API origin is unavailable
What it means
The project-tools MCP endpoint proxies tool calls to the Paperclip API via callProjectTool, and it requires the origin of that API from the PAPERCLIP_API_URL environment variable. When the variable is unset (empty string is falsy), the server cannot construct the callback URL and throws this error instead of making a doomed request. It is a startup/deployment configuration guard for the tool-call path only.
Solutions
- Set PAPERCLIP_API_URL to the externally reachable origin of the Paperclip API (e.g. https://paperclip.example.com) and restart the server.
- In dev, use the standard `pnpm dev` flow which provisions the API origin automatically.
- Add the variable to your deployment manifest/Dockerfile env and verify with `curl $PAPERCLIP_API_URL/api/health`.
- If the server should default to localhost, export PAPERCLIP_API_URL=http://localhost:3100 in the shell profile.
Example fix
// before (docker-compose.yml) // environment: // - NODE_ENV=production // after environment: - NODE_ENV=production - PAPERCLIP_API_URL=https://paperclip.internal.example.com
Defensive patterns
Strategy: validation
Validate before calling
if (!process.env.PAPERCLIP_API_URL) {
throw new Error("PAPERCLIP_API_URL must be set for project tool calls");
} Type guard
null
Try / catch
try { await callMcpTool(name, args); }
catch (e) {
if (e.message === "Paperclip API origin is unavailable") {
process.exitCode = 1; // fail fast at boot, not at call time
}
throw e;
} Prevention
- Assert PAPERCLIP_API_URL at server startup, not first tool call
- Include the var in deployment manifests and health checks
- Smoke-test with curl $PAPERCLIP_API_URL/api/health after deploy
- Document the requirement in deployment runbooks
When it happens
Trigger: A tools/call request reaches /api project-tools route in a deployment where process.env.PAPERCLIP_API_URL is not set; the tools/list path works because it never needs the origin, so the misconfiguration only surfaces on actual tool invocation.
Common situations: Self-hosted deployments behind a reverse proxy where only PORT/HOST were configured; running the server outside the standard dev script which sets PAPERCLIP_API_URL; Docker/K8s manifests missing the env entry; new env-var naming after a refactor.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- Codex working directory inside the host HOME requires an…
- managed_profile_not_found
- PAPERCLIP_CLOUD_RUNTIME_IDENTITY_JWKS is not configured
- PAPERCLIP_EVAL_MAX_CAMPAIGN_COST_USD must be a positive…
- A trusted viewer build is required for public chat reports
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/1401762d103cf851.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/routes/project-tools.ts:24
import { forbidden } from "../errors.js";
/** Mounted after actor middleware; connection-scoped tokens cannot authenticate here. */
export function projectToolRoutes(db: Db) {
const router = Router();
router.post("/mcp/project-tools", async (req, res) => {
const context = await projectToolContext(db, req.actor);
assertCompanyAccess(req, context.run.companyId);
const { id = null, method, params } = req.body;
const send = (result: unknown) => res.json({ jsonrpc: "2.0", id, result });
if (method === "initialize") return send({ protocolVersion: "2025-03-26", capabilities: { tools: { listChanged: false } }, serverInfo: { name: "paperclip-project-tools", version: "1" } });
if (method === "notifications/initialized") return res.status(202).end();
const definitions = projectToolDefinitions(context.issue.workMode, true);
if (method === "tools/list") return send({ tools: definitions });
if (method !== "tools/call") return res.json({ jsonrpc: "2.0", id, error: { code: -32601, message: "Method not found" } });
try {
if (!definitions.some(tool => tool.name === params?.name)) throw forbidden("Tool is unavailable in this mode");
const apiUrl = process.env.PAPERCLIP_API_URL;
if (!apiUrl) throw new Error("Paperclip API origin is unavailable");
const result = await callProjectTool({
name: params.name, arguments: params.arguments ?? {}, apiUrl,
token: req.header("authorization")!.replace(/^Bearer\s+/i, ""),
companyId: context.run.companyId, issueId: context.issue.id, agentId: context.run.agentId,
conversation: Boolean(context.issue.conversationAgentId),
});
return send({ content: [{ type: "text", text: JSON.stringify(result) }], structuredContent: result });
} catch (error) {
return send({ isError: true, content: [{ type: "text", text: error instanceof Error ? error.message : "Project tool failed" }] });
}
});
return router;
}
View on GitHub (pinned to 3f1d897a7c)