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

Function createMcpRequestHandler

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

Source from the content-addressed store, hash-verified

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

Callers 2

makeMcpFetchFunction · 0.90
createServerHandlersFunction · 0.90

Calls 15

readElicitationModeFunction · 0.90
createExecutorMcpServerFunction · 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
readResumeResponseFunction · 0.85

Tested by 1

makeMcpFetchFunction · 0.72