Skip to content

Commit

Permalink
✨ feat: application
Browse files Browse the repository at this point in the history
add pglite application
  • Loading branch information
junjiepro committed Dec 5, 2024
1 parent 036ba2a commit 53f279a
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 0 deletions.
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"lint": "next lint"
},
"dependencies": {
"@electric-sql/pglite": "^0.2.14",
"@hookform/resolvers": "^3.3.4",
"@mlc-ai/web-llm": "^0.2.46",
"@modelcontextprotocol/sdk": "^1.0.1",
Expand Down
2 changes: 2 additions & 0 deletions src/components/applications/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

import React from "react";
import exampleRegister from "@/lib/applications/example";
import pgliteRegister from "@/lib/applications/pglite";

export default function ApplicationsRegister() {
React.useEffect(() => {
exampleRegister();
pgliteRegister();
}, []);
return null;
}
18 changes: 18 additions & 0 deletions src/lib/applications/pglite/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";

export const starter = async (transport: Transport) => {
const client = new Client(
{
name: "pglite-client",
version: "1.0.0",
},
{
capabilities: {},
}
);

await client.connect(transport);

return client;
};
10 changes: 10 additions & 0 deletions src/lib/applications/pglite/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { registerClient, registerServer } from "../base/host";
import { starter as clientStarter } from "./client";
import { starter as serverStarter } from "./server";

const register = () => {
registerClient("pglite", clientStarter);
registerServer("pglite", serverStarter);
};

export default register;
113 changes: 113 additions & 0 deletions src/lib/applications/pglite/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import {
CallToolRequestSchema,
ListResourcesRequestSchema,
ListToolsRequestSchema,
ReadResourceRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
import { PGlite } from "@electric-sql/pglite";

const mainDb = new PGlite("idb://xp-main-pgdata");

export const starter = async (transport: Transport) => {
const server = new Server(
{
name: "pglite-server",
version: "1.0.0",
},
{
capabilities: {
resources: {},
tools: {},
},
}
);

const SCHEMA_PATH = "schema";

server.setRequestHandler(ListResourcesRequestSchema, async () => {
const result = await mainDb.query(
"SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'"
);
return {
resources: (result.rows as any[]).map((row) => ({
uri: new URL(`${row.table_name}/${SCHEMA_PATH}`).href,
mimeType: "application/json",
name: `"${row.table_name}" database schema`,
})),
};
});

server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const resourceUrl = new URL(request.params.uri);

const pathComponents = resourceUrl.pathname.split("/");
const schema = pathComponents.pop();
const tableName = pathComponents.pop();

if (schema !== SCHEMA_PATH) {
throw new Error("Invalid resource URI");
}

const result = await mainDb.query(
"SELECT column_name, data_type FROM information_schema.columns WHERE table_name = $1",
[tableName]
);

return {
contents: [
{
uri: request.params.uri,
mimeType: "application/json",
text: JSON.stringify(result.rows, null, 2),
},
],
};
});

server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "query",
description: "Run a read-only SQL query",
inputSchema: {
type: "object",
properties: {
sql: { type: "string" },
},
},
},
],
};
});

server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "query") {
const sql = request.params.arguments?.sql as string;

try {
await mainDb.query("BEGIN TRANSACTION READ ONLY");
const result = await mainDb.query(sql);
return {
content: [
{ type: "text", text: JSON.stringify(result.rows, null, 2) },
],
isError: false,
};
} catch (error) {
throw error;
} finally {
mainDb
.query("ROLLBACK")
.catch((error) =>
console.warn("Could not roll back transaction:", error)
);
}
}
throw new Error(`Unknown tool: ${request.params.name}`);
});

await server.connect(transport);
};

0 comments on commit 53f279a

Please sign in to comment.