stackby-mcp-server 0.2.2 → 0.3.0
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.
- package/README.md +157 -103
- package/dist/index.js +4 -547
- package/dist/list-workspaces.d.ts +1 -0
- package/dist/list-workspaces.js +31 -0
- package/dist/mcp-server.d.ts +5 -0
- package/dist/mcp-server.js +549 -0
- package/dist/request-context.d.ts +8 -0
- package/dist/request-context.js +21 -0
- package/dist/server-http.d.ts +1 -0
- package/dist/server-http.js +105 -0
- package/dist/stackby-api.d.ts +1 -5
- package/dist/stackby-api.js +41 -19
- package/package.json +44 -26
package/dist/stackby-api.d.ts
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Stackby API client for MCP server.
|
|
3
|
-
* Uses dedicated MCP API only: /api/v1/mcp/* (existing developer API is unchanged).
|
|
4
|
-
*/
|
|
5
1
|
export declare function hasApiKey(): boolean;
|
|
6
2
|
/** Returns the base URL actually in use (for error messages). */
|
|
7
3
|
export declare function getApiBaseUrl(): string;
|
|
@@ -57,7 +53,7 @@ export interface DescribeTableResult {
|
|
|
57
53
|
fields: TableField[];
|
|
58
54
|
views: TableView[];
|
|
59
55
|
}
|
|
60
|
-
/**
|
|
56
|
+
/** GET /api/v1/mcp/stacks/:stackId/tables/:tableId — describe table (single API: id, name, fields, views). */
|
|
61
57
|
export declare function describeTable(stackId: string, tableId: string): Promise<DescribeTableResult>;
|
|
62
58
|
export interface TableRecord {
|
|
63
59
|
id: string;
|
package/dist/stackby-api.js
CHANGED
|
@@ -1,21 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Stackby API client for MCP server.
|
|
3
3
|
* Uses dedicated MCP API only: /api/v1/mcp/* (existing developer API is unchanged).
|
|
4
|
+
* In HTTP (hosted) mode, API key and URL come from request context; in stdio mode from process.env.
|
|
4
5
|
*/
|
|
5
|
-
|
|
6
|
-
const
|
|
6
|
+
import { getApiKeyFromContext, getApiUrlFromContext } from "./request-context.js";
|
|
7
|
+
const DEFAULT_BASE_URL = process.env.STACKBY_API_URL || "https://stackby.com";
|
|
8
|
+
const ENV_API_KEY = process.env.STACKBY_API_KEY || "";
|
|
7
9
|
const MCP_API = "/api/v1/mcp";
|
|
10
|
+
function getEffectiveApiKey() {
|
|
11
|
+
const fromContext = getApiKeyFromContext();
|
|
12
|
+
if (fromContext)
|
|
13
|
+
return fromContext;
|
|
14
|
+
return ENV_API_KEY.trim();
|
|
15
|
+
}
|
|
16
|
+
function getEffectiveBaseUrl() {
|
|
17
|
+
const fromContext = getApiUrlFromContext();
|
|
18
|
+
if (fromContext)
|
|
19
|
+
return fromContext.replace(/\/$/, "");
|
|
20
|
+
return DEFAULT_BASE_URL.replace(/\/$/, "");
|
|
21
|
+
}
|
|
8
22
|
export function hasApiKey() {
|
|
9
|
-
return Boolean(
|
|
23
|
+
return Boolean(getEffectiveApiKey());
|
|
10
24
|
}
|
|
11
25
|
/** Returns the base URL actually in use (for error messages). */
|
|
12
26
|
export function getApiBaseUrl() {
|
|
13
|
-
return
|
|
27
|
+
return getEffectiveBaseUrl();
|
|
14
28
|
}
|
|
15
29
|
function authHeaders() {
|
|
16
|
-
const key =
|
|
30
|
+
const key = getEffectiveApiKey();
|
|
17
31
|
if (!key) {
|
|
18
|
-
throw new Error("STACKBY_API_KEY is not set. Set it in your MCP config (e.g. Cursor mcp.json env).");
|
|
32
|
+
throw new Error("STACKBY_API_KEY is not set. Set it in your MCP config (e.g. Cursor mcp.json env) or send header X-Stackby-API-Key (hosted).");
|
|
19
33
|
}
|
|
20
34
|
return {
|
|
21
35
|
"Content-Type": "application/json",
|
|
@@ -23,8 +37,19 @@ function authHeaders() {
|
|
|
23
37
|
...(key.startsWith("pat_") ? { Authorization: `Bearer ${key}` } : {}),
|
|
24
38
|
};
|
|
25
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Backend sendResponseAuthentication.js sends MCP routes as "plain": the raw payload
|
|
42
|
+
* (body.data) is sent, not { data: body.data }. So we accept both shapes.
|
|
43
|
+
*/
|
|
44
|
+
function normalizeResponse(body) {
|
|
45
|
+
if (body != null && typeof body === "object" && "data" in body && body.data !== undefined) {
|
|
46
|
+
return { data: body.data };
|
|
47
|
+
}
|
|
48
|
+
return { data: body };
|
|
49
|
+
}
|
|
26
50
|
async function request(path, options = {}) {
|
|
27
|
-
const
|
|
51
|
+
const base = getEffectiveBaseUrl();
|
|
52
|
+
const url = path.startsWith("http") ? path : `${base}${path.startsWith("/") ? path : `/${path}`}`;
|
|
28
53
|
const res = await fetch(url, {
|
|
29
54
|
...options,
|
|
30
55
|
headers: { ...authHeaders(), ...options.headers },
|
|
@@ -34,7 +59,7 @@ async function request(path, options = {}) {
|
|
|
34
59
|
const msg = body?.error ?? body?.message ?? res.statusText;
|
|
35
60
|
throw new Error(`Stackby API ${res.status}: ${msg}`);
|
|
36
61
|
}
|
|
37
|
-
return body;
|
|
62
|
+
return normalizeResponse(body);
|
|
38
63
|
}
|
|
39
64
|
/** GET /api/v1/mcp/workspaces — list workspaces (MCP API only). */
|
|
40
65
|
export async function getWorkspaces() {
|
|
@@ -91,19 +116,16 @@ export async function getTableViewList(stackId, tableId) {
|
|
|
91
116
|
const out = await request(path, { method: "GET" });
|
|
92
117
|
return Array.isArray(out.data) ? out.data : [];
|
|
93
118
|
}
|
|
94
|
-
/**
|
|
119
|
+
/** GET /api/v1/mcp/stacks/:stackId/tables/:tableId — describe table (single API: id, name, fields, views). */
|
|
95
120
|
export async function describeTable(stackId, tableId) {
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
getTableViewList(stackId, tableId),
|
|
100
|
-
]);
|
|
101
|
-
const tableMeta = tables.find((t) => t.id === tableId);
|
|
121
|
+
const path = `${MCP_API}/stacks/${encodeURIComponent(stackId)}/tables/${encodeURIComponent(tableId)}`;
|
|
122
|
+
const out = await request(path, { method: "GET" });
|
|
123
|
+
const d = out.data;
|
|
102
124
|
return {
|
|
103
|
-
id: tableId,
|
|
104
|
-
name:
|
|
105
|
-
fields,
|
|
106
|
-
views,
|
|
125
|
+
id: d?.id ?? tableId,
|
|
126
|
+
name: d?.name ?? tableId,
|
|
127
|
+
fields: Array.isArray(d?.fields) ? d.fields : [],
|
|
128
|
+
views: Array.isArray(d?.views) ? d.views : [],
|
|
107
129
|
};
|
|
108
130
|
}
|
|
109
131
|
/** GET /api/v1/mcp/stacks/:stackId/tables/:tableId/rows — list rows (MCP API). */
|
package/package.json
CHANGED
|
@@ -1,26 +1,44 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "stackby-mcp-server",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "MCP server for Stackby — list stacks, tables, records; create/update/delete rows and schema via AI clients (Cursor, Claude, Cline).",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"bin": {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"
|
|
21
|
-
},
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
|
|
26
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "stackby-mcp-server",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "MCP server for Stackby — list stacks, tables, records; create/update/delete rows and schema via AI clients (Cursor, Claude, Cline).",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"stackby-mcp-server": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc && node -e \"console.log('\\nBuild OK. Output in dist/'); console.log('Run npm start to run the server.');\"",
|
|
14
|
+
"start": "node dist/index.js",
|
|
15
|
+
"start:http": "node dist/server-http.js",
|
|
16
|
+
"dev": "tsc && node dist/index.js",
|
|
17
|
+
"prepare": "npm run build"
|
|
18
|
+
},
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=18"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"mcp",
|
|
24
|
+
"stackby",
|
|
25
|
+
"model-context-protocol",
|
|
26
|
+
"cursor",
|
|
27
|
+
"claude",
|
|
28
|
+
"ai"
|
|
29
|
+
],
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/stackbyhq/stackby-mcp-server"
|
|
34
|
+
},
|
|
35
|
+
"type": "module",
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
38
|
+
"zod": "^3.23.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^20.10.0",
|
|
42
|
+
"typescript": "^5.3.0"
|
|
43
|
+
}
|
|
44
|
+
}
|