@chaprola/mcp-server 1.9.0 → 1.10.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/dist/index.js +32 -6
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -585,7 +585,7 @@ server.tool("chaprola_download", "Get a presigned S3 URL to download any file yo
|
|
|
585
585
|
server.tool("chaprola_query", "SQL-free data query with WHERE, SELECT, aggregation, ORDER BY, JOIN, pivot, and Mercury scoring", {
|
|
586
586
|
project: z.string().describe("Project name"),
|
|
587
587
|
file: z.string().describe("Data file to query"),
|
|
588
|
-
where: z.string().optional().describe("JSON object of filter conditions, e.g. {\"field\": \"status\", \"op\": \"eq\", \"value\": \"active\"}. Ops: eq, ne, gt, ge, lt, le, between, contains, starts_with"),
|
|
588
|
+
where: z.string().optional().describe("JSON object of filter conditions, e.g. {\"field\": \"status\", \"op\": \"eq\", \"value\": \"active\"}. Ops: eq, ne, gt, ge, lt, le, between, contains, starts_with, in, not_in. For in/not_in, value must be a JSON array of strings, e.g. {\"field\": \"status\", \"op\": \"in\", \"value\": [\"active\", \"pending\"]}"),
|
|
589
589
|
select: z.array(z.string()).optional().describe("Fields to include in output"),
|
|
590
590
|
aggregate: z.string().optional().describe("JSON array of aggregation specs, e.g. [{\"field\": \"amount\", \"func\": \"sum\"}]. Funcs: count, sum, avg, min, max, stddev"),
|
|
591
591
|
order_by: z.string().optional().describe("JSON array of sort specs, e.g. [{\"field\": \"name\", \"dir\": \"asc\"}]"),
|
|
@@ -868,15 +868,22 @@ server.tool("chaprola_schedule_delete", "Delete a scheduled job by name", {
|
|
|
868
868
|
return textResult(res);
|
|
869
869
|
}));
|
|
870
870
|
// --- Record CRUD ---
|
|
871
|
-
server.tool("chaprola_insert_record", "Insert
|
|
871
|
+
server.tool("chaprola_insert_record", "Insert one or more records into a data file. For single insert, use record. For batch insert (up to 1000), use records. All records are validated before any writes — invalid batch = no partial writes.", {
|
|
872
872
|
project: z.string().describe("Project name"),
|
|
873
873
|
file: z.string().describe("Data file name (without extension)"),
|
|
874
|
-
record: z.string().describe("JSON object of
|
|
874
|
+
record: z.string().optional().describe("JSON object of a single record to insert, e.g. {\"name\": \"foo\", \"status\": \"active\"}. Use this OR records, not both."),
|
|
875
|
+
records: z.string().optional().describe("JSON array of records for batch insert (max 1000), e.g. [{\"name\": \"foo\"}, {\"name\": \"bar\"}]. Use this OR record, not both."),
|
|
875
876
|
userid: z.string().optional().describe("Project owner's username. Required when accessing a shared project where you are a writer. Defaults to the authenticated user."),
|
|
876
|
-
}, async ({ project, file, record: recordStr, userid }) => withBaaCheck(async () => {
|
|
877
|
-
const record = typeof recordStr === 'string' ? JSON.parse(recordStr) : recordStr;
|
|
877
|
+
}, async ({ project, file, record: recordStr, records: recordsStr, userid }) => withBaaCheck(async () => {
|
|
878
|
+
const record = recordStr ? (typeof recordStr === 'string' ? JSON.parse(recordStr) : recordStr) : undefined;
|
|
879
|
+
const records = recordsStr ? (typeof recordsStr === 'string' ? JSON.parse(recordsStr) : recordsStr) : undefined;
|
|
878
880
|
const { username } = getCredentials();
|
|
879
|
-
const
|
|
881
|
+
const body = { userid: userid || username, project, file };
|
|
882
|
+
if (record)
|
|
883
|
+
body.record = record;
|
|
884
|
+
if (records)
|
|
885
|
+
body.records = records;
|
|
886
|
+
const res = await authedFetch("/insert-record", body);
|
|
880
887
|
return textResult(res);
|
|
881
888
|
}));
|
|
882
889
|
server.tool("chaprola_update_record", "Update fields in a single record matched by a where clause. If no sort-key changes, updates in place; otherwise marks old record ignored and appends to merge file.", {
|
|
@@ -903,6 +910,25 @@ server.tool("chaprola_delete_record", "Delete a single record matched by a where
|
|
|
903
910
|
const res = await authedFetch("/delete-record", { userid: userid || username, project, file, where: whereClause });
|
|
904
911
|
return textResult(res);
|
|
905
912
|
}));
|
|
913
|
+
server.tool("chaprola_upsert_record", "Insert or update a record by key field. If a record with the matching key value exists, update it in place. If not, insert it. Supports batch: pass records array to upsert multiple records in one call.", {
|
|
914
|
+
project: z.string().describe("Project name"),
|
|
915
|
+
file: z.string().describe("Data file name (without extension)"),
|
|
916
|
+
key: z.string().describe("Field name to match on, e.g. \"contact_id\". Must exist in the format file."),
|
|
917
|
+
record: z.string().optional().describe("JSON object of a single record to upsert, e.g. {\"contact_id\": \"c-42\", \"name\": \"Alice\"}. Must contain the key field. Use this OR records, not both."),
|
|
918
|
+
records: z.string().optional().describe("JSON array of records for batch upsert (max 1000). Each must contain the key field. Use this OR record, not both."),
|
|
919
|
+
userid: z.string().optional().describe("Project owner's username. Required when accessing a shared project where you are a writer. Defaults to the authenticated user."),
|
|
920
|
+
}, async ({ project, file, key, record: recordStr, records: recordsStr, userid }) => withBaaCheck(async () => {
|
|
921
|
+
const record = recordStr ? (typeof recordStr === 'string' ? JSON.parse(recordStr) : recordStr) : undefined;
|
|
922
|
+
const records = recordsStr ? (typeof recordsStr === 'string' ? JSON.parse(recordsStr) : recordsStr) : undefined;
|
|
923
|
+
const { username } = getCredentials();
|
|
924
|
+
const body = { userid: userid || username, project, file, key };
|
|
925
|
+
if (record)
|
|
926
|
+
body.record = record;
|
|
927
|
+
if (records)
|
|
928
|
+
body.records = records;
|
|
929
|
+
const res = await authedFetch("/upsert-record", body);
|
|
930
|
+
return textResult(res);
|
|
931
|
+
}));
|
|
906
932
|
server.tool("chaprola_consolidate", "Merge a .MRG file into its parent .DA, producing a clean sorted data file. Deletes .MRG and .IGN after success. Aborts if .MRG was modified during the operation.", {
|
|
907
933
|
project: z.string().describe("Project name"),
|
|
908
934
|
file: z.string().describe("Data file name (without extension)"),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chaprola/mcp-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "MCP server for Chaprola — agent-first data platform. Gives AI agents tools for structured data storage, record CRUD, querying, schema inspection, documentation lookup, web search, URL fetching, scheduled jobs, scoped site keys, and execution via plain HTTP.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|