@xiaou66/vite-plugin-vue-mcp-next 1.1.1 → 1.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/README.md +20 -0
- package/dist/index.cjs +470 -79
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +77 -0
- package/dist/index.d.ts +77 -0
- package/dist/index.js +470 -79
- package/dist/index.js.map +1 -1
- package/dist/runtime/client.cjs +500 -126
- package/dist/runtime/client.cjs.map +1 -1
- package/dist/runtime/client.js +500 -126
- package/dist/runtime/client.js.map +1 -1
- package/package.json +1 -1
- package/skills/vite-mcp-next/SKILL.md +7 -2
package/dist/index.js
CHANGED
|
@@ -35,6 +35,11 @@ var MCP_TOOL_NAMES = {
|
|
|
35
35
|
getNetworkRequests: "get_network_requests",
|
|
36
36
|
getNetworkRequestDetail: "get_network_request_detail",
|
|
37
37
|
clearNetworkRequests: "clear_network_requests",
|
|
38
|
+
listStorage: "list_storage",
|
|
39
|
+
getStorageItem: "get_storage_item",
|
|
40
|
+
setStorageItem: "set_storage_item",
|
|
41
|
+
deleteStorageItem: "delete_storage_item",
|
|
42
|
+
clearStorage: "clear_storage",
|
|
38
43
|
recordPerformance: "record_performance",
|
|
39
44
|
startPerformanceRecording: "start_performance_recording",
|
|
40
45
|
stopPerformanceRecording: "stop_performance_recording",
|
|
@@ -57,11 +62,6 @@ var RESOLVED_VIRTUAL_SNAPDOM_LOADER_ID = `\0${VIRTUAL_SNAPDOM_LOADER_ID}`;
|
|
|
57
62
|
var DEFAULT_MCP_CLIENT_SERVER_NAME = "vite-mcp-next";
|
|
58
63
|
var LEGACY_MCP_CLIENT_SERVER_NAMES = ["vue-mcp-next"];
|
|
59
64
|
var RUNTIME_PAGE_RECONNECTED_EVENT = "vite-plugin-vue-mcp-next:page-reconnected";
|
|
60
|
-
var RUNTIME_PAGE_CONNECTED_EVENT = "vite-plugin-vue-mcp-next:page-connected";
|
|
61
|
-
var RUNTIME_PAGE_DISCONNECTED_EVENT = "vite-plugin-vue-mcp-next:page-disconnected";
|
|
62
|
-
var RUNTIME_PAGE_HEARTBEAT_EVENT = "vite-plugin-vue-mcp-next:heartbeat";
|
|
63
|
-
var DEFAULT_RUNTIME_PAGE_HEARTBEAT_TIMEOUT_MS = 45e3;
|
|
64
|
-
var DEFAULT_RUNTIME_PAGE_HEARTBEAT_SCAN_INTERVAL_MS = 45e3;
|
|
65
65
|
var DEFAULT_OPTIONS = {
|
|
66
66
|
mcpPath: DEFAULT_MCP_PATH,
|
|
67
67
|
host: "localhost",
|
|
@@ -1511,9 +1511,431 @@ function getPathname(url) {
|
|
|
1511
1511
|
}
|
|
1512
1512
|
}
|
|
1513
1513
|
|
|
1514
|
-
// src/mcp/tools/
|
|
1514
|
+
// src/mcp/tools/storage.ts
|
|
1515
1515
|
import { z as z7 } from "zod";
|
|
1516
1516
|
|
|
1517
|
+
// src/cdp/cdpStorage.ts
|
|
1518
|
+
function createCdpStorageAdapter(client) {
|
|
1519
|
+
return {
|
|
1520
|
+
async manageStorage(request) {
|
|
1521
|
+
try {
|
|
1522
|
+
return await manageCdpStorage(client, request);
|
|
1523
|
+
} catch (error) {
|
|
1524
|
+
return createCdpStorageError(
|
|
1525
|
+
request,
|
|
1526
|
+
error instanceof Error ? error.message : String(error)
|
|
1527
|
+
);
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
};
|
|
1531
|
+
}
|
|
1532
|
+
async function manageCdpStorage(client, request) {
|
|
1533
|
+
if (request.scope === "cookie") {
|
|
1534
|
+
return manageCdpCookies(client, request);
|
|
1535
|
+
}
|
|
1536
|
+
if (request.scope === "indexedDB") {
|
|
1537
|
+
return manageCdpIndexedDb(client, request);
|
|
1538
|
+
}
|
|
1539
|
+
return manageCdpDomStorage(client, request);
|
|
1540
|
+
}
|
|
1541
|
+
async function manageCdpCookies(client, request) {
|
|
1542
|
+
if (request.action === "list" || request.action === "get") {
|
|
1543
|
+
const result2 = await client.Storage.getCookies();
|
|
1544
|
+
const cookies2 = result2.cookies.filter(
|
|
1545
|
+
(cookie) => isCookieInOrigin(cookie, request.origin)
|
|
1546
|
+
);
|
|
1547
|
+
return createCdpStorageSuccess(request, {
|
|
1548
|
+
origin: request.origin,
|
|
1549
|
+
cookies: request.action === "get" && request.cookie?.name ? cookies2.filter((cookie) => cookie.name === request.cookie?.name) : cookies2
|
|
1550
|
+
});
|
|
1551
|
+
}
|
|
1552
|
+
if (request.action === "set") {
|
|
1553
|
+
if (!request.cookie?.name) {
|
|
1554
|
+
throw new Error("Cookie name is required for set operation");
|
|
1555
|
+
}
|
|
1556
|
+
await client.Storage.setCookies({
|
|
1557
|
+
cookies: [
|
|
1558
|
+
{
|
|
1559
|
+
name: request.cookie.name,
|
|
1560
|
+
value: request.cookie.value ?? request.value ?? "",
|
|
1561
|
+
url: request.cookie.url ?? request.origin,
|
|
1562
|
+
domain: request.cookie.domain,
|
|
1563
|
+
path: request.cookie.path,
|
|
1564
|
+
httpOnly: request.cookie.httpOnly,
|
|
1565
|
+
secure: request.cookie.secure,
|
|
1566
|
+
sameSite: normalizeCookieSameSite(request.cookie.sameSite),
|
|
1567
|
+
expires: request.cookie.expires
|
|
1568
|
+
}
|
|
1569
|
+
]
|
|
1570
|
+
});
|
|
1571
|
+
return createCdpStorageSuccess(request, { ok: true });
|
|
1572
|
+
}
|
|
1573
|
+
const result = await client.Storage.getCookies();
|
|
1574
|
+
const cookies = result.cookies.filter(
|
|
1575
|
+
(cookie) => isCookieInOrigin(cookie, request.origin)
|
|
1576
|
+
);
|
|
1577
|
+
const candidates = request.action === "delete" && request.cookie?.name ? cookies.filter((cookie) => cookie.name === request.cookie?.name) : cookies;
|
|
1578
|
+
const deletable = candidates.filter((cookie) => !cookie.httpOnly);
|
|
1579
|
+
const skippedHttpOnlyCount = candidates.length - deletable.length;
|
|
1580
|
+
for (const cookie of deletable) {
|
|
1581
|
+
await client.Network.deleteCookies({
|
|
1582
|
+
name: cookie.name,
|
|
1583
|
+
domain: cookie.domain,
|
|
1584
|
+
path: cookie.path
|
|
1585
|
+
});
|
|
1586
|
+
}
|
|
1587
|
+
return createCdpStorageSuccess(request, {
|
|
1588
|
+
deletedCount: deletable.length,
|
|
1589
|
+
skippedHttpOnlyCount
|
|
1590
|
+
});
|
|
1591
|
+
}
|
|
1592
|
+
async function manageCdpDomStorage(client, request) {
|
|
1593
|
+
const storageId = {
|
|
1594
|
+
securityOrigin: request.origin,
|
|
1595
|
+
isLocalStorage: request.scope === "localStorage"
|
|
1596
|
+
};
|
|
1597
|
+
if (request.action === "list") {
|
|
1598
|
+
const result2 = await client.DOMStorage.getDOMStorageItems({ storageId });
|
|
1599
|
+
return createCdpStorageSuccess(request, {
|
|
1600
|
+
origin: request.origin,
|
|
1601
|
+
scope: request.scope,
|
|
1602
|
+
entries: result2.entries.map(([key, value]) => ({ key, value }))
|
|
1603
|
+
});
|
|
1604
|
+
}
|
|
1605
|
+
if (request.action === "get") {
|
|
1606
|
+
assertStorageKey(request);
|
|
1607
|
+
const result2 = await client.DOMStorage.getDOMStorageItems({ storageId });
|
|
1608
|
+
const entry = result2.entries.find(([key]) => key === request.key);
|
|
1609
|
+
return createCdpStorageSuccess(request, {
|
|
1610
|
+
key: request.key,
|
|
1611
|
+
value: entry?.[1] ?? null
|
|
1612
|
+
});
|
|
1613
|
+
}
|
|
1614
|
+
if (request.action === "set") {
|
|
1615
|
+
assertStorageKey(request);
|
|
1616
|
+
await client.DOMStorage.setDOMStorageItem({
|
|
1617
|
+
storageId,
|
|
1618
|
+
key: request.key,
|
|
1619
|
+
value: request.value ?? ""
|
|
1620
|
+
});
|
|
1621
|
+
return createCdpStorageSuccess(request, { ok: true });
|
|
1622
|
+
}
|
|
1623
|
+
if (request.action === "delete") {
|
|
1624
|
+
assertStorageKey(request);
|
|
1625
|
+
await client.DOMStorage.removeDOMStorageItem({
|
|
1626
|
+
storageId,
|
|
1627
|
+
key: request.key
|
|
1628
|
+
});
|
|
1629
|
+
return createCdpStorageSuccess(request, { ok: true });
|
|
1630
|
+
}
|
|
1631
|
+
const result = await client.DOMStorage.getDOMStorageItems({ storageId });
|
|
1632
|
+
for (const [key] of result.entries) {
|
|
1633
|
+
await client.DOMStorage.removeDOMStorageItem({ storageId, key });
|
|
1634
|
+
}
|
|
1635
|
+
return createCdpStorageSuccess(request, { deletedCount: result.entries.length });
|
|
1636
|
+
}
|
|
1637
|
+
async function manageCdpIndexedDb(client, request) {
|
|
1638
|
+
if (request.action === "list") {
|
|
1639
|
+
const result = await client.IndexedDB.requestDatabaseNames({
|
|
1640
|
+
securityOrigin: request.origin
|
|
1641
|
+
});
|
|
1642
|
+
return createCdpStorageSuccess(request, {
|
|
1643
|
+
origin: request.origin,
|
|
1644
|
+
databases: result.databaseNames
|
|
1645
|
+
});
|
|
1646
|
+
}
|
|
1647
|
+
assertIndexedDbTarget(request);
|
|
1648
|
+
if (request.action === "get") {
|
|
1649
|
+
const result = await client.IndexedDB.requestData({
|
|
1650
|
+
securityOrigin: request.origin,
|
|
1651
|
+
databaseName: request.databaseName,
|
|
1652
|
+
objectStoreName: request.objectStoreName,
|
|
1653
|
+
indexName: request.indexName ?? "",
|
|
1654
|
+
skipCount: 0,
|
|
1655
|
+
pageSize: 100
|
|
1656
|
+
});
|
|
1657
|
+
return createCdpStorageSuccess(request, {
|
|
1658
|
+
entries: result.objectStoreDataEntries,
|
|
1659
|
+
hasMore: result.hasMore
|
|
1660
|
+
});
|
|
1661
|
+
}
|
|
1662
|
+
if (request.action === "delete") {
|
|
1663
|
+
assertStorageKey(request);
|
|
1664
|
+
await client.IndexedDB.deleteObjectStoreEntries({
|
|
1665
|
+
securityOrigin: request.origin,
|
|
1666
|
+
databaseName: request.databaseName,
|
|
1667
|
+
objectStoreName: request.objectStoreName,
|
|
1668
|
+
keyRange: createExactCdpKeyRange(request.key)
|
|
1669
|
+
});
|
|
1670
|
+
return createCdpStorageSuccess(request, { ok: true });
|
|
1671
|
+
}
|
|
1672
|
+
if (request.action === "clear") {
|
|
1673
|
+
if (request.objectStoreName) {
|
|
1674
|
+
await client.IndexedDB.clearObjectStore({
|
|
1675
|
+
securityOrigin: request.origin,
|
|
1676
|
+
databaseName: request.databaseName,
|
|
1677
|
+
objectStoreName: request.objectStoreName
|
|
1678
|
+
});
|
|
1679
|
+
return createCdpStorageSuccess(request, { ok: true });
|
|
1680
|
+
}
|
|
1681
|
+
await client.IndexedDB.deleteDatabase({
|
|
1682
|
+
securityOrigin: request.origin,
|
|
1683
|
+
databaseName: request.databaseName
|
|
1684
|
+
});
|
|
1685
|
+
return createCdpStorageSuccess(request, { ok: true });
|
|
1686
|
+
}
|
|
1687
|
+
return createCdpStorageError(
|
|
1688
|
+
request,
|
|
1689
|
+
"IndexedDB set operation requires runtime bridge"
|
|
1690
|
+
);
|
|
1691
|
+
}
|
|
1692
|
+
function isCookieInOrigin(cookie, origin) {
|
|
1693
|
+
const hostname = new URL(origin).hostname;
|
|
1694
|
+
const domain = cookie.domain?.replace(/^\./, "");
|
|
1695
|
+
return Boolean(domain && (hostname === domain || hostname.endsWith(`.${domain}`)));
|
|
1696
|
+
}
|
|
1697
|
+
function normalizeCookieSameSite(sameSite) {
|
|
1698
|
+
if (!sameSite) {
|
|
1699
|
+
return void 0;
|
|
1700
|
+
}
|
|
1701
|
+
if (sameSite === "strict") {
|
|
1702
|
+
return "Strict";
|
|
1703
|
+
}
|
|
1704
|
+
if (sameSite === "lax") {
|
|
1705
|
+
return "Lax";
|
|
1706
|
+
}
|
|
1707
|
+
return "None";
|
|
1708
|
+
}
|
|
1709
|
+
function createExactCdpKeyRange(key) {
|
|
1710
|
+
const parsedKey = parseJsonValue(key);
|
|
1711
|
+
return {
|
|
1712
|
+
lower: parsedKey,
|
|
1713
|
+
upper: parsedKey,
|
|
1714
|
+
lowerOpen: false,
|
|
1715
|
+
upperOpen: false
|
|
1716
|
+
};
|
|
1717
|
+
}
|
|
1718
|
+
function parseJsonValue(value) {
|
|
1719
|
+
try {
|
|
1720
|
+
return JSON.parse(value);
|
|
1721
|
+
} catch {
|
|
1722
|
+
return value;
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
function assertStorageKey(request) {
|
|
1726
|
+
if (!request.key) {
|
|
1727
|
+
throw new Error("Storage key is required for this operation");
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
function assertIndexedDbTarget(request) {
|
|
1731
|
+
if (!request.databaseName || !request.objectStoreName) {
|
|
1732
|
+
throw new Error("IndexedDB databaseName and objectStoreName are required");
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
function createCdpStorageSuccess(request, data) {
|
|
1736
|
+
return {
|
|
1737
|
+
ok: true,
|
|
1738
|
+
source: "cdp",
|
|
1739
|
+
action: request.action,
|
|
1740
|
+
scope: request.scope,
|
|
1741
|
+
data
|
|
1742
|
+
};
|
|
1743
|
+
}
|
|
1744
|
+
function createCdpStorageError(request, error) {
|
|
1745
|
+
return {
|
|
1746
|
+
ok: false,
|
|
1747
|
+
source: "cdp",
|
|
1748
|
+
action: request.action,
|
|
1749
|
+
scope: request.scope,
|
|
1750
|
+
error
|
|
1751
|
+
};
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
// src/mcp/tools/storage.ts
|
|
1755
|
+
function registerStorageTools(server, ctx) {
|
|
1756
|
+
registerStorageTool(server, MCP_TOOL_NAMES.listStorage, {
|
|
1757
|
+
description: "List same-origin storage and CDP cookies when available.",
|
|
1758
|
+
inputSchema: {
|
|
1759
|
+
pageId: z7.string().optional()
|
|
1760
|
+
},
|
|
1761
|
+
action: "list",
|
|
1762
|
+
handler: (input) => handleListStorage(ctx, input.pageId)
|
|
1763
|
+
});
|
|
1764
|
+
registerStorageTool(server, MCP_TOOL_NAMES.getStorageItem, {
|
|
1765
|
+
description: "Read one storage entry.",
|
|
1766
|
+
inputSchema: createStorageInputSchema(),
|
|
1767
|
+
action: "get",
|
|
1768
|
+
handler: (input) => handleStorageAction(ctx, { ...input, action: "get" })
|
|
1769
|
+
});
|
|
1770
|
+
registerStorageTool(server, MCP_TOOL_NAMES.setStorageItem, {
|
|
1771
|
+
description: "Write one storage entry.",
|
|
1772
|
+
inputSchema: createStorageInputSchema(),
|
|
1773
|
+
action: "set",
|
|
1774
|
+
handler: (input) => handleStorageAction(ctx, { ...input, action: "set" })
|
|
1775
|
+
});
|
|
1776
|
+
registerStorageTool(server, MCP_TOOL_NAMES.deleteStorageItem, {
|
|
1777
|
+
description: "Delete one storage entry.",
|
|
1778
|
+
inputSchema: createStorageInputSchema(),
|
|
1779
|
+
action: "delete",
|
|
1780
|
+
handler: (input) => handleStorageAction(ctx, { ...input, action: "delete" })
|
|
1781
|
+
});
|
|
1782
|
+
registerStorageTool(server, MCP_TOOL_NAMES.clearStorage, {
|
|
1783
|
+
description: "Clear one storage scope.",
|
|
1784
|
+
inputSchema: createStorageInputSchema(),
|
|
1785
|
+
action: "clear",
|
|
1786
|
+
handler: (input) => handleStorageAction(ctx, { ...input, action: "clear" })
|
|
1787
|
+
});
|
|
1788
|
+
}
|
|
1789
|
+
function registerStorageTool(server, name, options) {
|
|
1790
|
+
server.registerTool(
|
|
1791
|
+
name,
|
|
1792
|
+
{
|
|
1793
|
+
description: options.description,
|
|
1794
|
+
inputSchema: options.inputSchema
|
|
1795
|
+
},
|
|
1796
|
+
(async (input) => options.handler(
|
|
1797
|
+
input
|
|
1798
|
+
))
|
|
1799
|
+
);
|
|
1800
|
+
}
|
|
1801
|
+
function createStorageInputSchema() {
|
|
1802
|
+
return {
|
|
1803
|
+
pageId: z7.string().optional(),
|
|
1804
|
+
scope: z7.enum(["localStorage", "sessionStorage", "indexedDB", "cookie"]).optional(),
|
|
1805
|
+
key: z7.string().optional(),
|
|
1806
|
+
value: z7.string().optional(),
|
|
1807
|
+
databaseName: z7.string().optional(),
|
|
1808
|
+
objectStoreName: z7.string().optional(),
|
|
1809
|
+
indexName: z7.string().optional(),
|
|
1810
|
+
cookie: z7.object({
|
|
1811
|
+
name: z7.string(),
|
|
1812
|
+
value: z7.string().optional(),
|
|
1813
|
+
domain: z7.string().optional(),
|
|
1814
|
+
path: z7.string().optional(),
|
|
1815
|
+
url: z7.string().optional(),
|
|
1816
|
+
httpOnly: z7.boolean().optional(),
|
|
1817
|
+
secure: z7.boolean().optional(),
|
|
1818
|
+
sameSite: z7.enum(["strict", "lax", "none"]).optional(),
|
|
1819
|
+
expires: z7.number().optional()
|
|
1820
|
+
}).optional()
|
|
1821
|
+
};
|
|
1822
|
+
}
|
|
1823
|
+
async function handleListStorage(ctx, pageId) {
|
|
1824
|
+
let baseRequest;
|
|
1825
|
+
try {
|
|
1826
|
+
baseRequest = createStorageRequest(ctx, {
|
|
1827
|
+
pageId,
|
|
1828
|
+
action: "list",
|
|
1829
|
+
scope: "localStorage"
|
|
1830
|
+
});
|
|
1831
|
+
} catch (error) {
|
|
1832
|
+
return createToolError(error instanceof Error ? error.message : String(error));
|
|
1833
|
+
}
|
|
1834
|
+
const [localStorage, sessionStorage, indexedDB] = await Promise.all([
|
|
1835
|
+
requestRuntimeStorage(ctx, { ...baseRequest, scope: "localStorage" }),
|
|
1836
|
+
requestRuntimeStorage(ctx, { ...baseRequest, scope: "sessionStorage" }),
|
|
1837
|
+
requestRuntimeStorage(ctx, { ...baseRequest, scope: "indexedDB" })
|
|
1838
|
+
]);
|
|
1839
|
+
const cookie = await listCookiesIfCdpAvailable(ctx, baseRequest, pageId);
|
|
1840
|
+
return createToolResponse({
|
|
1841
|
+
ok: true,
|
|
1842
|
+
origin: baseRequest.origin,
|
|
1843
|
+
localStorage: extractStorageData(localStorage),
|
|
1844
|
+
sessionStorage: extractStorageData(sessionStorage),
|
|
1845
|
+
indexedDB: extractStorageData(indexedDB),
|
|
1846
|
+
cookie
|
|
1847
|
+
});
|
|
1848
|
+
}
|
|
1849
|
+
async function handleStorageAction(ctx, input) {
|
|
1850
|
+
let request;
|
|
1851
|
+
try {
|
|
1852
|
+
request = createStorageRequest(ctx, input);
|
|
1853
|
+
} catch (error) {
|
|
1854
|
+
return createToolError(error instanceof Error ? error.message : String(error));
|
|
1855
|
+
}
|
|
1856
|
+
const cdp = await connectCdpForPage(ctx, input.pageId);
|
|
1857
|
+
if (cdp && shouldUseCdpStorage(request)) {
|
|
1858
|
+
try {
|
|
1859
|
+
const result2 = await createCdpStorageAdapter(cdp.client).manageStorage(
|
|
1860
|
+
request
|
|
1861
|
+
);
|
|
1862
|
+
return createToolResponse(result2);
|
|
1863
|
+
} finally {
|
|
1864
|
+
await closeCdpClient(cdp.client);
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
const result = await requestRuntimeStorage(ctx, request);
|
|
1868
|
+
return createToolResponse(result);
|
|
1869
|
+
}
|
|
1870
|
+
async function requestRuntimeStorage(ctx, request) {
|
|
1871
|
+
return requestRuntimeData(ctx, (event) => {
|
|
1872
|
+
void ctx.rpcServer?.manageStorage({
|
|
1873
|
+
...request,
|
|
1874
|
+
event
|
|
1875
|
+
});
|
|
1876
|
+
});
|
|
1877
|
+
}
|
|
1878
|
+
async function listCookiesIfCdpAvailable(ctx, request, pageId) {
|
|
1879
|
+
if (!hasCdpConfig2(ctx)) {
|
|
1880
|
+
return extractStorageData(
|
|
1881
|
+
await requestRuntimeStorage(ctx, { ...request, scope: "cookie" })
|
|
1882
|
+
);
|
|
1883
|
+
}
|
|
1884
|
+
const cdp = await connectCdpForPage(ctx, pageId);
|
|
1885
|
+
if (!cdp) {
|
|
1886
|
+
return extractStorageData(
|
|
1887
|
+
await requestRuntimeStorage(ctx, { ...request, scope: "cookie" })
|
|
1888
|
+
);
|
|
1889
|
+
}
|
|
1890
|
+
try {
|
|
1891
|
+
const result = await createCdpStorageAdapter(cdp.client).manageStorage({
|
|
1892
|
+
...request,
|
|
1893
|
+
scope: "cookie"
|
|
1894
|
+
});
|
|
1895
|
+
return extractStorageData(result);
|
|
1896
|
+
} finally {
|
|
1897
|
+
await closeCdpClient(cdp.client);
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
function extractStorageData(result) {
|
|
1901
|
+
if (!isStorageResultRecord(result)) {
|
|
1902
|
+
return result;
|
|
1903
|
+
}
|
|
1904
|
+
return result.data ?? result;
|
|
1905
|
+
}
|
|
1906
|
+
function isStorageResultRecord(value) {
|
|
1907
|
+
return typeof value === "object" && value !== null && "ok" in value;
|
|
1908
|
+
}
|
|
1909
|
+
function shouldUseCdpStorage(request) {
|
|
1910
|
+
return request.scope === "cookie";
|
|
1911
|
+
}
|
|
1912
|
+
function createStorageRequest(ctx, input) {
|
|
1913
|
+
const page = resolvePageTarget(ctx, input.pageId);
|
|
1914
|
+
const origin = new URL(page.url).origin;
|
|
1915
|
+
return {
|
|
1916
|
+
event: "",
|
|
1917
|
+
pageId: page.pageId,
|
|
1918
|
+
origin,
|
|
1919
|
+
action: input.action,
|
|
1920
|
+
scope: normalizeScope(input.scope),
|
|
1921
|
+
key: input.key,
|
|
1922
|
+
value: input.value,
|
|
1923
|
+
databaseName: input.databaseName,
|
|
1924
|
+
objectStoreName: input.objectStoreName,
|
|
1925
|
+
indexName: input.indexName,
|
|
1926
|
+
cookie: input.cookie
|
|
1927
|
+
};
|
|
1928
|
+
}
|
|
1929
|
+
function normalizeScope(scope) {
|
|
1930
|
+
return scope ?? "localStorage";
|
|
1931
|
+
}
|
|
1932
|
+
function hasCdpConfig2(ctx) {
|
|
1933
|
+
return Boolean(ctx.options.cdp.browserUrl || ctx.options.cdp.wsEndpoint);
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
// src/mcp/tools/screenshot.ts
|
|
1937
|
+
import { z as z8 } from "zod";
|
|
1938
|
+
|
|
1517
1939
|
// src/cdp/cdpScreenshot.ts
|
|
1518
1940
|
async function cdpCaptureScreenshot(options) {
|
|
1519
1941
|
if (options.target === "element") {
|
|
@@ -1672,14 +2094,14 @@ function createProjectRelativePath(ctx, filePath) {
|
|
|
1672
2094
|
var DEFAULT_SCREENSHOT_TARGET = "viewport";
|
|
1673
2095
|
var DEFAULT_SCREENSHOT_FORMAT = "png";
|
|
1674
2096
|
var screenshotInputSchema = {
|
|
1675
|
-
pageId:
|
|
1676
|
-
target:
|
|
1677
|
-
selector:
|
|
1678
|
-
format:
|
|
1679
|
-
prefer:
|
|
1680
|
-
quality:
|
|
1681
|
-
scale:
|
|
1682
|
-
snapdom:
|
|
2097
|
+
pageId: z8.string().optional(),
|
|
2098
|
+
target: z8.enum(["viewport", "fullPage", "element"]).optional(),
|
|
2099
|
+
selector: z8.string().optional(),
|
|
2100
|
+
format: z8.enum(["png", "jpeg", "webp"]).optional(),
|
|
2101
|
+
prefer: z8.enum(["auto", "cdp", "runtime"]).optional(),
|
|
2102
|
+
quality: z8.number().optional(),
|
|
2103
|
+
scale: z8.number().optional(),
|
|
2104
|
+
snapdom: z8.record(z8.string(), z8.unknown()).optional()
|
|
1683
2105
|
};
|
|
1684
2106
|
function registerScreenshotTools(server, ctx) {
|
|
1685
2107
|
server.registerTool(
|
|
@@ -1799,7 +2221,7 @@ function isScreenshotImagePayload(result) {
|
|
|
1799
2221
|
|
|
1800
2222
|
// src/mcp/tools/vue.ts
|
|
1801
2223
|
import { nanoid as nanoid3 } from "nanoid";
|
|
1802
|
-
import { z as
|
|
2224
|
+
import { z as z9 } from "zod";
|
|
1803
2225
|
function registerVueTools(server, ctx) {
|
|
1804
2226
|
server.registerTool(
|
|
1805
2227
|
MCP_TOOL_NAMES.getComponentTree,
|
|
@@ -1812,7 +2234,7 @@ function registerVueTools(server, ctx) {
|
|
|
1812
2234
|
MCP_TOOL_NAMES.getComponentState,
|
|
1813
2235
|
{
|
|
1814
2236
|
description: "Get Vue component state.",
|
|
1815
|
-
inputSchema: { componentName:
|
|
2237
|
+
inputSchema: { componentName: z9.string() }
|
|
1816
2238
|
},
|
|
1817
2239
|
async ({ componentName }) => requestVueData(ctx, (event) => {
|
|
1818
2240
|
void ctx.rpcServer?.getInspectorState({ event, componentName });
|
|
@@ -1823,10 +2245,10 @@ function registerVueTools(server, ctx) {
|
|
|
1823
2245
|
{
|
|
1824
2246
|
description: "Edit Vue component state.",
|
|
1825
2247
|
inputSchema: {
|
|
1826
|
-
componentName:
|
|
1827
|
-
path:
|
|
1828
|
-
value:
|
|
1829
|
-
valueType:
|
|
2248
|
+
componentName: z9.string(),
|
|
2249
|
+
path: z9.array(z9.string()),
|
|
2250
|
+
value: z9.string(),
|
|
2251
|
+
valueType: z9.enum(["string", "number", "boolean", "object", "array"])
|
|
1830
2252
|
}
|
|
1831
2253
|
},
|
|
1832
2254
|
({ componentName, path: path8, value, valueType }) => {
|
|
@@ -1846,7 +2268,7 @@ function registerVueTools(server, ctx) {
|
|
|
1846
2268
|
MCP_TOOL_NAMES.highlightComponent,
|
|
1847
2269
|
{
|
|
1848
2270
|
description: "Highlight a Vue component.",
|
|
1849
|
-
inputSchema: { componentName:
|
|
2271
|
+
inputSchema: { componentName: z9.string() }
|
|
1850
2272
|
},
|
|
1851
2273
|
({ componentName }) => {
|
|
1852
2274
|
if (!ctx.rpcServer) {
|
|
@@ -1874,7 +2296,7 @@ function registerVueTools(server, ctx) {
|
|
|
1874
2296
|
MCP_TOOL_NAMES.getPiniaState,
|
|
1875
2297
|
{
|
|
1876
2298
|
description: "Get Pinia store state.",
|
|
1877
|
-
inputSchema: { storeName:
|
|
2299
|
+
inputSchema: { storeName: z9.string() }
|
|
1878
2300
|
},
|
|
1879
2301
|
async ({ storeName }) => requestVueData(ctx, (event) => {
|
|
1880
2302
|
void ctx.rpcServer?.getPiniaState({ event, storeName });
|
|
@@ -1921,6 +2343,7 @@ function createMcpServer(ctx, vite) {
|
|
|
1921
2343
|
registerConsoleTools(server, ctx);
|
|
1922
2344
|
registerEvaluateTools(server, ctx);
|
|
1923
2345
|
registerNetworkTools(server, ctx);
|
|
2346
|
+
registerStorageTools(server, ctx);
|
|
1924
2347
|
registerPerformanceTools(server, ctx);
|
|
1925
2348
|
registerVueTools(server, ctx);
|
|
1926
2349
|
return server;
|
|
@@ -2009,6 +2432,10 @@ function createServerVueRuntimeRpc(ctx) {
|
|
|
2009
2432
|
onScreenshotTaken: (event, data) => {
|
|
2010
2433
|
void ctx.hooks.callHook(event, data);
|
|
2011
2434
|
},
|
|
2435
|
+
manageStorage: () => void 0,
|
|
2436
|
+
onStorageUpdated: (event, data) => {
|
|
2437
|
+
void ctx.hooks.callHook(event, data);
|
|
2438
|
+
},
|
|
2012
2439
|
recordPerformance: () => void 0,
|
|
2013
2440
|
onPerformanceRecorded: (event, data) => {
|
|
2014
2441
|
void ctx.hooks.callHook(event, data);
|
|
@@ -2917,53 +3344,32 @@ function vueMcpNext(userOptions = {}) {
|
|
|
2917
3344
|
() => createMcpServer(ctx, server),
|
|
2918
3345
|
server
|
|
2919
3346
|
);
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
continue;
|
|
2928
|
-
}
|
|
2929
|
-
if (now - seenAt >= DEFAULT_RUNTIME_PAGE_HEARTBEAT_TIMEOUT_MS) {
|
|
2930
|
-
ctx.pages.disconnect(pageId, now);
|
|
2931
|
-
lastSeenAt.delete(pageId);
|
|
3347
|
+
server.ws.on(
|
|
3348
|
+
"vite-plugin-vue-mcp-next:page-connected",
|
|
3349
|
+
(payload) => {
|
|
3350
|
+
if (isRuntimePageTarget(payload)) {
|
|
3351
|
+
ctx.pages.upsert(payload);
|
|
3352
|
+
void ctx.hooks.callHook(RUNTIME_PAGE_RECONNECTED_EVENT, payload);
|
|
3353
|
+
void cdpLifecycle.connectPage(payload);
|
|
2932
3354
|
}
|
|
2933
3355
|
}
|
|
2934
|
-
|
|
2935
|
-
server.ws.on(
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
void cdpLifecycle.connectPage(payload);
|
|
2941
|
-
}
|
|
2942
|
-
});
|
|
2943
|
-
server.ws.on(RUNTIME_PAGE_HEARTBEAT_EVENT, (payload) => {
|
|
2944
|
-
if (isRuntimeHeartbeatTarget(payload)) {
|
|
2945
|
-
const target = ctx.pages.get(payload.pageId);
|
|
2946
|
-
if (target?.source === "runtime" && target.connected) {
|
|
2947
|
-
lastSeenAt.set(payload.pageId, payload.timestamp);
|
|
3356
|
+
);
|
|
3357
|
+
server.ws.on(
|
|
3358
|
+
"vite-plugin-vue-mcp-next:console-record",
|
|
3359
|
+
(payload) => {
|
|
3360
|
+
if (isConsoleRecord(payload)) {
|
|
3361
|
+
ctx.consoleRecords.push(payload);
|
|
2948
3362
|
}
|
|
2949
3363
|
}
|
|
2950
|
-
|
|
2951
|
-
server.ws.on(
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
server.ws.on("vite-plugin-vue-mcp-next:console-record", (payload) => {
|
|
2958
|
-
if (isConsoleRecord(payload)) {
|
|
2959
|
-
ctx.consoleRecords.push(payload);
|
|
2960
|
-
}
|
|
2961
|
-
});
|
|
2962
|
-
server.ws.on("vite-plugin-vue-mcp-next:network-record", (payload) => {
|
|
2963
|
-
if (isNetworkRecord(payload)) {
|
|
2964
|
-
ctx.networkRecords.push(payload);
|
|
3364
|
+
);
|
|
3365
|
+
server.ws.on(
|
|
3366
|
+
"vite-plugin-vue-mcp-next:network-record",
|
|
3367
|
+
(payload) => {
|
|
3368
|
+
if (isNetworkRecord(payload)) {
|
|
3369
|
+
ctx.networkRecords.push(payload);
|
|
3370
|
+
}
|
|
2965
3371
|
}
|
|
2966
|
-
|
|
3372
|
+
);
|
|
2967
3373
|
server.ws.on(
|
|
2968
3374
|
"vite-plugin-vue-mcp-next:performance-record",
|
|
2969
3375
|
(payload) => {
|
|
@@ -2993,7 +3399,6 @@ function vueMcpNext(userOptions = {}) {
|
|
|
2993
3399
|
}, 300);
|
|
2994
3400
|
}
|
|
2995
3401
|
server.httpServer?.once("close", () => {
|
|
2996
|
-
clearInterval(heartbeatTimer);
|
|
2997
3402
|
void cdpLifecycle.closeAll();
|
|
2998
3403
|
});
|
|
2999
3404
|
},
|
|
@@ -3018,20 +3423,6 @@ function isRuntimePageTarget(payload) {
|
|
|
3018
3423
|
const target = payload;
|
|
3019
3424
|
return target.source === "runtime" && typeof target.pageId === "string" && typeof target.url === "string" && typeof target.pathname === "string" && typeof target.connected === "boolean" && (target.runtimeClientId === void 0 || typeof target.runtimeClientId === "string");
|
|
3020
3425
|
}
|
|
3021
|
-
function isRuntimeHeartbeatTarget(payload) {
|
|
3022
|
-
if (!payload || typeof payload !== "object") {
|
|
3023
|
-
return false;
|
|
3024
|
-
}
|
|
3025
|
-
const target = payload;
|
|
3026
|
-
return typeof target.pageId === "string" && typeof target.timestamp === "number";
|
|
3027
|
-
}
|
|
3028
|
-
function isRuntimeDisconnectTarget(payload) {
|
|
3029
|
-
if (!payload || typeof payload !== "object") {
|
|
3030
|
-
return false;
|
|
3031
|
-
}
|
|
3032
|
-
const target = payload;
|
|
3033
|
-
return typeof target.pageId === "string";
|
|
3034
|
-
}
|
|
3035
3426
|
function isConsoleRecord(payload) {
|
|
3036
3427
|
if (!payload || typeof payload !== "object") {
|
|
3037
3428
|
return false;
|