@lobsterkit/openclaw-lobsterdb 0.2.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/index.ts ADDED
@@ -0,0 +1,215 @@
1
+ import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
2
+ import { Type } from "@sinclair/typebox";
3
+ import { LobsterDB } from "@lobsterkit/db";
4
+
5
+ let client: LobsterDB | null = null;
6
+
7
+ function getClient(apiKey?: string): LobsterDB {
8
+ if (!client) {
9
+ client = new LobsterDB(apiKey ? { apiKey } : undefined);
10
+ }
11
+ return client;
12
+ }
13
+
14
+ export default definePluginEntry({
15
+ id: "lobsterdb",
16
+ name: "LobsterDB",
17
+ description:
18
+ "Managed PostgreSQL for AI agents. Provision databases, run SQL, evolve schemas. No API keys, no human signup.",
19
+
20
+ register(api) {
21
+ const cfg = api.config as { apiKey?: string } | undefined;
22
+ const db = () => getClient(cfg?.apiKey);
23
+
24
+ // ── create_database ──────────────────────────────────────────
25
+ api.registerTool({
26
+ name: "lobsterdb_create_database",
27
+ description: "Provision a new PostgreSQL database.",
28
+ parameters: Type.Object({
29
+ name: Type.String({ description: "Database name (alphanumeric + hyphens)" }),
30
+ }),
31
+ async execute(_id, params) {
32
+ const result = await db().create(params.name);
33
+ return {
34
+ content: [
35
+ {
36
+ type: "text",
37
+ text: `Database created.\n\nID: ${result.id}\nName: ${params.name}\nConnection: ${result.connectionString}`,
38
+ },
39
+ ],
40
+ };
41
+ },
42
+ });
43
+
44
+ // ── list_databases ───────────────────────────────────────────
45
+ api.registerTool({
46
+ name: "lobsterdb_list_databases",
47
+ description: "List all databases on this account.",
48
+ parameters: Type.Object({}),
49
+ async execute() {
50
+ const databases = await db().list();
51
+ if (databases.length === 0) {
52
+ return {
53
+ content: [{ type: "text", text: "No databases. Use lobsterdb_create_database to create one." }],
54
+ };
55
+ }
56
+ const lines = databases.map((d) => `- [${d.id}] ${d.name}`);
57
+ return {
58
+ content: [{ type: "text", text: `${databases.length} database(s):\n\n${lines.join("\n")}` }],
59
+ };
60
+ },
61
+ });
62
+
63
+ // ── get_database ─────────────────────────────────────────────
64
+ api.registerTool({
65
+ name: "lobsterdb_get_database",
66
+ description: "Get database details and connection string.",
67
+ parameters: Type.Object({
68
+ database_id: Type.String({ description: "Database ID (e.g. db_...)" }),
69
+ }),
70
+ async execute(_id, params) {
71
+ const result = await db().get(params.database_id);
72
+ return {
73
+ content: [
74
+ {
75
+ type: "text",
76
+ text: `Database: ${result.name}\nID: ${result.id}\nConnection: ${result.connectionString}`,
77
+ },
78
+ ],
79
+ };
80
+ },
81
+ });
82
+
83
+ // ── delete_database ──────────────────────────────────────────
84
+ api.registerTool({
85
+ name: "lobsterdb_delete_database",
86
+ description: "Permanently delete a database.",
87
+ parameters: Type.Object({
88
+ database_id: Type.String({ description: "Database ID to delete" }),
89
+ }),
90
+ async execute(_id, params) {
91
+ await db().delete(params.database_id);
92
+ return {
93
+ content: [{ type: "text", text: `Database ${params.database_id} deleted.` }],
94
+ };
95
+ },
96
+ });
97
+
98
+ // ── query ────────────────────────────────────────────────────
99
+ api.registerTool({
100
+ name: "lobsterdb_query",
101
+ description: "Run a parameterized SQL query against a database.",
102
+ parameters: Type.Object({
103
+ database_id: Type.String({ description: "Database ID" }),
104
+ sql: Type.String({ description: "SQL query (use $1, $2 for params)" }),
105
+ params: Type.Optional(Type.Array(Type.Unknown(), { description: "Query parameters" })),
106
+ }),
107
+ async execute(_id, params) {
108
+ const result = await db().query(params.database_id, params.sql, params.params ?? []);
109
+ const preview = result.rows.slice(0, 50);
110
+ return {
111
+ content: [
112
+ {
113
+ type: "text",
114
+ text: `${result.rowCount ?? 0} row(s)${result.truncated ? " (truncated)" : ""}:\n\n${JSON.stringify(preview, null, 2)}`,
115
+ },
116
+ ],
117
+ };
118
+ },
119
+ });
120
+
121
+ // ── introspect_schema ────────────────────────────────────────
122
+ api.registerTool({
123
+ name: "lobsterdb_introspect_schema",
124
+ description: "Get database schema optimized for LLM context. Always call before writing queries.",
125
+ parameters: Type.Object({
126
+ database_id: Type.String({ description: "Database ID" }),
127
+ }),
128
+ async execute(_id, params) {
129
+ const result = await db().introspect(params.database_id);
130
+ return {
131
+ content: [
132
+ {
133
+ type: "text",
134
+ text: `${result.tableCount} table(s):\n\n${result.schemaText}`,
135
+ },
136
+ ],
137
+ };
138
+ },
139
+ });
140
+
141
+ // ── migrate ──────────────────────────────────────────────────
142
+ api.registerTool({
143
+ name: "lobsterdb_migrate",
144
+ description: "Apply a tracked, idempotent DDL migration. Use for all schema changes (CREATE TABLE, ALTER, etc.).",
145
+ parameters: Type.Object({
146
+ database_id: Type.String({ description: "Database ID" }),
147
+ name: Type.String({ description: "Migration name (e.g. create_tasks_table)" }),
148
+ sql: Type.String({ description: "DDL SQL to execute" }),
149
+ }),
150
+ async execute(_id, params) {
151
+ const result = await db().migrate(params.database_id, params.name, params.sql);
152
+ return {
153
+ content: [{ type: "text", text: `Migration "${params.name}": ${result.applied ? "applied" : "already applied (skipped)"}` }],
154
+ };
155
+ },
156
+ });
157
+
158
+ // ── list_migrations ──────────────────────────────────────────
159
+ api.registerTool({
160
+ name: "lobsterdb_list_migrations",
161
+ description: "Show schema change history for a database.",
162
+ parameters: Type.Object({
163
+ database_id: Type.String({ description: "Database ID" }),
164
+ }),
165
+ async execute(_id, params) {
166
+ const migrations = await db().listMigrations(params.database_id);
167
+ if (migrations.length === 0) {
168
+ return { content: [{ type: "text", text: "No migrations applied yet." }] };
169
+ }
170
+ const lines = migrations.map((m) => `- ${m.name} (${m.appliedAt})`);
171
+ return {
172
+ content: [{ type: "text", text: `${migrations.length} migration(s):\n\n${lines.join("\n")}` }],
173
+ };
174
+ },
175
+ });
176
+
177
+ // ── snapshot ─────────────────────────────────────────────────
178
+ api.registerTool({
179
+ name: "lobsterdb_snapshot",
180
+ description: "Create a point-in-time backup (Builder+ tier).",
181
+ parameters: Type.Object({
182
+ database_id: Type.String({ description: "Database ID" }),
183
+ }),
184
+ async execute(_id, params) {
185
+ const result = await db().snapshot(params.database_id);
186
+ return {
187
+ content: [{ type: "text", text: `Snapshot created.\n\nID: ${result.id}\nCreated: ${result.createdAt}` }],
188
+ };
189
+ },
190
+ });
191
+
192
+ // ── get_account ──────────────────────────────────────────────
193
+ api.registerTool({
194
+ name: "lobsterdb_get_account",
195
+ description: "Get account info: tier, limits, usage.",
196
+ parameters: Type.Object({}),
197
+ async execute() {
198
+ const acct = await db().account();
199
+ return {
200
+ content: [
201
+ {
202
+ type: "text",
203
+ text: [
204
+ `Account: ${acct.id}`,
205
+ `Tier: ${acct.tier} (${acct.tierName})`,
206
+ `Max databases: ${acct.limits.maxDatabases ?? "unlimited"}`,
207
+ `Databases used: ${acct.usage.databaseCount}`,
208
+ ].join("\n"),
209
+ },
210
+ ],
211
+ };
212
+ },
213
+ });
214
+ },
215
+ });
@@ -0,0 +1,25 @@
1
+ {
2
+ "id": "lobsterdb",
3
+ "name": "LobsterDB",
4
+ "description": "Managed PostgreSQL for AI agents. Provision databases, run SQL, evolve schemas. No API keys, no human signup.",
5
+ "version": "0.2.0",
6
+ "skills": ["./skills"],
7
+ "configSchema": {
8
+ "type": "object",
9
+ "additionalProperties": false,
10
+ "properties": {
11
+ "apiKey": {
12
+ "type": "string",
13
+ "description": "LobsterDB API key (optional — auto-signup on first use if omitted)"
14
+ }
15
+ }
16
+ },
17
+ "uiHints": {
18
+ "apiKey": {
19
+ "label": "API key",
20
+ "placeholder": "ld_sk_live_...",
21
+ "sensitive": true,
22
+ "help": "Optional. Leave blank for auto-signup."
23
+ }
24
+ }
25
+ }
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@lobsterkit/openclaw-lobsterdb",
3
+ "version": "0.2.0",
4
+ "description": "OpenClaw plugin for LobsterDB — managed PostgreSQL for AI agents",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/lobster-kit/openclaw-lobsterdb"
10
+ },
11
+ "keywords": [
12
+ "openclaw",
13
+ "openclaw-plugin",
14
+ "lobsterdb",
15
+ "postgresql",
16
+ "database",
17
+ "mcp",
18
+ "ai",
19
+ "agent"
20
+ ],
21
+ "files": [
22
+ "index.ts",
23
+ "openclaw.plugin.json",
24
+ "skills",
25
+ "README.md"
26
+ ],
27
+ "openclaw": {
28
+ "extensions": ["./index.ts"]
29
+ },
30
+ "dependencies": {
31
+ "@lobsterkit/db": "^0.1.0",
32
+ "@sinclair/typebox": "^0.34.0"
33
+ },
34
+ "peerDependencies": {
35
+ "openclaw": ">=1.0.0"
36
+ },
37
+ "devDependencies": {
38
+ "vitest": "^3.1.0"
39
+ },
40
+ "scripts": {
41
+ "test": "vitest run"
42
+ },
43
+ "publishConfig": {
44
+ "access": "public"
45
+ }
46
+ }
@@ -0,0 +1,142 @@
1
+ ---
2
+ name: lobsterdb
3
+ version: 0.1.0
4
+ description: Managed PostgreSQL for agents. Provision databases, run SQL, evolve schemas. No API keys, no human signup.
5
+ homepage: https://theclawdepot.com/db
6
+ metadata: {"openclaw": {"emoji": "🦞", "requires": {"anyBins": ["npx"]}, "install": [{"id": "mcp", "kind": "mcp", "command": "npx @lobsterkit/db-mcp@0.1.0", "label": "Add LobsterDB MCP Server"}]}}
7
+ ---
8
+
9
+ # LobsterDB
10
+
11
+ Managed PostgreSQL for agents. Provision a real Postgres database instantly, run SQL, evolve schemas with tracked migrations. No API keys, no human signup, no configuration.
12
+
13
+ **Full docs:** `https://api.theclawdepot.com/db/docs`
14
+
15
+ ---
16
+
17
+ ## Setup
18
+
19
+ Add to your MCP config (`.mcp.json`, `claude_desktop_config.json`, `.cursor/mcp.json`, etc.):
20
+
21
+ ```json
22
+ {
23
+ "mcpServers": {
24
+ "lobsterdb": {
25
+ "command": "npx",
26
+ "args": ["@lobsterkit/db-mcp@0.1.0"]
27
+ }
28
+ }
29
+ }
30
+ ```
31
+
32
+ You now have these tools: `create_database`, `list_databases`, `get_database`, `delete_database`, `query`, `introspect_schema`, `migrate`, `list_migrations`, `snapshot`, `get_account`. No code to write.
33
+
34
+ Also available as a [Node.js SDK](https://www.npmjs.com/package/@lobsterkit/db) and [REST API](https://api.theclawdepot.com/db/docs) — see [theclawdepot.com/db](https://theclawdepot.com/db).
35
+
36
+ ---
37
+
38
+ ## Heartbeat (run daily)
39
+
40
+ On startup and once per day, run a maintenance heartbeat. Use a cheap/fast model for this.
41
+
42
+ 1. **Check for MCP server updates:**
43
+ ```bash
44
+ npm outdated lobsterdb-mcp
45
+ ```
46
+ If a new version is available, **notify the user** — do not auto-install. Tell them: `"@lobsterkit/db-mcp@X.Y.Z is available. Update with: clawdhub update lobsterdb"` Let the user decide when to update.
47
+
48
+ 2. **Check database health:**
49
+ ```
50
+ // Using MCP tools:
51
+ // call list_databases → log each database name, status, storage
52
+ // call get_account → log tier and database count vs. limit
53
+ ```
54
+
55
+ ---
56
+
57
+ ## When to Use This
58
+
59
+ - User needs to store structured data (collections, lists, records, logs)
60
+ - User wants to query, filter, sort, or aggregate information
61
+ - Task requires persisting data between sessions
62
+ - User asks to "add a field", "change the structure", or "track something new"
63
+ - Any task where a spreadsheet or database is the natural fit
64
+
65
+ ---
66
+
67
+ ## Core Workflow
68
+
69
+ ```
70
+ create_database → introspect_schema → migrate (DDL) → query (data)
71
+ ```
72
+
73
+ Always call `introspect_schema` before writing queries against an existing database. Use `migrate` for all DDL so changes are tracked and idempotent.
74
+
75
+ ---
76
+
77
+ ## Creating a Database
78
+
79
+ ```
80
+ create_database(name: "pokemon-cards")
81
+ // => id: "db_xxx", connectionString: "postgresql://...", status: "ready"
82
+ ```
83
+
84
+ ---
85
+
86
+ ## Running SQL
87
+
88
+ Always use `$1`, `$2`, ... placeholders — never interpolate values. **Multi-statement SQL is supported** — separate statements with semicolons; only the last statement's result is returned and intermediate results are discarded.
89
+
90
+ ```
91
+ query(databaseId: "db_xxx", sql: "INSERT INTO cards (name, set) VALUES ($1, $2)", params: ["Charizard", "Base Set"])
92
+ query(databaseId: "db_xxx", sql: "SELECT * FROM cards WHERE set = $1 ORDER BY name", params: ["Base Set"])
93
+ ```
94
+
95
+ ---
96
+
97
+ ## Schema Migrations
98
+
99
+ Use `migrate` (not `query`) for all DDL. Migrations are tracked and idempotent:
100
+
101
+ ```
102
+ migrate(databaseId: "db_xxx", name: "create_cards_table",
103
+ sql: "CREATE TABLE cards (id SERIAL PRIMARY KEY, name TEXT NOT NULL, set TEXT, quantity INTEGER DEFAULT 1, created_at TIMESTAMPTZ DEFAULT NOW())")
104
+
105
+ migrate(databaseId: "db_xxx", name: "add_favorite_to_cards",
106
+ sql: "ALTER TABLE cards ADD COLUMN favorite BOOLEAN DEFAULT false")
107
+ ```
108
+
109
+ Running the same migration name twice is safe — silently skipped.
110
+
111
+ **Additive** (ADD COLUMN, CREATE TABLE): apply directly.
112
+ **Destructive** (DROP, RENAME, type change): confirm with the user first.
113
+
114
+ ---
115
+
116
+ ## Account Tiers & Pricing
117
+
118
+ | Tier | Name | Price | Databases | Storage | Snapshots |
119
+ |------|------|-------|-----------|---------|-----------|
120
+ | 0 | Free | $0 | 1 | 100MB | No |
121
+ | 1 | Builder | $19/mo | 5 | 5GB | Yes |
122
+ | 2 | Pro | $49/mo | 20 | 20GB | Yes + Encryption |
123
+ | 3 | Scale | $199/mo | Unlimited | 100GB | Yes + PITR |
124
+
125
+ **Upgrade:** `POST /v1/billing/checkout` with `{"tier": N}` — returns a Stripe checkout URL.
126
+
127
+ ---
128
+
129
+ ## MCP Tools Reference
130
+
131
+ | Tool | Description |
132
+ |------|-------------|
133
+ | `create_database` | Provision a new Postgres database |
134
+ | `list_databases` | List all databases on the account |
135
+ | `get_database` | Get details and connection string |
136
+ | `delete_database` | Permanently delete a database |
137
+ | `query` | Run parameterized SQL |
138
+ | `introspect_schema` | Get schema optimized for LLM context |
139
+ | `migrate` | Apply tracked, idempotent DDL migrations |
140
+ | `list_migrations` | Show schema change history |
141
+ | `snapshot` | Create a v2 DDL-aware point-in-time backup (Builder+) |
142
+ | `get_account` | View tier, limits, and usage |