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

Function createMcpRequestHandler

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

Source from the content-addressed store, hash-verified

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

Callers 2

makeMcpFetchFunction · 0.90
createServerHandlersFunction · 0.90

Calls 15

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

Tested by 1

makeMcpFetchFunction · 0.72