MCPcopy Create free account
hub / github.com/UsefulSoftwareCo/executor / createMcpRequestHandler

Function createMcpRequestHandler

apps/local/src/mcp.ts:125–299  ·  view source on GitHub ↗
(
  input: ExecutorMcpServerConfig | LocalMcpRequestHandlerConfig,
)

Source from the content-addressed store, hash-verified

123): LocalMcpRequestHandlerConfig => ("defaultConfig" in input ? input : { defaultConfig: input });
124
125export const createMcpRequestHandler = (
126 input: ExecutorMcpServerConfig | LocalMcpRequestHandlerConfig,
127): McpRequestHandler => {
128 const handlerConfig = normalizeHandlerConfig(input);
129 const transports = new Map<string, WebStandardStreamableHTTPServerTransport>();
130 const servers = new Map<string, McpServer>();
131 const resources = new Map<string, McpResource>();
132 const sessionEngines = new Map<string, AnyExecutionEngine>();
133 const sessionClosers = new Map<string, () => Promise<void>>();
134 const approvals = makeInProcessBrowserApprovalStore();
135 const defaultEngine = engineFromConfig(handlerConfig.defaultConfig);
136
137 const pausedDetail = (
138 sessionId: string,
139 executionId: string,
140 ): Promise<ReturnType<typeof formatPausedExecution> | null> =>
141 (sessionEngines.get(sessionId) ?? defaultEngine)
142 ? Effect.runPromise(
143 (sessionEngines.get(sessionId) ?? defaultEngine)!.getPausedExecution(executionId).pipe(
144 Effect.map((paused) => (paused ? formatPausedExecution(paused) : null)),
145 Effect.orElseSucceed(() => null),
146 ),
147 )
148 : Promise.resolve(null);
149
150 const configForResource = async (resource: McpResource): Promise<LocalMcpServerConfig> => {
151 if (!handlerConfig.createConfigForResource) return { config: handlerConfig.defaultConfig };
152 return handlerConfig.createConfigForResource(resource);
153 };
154
155 const dispose = async (id: string, opts: { transport?: boolean; server?: boolean } = {}) => {
156 const t = transports.get(id);
157 const s = servers.get(id);
158 const close = sessionClosers.get(id);
159 transports.delete(id);
160 servers.delete(id);
161 resources.delete(id);
162 sessionEngines.delete(id);
163 sessionClosers.delete(id);
164 if (opts.transport) await ignoreClose(t ? () => t.close() : undefined);
165 if (opts.server) await ignoreClose(s ? () => s.close() : undefined);
166 await ignoreClose(close);
167 };
168
169 return {
170 handleRequest: async (request) => {
171 const resource = resourceFromRequest(request);
172 if (!resource) return jsonError(404, -32001, "MCP resource not found");
173 const sessionId = request.headers.get("mcp-session-id");
174
175 if (sessionId) {
176 const transport = transports.get(sessionId);
177 if (!transport) return jsonError(404, -32001, "Session not found");
178 const sessionResource = resources.get(sessionId);
179 if (!sessionResource || mcpResourceKey(sessionResource) !== mcpResourceKey(resource)) {
180 return jsonError(403, -32003, "Session belongs to a different MCP resource");
181 }
182 return transport.handleRequest(request);

Callers 3

makeMcpFetchFunction · 0.90
postFunction · 0.90
createServerHandlersFunction · 0.90

Calls 15

readElicitationModeFunction · 0.90
createExecutorMcpServerFunction · 0.90
readArtifactsEnabledFunction · 0.90
readSearchToolsEnabledFunction · 0.90
approvalUrlForRequestFunction · 0.90
normalizeHandlerConfigFunction · 0.85
engineFromConfigFunction · 0.85
resourceFromRequestFunction · 0.85
jsonErrorFunction · 0.85
mcpResourceKeyFunction · 0.85

Tested by 2

makeMcpFetchFunction · 0.72
postFunction · 0.72