@xiaou66/vite-plugin-vue-mcp-next 1.1.0 → 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 +449 -17
- 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 +449 -17
- package/dist/index.js.map +1 -1
- package/dist/runtime/client.cjs +404 -1
- package/dist/runtime/client.cjs.map +1 -1
- package/dist/runtime/client.js +404 -1
- package/dist/runtime/client.js.map +1 -1
- package/package.json +1 -1
- package/skills/vite-mcp-next/SKILL.md +7 -2
package/README.md
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
| Console 日志 | Runtime Hook | CDP 优先,Hook 兜底 | 采集 `log/info/warn/error/debug` 和运行时日志 |
|
|
16
16
|
| Evaluate 控制台执行 | Runtime Hook | CDP 优先,Hook 兜底 | 默认关闭,必须显式开启 |
|
|
17
17
|
| Network 请求 | Runtime Hook | CDP 优先,Hook 兜底 | 返回请求 URL、query、body、status、headers、response body |
|
|
18
|
+
| 浏览器存储 | Runtime Hook | CDP 优先,Hook 兜底 | 访问同源 Web Storage、IndexedDB;Cookie 在无 CDP 时回退到 `document.cookie` |
|
|
18
19
|
| Vue 组件树 | Vue Runtime Bridge | Vue Runtime Bridge | Vue 专属语义不走 CDP |
|
|
19
20
|
| Vue 组件状态 | Vue Runtime Bridge | Vue Runtime Bridge | 读取和编辑组件状态 |
|
|
20
21
|
| Router 信息 | Vue Runtime Bridge | Vue Runtime Bridge | 返回当前路由和路由表 |
|
|
@@ -548,6 +549,25 @@ interface NetworkRecord {
|
|
|
548
549
|
|
|
549
550
|
Vue 组件、Router、Pinia 是应用层语义,固定走 Vue Runtime Bridge,不用 CDP 替代。
|
|
550
551
|
|
|
552
|
+
### 浏览器存储
|
|
553
|
+
|
|
554
|
+
浏览器存储工具组面向调试当前页面的运行时数据。`localStorage`、`sessionStorage` 和 `IndexedDB` 只作用于当前选中页面同源,避免跨站误操作。Cookie 在无 CDP 时通过 `document.cookie` 访问当前页面可见的同源条目;配置 CDP 后可查询浏览器级 Cookie,并能读取 `HttpOnly` 条目,但删除和清空时会跳过 `HttpOnly` 并返回跳过数量。
|
|
555
|
+
|
|
556
|
+
| 资源 | Runtime Hook | CDP |
|
|
557
|
+
| --- | --- | --- |
|
|
558
|
+
| `localStorage` | 读 / 写 / 删 | 读 / 写 / 删 |
|
|
559
|
+
| `sessionStorage` | 读 / 写 / 删 | 读 / 写 / 删 |
|
|
560
|
+
| `IndexedDB` | 同源库和记录操作 | 同源库和记录操作 |
|
|
561
|
+
| `Cookie` | 查询 / 写入 / 删除当前页面可见条目 | 查询 / 写入 / 删除非 `HttpOnly` 条目,`HttpOnly` 仅可查询 |
|
|
562
|
+
|
|
563
|
+
相关 MCP 工具:
|
|
564
|
+
|
|
565
|
+
- `list_storage`:列出当前页面同源存储和 Cookie;有 CDP 时补充浏览器级 Cookie
|
|
566
|
+
- `get_storage_item`:读取指定 key、IndexedDB 记录或 Cookie
|
|
567
|
+
- `set_storage_item`:写入 Web Storage、IndexedDB 记录或 Cookie
|
|
568
|
+
- `delete_storage_item`:删除 Web Storage、IndexedDB 记录或 Cookie;`HttpOnly` Cookie 仅在 CDP 下可见且删除时会跳过
|
|
569
|
+
- `clear_storage`:清空指定范围,Cookie 清空会跳过 `HttpOnly`
|
|
570
|
+
|
|
551
571
|
## 本地验证
|
|
552
572
|
|
|
553
573
|
### 自动化检查
|
package/dist/index.cjs
CHANGED
|
@@ -72,6 +72,11 @@ var MCP_TOOL_NAMES = {
|
|
|
72
72
|
getNetworkRequests: "get_network_requests",
|
|
73
73
|
getNetworkRequestDetail: "get_network_request_detail",
|
|
74
74
|
clearNetworkRequests: "clear_network_requests",
|
|
75
|
+
listStorage: "list_storage",
|
|
76
|
+
getStorageItem: "get_storage_item",
|
|
77
|
+
setStorageItem: "set_storage_item",
|
|
78
|
+
deleteStorageItem: "delete_storage_item",
|
|
79
|
+
clearStorage: "clear_storage",
|
|
75
80
|
recordPerformance: "record_performance",
|
|
76
81
|
startPerformanceRecording: "start_performance_recording",
|
|
77
82
|
stopPerformanceRecording: "stop_performance_recording",
|
|
@@ -1543,9 +1548,431 @@ function getPathname(url) {
|
|
|
1543
1548
|
}
|
|
1544
1549
|
}
|
|
1545
1550
|
|
|
1546
|
-
// src/mcp/tools/
|
|
1551
|
+
// src/mcp/tools/storage.ts
|
|
1547
1552
|
var import_zod7 = require("zod");
|
|
1548
1553
|
|
|
1554
|
+
// src/cdp/cdpStorage.ts
|
|
1555
|
+
function createCdpStorageAdapter(client) {
|
|
1556
|
+
return {
|
|
1557
|
+
async manageStorage(request) {
|
|
1558
|
+
try {
|
|
1559
|
+
return await manageCdpStorage(client, request);
|
|
1560
|
+
} catch (error) {
|
|
1561
|
+
return createCdpStorageError(
|
|
1562
|
+
request,
|
|
1563
|
+
error instanceof Error ? error.message : String(error)
|
|
1564
|
+
);
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
};
|
|
1568
|
+
}
|
|
1569
|
+
async function manageCdpStorage(client, request) {
|
|
1570
|
+
if (request.scope === "cookie") {
|
|
1571
|
+
return manageCdpCookies(client, request);
|
|
1572
|
+
}
|
|
1573
|
+
if (request.scope === "indexedDB") {
|
|
1574
|
+
return manageCdpIndexedDb(client, request);
|
|
1575
|
+
}
|
|
1576
|
+
return manageCdpDomStorage(client, request);
|
|
1577
|
+
}
|
|
1578
|
+
async function manageCdpCookies(client, request) {
|
|
1579
|
+
if (request.action === "list" || request.action === "get") {
|
|
1580
|
+
const result2 = await client.Storage.getCookies();
|
|
1581
|
+
const cookies2 = result2.cookies.filter(
|
|
1582
|
+
(cookie) => isCookieInOrigin(cookie, request.origin)
|
|
1583
|
+
);
|
|
1584
|
+
return createCdpStorageSuccess(request, {
|
|
1585
|
+
origin: request.origin,
|
|
1586
|
+
cookies: request.action === "get" && request.cookie?.name ? cookies2.filter((cookie) => cookie.name === request.cookie?.name) : cookies2
|
|
1587
|
+
});
|
|
1588
|
+
}
|
|
1589
|
+
if (request.action === "set") {
|
|
1590
|
+
if (!request.cookie?.name) {
|
|
1591
|
+
throw new Error("Cookie name is required for set operation");
|
|
1592
|
+
}
|
|
1593
|
+
await client.Storage.setCookies({
|
|
1594
|
+
cookies: [
|
|
1595
|
+
{
|
|
1596
|
+
name: request.cookie.name,
|
|
1597
|
+
value: request.cookie.value ?? request.value ?? "",
|
|
1598
|
+
url: request.cookie.url ?? request.origin,
|
|
1599
|
+
domain: request.cookie.domain,
|
|
1600
|
+
path: request.cookie.path,
|
|
1601
|
+
httpOnly: request.cookie.httpOnly,
|
|
1602
|
+
secure: request.cookie.secure,
|
|
1603
|
+
sameSite: normalizeCookieSameSite(request.cookie.sameSite),
|
|
1604
|
+
expires: request.cookie.expires
|
|
1605
|
+
}
|
|
1606
|
+
]
|
|
1607
|
+
});
|
|
1608
|
+
return createCdpStorageSuccess(request, { ok: true });
|
|
1609
|
+
}
|
|
1610
|
+
const result = await client.Storage.getCookies();
|
|
1611
|
+
const cookies = result.cookies.filter(
|
|
1612
|
+
(cookie) => isCookieInOrigin(cookie, request.origin)
|
|
1613
|
+
);
|
|
1614
|
+
const candidates = request.action === "delete" && request.cookie?.name ? cookies.filter((cookie) => cookie.name === request.cookie?.name) : cookies;
|
|
1615
|
+
const deletable = candidates.filter((cookie) => !cookie.httpOnly);
|
|
1616
|
+
const skippedHttpOnlyCount = candidates.length - deletable.length;
|
|
1617
|
+
for (const cookie of deletable) {
|
|
1618
|
+
await client.Network.deleteCookies({
|
|
1619
|
+
name: cookie.name,
|
|
1620
|
+
domain: cookie.domain,
|
|
1621
|
+
path: cookie.path
|
|
1622
|
+
});
|
|
1623
|
+
}
|
|
1624
|
+
return createCdpStorageSuccess(request, {
|
|
1625
|
+
deletedCount: deletable.length,
|
|
1626
|
+
skippedHttpOnlyCount
|
|
1627
|
+
});
|
|
1628
|
+
}
|
|
1629
|
+
async function manageCdpDomStorage(client, request) {
|
|
1630
|
+
const storageId = {
|
|
1631
|
+
securityOrigin: request.origin,
|
|
1632
|
+
isLocalStorage: request.scope === "localStorage"
|
|
1633
|
+
};
|
|
1634
|
+
if (request.action === "list") {
|
|
1635
|
+
const result2 = await client.DOMStorage.getDOMStorageItems({ storageId });
|
|
1636
|
+
return createCdpStorageSuccess(request, {
|
|
1637
|
+
origin: request.origin,
|
|
1638
|
+
scope: request.scope,
|
|
1639
|
+
entries: result2.entries.map(([key, value]) => ({ key, value }))
|
|
1640
|
+
});
|
|
1641
|
+
}
|
|
1642
|
+
if (request.action === "get") {
|
|
1643
|
+
assertStorageKey(request);
|
|
1644
|
+
const result2 = await client.DOMStorage.getDOMStorageItems({ storageId });
|
|
1645
|
+
const entry = result2.entries.find(([key]) => key === request.key);
|
|
1646
|
+
return createCdpStorageSuccess(request, {
|
|
1647
|
+
key: request.key,
|
|
1648
|
+
value: entry?.[1] ?? null
|
|
1649
|
+
});
|
|
1650
|
+
}
|
|
1651
|
+
if (request.action === "set") {
|
|
1652
|
+
assertStorageKey(request);
|
|
1653
|
+
await client.DOMStorage.setDOMStorageItem({
|
|
1654
|
+
storageId,
|
|
1655
|
+
key: request.key,
|
|
1656
|
+
value: request.value ?? ""
|
|
1657
|
+
});
|
|
1658
|
+
return createCdpStorageSuccess(request, { ok: true });
|
|
1659
|
+
}
|
|
1660
|
+
if (request.action === "delete") {
|
|
1661
|
+
assertStorageKey(request);
|
|
1662
|
+
await client.DOMStorage.removeDOMStorageItem({
|
|
1663
|
+
storageId,
|
|
1664
|
+
key: request.key
|
|
1665
|
+
});
|
|
1666
|
+
return createCdpStorageSuccess(request, { ok: true });
|
|
1667
|
+
}
|
|
1668
|
+
const result = await client.DOMStorage.getDOMStorageItems({ storageId });
|
|
1669
|
+
for (const [key] of result.entries) {
|
|
1670
|
+
await client.DOMStorage.removeDOMStorageItem({ storageId, key });
|
|
1671
|
+
}
|
|
1672
|
+
return createCdpStorageSuccess(request, { deletedCount: result.entries.length });
|
|
1673
|
+
}
|
|
1674
|
+
async function manageCdpIndexedDb(client, request) {
|
|
1675
|
+
if (request.action === "list") {
|
|
1676
|
+
const result = await client.IndexedDB.requestDatabaseNames({
|
|
1677
|
+
securityOrigin: request.origin
|
|
1678
|
+
});
|
|
1679
|
+
return createCdpStorageSuccess(request, {
|
|
1680
|
+
origin: request.origin,
|
|
1681
|
+
databases: result.databaseNames
|
|
1682
|
+
});
|
|
1683
|
+
}
|
|
1684
|
+
assertIndexedDbTarget(request);
|
|
1685
|
+
if (request.action === "get") {
|
|
1686
|
+
const result = await client.IndexedDB.requestData({
|
|
1687
|
+
securityOrigin: request.origin,
|
|
1688
|
+
databaseName: request.databaseName,
|
|
1689
|
+
objectStoreName: request.objectStoreName,
|
|
1690
|
+
indexName: request.indexName ?? "",
|
|
1691
|
+
skipCount: 0,
|
|
1692
|
+
pageSize: 100
|
|
1693
|
+
});
|
|
1694
|
+
return createCdpStorageSuccess(request, {
|
|
1695
|
+
entries: result.objectStoreDataEntries,
|
|
1696
|
+
hasMore: result.hasMore
|
|
1697
|
+
});
|
|
1698
|
+
}
|
|
1699
|
+
if (request.action === "delete") {
|
|
1700
|
+
assertStorageKey(request);
|
|
1701
|
+
await client.IndexedDB.deleteObjectStoreEntries({
|
|
1702
|
+
securityOrigin: request.origin,
|
|
1703
|
+
databaseName: request.databaseName,
|
|
1704
|
+
objectStoreName: request.objectStoreName,
|
|
1705
|
+
keyRange: createExactCdpKeyRange(request.key)
|
|
1706
|
+
});
|
|
1707
|
+
return createCdpStorageSuccess(request, { ok: true });
|
|
1708
|
+
}
|
|
1709
|
+
if (request.action === "clear") {
|
|
1710
|
+
if (request.objectStoreName) {
|
|
1711
|
+
await client.IndexedDB.clearObjectStore({
|
|
1712
|
+
securityOrigin: request.origin,
|
|
1713
|
+
databaseName: request.databaseName,
|
|
1714
|
+
objectStoreName: request.objectStoreName
|
|
1715
|
+
});
|
|
1716
|
+
return createCdpStorageSuccess(request, { ok: true });
|
|
1717
|
+
}
|
|
1718
|
+
await client.IndexedDB.deleteDatabase({
|
|
1719
|
+
securityOrigin: request.origin,
|
|
1720
|
+
databaseName: request.databaseName
|
|
1721
|
+
});
|
|
1722
|
+
return createCdpStorageSuccess(request, { ok: true });
|
|
1723
|
+
}
|
|
1724
|
+
return createCdpStorageError(
|
|
1725
|
+
request,
|
|
1726
|
+
"IndexedDB set operation requires runtime bridge"
|
|
1727
|
+
);
|
|
1728
|
+
}
|
|
1729
|
+
function isCookieInOrigin(cookie, origin) {
|
|
1730
|
+
const hostname = new URL(origin).hostname;
|
|
1731
|
+
const domain = cookie.domain?.replace(/^\./, "");
|
|
1732
|
+
return Boolean(domain && (hostname === domain || hostname.endsWith(`.${domain}`)));
|
|
1733
|
+
}
|
|
1734
|
+
function normalizeCookieSameSite(sameSite) {
|
|
1735
|
+
if (!sameSite) {
|
|
1736
|
+
return void 0;
|
|
1737
|
+
}
|
|
1738
|
+
if (sameSite === "strict") {
|
|
1739
|
+
return "Strict";
|
|
1740
|
+
}
|
|
1741
|
+
if (sameSite === "lax") {
|
|
1742
|
+
return "Lax";
|
|
1743
|
+
}
|
|
1744
|
+
return "None";
|
|
1745
|
+
}
|
|
1746
|
+
function createExactCdpKeyRange(key) {
|
|
1747
|
+
const parsedKey = parseJsonValue(key);
|
|
1748
|
+
return {
|
|
1749
|
+
lower: parsedKey,
|
|
1750
|
+
upper: parsedKey,
|
|
1751
|
+
lowerOpen: false,
|
|
1752
|
+
upperOpen: false
|
|
1753
|
+
};
|
|
1754
|
+
}
|
|
1755
|
+
function parseJsonValue(value) {
|
|
1756
|
+
try {
|
|
1757
|
+
return JSON.parse(value);
|
|
1758
|
+
} catch {
|
|
1759
|
+
return value;
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
function assertStorageKey(request) {
|
|
1763
|
+
if (!request.key) {
|
|
1764
|
+
throw new Error("Storage key is required for this operation");
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1767
|
+
function assertIndexedDbTarget(request) {
|
|
1768
|
+
if (!request.databaseName || !request.objectStoreName) {
|
|
1769
|
+
throw new Error("IndexedDB databaseName and objectStoreName are required");
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
function createCdpStorageSuccess(request, data) {
|
|
1773
|
+
return {
|
|
1774
|
+
ok: true,
|
|
1775
|
+
source: "cdp",
|
|
1776
|
+
action: request.action,
|
|
1777
|
+
scope: request.scope,
|
|
1778
|
+
data
|
|
1779
|
+
};
|
|
1780
|
+
}
|
|
1781
|
+
function createCdpStorageError(request, error) {
|
|
1782
|
+
return {
|
|
1783
|
+
ok: false,
|
|
1784
|
+
source: "cdp",
|
|
1785
|
+
action: request.action,
|
|
1786
|
+
scope: request.scope,
|
|
1787
|
+
error
|
|
1788
|
+
};
|
|
1789
|
+
}
|
|
1790
|
+
|
|
1791
|
+
// src/mcp/tools/storage.ts
|
|
1792
|
+
function registerStorageTools(server, ctx) {
|
|
1793
|
+
registerStorageTool(server, MCP_TOOL_NAMES.listStorage, {
|
|
1794
|
+
description: "List same-origin storage and CDP cookies when available.",
|
|
1795
|
+
inputSchema: {
|
|
1796
|
+
pageId: import_zod7.z.string().optional()
|
|
1797
|
+
},
|
|
1798
|
+
action: "list",
|
|
1799
|
+
handler: (input) => handleListStorage(ctx, input.pageId)
|
|
1800
|
+
});
|
|
1801
|
+
registerStorageTool(server, MCP_TOOL_NAMES.getStorageItem, {
|
|
1802
|
+
description: "Read one storage entry.",
|
|
1803
|
+
inputSchema: createStorageInputSchema(),
|
|
1804
|
+
action: "get",
|
|
1805
|
+
handler: (input) => handleStorageAction(ctx, { ...input, action: "get" })
|
|
1806
|
+
});
|
|
1807
|
+
registerStorageTool(server, MCP_TOOL_NAMES.setStorageItem, {
|
|
1808
|
+
description: "Write one storage entry.",
|
|
1809
|
+
inputSchema: createStorageInputSchema(),
|
|
1810
|
+
action: "set",
|
|
1811
|
+
handler: (input) => handleStorageAction(ctx, { ...input, action: "set" })
|
|
1812
|
+
});
|
|
1813
|
+
registerStorageTool(server, MCP_TOOL_NAMES.deleteStorageItem, {
|
|
1814
|
+
description: "Delete one storage entry.",
|
|
1815
|
+
inputSchema: createStorageInputSchema(),
|
|
1816
|
+
action: "delete",
|
|
1817
|
+
handler: (input) => handleStorageAction(ctx, { ...input, action: "delete" })
|
|
1818
|
+
});
|
|
1819
|
+
registerStorageTool(server, MCP_TOOL_NAMES.clearStorage, {
|
|
1820
|
+
description: "Clear one storage scope.",
|
|
1821
|
+
inputSchema: createStorageInputSchema(),
|
|
1822
|
+
action: "clear",
|
|
1823
|
+
handler: (input) => handleStorageAction(ctx, { ...input, action: "clear" })
|
|
1824
|
+
});
|
|
1825
|
+
}
|
|
1826
|
+
function registerStorageTool(server, name, options) {
|
|
1827
|
+
server.registerTool(
|
|
1828
|
+
name,
|
|
1829
|
+
{
|
|
1830
|
+
description: options.description,
|
|
1831
|
+
inputSchema: options.inputSchema
|
|
1832
|
+
},
|
|
1833
|
+
(async (input) => options.handler(
|
|
1834
|
+
input
|
|
1835
|
+
))
|
|
1836
|
+
);
|
|
1837
|
+
}
|
|
1838
|
+
function createStorageInputSchema() {
|
|
1839
|
+
return {
|
|
1840
|
+
pageId: import_zod7.z.string().optional(),
|
|
1841
|
+
scope: import_zod7.z.enum(["localStorage", "sessionStorage", "indexedDB", "cookie"]).optional(),
|
|
1842
|
+
key: import_zod7.z.string().optional(),
|
|
1843
|
+
value: import_zod7.z.string().optional(),
|
|
1844
|
+
databaseName: import_zod7.z.string().optional(),
|
|
1845
|
+
objectStoreName: import_zod7.z.string().optional(),
|
|
1846
|
+
indexName: import_zod7.z.string().optional(),
|
|
1847
|
+
cookie: import_zod7.z.object({
|
|
1848
|
+
name: import_zod7.z.string(),
|
|
1849
|
+
value: import_zod7.z.string().optional(),
|
|
1850
|
+
domain: import_zod7.z.string().optional(),
|
|
1851
|
+
path: import_zod7.z.string().optional(),
|
|
1852
|
+
url: import_zod7.z.string().optional(),
|
|
1853
|
+
httpOnly: import_zod7.z.boolean().optional(),
|
|
1854
|
+
secure: import_zod7.z.boolean().optional(),
|
|
1855
|
+
sameSite: import_zod7.z.enum(["strict", "lax", "none"]).optional(),
|
|
1856
|
+
expires: import_zod7.z.number().optional()
|
|
1857
|
+
}).optional()
|
|
1858
|
+
};
|
|
1859
|
+
}
|
|
1860
|
+
async function handleListStorage(ctx, pageId) {
|
|
1861
|
+
let baseRequest;
|
|
1862
|
+
try {
|
|
1863
|
+
baseRequest = createStorageRequest(ctx, {
|
|
1864
|
+
pageId,
|
|
1865
|
+
action: "list",
|
|
1866
|
+
scope: "localStorage"
|
|
1867
|
+
});
|
|
1868
|
+
} catch (error) {
|
|
1869
|
+
return createToolError(error instanceof Error ? error.message : String(error));
|
|
1870
|
+
}
|
|
1871
|
+
const [localStorage, sessionStorage, indexedDB] = await Promise.all([
|
|
1872
|
+
requestRuntimeStorage(ctx, { ...baseRequest, scope: "localStorage" }),
|
|
1873
|
+
requestRuntimeStorage(ctx, { ...baseRequest, scope: "sessionStorage" }),
|
|
1874
|
+
requestRuntimeStorage(ctx, { ...baseRequest, scope: "indexedDB" })
|
|
1875
|
+
]);
|
|
1876
|
+
const cookie = await listCookiesIfCdpAvailable(ctx, baseRequest, pageId);
|
|
1877
|
+
return createToolResponse({
|
|
1878
|
+
ok: true,
|
|
1879
|
+
origin: baseRequest.origin,
|
|
1880
|
+
localStorage: extractStorageData(localStorage),
|
|
1881
|
+
sessionStorage: extractStorageData(sessionStorage),
|
|
1882
|
+
indexedDB: extractStorageData(indexedDB),
|
|
1883
|
+
cookie
|
|
1884
|
+
});
|
|
1885
|
+
}
|
|
1886
|
+
async function handleStorageAction(ctx, input) {
|
|
1887
|
+
let request;
|
|
1888
|
+
try {
|
|
1889
|
+
request = createStorageRequest(ctx, input);
|
|
1890
|
+
} catch (error) {
|
|
1891
|
+
return createToolError(error instanceof Error ? error.message : String(error));
|
|
1892
|
+
}
|
|
1893
|
+
const cdp = await connectCdpForPage(ctx, input.pageId);
|
|
1894
|
+
if (cdp && shouldUseCdpStorage(request)) {
|
|
1895
|
+
try {
|
|
1896
|
+
const result2 = await createCdpStorageAdapter(cdp.client).manageStorage(
|
|
1897
|
+
request
|
|
1898
|
+
);
|
|
1899
|
+
return createToolResponse(result2);
|
|
1900
|
+
} finally {
|
|
1901
|
+
await closeCdpClient(cdp.client);
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
const result = await requestRuntimeStorage(ctx, request);
|
|
1905
|
+
return createToolResponse(result);
|
|
1906
|
+
}
|
|
1907
|
+
async function requestRuntimeStorage(ctx, request) {
|
|
1908
|
+
return requestRuntimeData(ctx, (event) => {
|
|
1909
|
+
void ctx.rpcServer?.manageStorage({
|
|
1910
|
+
...request,
|
|
1911
|
+
event
|
|
1912
|
+
});
|
|
1913
|
+
});
|
|
1914
|
+
}
|
|
1915
|
+
async function listCookiesIfCdpAvailable(ctx, request, pageId) {
|
|
1916
|
+
if (!hasCdpConfig2(ctx)) {
|
|
1917
|
+
return extractStorageData(
|
|
1918
|
+
await requestRuntimeStorage(ctx, { ...request, scope: "cookie" })
|
|
1919
|
+
);
|
|
1920
|
+
}
|
|
1921
|
+
const cdp = await connectCdpForPage(ctx, pageId);
|
|
1922
|
+
if (!cdp) {
|
|
1923
|
+
return extractStorageData(
|
|
1924
|
+
await requestRuntimeStorage(ctx, { ...request, scope: "cookie" })
|
|
1925
|
+
);
|
|
1926
|
+
}
|
|
1927
|
+
try {
|
|
1928
|
+
const result = await createCdpStorageAdapter(cdp.client).manageStorage({
|
|
1929
|
+
...request,
|
|
1930
|
+
scope: "cookie"
|
|
1931
|
+
});
|
|
1932
|
+
return extractStorageData(result);
|
|
1933
|
+
} finally {
|
|
1934
|
+
await closeCdpClient(cdp.client);
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
function extractStorageData(result) {
|
|
1938
|
+
if (!isStorageResultRecord(result)) {
|
|
1939
|
+
return result;
|
|
1940
|
+
}
|
|
1941
|
+
return result.data ?? result;
|
|
1942
|
+
}
|
|
1943
|
+
function isStorageResultRecord(value) {
|
|
1944
|
+
return typeof value === "object" && value !== null && "ok" in value;
|
|
1945
|
+
}
|
|
1946
|
+
function shouldUseCdpStorage(request) {
|
|
1947
|
+
return request.scope === "cookie";
|
|
1948
|
+
}
|
|
1949
|
+
function createStorageRequest(ctx, input) {
|
|
1950
|
+
const page = resolvePageTarget(ctx, input.pageId);
|
|
1951
|
+
const origin = new URL(page.url).origin;
|
|
1952
|
+
return {
|
|
1953
|
+
event: "",
|
|
1954
|
+
pageId: page.pageId,
|
|
1955
|
+
origin,
|
|
1956
|
+
action: input.action,
|
|
1957
|
+
scope: normalizeScope(input.scope),
|
|
1958
|
+
key: input.key,
|
|
1959
|
+
value: input.value,
|
|
1960
|
+
databaseName: input.databaseName,
|
|
1961
|
+
objectStoreName: input.objectStoreName,
|
|
1962
|
+
indexName: input.indexName,
|
|
1963
|
+
cookie: input.cookie
|
|
1964
|
+
};
|
|
1965
|
+
}
|
|
1966
|
+
function normalizeScope(scope) {
|
|
1967
|
+
return scope ?? "localStorage";
|
|
1968
|
+
}
|
|
1969
|
+
function hasCdpConfig2(ctx) {
|
|
1970
|
+
return Boolean(ctx.options.cdp.browserUrl || ctx.options.cdp.wsEndpoint);
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
// src/mcp/tools/screenshot.ts
|
|
1974
|
+
var import_zod8 = require("zod");
|
|
1975
|
+
|
|
1549
1976
|
// src/cdp/cdpScreenshot.ts
|
|
1550
1977
|
async function cdpCaptureScreenshot(options) {
|
|
1551
1978
|
if (options.target === "element") {
|
|
@@ -1704,14 +2131,14 @@ function createProjectRelativePath(ctx, filePath) {
|
|
|
1704
2131
|
var DEFAULT_SCREENSHOT_TARGET = "viewport";
|
|
1705
2132
|
var DEFAULT_SCREENSHOT_FORMAT = "png";
|
|
1706
2133
|
var screenshotInputSchema = {
|
|
1707
|
-
pageId:
|
|
1708
|
-
target:
|
|
1709
|
-
selector:
|
|
1710
|
-
format:
|
|
1711
|
-
prefer:
|
|
1712
|
-
quality:
|
|
1713
|
-
scale:
|
|
1714
|
-
snapdom:
|
|
2134
|
+
pageId: import_zod8.z.string().optional(),
|
|
2135
|
+
target: import_zod8.z.enum(["viewport", "fullPage", "element"]).optional(),
|
|
2136
|
+
selector: import_zod8.z.string().optional(),
|
|
2137
|
+
format: import_zod8.z.enum(["png", "jpeg", "webp"]).optional(),
|
|
2138
|
+
prefer: import_zod8.z.enum(["auto", "cdp", "runtime"]).optional(),
|
|
2139
|
+
quality: import_zod8.z.number().optional(),
|
|
2140
|
+
scale: import_zod8.z.number().optional(),
|
|
2141
|
+
snapdom: import_zod8.z.record(import_zod8.z.string(), import_zod8.z.unknown()).optional()
|
|
1715
2142
|
};
|
|
1716
2143
|
function registerScreenshotTools(server, ctx) {
|
|
1717
2144
|
server.registerTool(
|
|
@@ -1831,7 +2258,7 @@ function isScreenshotImagePayload(result) {
|
|
|
1831
2258
|
|
|
1832
2259
|
// src/mcp/tools/vue.ts
|
|
1833
2260
|
var import_nanoid3 = require("nanoid");
|
|
1834
|
-
var
|
|
2261
|
+
var import_zod9 = require("zod");
|
|
1835
2262
|
function registerVueTools(server, ctx) {
|
|
1836
2263
|
server.registerTool(
|
|
1837
2264
|
MCP_TOOL_NAMES.getComponentTree,
|
|
@@ -1844,7 +2271,7 @@ function registerVueTools(server, ctx) {
|
|
|
1844
2271
|
MCP_TOOL_NAMES.getComponentState,
|
|
1845
2272
|
{
|
|
1846
2273
|
description: "Get Vue component state.",
|
|
1847
|
-
inputSchema: { componentName:
|
|
2274
|
+
inputSchema: { componentName: import_zod9.z.string() }
|
|
1848
2275
|
},
|
|
1849
2276
|
async ({ componentName }) => requestVueData(ctx, (event) => {
|
|
1850
2277
|
void ctx.rpcServer?.getInspectorState({ event, componentName });
|
|
@@ -1855,10 +2282,10 @@ function registerVueTools(server, ctx) {
|
|
|
1855
2282
|
{
|
|
1856
2283
|
description: "Edit Vue component state.",
|
|
1857
2284
|
inputSchema: {
|
|
1858
|
-
componentName:
|
|
1859
|
-
path:
|
|
1860
|
-
value:
|
|
1861
|
-
valueType:
|
|
2285
|
+
componentName: import_zod9.z.string(),
|
|
2286
|
+
path: import_zod9.z.array(import_zod9.z.string()),
|
|
2287
|
+
value: import_zod9.z.string(),
|
|
2288
|
+
valueType: import_zod9.z.enum(["string", "number", "boolean", "object", "array"])
|
|
1862
2289
|
}
|
|
1863
2290
|
},
|
|
1864
2291
|
({ componentName, path: path8, value, valueType }) => {
|
|
@@ -1878,7 +2305,7 @@ function registerVueTools(server, ctx) {
|
|
|
1878
2305
|
MCP_TOOL_NAMES.highlightComponent,
|
|
1879
2306
|
{
|
|
1880
2307
|
description: "Highlight a Vue component.",
|
|
1881
|
-
inputSchema: { componentName:
|
|
2308
|
+
inputSchema: { componentName: import_zod9.z.string() }
|
|
1882
2309
|
},
|
|
1883
2310
|
({ componentName }) => {
|
|
1884
2311
|
if (!ctx.rpcServer) {
|
|
@@ -1906,7 +2333,7 @@ function registerVueTools(server, ctx) {
|
|
|
1906
2333
|
MCP_TOOL_NAMES.getPiniaState,
|
|
1907
2334
|
{
|
|
1908
2335
|
description: "Get Pinia store state.",
|
|
1909
|
-
inputSchema: { storeName:
|
|
2336
|
+
inputSchema: { storeName: import_zod9.z.string() }
|
|
1910
2337
|
},
|
|
1911
2338
|
async ({ storeName }) => requestVueData(ctx, (event) => {
|
|
1912
2339
|
void ctx.rpcServer?.getPiniaState({ event, storeName });
|
|
@@ -1953,6 +2380,7 @@ function createMcpServer(ctx, vite) {
|
|
|
1953
2380
|
registerConsoleTools(server, ctx);
|
|
1954
2381
|
registerEvaluateTools(server, ctx);
|
|
1955
2382
|
registerNetworkTools(server, ctx);
|
|
2383
|
+
registerStorageTools(server, ctx);
|
|
1956
2384
|
registerPerformanceTools(server, ctx);
|
|
1957
2385
|
registerVueTools(server, ctx);
|
|
1958
2386
|
return server;
|
|
@@ -2041,6 +2469,10 @@ function createServerVueRuntimeRpc(ctx) {
|
|
|
2041
2469
|
onScreenshotTaken: (event, data) => {
|
|
2042
2470
|
void ctx.hooks.callHook(event, data);
|
|
2043
2471
|
},
|
|
2472
|
+
manageStorage: () => void 0,
|
|
2473
|
+
onStorageUpdated: (event, data) => {
|
|
2474
|
+
void ctx.hooks.callHook(event, data);
|
|
2475
|
+
},
|
|
2044
2476
|
recordPerformance: () => void 0,
|
|
2045
2477
|
onPerformanceRecorded: (event, data) => {
|
|
2046
2478
|
void ctx.hooks.callHook(event, data);
|