@sonoma-security/mcp-gateway 0.1.12 → 0.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/__tests__/config.test.js +140 -2
  2. package/dist/__tests__/config.test.js.map +1 -1
  3. package/dist/__tests__/plugin-discovery.test.d.ts +12 -0
  4. package/dist/__tests__/plugin-discovery.test.d.ts.map +1 -0
  5. package/dist/__tests__/plugin-discovery.test.js +367 -0
  6. package/dist/__tests__/plugin-discovery.test.js.map +1 -0
  7. package/dist/__tests__/tool-blocking.test.d.ts +2 -0
  8. package/dist/__tests__/tool-blocking.test.d.ts.map +1 -0
  9. package/dist/__tests__/tool-blocking.test.js +256 -0
  10. package/dist/__tests__/tool-blocking.test.js.map +1 -0
  11. package/dist/auth/keychain.d.ts +34 -0
  12. package/dist/auth/keychain.d.ts.map +1 -0
  13. package/dist/auth/keychain.js +305 -0
  14. package/dist/auth/keychain.js.map +1 -0
  15. package/dist/auth/storage.d.ts +5 -6
  16. package/dist/auth/storage.d.ts.map +1 -1
  17. package/dist/auth/storage.js +72 -21
  18. package/dist/auth/storage.js.map +1 -1
  19. package/dist/auth/upstream-oauth.d.ts.map +1 -1
  20. package/dist/auth/upstream-oauth.js +8 -5
  21. package/dist/auth/upstream-oauth.js.map +1 -1
  22. package/dist/auth/upstream-token-store.d.ts +18 -6
  23. package/dist/auth/upstream-token-store.d.ts.map +1 -1
  24. package/dist/auth/upstream-token-store.js +127 -35
  25. package/dist/auth/upstream-token-store.js.map +1 -1
  26. package/dist/cli.js +48 -2
  27. package/dist/cli.js.map +1 -1
  28. package/dist/config.d.ts.map +1 -1
  29. package/dist/config.js +122 -27
  30. package/dist/config.js.map +1 -1
  31. package/dist/gateway.d.ts +15 -0
  32. package/dist/gateway.d.ts.map +1 -1
  33. package/dist/gateway.js +302 -68
  34. package/dist/gateway.js.map +1 -1
  35. package/dist/http-proxy.d.ts +126 -0
  36. package/dist/http-proxy.d.ts.map +1 -0
  37. package/dist/http-proxy.js +875 -0
  38. package/dist/http-proxy.js.map +1 -0
  39. package/dist/index.d.ts +3 -0
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +2 -0
  42. package/dist/index.js.map +1 -1
  43. package/dist/pattern-matcher.d.ts +25 -0
  44. package/dist/pattern-matcher.d.ts.map +1 -1
  45. package/dist/pattern-matcher.js +65 -0
  46. package/dist/pattern-matcher.js.map +1 -1
  47. package/dist/sonoma-client.d.ts +17 -1
  48. package/dist/sonoma-client.d.ts.map +1 -1
  49. package/dist/sonoma-client.js +67 -43
  50. package/dist/sonoma-client.js.map +1 -1
  51. package/dist/types.d.ts +14 -0
  52. package/dist/types.d.ts.map +1 -1
  53. package/package.json +1 -1
@@ -0,0 +1,126 @@
1
+ /**
2
+ * HTTP Proxy Server for MCP Gateway
3
+ *
4
+ * Transparent HTTP passthrough that forwards all MCP traffic (including OAuth
5
+ * discovery, auth headers, SSE streams) to upstream servers. Parses JSON-RPC
6
+ * request/response bodies for telemetry and policy enforcement.
7
+ *
8
+ * Architecture:
9
+ * Client (http://localhost:{port}/proxy/{serverName}/mcp)
10
+ * -> HTTP Proxy (parse JSON-RPC, enforce policy, record telemetry)
11
+ * -> Upstream MCP Server (https://mcp.example.com/mcp)
12
+ *
13
+ * Unlike the previous MCP-level proxy (which terminated MCP sessions and
14
+ * created its own Server/Transport), this is a true HTTP passthrough.
15
+ * OAuth, SSE, session headers all flow through untouched.
16
+ */
17
+ import { type Server } from "node:http";
18
+ /**
19
+ * Bind an HTTP server to the given port immediately, returning both the server
20
+ * and a promise that resolves once it's listening. The server responds to any
21
+ * request with 503 Service Unavailable until `adoptHttpServer` swaps in a real
22
+ * handler. This lets the caller hold the port during slow startup work (auth,
23
+ * policy fetch, upstream connections) so clients probing the port get
24
+ * "service starting" instead of ECONNREFUSED.
25
+ *
26
+ * On EADDRINUSE, the bind is retried for up to ~10s. The launchd/Scheduled
27
+ * Task supervisor races its own bootout against the new process, and the
28
+ * old owner can hold the socket briefly during teardown. Without the retry
29
+ * the fresh daemon crashes immediately, and each crash-loop wipes any
30
+ * in-memory MCP session state, stranding clients with stale session IDs.
31
+ */
32
+ export declare function preListenHttpServer(port: number): {
33
+ server: Server;
34
+ listening: Promise<void>;
35
+ };
36
+ export interface HttpProxyCallbacks {
37
+ /** Resolve a server name to its upstream URL */
38
+ getUpstreamUrl(serverName: string): string | undefined;
39
+ /** Check if a server has a connected stdio upstream (no URL, command-based) */
40
+ hasStdioUpstream(serverName: string): boolean;
41
+ /**
42
+ * Forward a JSON-RPC request to a stdio upstream and return the JSON-RPC response.
43
+ * Used for servers that have no URL (command-based / stdio transports).
44
+ */
45
+ forwardJsonRpc(serverName: string, method: string, params?: unknown): Promise<{
46
+ result?: unknown;
47
+ error?: {
48
+ code: number;
49
+ message: string;
50
+ data?: unknown;
51
+ };
52
+ }>;
53
+ /** Check if a tool is blocked by policy. Returns true if blocked. */
54
+ isToolBlocked(serverName: string, toolName: string): boolean;
55
+ /** Record a tool call event for telemetry */
56
+ recordToolCall(event: {
57
+ serverName: string;
58
+ toolName: string;
59
+ durationMs: number;
60
+ status: "success" | "error" | "blocked";
61
+ errorMessage?: string;
62
+ argumentKeys?: string[];
63
+ }): void;
64
+ /** Debug logging */
65
+ log(message: string): void;
66
+ }
67
+ export declare class HttpProxyServer {
68
+ private httpServer;
69
+ private callbacks;
70
+ private port;
71
+ private lastOAuthServerName;
72
+ private upstreamAsEndpoints;
73
+ constructor(port: number, callbacks: HttpProxyCallbacks, preboundServer?: Server);
74
+ private preboundAdopted;
75
+ start(): Promise<void>;
76
+ stop(): Promise<void>;
77
+ /**
78
+ * Get the proxy URL for a specific server.
79
+ * Plugins should rewrite their URLs to this endpoint.
80
+ */
81
+ getProxyUrl(serverName: string): string;
82
+ private handleRequest;
83
+ /**
84
+ * Forward OAuth discovery requests to the upstream server.
85
+ * Rewrites the `resource` field in oauth-protected-resource responses
86
+ * to match the proxy URL so the SDK's validation passes.
87
+ */
88
+ private forwardOAuthDiscovery;
89
+ /**
90
+ * Forward root-level OAuth requests (/token, /register) to the upstream.
91
+ * Rewrites the `resource` parameter from the proxy URL to the upstream's
92
+ * canonical resource URI (RFC 8707) so the upstream AS accepts the token
93
+ * request bound to the resource it knows about.
94
+ */
95
+ private forwardRootOAuth;
96
+ /**
97
+ * Build synthetic OAuth authorization server metadata for stdio-bridged servers.
98
+ * Points all OAuth endpoints back to this proxy so the full flow completes locally.
99
+ */
100
+ private buildStdioAuthServerMetadata;
101
+ /**
102
+ * Handle OAuth endpoints for stdio-bridged servers.
103
+ * Synthesizes valid responses so Claude Code's proactive auth flow succeeds
104
+ * without requiring actual user authentication. The bridge ignores the
105
+ * Authorization header, so the dummy token is harmless.
106
+ */
107
+ private handleStdioOAuth;
108
+ /**
109
+ * Bridge an HTTP MCP request to a stdio upstream via JSON-RPC.
110
+ *
111
+ * For command-based (stdio) servers that have no HTTP URL, we parse the
112
+ * incoming JSON-RPC request, forward it through the gateway's MCP Client
113
+ * connection, and return the response as HTTP.
114
+ *
115
+ * Handles: initialize, tools/list, tools/call, resources/list, etc.
116
+ * Also synthesizes MCP server metadata for the initial handshake.
117
+ */
118
+ private bridgeToStdio;
119
+ /**
120
+ * Forward an MCP request to the upstream server.
121
+ * For POST requests, parses the JSON-RPC body to detect tools/call for
122
+ * policy enforcement and telemetry. All other requests pass through as-is.
123
+ */
124
+ private forwardMcpRequest;
125
+ }
126
+ //# sourceMappingURL=http-proxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-proxy.d.ts","sourceRoot":"","sources":["../src/http-proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAsC,KAAK,MAAM,EAAuB,MAAM,WAAW,CAAC;AAEjG;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CA0B9F;AAED,MAAM,WAAW,kBAAkB;IACjC,gDAAgD;IAChD,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACvD,+EAA+E;IAC/E,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9C;;;OAGG;IACH,cAAc,CACZ,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,OAAO,GACf,OAAO,CAAC;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,OAAO,CAAA;SAAE,CAAA;KAAE,CAAC,CAAC;IAC5F,qEAAqE;IACrE,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAC7D,6CAA6C;IAC7C,cAAc,CAAC,KAAK,EAAE;QACpB,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;QACxC,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;KACzB,GAAG,IAAI,CAAC;IACT,oBAAoB;IACpB,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,UAAU,CAAkC;IACpD,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,IAAI,CAAS;IAMrB,OAAO,CAAC,mBAAmB,CAAqB;IAIhD,OAAO,CAAC,mBAAmB,CAOtB;gBAEO,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,kBAAkB,EAAE,cAAc,CAAC,EAAE,MAAM;IAahF,OAAO,CAAC,eAAe,CAAS;IAE1B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IActB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAM3B;;;OAGG;IACH,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;YAIzB,aAAa;IAqJ3B;;;;OAIG;YACW,qBAAqB;IA2HnC;;;;;OAKG;YACW,gBAAgB;IA2E9B;;;OAGG;IACH,OAAO,CAAC,4BAA4B;IAcpC;;;;;OAKG;YACW,gBAAgB;IA8F9B;;;;;;;;;OASG;YACW,aAAa;IA2I3B;;;;OAIG;YACW,iBAAiB;CAkMhC"}