diff --git a/docs/kit/rpc.md b/docs/kit/rpc.md
index 0c384547..0322a398 100644
--- a/docs/kit/rpc.md
+++ b/docs/kit/rpc.md
@@ -393,6 +393,22 @@ export default function setup(ctx: DockClientScriptContext) {
}
```
+### Global Client Context
+
+Use `getDevToolsClientContext()` to access the client context (`DevToolsClientContext`) from anywhere on the client side. This is set automatically when DevTools initializes in embedded or standalone mode.
+
+```ts
+import { getDevToolsClientContext } from '@vitejs/devtools-kit/client'
+
+const ctx = getDevToolsClientContext()
+if (ctx) {
+ const modules = await ctx.rpc.call('my-plugin:get-modules')
+}
+```
+
+Returns `undefined` if the context has not been initialized yet.
+```
+
## Client-Side Functions
You can also define functions on the client that the server can call.
diff --git a/docs/kit/shared-state.md b/docs/kit/shared-state.md
index f6b8e597..df709574 100644
--- a/docs/kit/shared-state.md
+++ b/docs/kit/shared-state.md
@@ -118,6 +118,17 @@ const state = await client.sharedState.get('my-plugin:state')
console.log(state.value())
```
+You can also access shared state through the global client context:
+
+```ts
+import { getDevToolsClientContext } from '@vitejs/devtools-kit/client'
+
+const ctx = getDevToolsClientContext()
+if (ctx) {
+ const state = await ctx.rpc.sharedState.get('my-plugin:state')
+}
+```
+
### Subscribing to Changes
Use `state.on('updated', ...)` to react to state changes:
diff --git a/packages/core/src/client/inject/index.ts b/packages/core/src/client/inject/index.ts
index 61977014..a1a90969 100644
--- a/packages/core/src/client/inject/index.ts
+++ b/packages/core/src/client/inject/index.ts
@@ -2,7 +2,7 @@
///
import type { DockPanelStorage } from '@vitejs/devtools-kit/client'
-import { getDevToolsRpcClient } from '@vitejs/devtools-kit/client'
+import { CLIENT_CONTEXT_KEY, getDevToolsRpcClient } from '@vitejs/devtools-kit/client'
import { useLocalStorage } from '@vueuse/core'
import { createDocksContext } from '../webcomponents/state/context'
@@ -31,6 +31,7 @@ export async function init(): Promise {
rpc,
state,
)
+ ;(globalThis as any)[CLIENT_CONTEXT_KEY] = context
const { DockEmbedded } = import.meta.env.VITE_DEVTOOLS_LOCAL_DEV
? await import('../webcomponents')
diff --git a/packages/core/src/client/standalone/App.vue b/packages/core/src/client/standalone/App.vue
index d97770ea..2ad3e22f 100644
--- a/packages/core/src/client/standalone/App.vue
+++ b/packages/core/src/client/standalone/App.vue
@@ -1,6 +1,6 @@
diff --git a/packages/kit/src/client/context.ts b/packages/kit/src/client/context.ts
new file mode 100644
index 00000000..2aad9126
--- /dev/null
+++ b/packages/kit/src/client/context.ts
@@ -0,0 +1,12 @@
+import type { DevToolsClientContext } from './docks'
+
+const CLIENT_CONTEXT_KEY = '__VITE_DEVTOOLS_CLIENT_CONTEXT__'
+
+/**
+ * Get the global DevTools client context, or `undefined` if not yet initialized.
+ */
+export function getDevToolsClientContext(): DevToolsClientContext | undefined {
+ return (globalThis as any)[CLIENT_CONTEXT_KEY]
+}
+
+export { CLIENT_CONTEXT_KEY }
diff --git a/packages/kit/src/client/index.ts b/packages/kit/src/client/index.ts
index 120e6176..676f6fdc 100644
--- a/packages/kit/src/client/index.ts
+++ b/packages/kit/src/client/index.ts
@@ -1,3 +1,4 @@
export * from './client-script'
+export * from './context'
export * from './docks'
export * from './rpc'
diff --git a/skills/vite-devtools-kit/SKILL.md b/skills/vite-devtools-kit/SKILL.md
index 3d856898..73c5d5e6 100644
--- a/skills/vite-devtools-kit/SKILL.md
+++ b/skills/vite-devtools-kit/SKILL.md
@@ -360,6 +360,19 @@ export default function setup(ctx: DevToolsClientScriptContext) {
}
```
+## Client Context
+
+The global client context (`DevToolsClientContext`) provides access to the RPC client and is set automatically when DevTools initializes (embedded or standalone). Use `getDevToolsClientContext()` to access it from anywhere on the client side:
+
+```ts
+import { getDevToolsClientContext } from '@vitejs/devtools-kit/client'
+
+const ctx = getDevToolsClientContext()
+if (ctx) {
+ const modules = await ctx.rpc.call('my-plugin:get-modules')
+}
+```
+
### Broadcasting to Clients
```ts
diff --git a/skills/vite-devtools-kit/references/project-structure.md b/skills/vite-devtools-kit/references/project-structure.md
index 4aa23447..efd717b7 100644
--- a/skills/vite-devtools-kit/references/project-structure.md
+++ b/skills/vite-devtools-kit/references/project-structure.md
@@ -187,6 +187,15 @@ export function useRpc() {
}
```
+Alternatively, use `getDevToolsClientContext()` to access the global client context synchronously (returns `undefined` if not yet initialized):
+
+```ts
+import { getDevToolsClientContext } from '@vitejs/devtools-kit/client'
+
+const ctx = getDevToolsClientContext()
+// ctx?.rpc is the DevToolsRpcClient
+```
+
## Client App Component (src/client/App.vue)
```vue
diff --git a/skills/vite-devtools-kit/references/rpc-patterns.md b/skills/vite-devtools-kit/references/rpc-patterns.md
index bfce7cee..55a7e0b8 100644
--- a/skills/vite-devtools-kit/references/rpc-patterns.md
+++ b/skills/vite-devtools-kit/references/rpc-patterns.md
@@ -119,6 +119,21 @@ ctx.rpc.broadcast({
})
```
+## Global Client Context
+
+Use `getDevToolsClientContext()` to access the client context (`DevToolsClientContext`) globally. Returns `undefined` if the context has not been initialized yet.
+
+```ts
+import { getDevToolsClientContext } from '@vitejs/devtools-kit/client'
+
+const ctx = getDevToolsClientContext()
+if (ctx) {
+ await ctx.rpc.call('my-plugin:get-modules')
+}
+```
+
+This is set automatically when DevTools initializes in embedded or standalone mode. For iframe pages, `getDevToolsRpcClient()` is still the recommended way to get the RPC client directly.
+
## Client Function Registration
```ts
diff --git a/skills/vite-devtools-kit/references/shared-state-patterns.md b/skills/vite-devtools-kit/references/shared-state-patterns.md
index 32e8a301..bc16730f 100644
--- a/skills/vite-devtools-kit/references/shared-state-patterns.md
+++ b/skills/vite-devtools-kit/references/shared-state-patterns.md
@@ -33,7 +33,7 @@ state.mutate((draft) => {
import { getDevToolsRpcClient } from '@vitejs/devtools-kit/client'
const client = await getDevToolsRpcClient()
-const state = await client.rpc.sharedState.get('my-plugin:state')
+const state = await client.sharedState.get('my-plugin:state')
// Read
console.log(state.value())
@@ -44,6 +44,17 @@ state.on('updated', (newState) => {
})
```
+You can also access shared state through the global client context:
+
+```ts
+import { getDevToolsClientContext } from '@vitejs/devtools-kit/client'
+
+const ctx = getDevToolsClientContext()
+if (ctx) {
+ const state = await ctx.rpc.sharedState.get('my-plugin:state')
+}
+```
+
## Type-Safe Shared State
```ts
diff --git a/test/exports/@vitejs/devtools-kit.yaml b/test/exports/@vitejs/devtools-kit.yaml
index 1fb0a1db..afd10693 100644
--- a/test/exports/@vitejs/devtools-kit.yaml
+++ b/test/exports/@vitejs/devtools-kit.yaml
@@ -2,6 +2,8 @@
defineJsonRenderSpec: function
defineRpcFunction: function
./client:
+ CLIENT_CONTEXT_KEY: string
+ getDevToolsClientContext: function
getDevToolsRpcClient: function
./constants:
DEFAULT_CATEGORIES_ORDER: object