@octavus/docs 3.3.0 → 3.5.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/content/02-server-sdk/02-sessions.md +61 -0
- package/content/02-server-sdk/03-tools.md +8 -7
- package/content/02-server-sdk/09-inline-mcp.md +204 -0
- package/content/04-protocol/13-mcp-servers.md +73 -14
- package/dist/{chunk-WYXUBTV7.js → chunk-VGQQ3XM5.js} +37 -19
- package/dist/chunk-VGQQ3XM5.js.map +1 -0
- package/dist/content.js +1 -1
- package/dist/docs.json +18 -9
- package/dist/index.js +1 -1
- package/dist/search-index.json +1 -1
- package/dist/search.js +1 -1
- package/dist/search.js.map +1 -1
- package/dist/sections.json +18 -9
- package/package.json +1 -1
- package/dist/chunk-WYXUBTV7.js.map +0 -1
|
@@ -75,6 +75,67 @@ console.log({
|
|
|
75
75
|
|
|
76
76
|
> **Note**: Use `getMessages()` for client-facing code. The `get()` method returns internal message format that includes hidden content not intended for end users.
|
|
77
77
|
|
|
78
|
+
## Getting Execution Logs
|
|
79
|
+
|
|
80
|
+
`getLogs()` returns the chronological execution trace for a session - triggers, messages, tool calls, LLM responses, errors, and other events emitted while the agent ran. Useful for debugging, observability, and building custom timeline views.
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
const result = await client.agentSessions.getLogs(sessionId);
|
|
84
|
+
|
|
85
|
+
if (result.status === 'expired') {
|
|
86
|
+
console.log('Session expired:', result.sessionId);
|
|
87
|
+
} else {
|
|
88
|
+
for (const entry of result.entries) {
|
|
89
|
+
console.log(entry.type, entry.timestamp);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Each entry is a typed variant of `ExecutionLogEntry` (a discriminated union) so consumers can narrow on `entry.type`:
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
const result = await client.agentSessions.getLogs(sessionId);
|
|
98
|
+
|
|
99
|
+
if (result.status !== 'expired') {
|
|
100
|
+
const toolCalls = result.entries.filter((e) => e.type === 'tool-call');
|
|
101
|
+
for (const call of toolCalls) {
|
|
102
|
+
// call.toolName, call.toolArguments are typed without optional chaining
|
|
103
|
+
console.log(call.toolName, call.toolArguments);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Excluding Model Request Payloads
|
|
109
|
+
|
|
110
|
+
Model-request entries include the full provider request body and can be large. Pass `excludeModelRequests: true` to skip them:
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
const result = await client.agentSessions.getLogs(sessionId, {
|
|
114
|
+
excludeModelRequests: true,
|
|
115
|
+
});
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Truncation
|
|
119
|
+
|
|
120
|
+
Responses are capped at 1000 entries (most recent). When the log exceeds that cap, the response includes `total` and `truncated` so consumers can detect this:
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
const result = await client.agentSessions.getLogs(sessionId);
|
|
124
|
+
|
|
125
|
+
if (result.status !== 'expired' && result.truncated) {
|
|
126
|
+
console.warn(`Showing latest 1000 of ${result.total} entries`);
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Response Types
|
|
131
|
+
|
|
132
|
+
| Status | Type | Description |
|
|
133
|
+
| --------- | --------------------- | -------------------------------------------------------------------------------------------- |
|
|
134
|
+
| `active` | `ExecutionLogsResult` | `{ sessionId, entries, total?, truncated? }`. `total` and `truncated` are present when known |
|
|
135
|
+
| `expired` | `ExpiredSessionState` | `{ sessionId, agentId, status: 'expired', createdAt }` |
|
|
136
|
+
|
|
137
|
+
> **Forward-compatible types**: `ExecutionLogEntry` may gain new variants over time. Include a `default` case when switching on `entry.type` so unknown variants are handled gracefully.
|
|
138
|
+
|
|
78
139
|
## Attaching to Sessions
|
|
79
140
|
|
|
80
141
|
To trigger actions on a session, you need to attach to it first:
|
|
@@ -9,18 +9,19 @@ Tools extend what agents can do. In Octavus, tools can execute either on your se
|
|
|
9
9
|
|
|
10
10
|
## Server Tools vs Client Tools
|
|
11
11
|
|
|
12
|
-
| Location
|
|
13
|
-
|
|
|
14
|
-
| **Server**
|
|
15
|
-
| **MCP**
|
|
16
|
-
| **
|
|
12
|
+
| Location | Use Case | Registration |
|
|
13
|
+
| -------------- | ------------------------------------------------- | -------------------------------------------------------- |
|
|
14
|
+
| **Server** | Database queries, API calls, sensitive operations | Register handler in `attach()` |
|
|
15
|
+
| **Inline MCP** | Group an integration's tools (GitHub, Salesforce) | [`createInlineMcpServer()`](/docs/server-sdk/inline-mcp) |
|
|
16
|
+
| **Computer** | Browser, filesystem, shell, external services | [`session.setDynamicTools()`](/docs/server-sdk/computer) |
|
|
17
|
+
| **Client** | Browser APIs, interactive UIs, confirmations | No server handler (forwarded to client) |
|
|
17
18
|
|
|
18
19
|
When the Server SDK encounters a tool call:
|
|
19
20
|
|
|
20
|
-
1. **Handler exists** (server or dynamic) → Execute on server, continue automatically
|
|
21
|
+
1. **Handler exists** (server, inline MCP, or dynamic) → Execute on server, continue automatically
|
|
21
22
|
2. **No handler** → Forward to client via `client-tool-request` event
|
|
22
23
|
|
|
23
|
-
MCP
|
|
24
|
+
Inline MCP tools and dynamic tools registered via `session.setDynamicTools()` (e.g., from `@octavus/computer`) work identically to manual handlers from the platform's perspective. See [Inline MCP Servers](/docs/server-sdk/inline-mcp) for namespaced consumer-defined tool groups, and [Computer](/docs/server-sdk/computer) for device-side MCPs.
|
|
24
25
|
|
|
25
26
|
For client-side tool handling, see [Client Tools](/docs/client-sdk/client-tools).
|
|
26
27
|
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Inline MCP Servers
|
|
3
|
+
description: Group an integration's tools into a Zod-typed bundle that runs in your server process.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Inline MCP Servers
|
|
7
|
+
|
|
8
|
+
Inline MCP servers let you group an integration's tools (e.g., GitHub, Salesforce, an internal microservice) into a namespaced bundle with Zod-typed handler arguments. The tools execute in your server process via the same tool-request/continue path as ordinary [server tools](/docs/server-sdk/tools), so authentication and credentials stay in your process.
|
|
9
|
+
|
|
10
|
+
## When to Use
|
|
11
|
+
|
|
12
|
+
Use an inline MCP server when:
|
|
13
|
+
|
|
14
|
+
- You're integrating a third-party API and want a logical grouping (`github__list-prs`, `github__get-issue`).
|
|
15
|
+
- You want type-safe handler arguments instead of casting `args` from `unknown`.
|
|
16
|
+
- You want to evolve the toolset without protocol-yaml round trips - tool names and schemas are sent at runtime.
|
|
17
|
+
- Tool calls need credentials your platform should never see (OAuth tokens, customer API keys).
|
|
18
|
+
|
|
19
|
+
For comparison with the other tool registration paths, see the [tools overview](/docs/server-sdk/tools#server-tools-vs-client-tools).
|
|
20
|
+
|
|
21
|
+
## Protocol Declaration
|
|
22
|
+
|
|
23
|
+
Declare the namespace in `protocol.yaml` with `source: consumer`. The platform learns the namespace and routes tool calls to your process; tool names and JSON schemas are provided by the SDK at runtime.
|
|
24
|
+
|
|
25
|
+
```yaml
|
|
26
|
+
mcpServers:
|
|
27
|
+
github:
|
|
28
|
+
description: Repository management - issues, pull requests, code
|
|
29
|
+
source: consumer
|
|
30
|
+
display: name
|
|
31
|
+
|
|
32
|
+
agent:
|
|
33
|
+
mcpServers:
|
|
34
|
+
- github
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
See [MCP Servers in the protocol reference](/docs/protocol/mcp-servers) for the full set of MCP source types and field semantics.
|
|
38
|
+
|
|
39
|
+
## Defining the Server
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import { z } from 'zod';
|
|
43
|
+
import { createInlineMcpServer, defineInlineMcpTool } from '@octavus/server-sdk';
|
|
44
|
+
|
|
45
|
+
const github = createInlineMcpServer('github', {
|
|
46
|
+
tools: {
|
|
47
|
+
'get-pr-overview': defineInlineMcpTool({
|
|
48
|
+
description: 'Get pull request metadata and file changes',
|
|
49
|
+
parameters: z.object({
|
|
50
|
+
owner: z.string(),
|
|
51
|
+
repo: z.string(),
|
|
52
|
+
pullNumber: z.number(),
|
|
53
|
+
}),
|
|
54
|
+
handler: async (args) => {
|
|
55
|
+
// args is { owner: string; repo: string; pullNumber: number }
|
|
56
|
+
return await githubService.getPrOverview(args.owner, args.repo, args.pullNumber);
|
|
57
|
+
},
|
|
58
|
+
}),
|
|
59
|
+
|
|
60
|
+
'list-issues': defineInlineMcpTool({
|
|
61
|
+
description: 'List open issues for a repository',
|
|
62
|
+
parameters: z.object({
|
|
63
|
+
owner: z.string(),
|
|
64
|
+
repo: z.string(),
|
|
65
|
+
state: z.enum(['open', 'closed', 'all']).default('open'),
|
|
66
|
+
}),
|
|
67
|
+
handler: async (args) => {
|
|
68
|
+
return await githubService.listIssues(args.owner, args.repo, args.state);
|
|
69
|
+
},
|
|
70
|
+
}),
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The factory:
|
|
76
|
+
|
|
77
|
+
1. Validates the namespace and each tool name (see [naming rules](#naming-rules)).
|
|
78
|
+
2. Converts each Zod schema to JSON Schema once at creation time.
|
|
79
|
+
3. Returns an `InlineMcpServer` exposing `toolSchemas()` and `toolHandlers()`.
|
|
80
|
+
|
|
81
|
+
The resulting tool names are namespaced: `github__get-pr-overview`, `github__list-issues`.
|
|
82
|
+
|
|
83
|
+
## Why `defineInlineMcpTool`
|
|
84
|
+
|
|
85
|
+
`defineInlineMcpTool()` is a no-op at runtime, but it preserves Zod type inference. Without the wrapper, TypeScript collapses the per-tool generic when the tools are placed in a record literal, leaving `args` typed as `unknown`:
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
// Without defineInlineMcpTool - args ends up as `unknown`
|
|
89
|
+
tools: {
|
|
90
|
+
'get-pr-overview': {
|
|
91
|
+
description: '...',
|
|
92
|
+
parameters: z.object({ owner: z.string() }),
|
|
93
|
+
handler: async (args) => args.owner, // ❌ TS error: args is 'unknown'
|
|
94
|
+
},
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// With defineInlineMcpTool - args inferred from the schema
|
|
98
|
+
tools: {
|
|
99
|
+
'get-pr-overview': defineInlineMcpTool({
|
|
100
|
+
description: '...',
|
|
101
|
+
parameters: z.object({ owner: z.string() }),
|
|
102
|
+
handler: async (args) => args.owner, // ✓ args is { owner: string }
|
|
103
|
+
}),
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The handler also receives Zod-validated arguments. Invalid inputs throw before reaching your code, with the failed paths and messages joined into the error.
|
|
108
|
+
|
|
109
|
+
## Attaching to a Session
|
|
110
|
+
|
|
111
|
+
Pass inline MCP servers via `mcpServers` on `attach()`. They merge with `tools` and survive across `setDynamicTools()` calls:
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
const session = client.agentSessions.attach(sessionId, {
|
|
115
|
+
tools: {
|
|
116
|
+
'get-user-account': async (args) => db.users.findById(args.userId as string),
|
|
117
|
+
},
|
|
118
|
+
mcpServers: [github, salesforce],
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Workers accept the same option:
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
const { output } = await client.workers.generate(agentId, input, {
|
|
126
|
+
mcpServers: [github],
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Authentication and Credentials
|
|
131
|
+
|
|
132
|
+
Handlers close over your server's auth context, so credentials never leave your process. The platform receives the namespaced schema list and the tool call name; it never sees the keys you use to fulfill the call.
|
|
133
|
+
|
|
134
|
+
A common pattern is to build the MCP server per-request when auth depends on the user:
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
function buildGithubMcp(token: string) {
|
|
138
|
+
const client = new GithubClient({ token });
|
|
139
|
+
return createInlineMcpServer('github', {
|
|
140
|
+
tools: {
|
|
141
|
+
'get-pr-overview': defineInlineMcpTool({
|
|
142
|
+
description: 'Get pull request metadata and file changes',
|
|
143
|
+
parameters: z.object({
|
|
144
|
+
owner: z.string(),
|
|
145
|
+
repo: z.string(),
|
|
146
|
+
pullNumber: z.number(),
|
|
147
|
+
}),
|
|
148
|
+
handler: async (args) => client.pulls.get(args),
|
|
149
|
+
}),
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export async function POST(request: Request) {
|
|
155
|
+
const user = await authenticate(request);
|
|
156
|
+
const session = client.agentSessions.attach(sessionId, {
|
|
157
|
+
mcpServers: [buildGithubMcp(user.githubToken)],
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
const events = session.execute(payload, { signal: request.signal });
|
|
161
|
+
return new Response(toSSEStream(events));
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
For static credentials (one tenant per deployment), build the server once at module scope.
|
|
166
|
+
|
|
167
|
+
## How Tool Calls Flow
|
|
168
|
+
|
|
169
|
+
1. The agent emits a `tool-request` event for `github__get-pr-overview` (or another inline-MCP-namespaced tool).
|
|
170
|
+
2. The Server SDK looks up the handler registered by `createInlineMcpServer()` and runs it. Zod validates `args` against the tool's schema; a validation failure becomes a tool error sent back to the LLM.
|
|
171
|
+
3. The handler returns; the SDK posts the result back to the platform via the same continuation request used for ordinary server tools.
|
|
172
|
+
4. The platform feeds the result to the LLM and streams the next response chunk.
|
|
173
|
+
|
|
174
|
+
There is no separate transport - inline MCP tools ride on the same `dynamicToolSchemas` channel that device MCPs use, so no additional infrastructure is required.
|
|
175
|
+
|
|
176
|
+
## Naming Rules
|
|
177
|
+
|
|
178
|
+
`createInlineMcpServer()` validates the namespace and each tool name at construction time. Invalid values throw immediately:
|
|
179
|
+
|
|
180
|
+
- **Namespace:** lowercase letters, digits, and hyphens; must start with a letter (`/^[a-z][a-z0-9-]*$/`).
|
|
181
|
+
- **Tool name:** lowercase letters, digits, underscores, and hyphens; must start with a letter (`/^[a-z][a-z0-9_-]*$/`).
|
|
182
|
+
|
|
183
|
+
The resulting `${namespace}__${toolName}` is what the LLM sees and what flows through the platform's MCP routing.
|
|
184
|
+
|
|
185
|
+
## Collision Rules
|
|
186
|
+
|
|
187
|
+
The resolver throws on the following conflicts so problems surface at attach time, not mid-stream:
|
|
188
|
+
|
|
189
|
+
- Each inline MCP server's `namespace` must be unique across the array passed to `attach()` or the workers API.
|
|
190
|
+
- A namespaced tool name (`namespace__tool`) cannot collide with a static tool handler key passed via `tools`.
|
|
191
|
+
- A namespaced tool name cannot collide with a `dynamicToolSchemas` entry passed to the workers API.
|
|
192
|
+
|
|
193
|
+
If a tool registered via `setDynamicTools()` later collides with an inline MCP tool name, the dynamic handler wins for the duration of that dynamic-tool set; the inline MCP handler is restored on the next `setDynamicTools()` call that doesn't re-register the same name.
|
|
194
|
+
|
|
195
|
+
## Inline vs Computer
|
|
196
|
+
|
|
197
|
+
Both inline MCP and the `Computer` integration register tools that flow through `dynamicToolSchemas`. Pick based on where the tool process runs:
|
|
198
|
+
|
|
199
|
+
| Tool surface | Process location | Best for |
|
|
200
|
+
| ------------ | -------------------------------- | ------------------------------------------------------------------------------------------------------------- |
|
|
201
|
+
| Inline MCP | Your server (in-process closure) | Third-party APIs, internal microservices, anything where credentials live in your backend. |
|
|
202
|
+
| Computer | The agent's machine (STDIO MCP) | Browser automation, filesystem, shell - device-local capabilities. See [Computer](/docs/server-sdk/computer). |
|
|
203
|
+
|
|
204
|
+
The two can coexist on the same session.
|
|
@@ -7,12 +7,13 @@ description: Connecting agents to external tools via Model Context Protocol (MCP
|
|
|
7
7
|
|
|
8
8
|
MCP servers extend your agent with tools from external services. Define them in your protocol, and agents automatically discover and use their tools at runtime.
|
|
9
9
|
|
|
10
|
-
There are
|
|
10
|
+
There are three types of MCP servers:
|
|
11
11
|
|
|
12
|
-
| Source
|
|
13
|
-
|
|
|
14
|
-
| `remote`
|
|
15
|
-
| `device`
|
|
12
|
+
| Source | Description | Example |
|
|
13
|
+
| ---------- | ----------------------------------------------------------------------------------- | ------------------------------------- |
|
|
14
|
+
| `remote` | HTTP-based MCP servers, managed by the platform | Figma, Sentry, GitHub |
|
|
15
|
+
| `device` | Local MCP servers running on the agent's machine via `@octavus/computer` | Browser automation, filesystem |
|
|
16
|
+
| `consumer` | Inline MCP servers defined in your server-sdk process via `createInlineMcpServer()` | Custom integrations, third-party APIs |
|
|
16
17
|
|
|
17
18
|
## Defining MCP Servers
|
|
18
19
|
|
|
@@ -29,17 +30,22 @@ mcpServers:
|
|
|
29
30
|
description: Chrome DevTools browser automation
|
|
30
31
|
source: device
|
|
31
32
|
display: name
|
|
33
|
+
|
|
34
|
+
github:
|
|
35
|
+
description: Repository management - issues, pull requests, code
|
|
36
|
+
source: consumer
|
|
37
|
+
display: name
|
|
32
38
|
```
|
|
33
39
|
|
|
34
40
|
### Fields
|
|
35
41
|
|
|
36
|
-
| Field | Required | Description
|
|
37
|
-
| ------------- | -------- |
|
|
38
|
-
| `description` | Yes | What the MCP server provides
|
|
39
|
-
| `source` | Yes | `remote`
|
|
40
|
-
| `display` | No | How tool calls appear in UI: `hidden`, `name`, `description` (default: `description`)
|
|
41
|
-
| `connection` | No | When to connect: `eager` or `lazy` (default: `lazy`).
|
|
42
|
-
| `execution` | No | Where the MCP process runs: `sandbox` (default) or `device`. See [Device Execution](#device-execution). |
|
|
42
|
+
| Field | Required | Description |
|
|
43
|
+
| ------------- | -------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
44
|
+
| `description` | Yes | What the MCP server provides |
|
|
45
|
+
| `source` | Yes | `remote`, `device`, or `consumer` (see source types above) |
|
|
46
|
+
| `display` | No | How tool calls appear in UI: `hidden`, `name`, `description` (default: `description`) |
|
|
47
|
+
| `connection` | No | When to connect: `eager` or `lazy` (default: `lazy`). `remote` only. |
|
|
48
|
+
| `execution` | No | Where the MCP process runs: `sandbox` (default) or `device`. `remote` only. See [Device Execution](#device-execution). |
|
|
43
49
|
|
|
44
50
|
### Display Modes
|
|
45
51
|
|
|
@@ -122,9 +128,13 @@ Device MCP tools (auto-discovered):
|
|
|
122
128
|
filesystem__read_file
|
|
123
129
|
filesystem__write_file
|
|
124
130
|
filesystem__list_directory
|
|
131
|
+
|
|
132
|
+
Consumer MCP tools (provided by the server-sdk):
|
|
133
|
+
github__get-pr-overview
|
|
134
|
+
github__list-issues
|
|
125
135
|
```
|
|
126
136
|
|
|
127
|
-
You don't define individual MCP tool schemas in the protocol -
|
|
137
|
+
You don't define individual MCP tool schemas in the protocol - remote and device tools are auto-discovered from each MCP server at runtime, and consumer tools are supplied by the server-sdk.
|
|
128
138
|
|
|
129
139
|
## Remote MCP Servers
|
|
130
140
|
|
|
@@ -203,7 +213,7 @@ Use `execution: device` when the MCP server needs access to the agent's local en
|
|
|
203
213
|
### Rules
|
|
204
214
|
|
|
205
215
|
- `execution` is only meaningful for `source: remote` MCPs that use STDIO transport. HTTP-transport remote MCPs always connect from the platform regardless of the `execution` setting.
|
|
206
|
-
- `execution
|
|
216
|
+
- `execution` is **invalid** on `source: device` and `source: consumer` MCPs - they already run outside the platform. Using it produces a validation error.
|
|
207
217
|
- The `connection` field (`eager` or `lazy`) is respected for device-executed MCPs the same way as sandbox-executed MCPs.
|
|
208
218
|
|
|
209
219
|
## Device MCP Servers
|
|
@@ -243,6 +253,55 @@ const computer = new Computer({
|
|
|
243
253
|
|
|
244
254
|
If the consumer provides a namespace not declared in the protocol, the platform rejects it.
|
|
245
255
|
|
|
256
|
+
## Consumer MCP Servers
|
|
257
|
+
|
|
258
|
+
Consumer MCP servers (`source: consumer`) are defined inline in your server-sdk process. Tool schemas and handlers live in your code; the platform learns the namespace from the protocol and routes tool calls to your process via the same `dynamicToolSchemas` channel that device MCPs use.
|
|
259
|
+
|
|
260
|
+
```yaml
|
|
261
|
+
mcpServers:
|
|
262
|
+
github:
|
|
263
|
+
description: Repository management - issues, pull requests, code
|
|
264
|
+
source: consumer
|
|
265
|
+
display: name
|
|
266
|
+
|
|
267
|
+
agent:
|
|
268
|
+
mcpServers:
|
|
269
|
+
- github
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
The protocol declaration is intentionally minimal - the SDK supplies tool names and JSON schemas at runtime, so adding or evolving tools doesn't require a protocol change.
|
|
273
|
+
|
|
274
|
+
Use consumer MCPs when:
|
|
275
|
+
|
|
276
|
+
- The integration's credentials should never reach the platform (OAuth tokens, customer API keys).
|
|
277
|
+
- You want to group an integration's tools (`github__list-prs`, `github__get-issue`) without enumerating each one in YAML.
|
|
278
|
+
- You want type-safe handler arguments via Zod schemas.
|
|
279
|
+
|
|
280
|
+
See [`createInlineMcpServer`](/docs/server-sdk/inline-mcp) in the server-sdk reference for the full implementation guide.
|
|
281
|
+
|
|
282
|
+
### Namespace Matching
|
|
283
|
+
|
|
284
|
+
The protocol namespace must match the namespace passed to `createInlineMcpServer()`:
|
|
285
|
+
|
|
286
|
+
```yaml
|
|
287
|
+
# protocol.yaml
|
|
288
|
+
mcpServers:
|
|
289
|
+
github: # ← must match
|
|
290
|
+
source: consumer
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
const github = createInlineMcpServer('github', {
|
|
295
|
+
/* tools... */
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
session = client.agentSessions.attach(sessionId, {
|
|
299
|
+
mcpServers: [github],
|
|
300
|
+
});
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
If the SDK provides a namespace not declared in the protocol, those tools are filtered out at the runtime boundary and the LLM never sees them.
|
|
304
|
+
|
|
246
305
|
## Thread-Level Scoping
|
|
247
306
|
|
|
248
307
|
Threads can scope which MCP servers are available, the same way they scope [tools](/docs/protocol/handlers#start-thread):
|