mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
feat: add mcp server (#303)
* feat: added the mcp server * feat: added the mcp server * fix: api for database not linked to any projects * fix: added variable to disable MCP * chore: refactoring
This commit is contained in:
+2
-1
@@ -76,4 +76,5 @@ RETENTION_CRON="* * * * *"
|
||||
TRUSTED_DOMAINS="http://localhost:8887, http://localhost:3055, http://localhost:3056"
|
||||
|
||||
#OPENAPI_ENABLED=true
|
||||
#API_ENABLED=true
|
||||
#API_ENABLED=true
|
||||
#MCP_ENABLED=true
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
||||
import { NextResponse } from "next/server";
|
||||
import { withApiKey } from "@/lib/api-v1/middleware";
|
||||
import { createPortabaseMcpServer } from "@/lib/mcp/server";
|
||||
import type { ApiKeyContext } from "@/lib/api-v1/types";
|
||||
import { env } from "@/env.mjs";
|
||||
|
||||
/**
|
||||
* MCP endpoint — Streamable HTTP transport, stateless mode.
|
||||
*
|
||||
* Auth is handled by withApiKey before MCP is ever touched.
|
||||
* The validated key is forwarded by MCP tools to downstream /api/v1 REST calls.
|
||||
*/
|
||||
const apiEnabled = String(env.API_ENABLED) === "true";
|
||||
const mcpEnabled = String(env.MCP_ENABLED) === "true";
|
||||
|
||||
export const POST = apiEnabled && mcpEnabled
|
||||
? withApiKey(async (req: Request, ctx: ApiKeyContext) => {
|
||||
const apiKey = req.headers.get("x-api-key")!;
|
||||
|
||||
const server = createPortabaseMcpServer(ctx, apiKey);
|
||||
|
||||
const transport = new WebStandardStreamableHTTPServerTransport({
|
||||
sessionIdGenerator: undefined,
|
||||
});
|
||||
|
||||
await server.connect(transport);
|
||||
|
||||
return transport.handleRequest(req);
|
||||
})
|
||||
: () => NextResponse.json({ error: "Not found" }, { status: 404 });
|
||||
@@ -21,6 +21,7 @@
|
||||
"@better-auth/passkey": "1.6.11",
|
||||
"@better-auth/sso": "1.6.11",
|
||||
"@hookform/resolvers": "^5.4.0",
|
||||
"@modelcontextprotocol/sdk": "^1.29.0",
|
||||
"@radix-ui/react-accordion": "^1.2.12",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.15",
|
||||
"@radix-ui/react-aspect-ratio": "^1.1.8",
|
||||
|
||||
Generated
+412
@@ -26,6 +26,9 @@ importers:
|
||||
'@hookform/resolvers':
|
||||
specifier: ^5.4.0
|
||||
version: 5.4.0(react-hook-form@7.76.1(react@19.2.6))
|
||||
'@modelcontextprotocol/sdk':
|
||||
specifier: ^1.29.0
|
||||
version: 1.29.0(zod@4.3.6)
|
||||
'@radix-ui/react-accordion':
|
||||
specifier: ^1.2.12
|
||||
version: 1.2.12(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
||||
@@ -1454,6 +1457,12 @@ packages:
|
||||
'@hexagon/base64@1.1.28':
|
||||
resolution: {integrity: sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==}
|
||||
|
||||
'@hono/node-server@1.19.14':
|
||||
resolution: {integrity: sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==}
|
||||
engines: {node: '>=18.14.1'}
|
||||
peerDependencies:
|
||||
hono: ^4
|
||||
|
||||
'@hookform/resolvers@5.4.0':
|
||||
resolution: {integrity: sha512-EIsqr/t/qbinPIhGjMdtvutIN1Kk4uwbROE9/UQ93CAVGR7GkA7Y92+fX80OzXi/OB67jVFYwKGO1WzkxmkFZw==}
|
||||
peerDependencies:
|
||||
@@ -1950,6 +1959,16 @@ packages:
|
||||
'@lottiefiles/dotlottie-web@0.42.0':
|
||||
resolution: {integrity: sha512-Zr2LCaOAoPCsdAQgeLyCSiQ1+xrAJtRCyuEYDj0qR5heUwpc+Pxbb88JyTVumcXFfKOBMOMmrlsTScLz2mrvQQ==}
|
||||
|
||||
'@modelcontextprotocol/sdk@1.29.0':
|
||||
resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
'@cfworker/json-schema': ^4.1.1
|
||||
zod: ^3.25 || ^4.0
|
||||
peerDependenciesMeta:
|
||||
'@cfworker/json-schema':
|
||||
optional: true
|
||||
|
||||
'@napi-rs/wasm-runtime@1.1.4':
|
||||
resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==}
|
||||
peerDependencies:
|
||||
@@ -3820,6 +3839,10 @@ packages:
|
||||
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
accepts@2.0.0:
|
||||
resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
acorn-import-phases@1.0.4:
|
||||
resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
@@ -3852,6 +3875,14 @@ packages:
|
||||
ajv:
|
||||
optional: true
|
||||
|
||||
ajv-formats@3.0.1:
|
||||
resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==}
|
||||
peerDependencies:
|
||||
ajv: ^8.0.0
|
||||
peerDependenciesMeta:
|
||||
ajv:
|
||||
optional: true
|
||||
|
||||
ajv-keywords@5.1.0:
|
||||
resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==}
|
||||
peerDependencies:
|
||||
@@ -4113,6 +4144,10 @@ packages:
|
||||
block-stream2@2.1.0:
|
||||
resolution: {integrity: sha512-suhjmLI57Ewpmq00qaygS8UgEq2ly2PCItenIyhMqVjo4t4pGzqMvfgJuX8iWTeSDdfSSqS6j38fL4ToNL7Pfg==}
|
||||
|
||||
body-parser@2.2.2:
|
||||
resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
boolbase@1.0.0:
|
||||
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
|
||||
|
||||
@@ -4162,6 +4197,10 @@ packages:
|
||||
resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
bytes@3.1.2:
|
||||
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
c12@3.1.0:
|
||||
resolution: {integrity: sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==}
|
||||
peerDependencies:
|
||||
@@ -4379,6 +4418,14 @@ packages:
|
||||
constant-case@3.0.4:
|
||||
resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==}
|
||||
|
||||
content-disposition@1.1.0:
|
||||
resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
content-type@1.0.5:
|
||||
resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
content-type@2.0.0:
|
||||
resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -4422,6 +4469,10 @@ packages:
|
||||
convert-source-map@2.0.0:
|
||||
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
|
||||
|
||||
cookie-signature@1.2.2:
|
||||
resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==}
|
||||
engines: {node: '>=6.6.0'}
|
||||
|
||||
cookie@0.7.2:
|
||||
resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
|
||||
engines: {node: '>= 0.6'}
|
||||
@@ -4617,6 +4668,10 @@ packages:
|
||||
resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
depd@2.0.0:
|
||||
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
destr@2.0.5:
|
||||
resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==}
|
||||
|
||||
@@ -4789,6 +4844,9 @@ packages:
|
||||
ecdsa-sig-formatter@1.0.11:
|
||||
resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
|
||||
|
||||
ee-first@1.1.1:
|
||||
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
|
||||
|
||||
effect@3.20.0:
|
||||
resolution: {integrity: sha512-qMLfDJscrNG8p/aw+IkT9W7fgj50Z4wG5bLBy0Txsxz8iUHjDIkOgO3SV0WZfnQbNG2VJYb0b+rDLMrhM4+Krw==}
|
||||
|
||||
@@ -4827,6 +4885,10 @@ packages:
|
||||
emphasize@4.2.0:
|
||||
resolution: {integrity: sha512-yGKvcFUHlBsUPwlxTlzKLR8+zhpbitkFOMCUxN8fTJng9bdH3WNzUGkhdaGdjndSUgqmMPBN7umfwnUdLz5Axg==}
|
||||
|
||||
encodeurl@2.0.0:
|
||||
resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
encoding-sniffer@0.2.1:
|
||||
resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==}
|
||||
|
||||
@@ -5084,6 +5146,10 @@ packages:
|
||||
resolution: {integrity: sha512-qifAYjuW5AM1eEEIsFnOwB+TGqu6ynU3OKj9WbUTOtUBHFPZqL03XUW34kbp3zm19Ald+U8dEyRXaVsUck+Y1g==}
|
||||
engines: {node: '>=20'}
|
||||
|
||||
etag@1.8.1:
|
||||
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
eventemitter3@4.0.7:
|
||||
resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
|
||||
|
||||
@@ -5094,10 +5160,28 @@ packages:
|
||||
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
|
||||
engines: {node: '>=0.8.x'}
|
||||
|
||||
eventsource-parser@3.1.0:
|
||||
resolution: {integrity: sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
eventsource@3.0.7:
|
||||
resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
execa@8.0.1:
|
||||
resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
|
||||
engines: {node: '>=16.17'}
|
||||
|
||||
express-rate-limit@8.5.2:
|
||||
resolution: {integrity: sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==}
|
||||
engines: {node: '>= 16'}
|
||||
peerDependencies:
|
||||
express: '>= 4.11'
|
||||
|
||||
express@5.2.1:
|
||||
resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
exsolve@1.0.8:
|
||||
resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==}
|
||||
|
||||
@@ -5189,6 +5273,10 @@ packages:
|
||||
resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
finalhandler@2.1.1:
|
||||
resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==}
|
||||
engines: {node: '>= 18.0.0'}
|
||||
|
||||
find-up@5.0.0:
|
||||
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -5216,6 +5304,10 @@ packages:
|
||||
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
|
||||
engines: {node: '>=12.20.0'}
|
||||
|
||||
forwarded@0.2.0:
|
||||
resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
fraction.js@4.3.7:
|
||||
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
|
||||
|
||||
@@ -5247,6 +5339,10 @@ packages:
|
||||
react-dom:
|
||||
optional: true
|
||||
|
||||
fresh@2.0.0:
|
||||
resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
fs-constants@1.0.0:
|
||||
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
|
||||
|
||||
@@ -5446,6 +5542,10 @@ packages:
|
||||
highlight.js@10.4.1:
|
||||
resolution: {integrity: sha512-yR5lWvNz7c85OhVAEAeFhVCc/GV4C30Fjzc/rCP0aCWzc1UUOPUk55dK/qdwTZHBvMZo+eZ2jpk62ndX/xMFlg==}
|
||||
|
||||
hono@4.12.23:
|
||||
resolution: {integrity: sha512-eIaZ9qDgu7XV0pxOCrg7/WhnQ6Ivm22UcxhXx/A3dcbqbbYgBEkc6e/J/s7j2tS96zoB0S9VBdLwQNCWwUo4LA==}
|
||||
engines: {node: '>=16.9.0'}
|
||||
|
||||
hosted-git-info@8.1.0:
|
||||
resolution: {integrity: sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==}
|
||||
engines: {node: ^18.17.0 || >=20.5.0}
|
||||
@@ -5460,6 +5560,10 @@ packages:
|
||||
htmlparser2@8.0.2:
|
||||
resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
|
||||
|
||||
http-errors@2.0.1:
|
||||
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
http-proxy-agent@7.0.2:
|
||||
resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
|
||||
engines: {node: '>= 14'}
|
||||
@@ -5537,6 +5641,10 @@ packages:
|
||||
resolution: {integrity: sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==}
|
||||
engines: {node: '>= 12'}
|
||||
|
||||
ipaddr.js@1.9.1:
|
||||
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
|
||||
engines: {node: '>= 0.10'}
|
||||
|
||||
ipaddr.js@2.4.0:
|
||||
resolution: {integrity: sha512-9VGk3HGanVE6JoZXHiCpnGy5X0jYDnN4EA4lntFPj+1vIWlFhIylq2CrrCOJH9EAhc5CYhq18F2Av2tgoAPsYQ==}
|
||||
engines: {node: '>= 10'}
|
||||
@@ -5642,6 +5750,9 @@ packages:
|
||||
resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
is-promise@4.0.0:
|
||||
resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
|
||||
|
||||
is-regex@1.2.1:
|
||||
resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -5770,6 +5881,9 @@ packages:
|
||||
json-schema-traverse@1.0.0:
|
||||
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
|
||||
|
||||
json-schema-typed@8.0.2:
|
||||
resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==}
|
||||
|
||||
json-stable-stringify-without-jsonify@1.0.1:
|
||||
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
|
||||
|
||||
@@ -6025,10 +6139,18 @@ packages:
|
||||
peerDependencies:
|
||||
react: ^18.0 || ^19.0
|
||||
|
||||
media-typer@1.1.0:
|
||||
resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
meow@13.2.0:
|
||||
resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
merge-descriptors@2.0.0:
|
||||
resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
merge-stream@2.0.0:
|
||||
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
|
||||
|
||||
@@ -6159,6 +6281,10 @@ packages:
|
||||
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
negotiator@1.0.0:
|
||||
resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
neo-async@2.6.2:
|
||||
resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
|
||||
|
||||
@@ -6381,6 +6507,10 @@ packages:
|
||||
resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
on-finished@2.4.1:
|
||||
resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
once@1.4.0:
|
||||
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
|
||||
|
||||
@@ -6478,6 +6608,10 @@ packages:
|
||||
parseley@0.12.1:
|
||||
resolution: {integrity: sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==}
|
||||
|
||||
parseurl@1.3.3:
|
||||
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
pascal-case@3.1.2:
|
||||
resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==}
|
||||
|
||||
@@ -6510,6 +6644,9 @@ packages:
|
||||
resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==}
|
||||
engines: {node: 18 || 20 || >=22}
|
||||
|
||||
path-to-regexp@8.4.2:
|
||||
resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==}
|
||||
|
||||
pathe@2.0.3:
|
||||
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
|
||||
|
||||
@@ -6589,6 +6726,10 @@ packages:
|
||||
resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
pkce-challenge@5.0.1:
|
||||
resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==}
|
||||
engines: {node: '>=16.20.0'}
|
||||
|
||||
pkg-types@1.3.1:
|
||||
resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
|
||||
|
||||
@@ -6727,6 +6868,10 @@ packages:
|
||||
protocols@2.0.2:
|
||||
resolution: {integrity: sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==}
|
||||
|
||||
proxy-addr@2.0.7:
|
||||
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
|
||||
engines: {node: '>= 0.10'}
|
||||
|
||||
proxy-agent@6.5.0:
|
||||
resolution: {integrity: sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==}
|
||||
engines: {node: '>= 14'}
|
||||
@@ -6771,6 +6916,14 @@ packages:
|
||||
quick-format-unescaped@4.0.4:
|
||||
resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==}
|
||||
|
||||
range-parser@1.2.1:
|
||||
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
raw-body@3.0.2:
|
||||
resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==}
|
||||
engines: {node: '>= 0.10'}
|
||||
|
||||
rc9@2.1.2:
|
||||
resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==}
|
||||
|
||||
@@ -6992,6 +7145,10 @@ packages:
|
||||
rou3@0.7.12:
|
||||
resolution: {integrity: sha512-iFE4hLDuloSWcD7mjdCDhx2bKcIsYbtOTpfH5MHHLSKMOUyjqQXTeZVa289uuwEGEKFoE/BAPbhaU4B774nceg==}
|
||||
|
||||
router@2.2.0:
|
||||
resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
run-applescript@7.1.0:
|
||||
resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -7068,9 +7225,17 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
send@1.2.1:
|
||||
resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
sentence-case@3.0.4:
|
||||
resolution: {integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==}
|
||||
|
||||
serve-static@2.2.1:
|
||||
resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
set-cookie-parser@3.1.0:
|
||||
resolution: {integrity: sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==}
|
||||
|
||||
@@ -7086,6 +7251,9 @@ packages:
|
||||
resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
setprototypeof@1.2.0:
|
||||
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
||||
|
||||
sharp@0.34.4:
|
||||
resolution: {integrity: sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
@@ -7228,6 +7396,10 @@ packages:
|
||||
resolution: {integrity: sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
statuses@2.0.2:
|
||||
resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
stdin-discarder@0.2.2:
|
||||
resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -7486,6 +7658,10 @@ packages:
|
||||
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
||||
engines: {node: '>=8.0'}
|
||||
|
||||
toidentifier@1.0.1:
|
||||
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
|
||||
engines: {node: '>=0.6'}
|
||||
|
||||
tr46@0.0.3:
|
||||
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
||||
|
||||
@@ -7555,6 +7731,10 @@ packages:
|
||||
resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==}
|
||||
engines: {node: '>=12.20'}
|
||||
|
||||
type-is@2.1.0:
|
||||
resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
typed-array-buffer@1.0.3:
|
||||
resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -7623,6 +7803,10 @@ packages:
|
||||
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
|
||||
unpipe@1.0.0:
|
||||
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
unrs-resolver@1.12.2:
|
||||
resolution: {integrity: sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==}
|
||||
|
||||
@@ -7957,6 +8141,11 @@ packages:
|
||||
peerDependencies:
|
||||
prisma: 5.0.0 - 6.7.x
|
||||
|
||||
zod-to-json-schema@3.25.2:
|
||||
resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==}
|
||||
peerDependencies:
|
||||
zod: ^3.25.28 || ^4
|
||||
|
||||
zod-validation-error@1.5.0:
|
||||
resolution: {integrity: sha512-/7eFkAI4qV0tcxMBB/3+d2c1P6jzzZYdYSlBuAklzMuCrJu5bzJfHS0yVAS87dRHVlhftd6RFJDIvv03JgkSbw==}
|
||||
engines: {node: '>=16.0.0'}
|
||||
@@ -8757,6 +8946,10 @@ snapshots:
|
||||
|
||||
'@hexagon/base64@1.1.28': {}
|
||||
|
||||
'@hono/node-server@1.19.14(hono@4.12.23)':
|
||||
dependencies:
|
||||
hono: 4.12.23
|
||||
|
||||
'@hookform/resolvers@5.4.0(react-hook-form@7.76.1(react@19.2.6))':
|
||||
dependencies:
|
||||
'@standard-schema/utils': 0.3.0
|
||||
@@ -9131,6 +9324,28 @@ snapshots:
|
||||
|
||||
'@lottiefiles/dotlottie-web@0.42.0': {}
|
||||
|
||||
'@modelcontextprotocol/sdk@1.29.0(zod@4.3.6)':
|
||||
dependencies:
|
||||
'@hono/node-server': 1.19.14(hono@4.12.23)
|
||||
ajv: 8.20.0
|
||||
ajv-formats: 3.0.1(ajv@8.20.0)
|
||||
content-type: 1.0.5
|
||||
cors: 2.8.6
|
||||
cross-spawn: 7.0.6
|
||||
eventsource: 3.0.7
|
||||
eventsource-parser: 3.1.0
|
||||
express: 5.2.1
|
||||
express-rate-limit: 8.5.2(express@5.2.1)
|
||||
hono: 4.12.23
|
||||
jose: 6.2.3
|
||||
json-schema-typed: 8.0.2
|
||||
pkce-challenge: 5.0.1
|
||||
raw-body: 3.0.2
|
||||
zod: 4.3.6
|
||||
zod-to-json-schema: 3.25.2(zod@4.3.6)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)':
|
||||
dependencies:
|
||||
'@emnapi/core': 1.10.0
|
||||
@@ -11595,6 +11810,11 @@ snapshots:
|
||||
mime-types: 2.1.35
|
||||
negotiator: 0.6.3
|
||||
|
||||
accepts@2.0.0:
|
||||
dependencies:
|
||||
mime-types: 3.0.2
|
||||
negotiator: 1.0.0
|
||||
|
||||
acorn-import-phases@1.0.4(acorn@8.16.0):
|
||||
dependencies:
|
||||
acorn: 8.16.0
|
||||
@@ -11617,6 +11837,10 @@ snapshots:
|
||||
optionalDependencies:
|
||||
ajv: 8.20.0
|
||||
|
||||
ajv-formats@3.0.1(ajv@8.20.0):
|
||||
optionalDependencies:
|
||||
ajv: 8.20.0
|
||||
|
||||
ajv-keywords@5.1.0(ajv@8.20.0):
|
||||
dependencies:
|
||||
ajv: 8.20.0
|
||||
@@ -11868,6 +12092,20 @@ snapshots:
|
||||
dependencies:
|
||||
readable-stream: 3.6.2
|
||||
|
||||
body-parser@2.2.2:
|
||||
dependencies:
|
||||
bytes: 3.1.2
|
||||
content-type: 1.0.5
|
||||
debug: 4.4.3
|
||||
http-errors: 2.0.1
|
||||
iconv-lite: 0.7.2
|
||||
on-finished: 2.4.1
|
||||
qs: 6.15.2
|
||||
raw-body: 3.0.2
|
||||
type-is: 2.1.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
boolbase@1.0.0: {}
|
||||
|
||||
brace-expansion@1.1.14:
|
||||
@@ -11920,6 +12158,8 @@ snapshots:
|
||||
dependencies:
|
||||
run-applescript: 7.1.0
|
||||
|
||||
bytes@3.1.2: {}
|
||||
|
||||
c12@3.1.0:
|
||||
dependencies:
|
||||
chokidar: 4.0.3
|
||||
@@ -12184,6 +12424,10 @@ snapshots:
|
||||
tslib: 2.8.1
|
||||
upper-case: 2.0.2
|
||||
|
||||
content-disposition@1.1.0: {}
|
||||
|
||||
content-type@1.0.5: {}
|
||||
|
||||
content-type@2.0.0: {}
|
||||
|
||||
conventional-changelog-angular@8.3.1:
|
||||
@@ -12235,6 +12479,8 @@ snapshots:
|
||||
|
||||
convert-source-map@2.0.0: {}
|
||||
|
||||
cookie-signature@1.2.2: {}
|
||||
|
||||
cookie@0.7.2: {}
|
||||
|
||||
copy-anything@3.0.5:
|
||||
@@ -12405,6 +12651,8 @@ snapshots:
|
||||
escodegen: 2.1.0
|
||||
esprima: 4.0.1
|
||||
|
||||
depd@2.0.0: {}
|
||||
|
||||
destr@2.0.5: {}
|
||||
|
||||
detect-indent@7.0.1: {}
|
||||
@@ -12508,6 +12756,8 @@ snapshots:
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
ee-first@1.1.1: {}
|
||||
|
||||
effect@3.20.0:
|
||||
dependencies:
|
||||
'@standard-schema/spec': 1.1.0
|
||||
@@ -12546,6 +12796,8 @@ snapshots:
|
||||
highlight.js: 10.4.1
|
||||
lowlight: 1.17.0
|
||||
|
||||
encodeurl@2.0.0: {}
|
||||
|
||||
encoding-sniffer@0.2.1:
|
||||
dependencies:
|
||||
iconv-lite: 0.6.3
|
||||
@@ -13086,12 +13338,20 @@ snapshots:
|
||||
|
||||
eta@4.5.0: {}
|
||||
|
||||
etag@1.8.1: {}
|
||||
|
||||
eventemitter3@4.0.7: {}
|
||||
|
||||
eventemitter3@5.0.4: {}
|
||||
|
||||
events@3.3.0: {}
|
||||
|
||||
eventsource-parser@3.1.0: {}
|
||||
|
||||
eventsource@3.0.7:
|
||||
dependencies:
|
||||
eventsource-parser: 3.1.0
|
||||
|
||||
execa@8.0.1:
|
||||
dependencies:
|
||||
cross-spawn: 7.0.6
|
||||
@@ -13104,6 +13364,44 @@ snapshots:
|
||||
signal-exit: 4.1.0
|
||||
strip-final-newline: 3.0.0
|
||||
|
||||
express-rate-limit@8.5.2(express@5.2.1):
|
||||
dependencies:
|
||||
express: 5.2.1
|
||||
ip-address: 10.2.0
|
||||
|
||||
express@5.2.1:
|
||||
dependencies:
|
||||
accepts: 2.0.0
|
||||
body-parser: 2.2.2
|
||||
content-disposition: 1.1.0
|
||||
content-type: 1.0.5
|
||||
cookie: 0.7.2
|
||||
cookie-signature: 1.2.2
|
||||
debug: 4.4.3
|
||||
depd: 2.0.0
|
||||
encodeurl: 2.0.0
|
||||
escape-html: 1.0.3
|
||||
etag: 1.8.1
|
||||
finalhandler: 2.1.1
|
||||
fresh: 2.0.0
|
||||
http-errors: 2.0.1
|
||||
merge-descriptors: 2.0.0
|
||||
mime-types: 3.0.2
|
||||
on-finished: 2.4.1
|
||||
once: 1.4.0
|
||||
parseurl: 1.3.3
|
||||
proxy-addr: 2.0.7
|
||||
qs: 6.15.2
|
||||
range-parser: 1.2.1
|
||||
router: 2.2.0
|
||||
send: 1.2.1
|
||||
serve-static: 2.2.1
|
||||
statuses: 2.0.2
|
||||
type-is: 2.1.0
|
||||
vary: 1.1.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
exsolve@1.0.8: {}
|
||||
|
||||
extend@3.0.2: {}
|
||||
@@ -13194,6 +13492,17 @@ snapshots:
|
||||
|
||||
filter-obj@1.1.0: {}
|
||||
|
||||
finalhandler@2.1.1:
|
||||
dependencies:
|
||||
debug: 4.4.3
|
||||
encodeurl: 2.0.0
|
||||
escape-html: 1.0.3
|
||||
on-finished: 2.4.1
|
||||
parseurl: 1.3.3
|
||||
statuses: 2.0.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
find-up@5.0.0:
|
||||
dependencies:
|
||||
locate-path: 6.0.0
|
||||
@@ -13221,6 +13530,8 @@ snapshots:
|
||||
dependencies:
|
||||
fetch-blob: 3.2.0
|
||||
|
||||
forwarded@0.2.0: {}
|
||||
|
||||
fraction.js@4.3.7: {}
|
||||
|
||||
framer-motion@12.23.22(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
|
||||
@@ -13241,6 +13552,8 @@ snapshots:
|
||||
react: 19.2.6
|
||||
react-dom: 19.2.6(react@19.2.6)
|
||||
|
||||
fresh@2.0.0: {}
|
||||
|
||||
fs-constants@1.0.0: {}
|
||||
|
||||
fs-extra@11.3.0:
|
||||
@@ -13464,6 +13777,8 @@ snapshots:
|
||||
|
||||
highlight.js@10.4.1: {}
|
||||
|
||||
hono@4.12.23: {}
|
||||
|
||||
hosted-git-info@8.1.0:
|
||||
dependencies:
|
||||
lru-cache: 10.4.3
|
||||
@@ -13490,6 +13805,14 @@ snapshots:
|
||||
domutils: 3.2.2
|
||||
entities: 4.5.0
|
||||
|
||||
http-errors@2.0.1:
|
||||
dependencies:
|
||||
depd: 2.0.0
|
||||
inherits: 2.0.4
|
||||
setprototypeof: 1.2.0
|
||||
statuses: 2.0.2
|
||||
toidentifier: 1.0.1
|
||||
|
||||
http-proxy-agent@7.0.2:
|
||||
dependencies:
|
||||
agent-base: 7.1.4
|
||||
@@ -13565,6 +13888,8 @@ snapshots:
|
||||
|
||||
ip-address@10.2.0: {}
|
||||
|
||||
ipaddr.js@1.9.1: {}
|
||||
|
||||
ipaddr.js@2.4.0: {}
|
||||
|
||||
is-array-buffer@3.0.5:
|
||||
@@ -13660,6 +13985,8 @@ snapshots:
|
||||
|
||||
is-plain-object@5.0.0: {}
|
||||
|
||||
is-promise@4.0.0: {}
|
||||
|
||||
is-regex@1.2.1:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
@@ -13776,6 +14103,8 @@ snapshots:
|
||||
|
||||
json-schema-traverse@1.0.0: {}
|
||||
|
||||
json-schema-typed@8.0.2: {}
|
||||
|
||||
json-stable-stringify-without-jsonify@1.0.1: {}
|
||||
|
||||
json-with-bigint@3.5.8: {}
|
||||
@@ -13993,8 +14322,12 @@ snapshots:
|
||||
marked: 7.0.4
|
||||
react: 19.2.6
|
||||
|
||||
media-typer@1.1.0: {}
|
||||
|
||||
meow@13.2.0: {}
|
||||
|
||||
merge-descriptors@2.0.0: {}
|
||||
|
||||
merge-stream@2.0.0: {}
|
||||
|
||||
merge2@1.4.1: {}
|
||||
@@ -14108,6 +14441,8 @@ snapshots:
|
||||
|
||||
negotiator@0.6.3: {}
|
||||
|
||||
negotiator@1.0.0: {}
|
||||
|
||||
neo-async@2.6.2: {}
|
||||
|
||||
netmask@2.1.1: {}
|
||||
@@ -14313,6 +14648,10 @@ snapshots:
|
||||
|
||||
on-exit-leak-free@2.1.2: {}
|
||||
|
||||
on-finished@2.4.1:
|
||||
dependencies:
|
||||
ee-first: 1.1.1
|
||||
|
||||
once@1.4.0:
|
||||
dependencies:
|
||||
wrappy: 1.0.2
|
||||
@@ -14464,6 +14803,8 @@ snapshots:
|
||||
leac: 0.6.0
|
||||
peberminta: 0.9.0
|
||||
|
||||
parseurl@1.3.3: {}
|
||||
|
||||
pascal-case@3.1.2:
|
||||
dependencies:
|
||||
no-case: 3.0.4
|
||||
@@ -14491,6 +14832,8 @@ snapshots:
|
||||
lru-cache: 11.5.0
|
||||
minipass: 7.1.3
|
||||
|
||||
path-to-regexp@8.4.2: {}
|
||||
|
||||
pathe@2.0.3: {}
|
||||
|
||||
peberminta@0.9.0: {}
|
||||
@@ -14580,6 +14923,8 @@ snapshots:
|
||||
|
||||
pirates@4.0.7: {}
|
||||
|
||||
pkce-challenge@5.0.1: {}
|
||||
|
||||
pkg-types@1.3.1:
|
||||
dependencies:
|
||||
confbox: 0.1.8
|
||||
@@ -14718,6 +15063,11 @@ snapshots:
|
||||
|
||||
protocols@2.0.2: {}
|
||||
|
||||
proxy-addr@2.0.7:
|
||||
dependencies:
|
||||
forwarded: 0.2.0
|
||||
ipaddr.js: 1.9.1
|
||||
|
||||
proxy-agent@6.5.0:
|
||||
dependencies:
|
||||
agent-base: 7.1.4
|
||||
@@ -14767,6 +15117,15 @@ snapshots:
|
||||
|
||||
quick-format-unescaped@4.0.4: {}
|
||||
|
||||
range-parser@1.2.1: {}
|
||||
|
||||
raw-body@3.0.2:
|
||||
dependencies:
|
||||
bytes: 3.1.2
|
||||
http-errors: 2.0.1
|
||||
iconv-lite: 0.7.2
|
||||
unpipe: 1.0.0
|
||||
|
||||
rc9@2.1.2:
|
||||
dependencies:
|
||||
defu: 6.1.7
|
||||
@@ -15069,6 +15428,16 @@ snapshots:
|
||||
|
||||
rou3@0.7.12: {}
|
||||
|
||||
router@2.2.0:
|
||||
dependencies:
|
||||
debug: 4.4.3
|
||||
depd: 2.0.0
|
||||
is-promise: 4.0.0
|
||||
parseurl: 1.3.3
|
||||
path-to-regexp: 8.4.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
run-applescript@7.1.0: {}
|
||||
|
||||
run-async@4.0.6: {}
|
||||
@@ -15147,12 +15516,37 @@ snapshots:
|
||||
|
||||
semver@7.8.1: {}
|
||||
|
||||
send@1.2.1:
|
||||
dependencies:
|
||||
debug: 4.4.3
|
||||
encodeurl: 2.0.0
|
||||
escape-html: 1.0.3
|
||||
etag: 1.8.1
|
||||
fresh: 2.0.0
|
||||
http-errors: 2.0.1
|
||||
mime-types: 3.0.2
|
||||
ms: 2.1.3
|
||||
on-finished: 2.4.1
|
||||
range-parser: 1.2.1
|
||||
statuses: 2.0.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
sentence-case@3.0.4:
|
||||
dependencies:
|
||||
no-case: 3.0.4
|
||||
tslib: 2.8.1
|
||||
upper-case-first: 2.0.2
|
||||
|
||||
serve-static@2.2.1:
|
||||
dependencies:
|
||||
encodeurl: 2.0.0
|
||||
escape-html: 1.0.3
|
||||
parseurl: 1.3.3
|
||||
send: 1.2.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
set-cookie-parser@3.1.0: {}
|
||||
|
||||
set-function-length@1.2.2:
|
||||
@@ -15177,6 +15571,8 @@ snapshots:
|
||||
es-errors: 1.3.0
|
||||
es-object-atoms: 1.1.2
|
||||
|
||||
setprototypeof@1.2.0: {}
|
||||
|
||||
sharp@0.34.4:
|
||||
dependencies:
|
||||
'@img/colour': 1.1.0
|
||||
@@ -15410,6 +15806,8 @@ snapshots:
|
||||
dependencies:
|
||||
type-fest: 0.7.1
|
||||
|
||||
statuses@2.0.2: {}
|
||||
|
||||
stdin-discarder@0.2.2: {}
|
||||
|
||||
stop-iteration-iterator@1.1.0:
|
||||
@@ -15687,6 +16085,8 @@ snapshots:
|
||||
dependencies:
|
||||
is-number: 7.0.0
|
||||
|
||||
toidentifier@1.0.1: {}
|
||||
|
||||
tr46@0.0.3: {}
|
||||
|
||||
traverse@0.6.11:
|
||||
@@ -15754,6 +16154,12 @@ snapshots:
|
||||
|
||||
type-fest@2.19.0: {}
|
||||
|
||||
type-is@2.1.0:
|
||||
dependencies:
|
||||
content-type: 2.0.0
|
||||
media-typer: 1.1.0
|
||||
mime-types: 3.0.2
|
||||
|
||||
typed-array-buffer@1.0.3:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
@@ -15837,6 +16243,8 @@ snapshots:
|
||||
|
||||
universalify@2.0.1: {}
|
||||
|
||||
unpipe@1.0.0: {}
|
||||
|
||||
unrs-resolver@1.12.2:
|
||||
dependencies:
|
||||
napi-postinstall: 0.3.4
|
||||
@@ -16241,6 +16649,10 @@ snapshots:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
zod-to-json-schema@3.25.2(zod@4.3.6):
|
||||
dependencies:
|
||||
zod: 4.3.6
|
||||
|
||||
zod-validation-error@1.5.0(zod@3.25.76):
|
||||
dependencies:
|
||||
zod: 3.25.76
|
||||
|
||||
@@ -105,6 +105,7 @@ function checkRouteExists(pathname: string) {
|
||||
/^\/api\/health\/?$/,
|
||||
/^\/api\/google\/drive\/callback\/?$/,
|
||||
// v1 external API
|
||||
/^\/api\/v1\/mcp\/?$/,
|
||||
/^\/api\/v1\/docs\/?$/,
|
||||
/^\/api\/v1\/openapi\/?$/,
|
||||
/^\/api\/v1\/agents\/?$/,
|
||||
|
||||
@@ -108,6 +108,11 @@ export const env = createEnv({
|
||||
.enum(["true", "false"])
|
||||
.transform((val) => val === "true")
|
||||
.default("false"),
|
||||
|
||||
MCP_ENABLED: z
|
||||
.enum(["true", "false"])
|
||||
.transform((val) => val === "true")
|
||||
.default("false"),
|
||||
},
|
||||
client: {
|
||||
NEXT_PUBLIC_PROJECT_VERSION: z.string().optional(),
|
||||
@@ -183,5 +188,7 @@ export const env = createEnv({
|
||||
|
||||
OPENAPI_ENABLED: process.env.OPENAPI_ENABLED,
|
||||
API_ENABLED: process.env.API_ENABLED,
|
||||
MCP_ENABLED: process.env.MCP_ENABLED,
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
@@ -66,6 +66,7 @@ export async function requireDatabaseAccess(
|
||||
|
||||
const access = await resolveDatabaseAccess(id, user);
|
||||
|
||||
|
||||
if (access === "ok") {
|
||||
return {
|
||||
ok: true,
|
||||
@@ -80,31 +81,55 @@ export async function requireDatabaseAccess(
|
||||
};
|
||||
}
|
||||
|
||||
if (access === "no_project_link") {
|
||||
return {
|
||||
ok: false,
|
||||
response: jsonError("Database is not linked to any project", 403),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
ok: false,
|
||||
response: jsonError("Not found", 404),
|
||||
};
|
||||
}
|
||||
|
||||
export type DatabaseAccessResult = "ok" | "forbidden" | "not_found";
|
||||
export type DatabaseAccessResult =
|
||||
| "ok"
|
||||
| "forbidden"
|
||||
| "not_found"
|
||||
| "no_project_link";
|
||||
|
||||
export async function resolveDatabaseAccess(
|
||||
id: string,
|
||||
user: ApiKeyContext["user"]
|
||||
): Promise<DatabaseAccessResult> {
|
||||
const accessibleIds = await getAccessibleDatabaseIds(user);
|
||||
const [accessibleIds, database] = await Promise.all([
|
||||
getAccessibleDatabaseIds(user),
|
||||
db.query.database.findFirst({
|
||||
where: and(
|
||||
eq(drizzleDb.schemas.database.id, id),
|
||||
isNull(drizzleDb.schemas.database.deletedAt)
|
||||
),
|
||||
columns: {
|
||||
id: true,
|
||||
projectId: true,
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
if (!database) {
|
||||
return "not_found";
|
||||
}
|
||||
|
||||
if (database.projectId === null) {
|
||||
return "no_project_link";
|
||||
}
|
||||
|
||||
if (accessibleIds.includes(id)) {
|
||||
return "ok";
|
||||
}
|
||||
|
||||
const exists = await db.query.database.findFirst({
|
||||
where: and(
|
||||
eq(drizzleDb.schemas.database.id, id),
|
||||
isNull(drizzleDb.schemas.database.deletedAt)
|
||||
),
|
||||
columns: { id: true },
|
||||
});
|
||||
|
||||
return exists ? "forbidden" : "not_found";
|
||||
return "forbidden";
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { getServerUrl } from "@/utils/get-server-url";
|
||||
|
||||
export type ApiV1Result =
|
||||
| { ok: true; status: number; data: unknown }
|
||||
| { ok: false; status: number; error: string };
|
||||
|
||||
/**
|
||||
* Thin fetch wrapper that proxies calls to the existing /api/v1 REST layer.
|
||||
* Forwards the caller's API key so the REST route runs its own auth + permission checks.
|
||||
*/
|
||||
export async function apiV1Fetch(
|
||||
path: string,
|
||||
options: RequestInit,
|
||||
apiKey: string
|
||||
): Promise<ApiV1Result> {
|
||||
const url = `${getServerUrl()}${path}`;
|
||||
|
||||
let res: Response;
|
||||
try {
|
||||
res = await fetch(url, {
|
||||
...options,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...options.headers,
|
||||
"x-api-key": apiKey,
|
||||
},
|
||||
});
|
||||
} catch {
|
||||
return { ok: false, status: 0, error: "Failed to reach internal API" };
|
||||
}
|
||||
|
||||
// 204 No Content has no body
|
||||
if (res.status === 204) {
|
||||
return { ok: true, status: 204, data: null };
|
||||
}
|
||||
|
||||
let body: unknown;
|
||||
try {
|
||||
body = await res.json();
|
||||
} catch {
|
||||
body = null;
|
||||
}
|
||||
|
||||
if (!res.ok) {
|
||||
const message =
|
||||
typeof body === "object" &&
|
||||
body !== null &&
|
||||
"error" in body &&
|
||||
typeof (body as Record<string, unknown>).error === "string"
|
||||
? (body as { error: string }).error
|
||||
: `Request failed with status ${res.status}`;
|
||||
return { ok: false, status: res.status, error: message };
|
||||
}
|
||||
|
||||
const data =
|
||||
typeof body === "object" &&
|
||||
body !== null &&
|
||||
"data" in body
|
||||
? (body as { data: unknown }).data
|
||||
: body;
|
||||
|
||||
return { ok: true, status: res.status, data };
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import type { ApiKeyContext } from "@/lib/api-v1/types";
|
||||
import { registerAgentTools } from "./tools/agents";
|
||||
import { registerDatabaseTools } from "./tools/databases";
|
||||
import { registerBackupTools } from "./tools/backups";
|
||||
|
||||
/**
|
||||
* Creates a configured McpServer for a single request.
|
||||
* A new instance is created per request (stateless transport pattern).
|
||||
*
|
||||
* @param _ctx - The validated API key context (user + org memberships). Reserved for
|
||||
* future tools that need server-side context beyond forwarded HTTP calls.
|
||||
* @param apiKey - The raw API key forwarded to all /api/v1 REST calls.
|
||||
*/
|
||||
export function createPortabaseMcpServer(
|
||||
_ctx: ApiKeyContext,
|
||||
apiKey: string
|
||||
): McpServer {
|
||||
const server = new McpServer({
|
||||
name: "portabase",
|
||||
version: process.env.npm_package_version ?? "1.0.0",
|
||||
});
|
||||
|
||||
registerAgentTools(server, apiKey);
|
||||
registerDatabaseTools(server, apiKey);
|
||||
registerBackupTools(server, apiKey);
|
||||
|
||||
return server;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { z } from "zod";
|
||||
import {apiV1Fetch} from "@/lib/mcp/http-client";
|
||||
import {err, ok} from "@/lib/mcp/tools/response";
|
||||
|
||||
|
||||
export function registerAgentTools(server: McpServer, apiKey: string) {
|
||||
server.tool(
|
||||
"list_agents",
|
||||
"List all agents accessible to the authenticated user",
|
||||
{},
|
||||
async () => {
|
||||
const result = await apiV1Fetch("/api/v1/agents", { method: "GET" }, apiKey);
|
||||
return result.ok ? ok(result.data) : err(result.error);
|
||||
}
|
||||
);
|
||||
|
||||
server.tool(
|
||||
"get_agent",
|
||||
"Get details for a specific agent, including its associated databases",
|
||||
{ id: z.string().describe("Agent ID") },
|
||||
async ({ id }) => {
|
||||
const result = await apiV1Fetch(`/api/v1/agents/${id}`, { method: "GET" }, apiKey);
|
||||
return result.ok ? ok(result.data) : err(result.error);
|
||||
}
|
||||
);
|
||||
|
||||
server.tool(
|
||||
"create_agent",
|
||||
"Create a new agent, optionally scoped to an organization",
|
||||
{
|
||||
name: z.string().min(1).describe("Agent name"),
|
||||
organizationId: z
|
||||
.string()
|
||||
.uuid()
|
||||
.optional()
|
||||
.describe("Organization ID to scope the agent to (optional)"),
|
||||
},
|
||||
async ({ name, organizationId }) => {
|
||||
const result = await apiV1Fetch(
|
||||
"/api/v1/agents",
|
||||
{ method: "POST", body: JSON.stringify({ name, organizationId }) },
|
||||
apiKey
|
||||
);
|
||||
return result.ok ? ok(result.data) : err(result.error);
|
||||
}
|
||||
);
|
||||
|
||||
server.tool(
|
||||
"delete_agent",
|
||||
"Delete an agent by ID",
|
||||
{ id: z.string().describe("Agent ID") },
|
||||
async ({ id }) => {
|
||||
const result = await apiV1Fetch(`/api/v1/agents/${id}`, { method: "DELETE" }, apiKey);
|
||||
return result.ok
|
||||
? ok({ message: `Agent ${id} deleted successfully` })
|
||||
: err(result.error);
|
||||
}
|
||||
);
|
||||
|
||||
server.tool(
|
||||
"get_agent_key",
|
||||
"Get the edge key for an agent (used by the agent to authenticate with Portabase)",
|
||||
{ id: z.string().describe("Agent ID") },
|
||||
async ({ id }) => {
|
||||
const result = await apiV1Fetch(`/api/v1/agents/${id}/key`, { method: "GET" }, apiKey);
|
||||
return result.ok ? ok(result.data) : err(result.error);
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { z } from "zod";
|
||||
import {err, ok} from "@/lib/mcp/tools/response";
|
||||
import {apiV1Fetch} from "@/lib/mcp/http-client";
|
||||
|
||||
export function registerBackupTools(server: McpServer, apiKey: string) {
|
||||
server.tool(
|
||||
"list_backups",
|
||||
"List all backups for a specific database, ordered by most recent first",
|
||||
{ databaseId: z.string().describe("Database ID") },
|
||||
async ({ databaseId }) => {
|
||||
const result = await apiV1Fetch(
|
||||
`/api/v1/databases/${databaseId}/backup`,
|
||||
{ method: "GET" },
|
||||
apiKey
|
||||
);
|
||||
return result.ok ? ok(result.data) : err(result.error);
|
||||
}
|
||||
);
|
||||
|
||||
server.tool(
|
||||
"get_backup",
|
||||
"Get details for a specific backup, including its storage locations",
|
||||
{
|
||||
databaseId: z.string().describe("Database ID"),
|
||||
backupId: z.string().describe("Backup ID"),
|
||||
},
|
||||
async ({ databaseId, backupId }) => {
|
||||
const result = await apiV1Fetch(
|
||||
`/api/v1/databases/${databaseId}/backup/${backupId}`,
|
||||
{ method: "GET" },
|
||||
apiKey
|
||||
);
|
||||
return result.ok ? ok(result.data) : err(result.error);
|
||||
}
|
||||
);
|
||||
|
||||
server.tool(
|
||||
"trigger_backup",
|
||||
"Trigger an immediate backup for a database. Returns 409 if a backup is already running.",
|
||||
{ databaseId: z.string().describe("Database ID") },
|
||||
async ({ databaseId }) => {
|
||||
const result = await apiV1Fetch(
|
||||
`/api/v1/databases/${databaseId}/backup`,
|
||||
{ method: "POST", body: JSON.stringify({}) },
|
||||
apiKey
|
||||
);
|
||||
return result.ok ? ok(result.data) : err(result.error);
|
||||
}
|
||||
);
|
||||
|
||||
server.tool(
|
||||
"trigger_restore",
|
||||
"Trigger a database restore from a specific backup storage. Use get_backup to find available backupStorageId values. Returns 409 if a restore is already running.",
|
||||
{
|
||||
databaseId: z.string().describe("Database ID"),
|
||||
backupId: z.string().uuid().describe("Backup ID"),
|
||||
backupStorageId: z
|
||||
.string()
|
||||
.uuid()
|
||||
.describe("Backup storage ID (from get_backup storages list)"),
|
||||
},
|
||||
async ({ databaseId, backupId, backupStorageId }) => {
|
||||
const result = await apiV1Fetch(
|
||||
`/api/v1/databases/${databaseId}/restore`,
|
||||
{
|
||||
method: "POST",
|
||||
body: JSON.stringify({ backupId, backupStorageId }),
|
||||
},
|
||||
apiKey
|
||||
);
|
||||
return result.ok ? ok(result.data) : err(result.error);
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import {McpServer} from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import {z} from "zod";
|
||||
import {err, ok} from "@/lib/mcp/tools/response";
|
||||
import {apiV1Fetch} from "@/lib/mcp/http-client";
|
||||
|
||||
|
||||
export function registerDatabaseTools(server: McpServer, apiKey: string) {
|
||||
server.tool(
|
||||
"list_databases",
|
||||
"List all databases accessible to the authenticated user",
|
||||
{},
|
||||
async () => {
|
||||
const result = await apiV1Fetch("/api/v1/databases", {method: "GET"}, apiKey);
|
||||
return result.ok ? ok(result.data) : err(result.error);
|
||||
}
|
||||
);
|
||||
|
||||
server.tool(
|
||||
"get_database",
|
||||
"Get details for a specific database",
|
||||
{id: z.string().describe("Database ID")},
|
||||
async ({id}) => {
|
||||
const result = await apiV1Fetch(`/api/v1/databases/${id}`, {method: "GET"}, apiKey);
|
||||
return result.ok ? ok(result.data) : err(result.error);
|
||||
}
|
||||
);
|
||||
|
||||
server.tool(
|
||||
"get_database_status",
|
||||
"Get the current status of a database, including latest backup and restoration state",
|
||||
{id: z.string().describe("Database ID")},
|
||||
async ({id}) => {
|
||||
const result = await apiV1Fetch(
|
||||
`/api/v1/databases/${id}/status`,
|
||||
{method: "GET"},
|
||||
apiKey
|
||||
);
|
||||
return result.ok ? ok(result.data) : err(result.error);
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
export function ok(data: unknown) {
|
||||
return {
|
||||
content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }],
|
||||
};
|
||||
}
|
||||
|
||||
export function err(message: string) {
|
||||
return {
|
||||
content: [{ type: "text" as const, text: message }],
|
||||
isError: true as const,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user