diff --git a/CLAUDE.md b/CLAUDE.md
index f45e18b9..8843f641 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -312,6 +312,6 @@ The SDK's main entry (`app.d.ts`) uses `export * from "./types"` to re-export al
- Resources discovered from `src/resources/{name}/{name}.tsx`
- Tools discovered from `src/tools/{name}.ts` (each exports `tool: AppToolConfig`, `schema`, optional `outputSchema`, `default` handler)
- Simulations discovered from `tests/simulations/*.json` (flat directory, `"tool"` string field references tool filename)
-- Optional server entry at `src/server.ts` (exports `server: ServerConfig` for identity/icons, `auth()` for request authentication)
+- Optional server entry at `src/server.ts` (exports `server: ServerConfig` for identity/icons/instructions, `auth()` for request authentication). `instructions` is a server-wide string sent in the MCP `initialize` response that hosts may inject into the model's system prompt — for cross-tool workflows and constraints.
- Hook file naming: `use-{kebab-name}.ts` → export `use{PascalName}` (e.g., `use-download-file.ts` → `useDownloadFile`)
- SDK re-exports in `src/index.ts` are organized into five sections: core classes/functions, app options/tool registration/Standard Schema types, method constants, Zod schemas, protocol types
diff --git a/docs/app-framework/tools/production-server.mdx b/docs/app-framework/tools/production-server.mdx
index 6107aa77..fd47bd9f 100644
--- a/docs/app-framework/tools/production-server.mdx
+++ b/docs/app-framework/tools/production-server.mdx
@@ -67,7 +67,7 @@ app.listen(3000);
- Full server identity. Overrides `name` and `version` when provided. Supports additional fields like `title`, `description`, `websiteUrl`, and `icons`.
+ Full server identity. Overrides `name` and `version` when provided. Supports additional fields like `title`, `description`, `websiteUrl`, `icons`, and `instructions` (sent in the MCP `initialize` response so hosts can inject it into the model's system prompt). See [Server Entry](/app-framework/tools/server-entry#server-object-optional) for the full field list.
diff --git a/docs/app-framework/tools/server-entry.mdx b/docs/app-framework/tools/server-entry.mdx
index 800a1e91..f8ea51f9 100644
--- a/docs/app-framework/tools/server-entry.mdx
+++ b/docs/app-framework/tools/server-entry.mdx
@@ -86,6 +86,34 @@ export const server = { name: 'My App', version: '1.0.0' };
Server version.
+
+ Human-readable display name. Shown by hosts when more polish is needed than `name`.
+
+
+
+ Short description of what the server does.
+
+
+
+ URL of the server's homepage.
+
+
+
+ 64x64 PNG icons (data URIs preferred). Light and dark variants supported via the `theme` field on each icon.
+
+
+
+ Server-wide instructions sent in the MCP `initialize` response. Hosts (ChatGPT, Claude) may surface this to the model, typically by injecting it into the system prompt. Use it for guidance that spans multiple tools or describes the server as a whole — e.g., "Always call `get_user` before `update_user`" or "This server is read-only between 5pm and 9am UTC". Per-tool guidance still belongs in each tool's `description`.
+
+ ```ts
+ export const server: ServerConfig = {
+ name: 'My App',
+ version: '1.0.0',
+ instructions: 'Call list_orders before fulfill_order. Refunds require a manager scope.',
+ };
+ ```
+
+
## Using Auth in Tool Handlers
The `authInfo` from the server entry is available in every tool handler:
diff --git a/docs/mcp-apps/mcp/overview.mdx b/docs/mcp-apps/mcp/overview.mdx
index a892cb58..faac769e 100644
--- a/docs/mcp-apps/mcp/overview.mdx
+++ b/docs/mcp-apps/mcp/overview.mdx
@@ -54,7 +54,7 @@ sequenceDiagram
```
1. The client sends `initialize` with its capabilities and preferred protocol version.
-2. The server responds with its own capabilities and the negotiated protocol version.
+2. The server responds with its own capabilities and the negotiated protocol version. The response can also include an optional `instructions` string the host may surface to the model (e.g., as part of the system prompt) to describe cross-tool relationships and constraints.
3. The client sends `notifications/initialized` to confirm the session is ready.
4. Requests flow in both directions for the duration of the session.
diff --git a/examples/albums-example/package.json b/examples/albums-example/package.json
index 3757fd8d..bc3c0b9c 100644
--- a/examples/albums-example/package.json
+++ b/examples/albums-example/package.json
@@ -18,7 +18,7 @@
"clsx": "^2.1.1",
"embla-carousel-react": "^8.6.0",
"embla-carousel-wheel-gestures": "^8.1.0",
- "sunpeak": "^0.20.16",
+ "sunpeak": "^0.20.17",
"tailwind-merge": "^3.5.0",
"zod": "^4.4.3"
},
diff --git a/examples/albums-example/src/server.ts b/examples/albums-example/src/server.ts
index 5ccbf9b8..5f4130c6 100644
--- a/examples/albums-example/src/server.ts
+++ b/examples/albums-example/src/server.ts
@@ -22,10 +22,15 @@ export async function auth(req: IncomingMessage): Promise {
* to embed the icon inline (no external fetch required by the host):
*
* icons: [{ src: 'data:image/png;base64,...', mimeType: 'image/png', sizes: ['64x64'] }]
+ *
+ * `instructions` is a server-wide hint hosts may inject into the model's
+ * system prompt — useful for cross-tool workflows or constraints that
+ * don't fit in any single tool's `description`.
*/
export const server: ServerConfig = {
// name defaults to package.json "name" field when omitted
version: '1.0.0',
description: 'A sunpeak MCP app',
+ // instructions: 'Always call get_user before update_user.',
// icons: [{ src: 'data:image/png;base64,...', mimeType: 'image/png', sizes: ['64x64'] }],
};
diff --git a/examples/carousel-example/package.json b/examples/carousel-example/package.json
index a6801888..60798dd8 100644
--- a/examples/carousel-example/package.json
+++ b/examples/carousel-example/package.json
@@ -18,7 +18,7 @@
"clsx": "^2.1.1",
"embla-carousel-react": "^8.6.0",
"embla-carousel-wheel-gestures": "^8.1.0",
- "sunpeak": "^0.20.16",
+ "sunpeak": "^0.20.17",
"tailwind-merge": "^3.5.0",
"zod": "^4.4.3"
},
diff --git a/examples/carousel-example/src/server.ts b/examples/carousel-example/src/server.ts
index 5ccbf9b8..5f4130c6 100644
--- a/examples/carousel-example/src/server.ts
+++ b/examples/carousel-example/src/server.ts
@@ -22,10 +22,15 @@ export async function auth(req: IncomingMessage): Promise {
* to embed the icon inline (no external fetch required by the host):
*
* icons: [{ src: 'data:image/png;base64,...', mimeType: 'image/png', sizes: ['64x64'] }]
+ *
+ * `instructions` is a server-wide hint hosts may inject into the model's
+ * system prompt — useful for cross-tool workflows or constraints that
+ * don't fit in any single tool's `description`.
*/
export const server: ServerConfig = {
// name defaults to package.json "name" field when omitted
version: '1.0.0',
description: 'A sunpeak MCP app',
+ // instructions: 'Always call get_user before update_user.',
// icons: [{ src: 'data:image/png;base64,...', mimeType: 'image/png', sizes: ['64x64'] }],
};
diff --git a/examples/map-example/package.json b/examples/map-example/package.json
index d12b208c..bc3a8bf2 100644
--- a/examples/map-example/package.json
+++ b/examples/map-example/package.json
@@ -18,7 +18,7 @@
"clsx": "^2.1.1",
"embla-carousel-react": "^8.6.0",
"mapbox-gl": "^3.23.1",
- "sunpeak": "^0.20.16",
+ "sunpeak": "^0.20.17",
"tailwind-merge": "^3.5.0",
"zod": "^4.4.3"
},
diff --git a/examples/map-example/src/server.ts b/examples/map-example/src/server.ts
index 5ccbf9b8..5f4130c6 100644
--- a/examples/map-example/src/server.ts
+++ b/examples/map-example/src/server.ts
@@ -22,10 +22,15 @@ export async function auth(req: IncomingMessage): Promise {
* to embed the icon inline (no external fetch required by the host):
*
* icons: [{ src: 'data:image/png;base64,...', mimeType: 'image/png', sizes: ['64x64'] }]
+ *
+ * `instructions` is a server-wide hint hosts may inject into the model's
+ * system prompt — useful for cross-tool workflows or constraints that
+ * don't fit in any single tool's `description`.
*/
export const server: ServerConfig = {
// name defaults to package.json "name" field when omitted
version: '1.0.0',
description: 'A sunpeak MCP app',
+ // instructions: 'Always call get_user before update_user.',
// icons: [{ src: 'data:image/png;base64,...', mimeType: 'image/png', sizes: ['64x64'] }],
};
diff --git a/examples/review-example/package.json b/examples/review-example/package.json
index 683281c7..dd1944fb 100644
--- a/examples/review-example/package.json
+++ b/examples/review-example/package.json
@@ -16,7 +16,7 @@
},
"dependencies": {
"clsx": "^2.1.1",
- "sunpeak": "^0.20.16",
+ "sunpeak": "^0.20.17",
"tailwind-merge": "^3.5.0",
"zod": "^4.4.3"
},
diff --git a/examples/review-example/src/server.ts b/examples/review-example/src/server.ts
index 5ccbf9b8..5f4130c6 100644
--- a/examples/review-example/src/server.ts
+++ b/examples/review-example/src/server.ts
@@ -22,10 +22,15 @@ export async function auth(req: IncomingMessage): Promise {
* to embed the icon inline (no external fetch required by the host):
*
* icons: [{ src: 'data:image/png;base64,...', mimeType: 'image/png', sizes: ['64x64'] }]
+ *
+ * `instructions` is a server-wide hint hosts may inject into the model's
+ * system prompt — useful for cross-tool workflows or constraints that
+ * don't fit in any single tool's `description`.
*/
export const server: ServerConfig = {
// name defaults to package.json "name" field when omitted
version: '1.0.0',
description: 'A sunpeak MCP app',
+ // instructions: 'Always call get_user before update_user.',
// icons: [{ src: 'data:image/png;base64,...', mimeType: 'image/png', sizes: ['64x64'] }],
};
diff --git a/packages/sunpeak/src/mcp/production-server.ts b/packages/sunpeak/src/mcp/production-server.ts
index 53fbfb0d..3e7bd224 100644
--- a/packages/sunpeak/src/mcp/production-server.ts
+++ b/packages/sunpeak/src/mcp/production-server.ts
@@ -261,7 +261,10 @@ export function createProductionMcpServer(config: ProductionServerConfig): McpSe
},
],
},
- { capabilities: { resources: {}, tools: {} } }
+ {
+ capabilities: { resources: {}, tools: {} },
+ ...(serverInfo?.instructions ? { instructions: serverInfo.instructions } : {}),
+ }
);
// Build resource lookup: resource name → ProductionResource
diff --git a/packages/sunpeak/src/mcp/server.ts b/packages/sunpeak/src/mcp/server.ts
index bea1aece..964f923b 100644
--- a/packages/sunpeak/src/mcp/server.ts
+++ b/packages/sunpeak/src/mcp/server.ts
@@ -290,7 +290,10 @@ function createAppServer(
},
],
},
- { capabilities: { resources: {}, tools: {} } }
+ {
+ capabilities: { resources: {}, tools: {} },
+ ...(serverInfo?.instructions ? { instructions: serverInfo.instructions } : {}),
+ }
);
// Capture the connecting host's clientInfo.name after MCP initialization.
diff --git a/packages/sunpeak/src/mcp/stateless.test.ts b/packages/sunpeak/src/mcp/stateless.test.ts
index 104b9b8b..82f5b882 100644
--- a/packages/sunpeak/src/mcp/stateless.test.ts
+++ b/packages/sunpeak/src/mcp/stateless.test.ts
@@ -159,6 +159,33 @@ describe('createHandler stateless mode', () => {
});
});
+describe('serverInfo.instructions', () => {
+ it('includes instructions in initialize result when set', async () => {
+ const text = 'Always call get_user before update_user.';
+ const handler = createHandler({
+ ...baseWebConfig,
+ serverInfo: { name: 'test', version: '1.0.0', instructions: text },
+ });
+ const res = await handler(makePostRequest(initializeBody()));
+ expect(res.status).toBe(200);
+
+ const body = await res.json();
+ expect(body.result?.instructions).toBe(text);
+ });
+
+ it('omits instructions from initialize result when unset', async () => {
+ const handler = createHandler({
+ ...baseWebConfig,
+ serverInfo: { name: 'test', version: '1.0.0' },
+ });
+ const res = await handler(makePostRequest(initializeBody()));
+ expect(res.status).toBe(200);
+
+ const body = await res.json();
+ expect(body.result?.instructions).toBeUndefined();
+ });
+});
+
describe('createHandler stateful mode (default)', () => {
it('returns 404 for unknown session ID', async () => {
const handler = createHandler({ ...baseWebConfig, stateless: false });
diff --git a/packages/sunpeak/src/mcp/types.ts b/packages/sunpeak/src/mcp/types.ts
index ee9d2541..3b4435a4 100644
--- a/packages/sunpeak/src/mcp/types.ts
+++ b/packages/sunpeak/src/mcp/types.ts
@@ -24,12 +24,17 @@ export type { AuthInfo } from '@modelcontextprotocol/sdk/server/auth/types.js';
*
* If omitted, a default sunpeak icon is used.
*
+ * `instructions` is sent in the MCP initialize response. Hosts may inject it
+ * into the model's system prompt to teach cross-tool relationships, workflow
+ * patterns, and constraints that don't fit in per-tool descriptions.
+ *
* @example
* ```ts
* export const server: ServerConfig = {
* name: 'my-app',
* version: '1.0.0',
* description: 'My MCP app',
+ * instructions: 'Always call get_user before update_user. Read-only after 5pm UTC.',
* icons: [
* { src: 'data:image/png;base64,...', mimeType: 'image/png', sizes: ['64x64'] },
* { src: 'data:image/png;base64,...', mimeType: 'image/png', sizes: ['64x64'], theme: 'dark' },
@@ -37,7 +42,22 @@ export type { AuthInfo } from '@modelcontextprotocol/sdk/server/auth/types.js';
* };
* ```
*/
-export type ServerConfig = Partial;
+export type ServerConfig = Partial & {
+ /**
+ * Server-wide instructions sent in the MCP initialize response.
+ *
+ * Hosts (ChatGPT, Claude) may surface this string to the model, typically
+ * by injecting it into the system prompt. Use it for guidance that spans
+ * multiple tools or describes the server as a whole, e.g.:
+ *
+ * - "Always call `get_user` before `update_user`"
+ * - "This server is read-only between 5pm and 9am UTC"
+ * - "Prefer `search_albums` over listing all albums for queries with a name"
+ *
+ * Per-tool guidance still belongs in each tool's `description`.
+ */
+ instructions?: string;
+};
/**
* Extra context passed to tool handlers as the second argument.
diff --git a/packages/sunpeak/template/src/server.ts b/packages/sunpeak/template/src/server.ts
index 5ccbf9b8..5f4130c6 100644
--- a/packages/sunpeak/template/src/server.ts
+++ b/packages/sunpeak/template/src/server.ts
@@ -22,10 +22,15 @@ export async function auth(req: IncomingMessage): Promise {
* to embed the icon inline (no external fetch required by the host):
*
* icons: [{ src: 'data:image/png;base64,...', mimeType: 'image/png', sizes: ['64x64'] }]
+ *
+ * `instructions` is a server-wide hint hosts may inject into the model's
+ * system prompt — useful for cross-tool workflows or constraints that
+ * don't fit in any single tool's `description`.
*/
export const server: ServerConfig = {
// name defaults to package.json "name" field when omitted
version: '1.0.0',
description: 'A sunpeak MCP app',
+ // instructions: 'Always call get_user before update_user.',
// icons: [{ src: 'data:image/png;base64,...', mimeType: 'image/png', sizes: ['64x64'] }],
};
diff --git a/skills/create-sunpeak-app/SKILL.md b/skills/create-sunpeak-app/SKILL.md
index 2fa3a64d..a431e723 100644
--- a/skills/create-sunpeak-app/SKILL.md
+++ b/skills/create-sunpeak-app/SKILL.md
@@ -27,7 +27,7 @@ sunpeak-app/
│ │ └── {name}.tsx # Resource component + ResourceConfig export
│ ├── tools/
│ │ └── {name}.ts # Tool metadata, Zod schema, handler
-│ ├── server.ts # Optional server entry (auth, config, icons)
+│ ├── server.ts # Optional server entry (auth, identity, icons, instructions)
│ └── styles/
│ └── globals.css # Tailwind imports
├── tests/