@papercraneai/sandbox-agent 0.1.13 → 0.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,98 @@
1
+ import { z } from "zod";
2
+ import { tool, createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";
3
+ function resultJson(payload) {
4
+ return {
5
+ content: [{
6
+ type: "text",
7
+ text: typeof payload === "string" ? payload : JSON.stringify(payload, null, 2)
8
+ }]
9
+ };
10
+ }
11
+ function resultError(message) {
12
+ return {
13
+ content: [{ type: "text", text: `Error: ${message}` }],
14
+ isError: true
15
+ };
16
+ }
17
+ /**
18
+ * Builds the papercrane-data MCP server for a shared-view chat session.
19
+ *
20
+ * Each tool is a thin HTTP wrapper around the share-scoped integrations
21
+ * endpoint at `/api/share/:shareCode/integrations/*`. Papercrane resolves the
22
+ * share's allowlist on every call (single source of truth, no staleness) and
23
+ * filters/gates the response server-side. The MCP server does no filtering of
24
+ * its own.
25
+ */
26
+ export function createPapercraneDataServer(options) {
27
+ const { apiBaseUrl, apiKey, shareCode, visitorSessionId } = options;
28
+ const baseUrl = `${apiBaseUrl}/api/share/${encodeURIComponent(shareCode)}/integrations`;
29
+ const headers = () => ({
30
+ "Authorization": `Bearer ${apiKey}`,
31
+ "Content-Type": "application/json",
32
+ "X-Papercrane-Visitor-Session": visitorSessionId
33
+ });
34
+ const listTool = tool("List", "List connected integrations. Paths use dot notation; segments prefixed with $ are variables (e.g. apiname.$projectId.list).", {}, async () => {
35
+ try {
36
+ const url = new URL(baseUrl);
37
+ url.searchParams.set("mode", "list");
38
+ const res = await fetch(url, { method: "GET", headers: headers() });
39
+ if (!res.ok) {
40
+ const body = await res.text();
41
+ return resultError(`list returned ${res.status}: ${body.slice(0, 500)}`);
42
+ }
43
+ return resultJson(await res.json());
44
+ }
45
+ catch (err) {
46
+ return resultError(err instanceof Error ? err.message : String(err));
47
+ }
48
+ });
49
+ const describeTool = tool("Describe", "Describe an integration or path.", {
50
+ path: z.string().describe("Dot-notation path. Segments prefixed with $ are variables (e.g. apiname.$projectId.list)."),
51
+ instance: z.string().describe("Integration instance name").default("Default")
52
+ }, async ({ path, instance }) => {
53
+ try {
54
+ const url = new URL(`${baseUrl}/${encodeURIComponent(path)}`);
55
+ url.searchParams.set("mode", "describe");
56
+ url.searchParams.set("instance", instance);
57
+ const res = await fetch(url, { method: "GET", headers: headers() });
58
+ if (!res.ok) {
59
+ const body = await res.text();
60
+ return resultError(`describe returned ${res.status}: ${body.slice(0, 500)}`);
61
+ }
62
+ return resultJson(await res.json());
63
+ }
64
+ catch (err) {
65
+ return resultError(err instanceof Error ? err.message : String(err));
66
+ }
67
+ });
68
+ const callTool = tool("Call", "Call an integration path.", {
69
+ path: z.string().describe("Dot-notation path. Segments prefixed with $ are variables (e.g. apiname.$projectId.list)."),
70
+ instance: z.string().describe("Integration instance name").default("Default"),
71
+ params: z.record(z.string(), z.unknown()).optional().describe("Parameters as a JSON object")
72
+ }, async ({ path, instance, params }) => {
73
+ try {
74
+ const url = new URL(`${baseUrl}/${encodeURIComponent(path)}`);
75
+ url.searchParams.set("instance", instance);
76
+ const res = await fetch(url, {
77
+ method: "POST",
78
+ headers: headers(),
79
+ body: JSON.stringify(params ?? {})
80
+ });
81
+ if (!res.ok) {
82
+ const body = await res.text();
83
+ return resultError(`call returned ${res.status}: ${body.slice(0, 500)}`);
84
+ }
85
+ const text = await res.text();
86
+ return { content: [{ type: "text", text }] };
87
+ }
88
+ catch (err) {
89
+ return resultError(err instanceof Error ? err.message : String(err));
90
+ }
91
+ });
92
+ return {
93
+ server: createSdkMcpServer({
94
+ name: "papercrane-data",
95
+ tools: [listTool, describeTool, callTool]
96
+ })
97
+ };
98
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@papercraneai/sandbox-agent",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "Claude Agent SDK server for sandbox environments",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -23,7 +23,8 @@
23
23
  "typecheck": "tsc --noEmit"
24
24
  },
25
25
  "dependencies": {
26
- "@anthropic-ai/claude-agent-sdk": "^0.2.5",
26
+ "@anthropic-ai/claude-agent-sdk": "^0.2.128",
27
+ "diff": "^5.2.0",
27
28
  "express": "^4.21.1",
28
29
  "multer": "^2.0.2",
29
30
  "tail": "^2.2.6",
@@ -31,6 +32,7 @@
31
32
  "zod": "^4.0.0"
32
33
  },
33
34
  "devDependencies": {
35
+ "@types/diff": "^5.2.3",
34
36
  "@types/express": "^5.0.0",
35
37
  "@types/multer": "^2.0.0",
36
38
  "@types/node": "^22.14.0",