-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmcp.ts
More file actions
87 lines (81 loc) · 3.19 KB
/
Copy pathmcp.ts
File metadata and controls
87 lines (81 loc) · 3.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import type { AppToolContext } from './types'
import type { AppToolName } from './openai'
import type { ToolHeaderNames } from './auth'
import { DEFAULT_HEADER_NAMES } from './auth'
/** Default route path each app tool is served at. A product mounts its routes
* at these paths (or supplies its own via {@link BuildMcpServerOptions.paths}). */
export const DEFAULT_APP_TOOL_PATHS: Record<AppToolName, string> = {
submit_proposal: '/api/tools/propose',
schedule_followup: '/api/tools/followup',
render_ui: '/api/tools/render-ui',
add_citation: '/api/tools/citation',
}
/** The portable MCP server entry the sandbox SDK accepts (transport + url +
* headers). Matches `AgentProfileMcpServer` structurally without importing the
* sandbox SDK — products spread it into their profile's `mcp` map. */
export interface AppToolMcpServer {
transport: 'http'
url: string
headers: Record<string, string>
enabled: true
metadata: { description: string }
}
export interface BuildHttpMcpServerOptions {
/** Route path on the app the sandbox POSTs to (e.g. `/api/tools/propose`). */
path: string
/** App base URL the sandbox reaches back to (no trailing slash required). */
baseUrl: string
/** Per-user capability token, baked into the Authorization header. */
token: string
ctx: AppToolContext
/** Tool description the model sees. */
description: string
headerNames?: ToolHeaderNames
}
/**
* Build ONE HTTP MCP server entry — the generic agent→app bridge. The
* capability token + the user/workspace/thread ids ride in server-set headers
* (never tool args), so the model can't forge identity or target another
* workspace. Workspace/thread headers are omitted when their `ctx` value is
* empty/null (e.g. an integration-invoke bridge that's user-scoped only). Used
* directly for non-app-tool bridges (integration_invoke) and via
* {@link buildAppToolMcpServer} for the four app tools.
*/
export function buildHttpMcpServer(opts: BuildHttpMcpServerOptions): AppToolMcpServer {
const base = opts.baseUrl.replace(/\/+$/, '')
const h = opts.headerNames ?? DEFAULT_HEADER_NAMES
return {
transport: 'http',
url: `${base}${opts.path}`,
headers: {
Authorization: `Bearer ${opts.token}`,
[h.userId]: opts.ctx.userId,
...(opts.ctx.workspaceId ? { [h.workspaceId]: opts.ctx.workspaceId } : {}),
...(opts.ctx.threadId ? { [h.threadId]: opts.ctx.threadId } : {}),
'Content-Type': 'application/json',
},
enabled: true,
metadata: { description: opts.description },
}
}
export interface BuildMcpServerOptions {
tool: AppToolName
baseUrl: string
token: string
ctx: AppToolContext
description: string
headerNames?: ToolHeaderNames
paths?: Partial<Record<AppToolName, string>>
}
/** Build one of the four app-tool MCP servers — a thin wrapper over
* {@link buildHttpMcpServer} that maps the tool name to its route path. */
export function buildAppToolMcpServer(opts: BuildMcpServerOptions): AppToolMcpServer {
return buildHttpMcpServer({
path: opts.paths?.[opts.tool] ?? DEFAULT_APP_TOOL_PATHS[opts.tool],
baseUrl: opts.baseUrl,
token: opts.token,
ctx: opts.ctx,
description: opts.description,
headerNames: opts.headerNames,
})
}