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

Function createMcpRequestHandler

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

Source from the content-addressed store, hash-verified

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

Callers 2

makeMcpFetchFunction · 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
configForResourceFunction · 0.85

Tested by 1

makeMcpFetchFunction · 0.72