mnehmos.trace.mcp 1.0.0

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 (339) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1662 -0
  3. package/dist/adapters/bootstrap.d.ts +29 -0
  4. package/dist/adapters/bootstrap.d.ts.map +1 -0
  5. package/dist/adapters/bootstrap.js +46 -0
  6. package/dist/adapters/bootstrap.js.map +1 -0
  7. package/dist/adapters/errors.d.ts +94 -0
  8. package/dist/adapters/errors.d.ts.map +1 -0
  9. package/dist/adapters/errors.js +107 -0
  10. package/dist/adapters/errors.js.map +1 -0
  11. package/dist/adapters/graphql/index.d.ts +9 -0
  12. package/dist/adapters/graphql/index.d.ts.map +1 -0
  13. package/dist/adapters/graphql/index.js +9 -0
  14. package/dist/adapters/graphql/index.js.map +1 -0
  15. package/dist/adapters/graphql/sdl-parser.d.ts +74 -0
  16. package/dist/adapters/graphql/sdl-parser.d.ts.map +1 -0
  17. package/dist/adapters/graphql/sdl-parser.js +559 -0
  18. package/dist/adapters/graphql/sdl-parser.js.map +1 -0
  19. package/dist/adapters/grpc/adapter.d.ts +76 -0
  20. package/dist/adapters/grpc/adapter.d.ts.map +1 -0
  21. package/dist/adapters/grpc/adapter.js +362 -0
  22. package/dist/adapters/grpc/adapter.js.map +1 -0
  23. package/dist/adapters/grpc/index.d.ts +10 -0
  24. package/dist/adapters/grpc/index.d.ts.map +1 -0
  25. package/dist/adapters/grpc/index.js +12 -0
  26. package/dist/adapters/grpc/index.js.map +1 -0
  27. package/dist/adapters/grpc/proto-parser.d.ts +76 -0
  28. package/dist/adapters/grpc/proto-parser.d.ts.map +1 -0
  29. package/dist/adapters/grpc/proto-parser.js +523 -0
  30. package/dist/adapters/grpc/proto-parser.js.map +1 -0
  31. package/dist/adapters/grpc/type-converter.d.ts +43 -0
  32. package/dist/adapters/grpc/type-converter.d.ts.map +1 -0
  33. package/dist/adapters/grpc/type-converter.js +270 -0
  34. package/dist/adapters/grpc/type-converter.js.map +1 -0
  35. package/dist/adapters/grpc/types.d.ts +85 -0
  36. package/dist/adapters/grpc/types.d.ts.map +1 -0
  37. package/dist/adapters/grpc/types.js +7 -0
  38. package/dist/adapters/grpc/types.js.map +1 -0
  39. package/dist/adapters/index.d.ts +39 -0
  40. package/dist/adapters/index.d.ts.map +1 -0
  41. package/dist/adapters/index.js +50 -0
  42. package/dist/adapters/index.js.map +1 -0
  43. package/dist/adapters/mcp.d.ts +23 -0
  44. package/dist/adapters/mcp.d.ts.map +1 -0
  45. package/dist/adapters/mcp.js +293 -0
  46. package/dist/adapters/mcp.js.map +1 -0
  47. package/dist/adapters/openapi/adapter.d.ts +213 -0
  48. package/dist/adapters/openapi/adapter.d.ts.map +1 -0
  49. package/dist/adapters/openapi/adapter.js +557 -0
  50. package/dist/adapters/openapi/adapter.js.map +1 -0
  51. package/dist/adapters/openapi/convert.d.ts +120 -0
  52. package/dist/adapters/openapi/convert.d.ts.map +1 -0
  53. package/dist/adapters/openapi/convert.js +363 -0
  54. package/dist/adapters/openapi/convert.js.map +1 -0
  55. package/dist/adapters/openapi/index.d.ts +39 -0
  56. package/dist/adapters/openapi/index.d.ts.map +1 -0
  57. package/dist/adapters/openapi/index.js +48 -0
  58. package/dist/adapters/openapi/index.js.map +1 -0
  59. package/dist/adapters/openapi/parser.d.ts +95 -0
  60. package/dist/adapters/openapi/parser.d.ts.map +1 -0
  61. package/dist/adapters/openapi/parser.js +171 -0
  62. package/dist/adapters/openapi/parser.js.map +1 -0
  63. package/dist/adapters/registry.d.ts +116 -0
  64. package/dist/adapters/registry.d.ts.map +1 -0
  65. package/dist/adapters/registry.js +246 -0
  66. package/dist/adapters/registry.js.map +1 -0
  67. package/dist/adapters/trpc/adapter.d.ts +159 -0
  68. package/dist/adapters/trpc/adapter.d.ts.map +1 -0
  69. package/dist/adapters/trpc/adapter.js +223 -0
  70. package/dist/adapters/trpc/adapter.js.map +1 -0
  71. package/dist/adapters/trpc/extractor.d.ts +218 -0
  72. package/dist/adapters/trpc/extractor.d.ts.map +1 -0
  73. package/dist/adapters/trpc/extractor.js +708 -0
  74. package/dist/adapters/trpc/extractor.js.map +1 -0
  75. package/dist/adapters/trpc/index.d.ts +31 -0
  76. package/dist/adapters/trpc/index.d.ts.map +1 -0
  77. package/dist/adapters/trpc/index.js +40 -0
  78. package/dist/adapters/trpc/index.js.map +1 -0
  79. package/dist/adapters/trpc/parser.d.ts +119 -0
  80. package/dist/adapters/trpc/parser.d.ts.map +1 -0
  81. package/dist/adapters/trpc/parser.js +128 -0
  82. package/dist/adapters/trpc/parser.js.map +1 -0
  83. package/dist/compare/index.d.ts +33 -0
  84. package/dist/compare/index.d.ts.map +1 -0
  85. package/dist/compare/index.js +261 -0
  86. package/dist/compare/index.js.map +1 -0
  87. package/dist/core/types.d.ts +188 -0
  88. package/dist/core/types.d.ts.map +1 -0
  89. package/dist/core/types.js +9 -0
  90. package/dist/core/types.js.map +1 -0
  91. package/dist/extract/index.d.ts +26 -0
  92. package/dist/extract/index.d.ts.map +1 -0
  93. package/dist/extract/index.js +44 -0
  94. package/dist/extract/index.js.map +1 -0
  95. package/dist/index.d.ts +9 -0
  96. package/dist/index.d.ts.map +1 -0
  97. package/dist/index.js +674 -0
  98. package/dist/index.js.map +1 -0
  99. package/dist/languages/base.d.ts +57 -0
  100. package/dist/languages/base.d.ts.map +1 -0
  101. package/dist/languages/base.js +6 -0
  102. package/dist/languages/base.js.map +1 -0
  103. package/dist/languages/bootstrap.d.ts +10 -0
  104. package/dist/languages/bootstrap.d.ts.map +1 -0
  105. package/dist/languages/bootstrap.js +25 -0
  106. package/dist/languages/bootstrap.js.map +1 -0
  107. package/dist/languages/go/handlers/chi.d.ts +24 -0
  108. package/dist/languages/go/handlers/chi.d.ts.map +1 -0
  109. package/dist/languages/go/handlers/chi.js +205 -0
  110. package/dist/languages/go/handlers/chi.js.map +1 -0
  111. package/dist/languages/go/handlers/gin.d.ts +24 -0
  112. package/dist/languages/go/handlers/gin.d.ts.map +1 -0
  113. package/dist/languages/go/handlers/gin.js +156 -0
  114. package/dist/languages/go/handlers/gin.js.map +1 -0
  115. package/dist/languages/go/handlers/stdlib.d.ts +19 -0
  116. package/dist/languages/go/handlers/stdlib.d.ts.map +1 -0
  117. package/dist/languages/go/handlers/stdlib.js +112 -0
  118. package/dist/languages/go/handlers/stdlib.js.map +1 -0
  119. package/dist/languages/go/index.d.ts +18 -0
  120. package/dist/languages/go/index.d.ts.map +1 -0
  121. package/dist/languages/go/index.js +20 -0
  122. package/dist/languages/go/index.js.map +1 -0
  123. package/dist/languages/go/parser.d.ts +33 -0
  124. package/dist/languages/go/parser.d.ts.map +1 -0
  125. package/dist/languages/go/parser.js +95 -0
  126. package/dist/languages/go/parser.js.map +1 -0
  127. package/dist/languages/go/struct-extractor.d.ts +59 -0
  128. package/dist/languages/go/struct-extractor.d.ts.map +1 -0
  129. package/dist/languages/go/struct-extractor.js +483 -0
  130. package/dist/languages/go/struct-extractor.js.map +1 -0
  131. package/dist/languages/go/tag-parser.d.ts +62 -0
  132. package/dist/languages/go/tag-parser.d.ts.map +1 -0
  133. package/dist/languages/go/tag-parser.js +108 -0
  134. package/dist/languages/go/tag-parser.js.map +1 -0
  135. package/dist/languages/go/type-converter.d.ts +32 -0
  136. package/dist/languages/go/type-converter.d.ts.map +1 -0
  137. package/dist/languages/go/type-converter.js +226 -0
  138. package/dist/languages/go/type-converter.js.map +1 -0
  139. package/dist/languages/go/types.d.ts +153 -0
  140. package/dist/languages/go/types.d.ts.map +1 -0
  141. package/dist/languages/go/types.js +6 -0
  142. package/dist/languages/go/types.js.map +1 -0
  143. package/dist/languages/import-resolver.d.ts +645 -0
  144. package/dist/languages/import-resolver.d.ts.map +1 -0
  145. package/dist/languages/import-resolver.js +1278 -0
  146. package/dist/languages/import-resolver.js.map +1 -0
  147. package/dist/languages/index.d.ts +34 -0
  148. package/dist/languages/index.d.ts.map +1 -0
  149. package/dist/languages/index.js +93 -0
  150. package/dist/languages/index.js.map +1 -0
  151. package/dist/languages/json-schema.d.ts +40 -0
  152. package/dist/languages/json-schema.d.ts.map +1 -0
  153. package/dist/languages/json-schema.js +188 -0
  154. package/dist/languages/json-schema.js.map +1 -0
  155. package/dist/languages/python-ast/index.d.ts +8 -0
  156. package/dist/languages/python-ast/index.d.ts.map +1 -0
  157. package/dist/languages/python-ast/index.js +7 -0
  158. package/dist/languages/python-ast/index.js.map +1 -0
  159. package/dist/languages/python-ast/parser.d.ts +174 -0
  160. package/dist/languages/python-ast/parser.d.ts.map +1 -0
  161. package/dist/languages/python-ast/parser.js +1205 -0
  162. package/dist/languages/python-ast/parser.js.map +1 -0
  163. package/dist/languages/python-ast/type-resolver.d.ts +75 -0
  164. package/dist/languages/python-ast/type-resolver.d.ts.map +1 -0
  165. package/dist/languages/python-ast/type-resolver.js +421 -0
  166. package/dist/languages/python-ast/type-resolver.js.map +1 -0
  167. package/dist/languages/python-ast/types.d.ts +216 -0
  168. package/dist/languages/python-ast/types.d.ts.map +1 -0
  169. package/dist/languages/python-ast/types.js +6 -0
  170. package/dist/languages/python-ast/types.js.map +1 -0
  171. package/dist/languages/python.d.ts +55 -0
  172. package/dist/languages/python.d.ts.map +1 -0
  173. package/dist/languages/python.js +311 -0
  174. package/dist/languages/python.js.map +1 -0
  175. package/dist/languages/typescript.d.ts +272 -0
  176. package/dist/languages/typescript.d.ts.map +1 -0
  177. package/dist/languages/typescript.js +1381 -0
  178. package/dist/languages/typescript.js.map +1 -0
  179. package/dist/patterns/base.d.ts +146 -0
  180. package/dist/patterns/base.d.ts.map +1 -0
  181. package/dist/patterns/base.js +89 -0
  182. package/dist/patterns/base.js.map +1 -0
  183. package/dist/patterns/errors.d.ts +172 -0
  184. package/dist/patterns/errors.d.ts.map +1 -0
  185. package/dist/patterns/errors.js +185 -0
  186. package/dist/patterns/errors.js.map +1 -0
  187. package/dist/patterns/extractors.d.ts +170 -0
  188. package/dist/patterns/extractors.d.ts.map +1 -0
  189. package/dist/patterns/extractors.js +305 -0
  190. package/dist/patterns/extractors.js.map +1 -0
  191. package/dist/patterns/graphql/apollo-client.d.ts +80 -0
  192. package/dist/patterns/graphql/apollo-client.d.ts.map +1 -0
  193. package/dist/patterns/graphql/apollo-client.js +800 -0
  194. package/dist/patterns/graphql/apollo-client.js.map +1 -0
  195. package/dist/patterns/graphql/apollo-server.d.ts +55 -0
  196. package/dist/patterns/graphql/apollo-server.d.ts.map +1 -0
  197. package/dist/patterns/graphql/apollo-server.js +523 -0
  198. package/dist/patterns/graphql/apollo-server.js.map +1 -0
  199. package/dist/patterns/graphql/index.d.ts +11 -0
  200. package/dist/patterns/graphql/index.d.ts.map +1 -0
  201. package/dist/patterns/graphql/index.js +12 -0
  202. package/dist/patterns/graphql/index.js.map +1 -0
  203. package/dist/patterns/graphql/types.d.ts +213 -0
  204. package/dist/patterns/graphql/types.d.ts.map +1 -0
  205. package/dist/patterns/graphql/types.js +16 -0
  206. package/dist/patterns/graphql/types.js.map +1 -0
  207. package/dist/patterns/http-clients/axios.d.ts +148 -0
  208. package/dist/patterns/http-clients/axios.d.ts.map +1 -0
  209. package/dist/patterns/http-clients/axios.js +652 -0
  210. package/dist/patterns/http-clients/axios.js.map +1 -0
  211. package/dist/patterns/http-clients/fetch.d.ts +88 -0
  212. package/dist/patterns/http-clients/fetch.d.ts.map +1 -0
  213. package/dist/patterns/http-clients/fetch.js +364 -0
  214. package/dist/patterns/http-clients/fetch.js.map +1 -0
  215. package/dist/patterns/http-clients/index.d.ts +36 -0
  216. package/dist/patterns/http-clients/index.d.ts.map +1 -0
  217. package/dist/patterns/http-clients/index.js +50 -0
  218. package/dist/patterns/http-clients/index.js.map +1 -0
  219. package/dist/patterns/http-clients/property-access.d.ts +46 -0
  220. package/dist/patterns/http-clients/property-access.d.ts.map +1 -0
  221. package/dist/patterns/http-clients/property-access.js +818 -0
  222. package/dist/patterns/http-clients/property-access.js.map +1 -0
  223. package/dist/patterns/http-clients/type-inference.d.ts +48 -0
  224. package/dist/patterns/http-clients/type-inference.d.ts.map +1 -0
  225. package/dist/patterns/http-clients/type-inference.js +293 -0
  226. package/dist/patterns/http-clients/type-inference.js.map +1 -0
  227. package/dist/patterns/http-clients/types.d.ts +168 -0
  228. package/dist/patterns/http-clients/types.d.ts.map +1 -0
  229. package/dist/patterns/http-clients/types.js +10 -0
  230. package/dist/patterns/http-clients/types.js.map +1 -0
  231. package/dist/patterns/http-clients/url-extractor.d.ts +53 -0
  232. package/dist/patterns/http-clients/url-extractor.d.ts.map +1 -0
  233. package/dist/patterns/http-clients/url-extractor.js +338 -0
  234. package/dist/patterns/http-clients/url-extractor.js.map +1 -0
  235. package/dist/patterns/index.d.ts +44 -0
  236. package/dist/patterns/index.d.ts.map +1 -0
  237. package/dist/patterns/index.js +49 -0
  238. package/dist/patterns/index.js.map +1 -0
  239. package/dist/patterns/python/aiohttp.d.ts +21 -0
  240. package/dist/patterns/python/aiohttp.d.ts.map +1 -0
  241. package/dist/patterns/python/aiohttp.js +188 -0
  242. package/dist/patterns/python/aiohttp.js.map +1 -0
  243. package/dist/patterns/python/httpx.d.ts +20 -0
  244. package/dist/patterns/python/httpx.d.ts.map +1 -0
  245. package/dist/patterns/python/httpx.js +183 -0
  246. package/dist/patterns/python/httpx.js.map +1 -0
  247. package/dist/patterns/python/index.d.ts +32 -0
  248. package/dist/patterns/python/index.d.ts.map +1 -0
  249. package/dist/patterns/python/index.js +63 -0
  250. package/dist/patterns/python/index.js.map +1 -0
  251. package/dist/patterns/python/property-access.d.ts +27 -0
  252. package/dist/patterns/python/property-access.d.ts.map +1 -0
  253. package/dist/patterns/python/property-access.js +132 -0
  254. package/dist/patterns/python/property-access.js.map +1 -0
  255. package/dist/patterns/python/requests.d.ts +19 -0
  256. package/dist/patterns/python/requests.d.ts.map +1 -0
  257. package/dist/patterns/python/requests.js +239 -0
  258. package/dist/patterns/python/requests.js.map +1 -0
  259. package/dist/patterns/python/types.d.ts +95 -0
  260. package/dist/patterns/python/types.d.ts.map +1 -0
  261. package/dist/patterns/python/types.js +43 -0
  262. package/dist/patterns/python/types.js.map +1 -0
  263. package/dist/patterns/registry.d.ts +181 -0
  264. package/dist/patterns/registry.d.ts.map +1 -0
  265. package/dist/patterns/registry.js +304 -0
  266. package/dist/patterns/registry.js.map +1 -0
  267. package/dist/patterns/rest/express.d.ts +78 -0
  268. package/dist/patterns/rest/express.d.ts.map +1 -0
  269. package/dist/patterns/rest/express.js +289 -0
  270. package/dist/patterns/rest/express.js.map +1 -0
  271. package/dist/patterns/rest/fastify.d.ts +93 -0
  272. package/dist/patterns/rest/fastify.d.ts.map +1 -0
  273. package/dist/patterns/rest/fastify.js +420 -0
  274. package/dist/patterns/rest/fastify.js.map +1 -0
  275. package/dist/patterns/rest/index.d.ts +31 -0
  276. package/dist/patterns/rest/index.d.ts.map +1 -0
  277. package/dist/patterns/rest/index.js +45 -0
  278. package/dist/patterns/rest/index.js.map +1 -0
  279. package/dist/patterns/rest/middleware.d.ts +25 -0
  280. package/dist/patterns/rest/middleware.d.ts.map +1 -0
  281. package/dist/patterns/rest/middleware.js +219 -0
  282. package/dist/patterns/rest/middleware.js.map +1 -0
  283. package/dist/patterns/rest/path-parser.d.ts +50 -0
  284. package/dist/patterns/rest/path-parser.d.ts.map +1 -0
  285. package/dist/patterns/rest/path-parser.js +137 -0
  286. package/dist/patterns/rest/path-parser.js.map +1 -0
  287. package/dist/patterns/rest/response-inference.d.ts +44 -0
  288. package/dist/patterns/rest/response-inference.d.ts.map +1 -0
  289. package/dist/patterns/rest/response-inference.js +218 -0
  290. package/dist/patterns/rest/response-inference.js.map +1 -0
  291. package/dist/patterns/rest/types.d.ts +102 -0
  292. package/dist/patterns/rest/types.d.ts.map +1 -0
  293. package/dist/patterns/rest/types.js +10 -0
  294. package/dist/patterns/rest/types.js.map +1 -0
  295. package/dist/patterns/types.d.ts +105 -0
  296. package/dist/patterns/types.d.ts.map +1 -0
  297. package/dist/patterns/types.js +11 -0
  298. package/dist/patterns/types.js.map +1 -0
  299. package/dist/report/index.d.ts +11 -0
  300. package/dist/report/index.d.ts.map +1 -0
  301. package/dist/report/index.js +55 -0
  302. package/dist/report/index.js.map +1 -0
  303. package/dist/tools/contract-comments.d.ts +48 -0
  304. package/dist/tools/contract-comments.d.ts.map +1 -0
  305. package/dist/tools/contract-comments.js +130 -0
  306. package/dist/tools/contract-comments.js.map +1 -0
  307. package/dist/tools/index.d.ts +6 -0
  308. package/dist/tools/index.d.ts.map +1 -0
  309. package/dist/tools/index.js +6 -0
  310. package/dist/tools/index.js.map +1 -0
  311. package/dist/tools/scaffold.d.ts +38 -0
  312. package/dist/tools/scaffold.d.ts.map +1 -0
  313. package/dist/tools/scaffold.js +373 -0
  314. package/dist/tools/scaffold.js.map +1 -0
  315. package/dist/trace/index.d.ts +28 -0
  316. package/dist/trace/index.d.ts.map +1 -0
  317. package/dist/trace/index.js +45 -0
  318. package/dist/trace/index.js.map +1 -0
  319. package/dist/types.d.ts +135 -0
  320. package/dist/types.d.ts.map +1 -0
  321. package/dist/types.js +22 -0
  322. package/dist/types.js.map +1 -0
  323. package/dist/watch/cache.d.ts +41 -0
  324. package/dist/watch/cache.d.ts.map +1 -0
  325. package/dist/watch/cache.js +230 -0
  326. package/dist/watch/cache.js.map +1 -0
  327. package/dist/watch/index.d.ts +9 -0
  328. package/dist/watch/index.d.ts.map +1 -0
  329. package/dist/watch/index.js +7 -0
  330. package/dist/watch/index.js.map +1 -0
  331. package/dist/watch/project.d.ts +128 -0
  332. package/dist/watch/project.d.ts.map +1 -0
  333. package/dist/watch/project.js +152 -0
  334. package/dist/watch/project.js.map +1 -0
  335. package/dist/watch/watcher.d.ts +76 -0
  336. package/dist/watch/watcher.d.ts.map +1 -0
  337. package/dist/watch/watcher.js +235 -0
  338. package/dist/watch/watcher.js.map +1 -0
  339. package/package.json +70 -0
package/dist/index.js ADDED
@@ -0,0 +1,674 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Trace MCP Server
4
+ *
5
+ * MCP server for detecting producer/consumer schema mismatches
6
+ * between MCP tool definitions and client code that uses them.
7
+ */
8
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
9
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
10
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
11
+ import { z } from 'zod';
12
+ import { extractProducerSchemas, extractFromFile } from './extract/index.js';
13
+ import { traceConsumerUsage, traceFromFile } from './trace/index.js';
14
+ import { compareDirectories } from './compare/index.js';
15
+ import { formatResult } from './report/index.js';
16
+ import { previewContractComments, addContractComments, scaffoldConsumerFromProducer, scaffoldProducerFromConsumer, } from './tools/index.js';
17
+ import { loadProject, getWatcher, stopWatcher, listActiveWatchers, } from './watch/index.js';
18
+ import { bootstrapLanguageParsers } from './languages/bootstrap.js';
19
+ // Bootstrap language parsers at startup
20
+ bootstrapLanguageParsers();
21
+ // Helper: log to stderr (MCP protocol requires stdout for JSON-RPC only)
22
+ const log = (...args) => console.error('[trace-mcp]', ...args);
23
+ // Tool input schemas
24
+ const ExtractSchemasInput = z.object({
25
+ rootDir: z.string().describe('Root directory of MCP server source code'),
26
+ include: z.array(z.string()).optional().describe('Glob patterns to include (default: **/*.ts)'),
27
+ exclude: z.array(z.string()).optional().describe('Glob patterns to exclude (default: node_modules, dist)'),
28
+ });
29
+ const TraceUsageInput = z.object({
30
+ rootDir: z.string().describe('Root directory of consumer/client source code'),
31
+ include: z.array(z.string()).optional().describe('Glob patterns to include'),
32
+ exclude: z.array(z.string()).optional().describe('Glob patterns to exclude'),
33
+ });
34
+ const CompareInput = z.object({
35
+ producerDir: z.string().describe('Path to MCP server source directory'),
36
+ consumerDir: z.string().describe('Path to consumer/client source directory'),
37
+ format: z.enum(['json', 'markdown', 'summary']).optional().describe('Output format (default: json)'),
38
+ strict: z.boolean().optional().describe('Strict mode: treat missing optional properties as warnings'),
39
+ direction: z.enum(['producer_to_consumer', 'consumer_to_producer', 'bidirectional']).optional().describe('Data flow direction for compatibility checking (default: producer_to_consumer)'),
40
+ });
41
+ const ExtractFileInput = z.object({
42
+ filePath: z.string().describe('Path to a single TypeScript file to extract schemas from'),
43
+ });
44
+ const TraceFileInput = z.object({
45
+ filePath: z.string().describe('Path to a single TypeScript file to trace tool usage in'),
46
+ });
47
+ const ScaffoldConsumerInput = z.object({
48
+ producerDir: z.string().describe('Path to MCP server source directory'),
49
+ toolName: z.string().describe('Name of the tool to scaffold consumer for'),
50
+ target: z.enum(['typescript', 'javascript', 'react-hook', 'zustand-action']).optional().describe('Output target format (default: typescript)'),
51
+ includeErrorHandling: z.boolean().optional().describe('Include try/catch error handling (default: true)'),
52
+ includeTypes: z.boolean().optional().describe('Include TypeScript type definitions (default: true)'),
53
+ });
54
+ const ScaffoldProducerInput = z.object({
55
+ consumerDir: z.string().describe('Path to consumer source directory'),
56
+ toolName: z.string().describe('Name of the tool to scaffold producer for'),
57
+ includeHandler: z.boolean().optional().describe('Include handler stub (default: true)'),
58
+ });
59
+ const CommentContractInput = z.object({
60
+ producerDir: z.string().describe('Path to MCP server source directory'),
61
+ consumerDir: z.string().describe('Path to consumer source directory'),
62
+ toolName: z.string().describe('Name of the validated tool'),
63
+ dryRun: z.boolean().optional().describe('Preview comments without writing to files (default: true)'),
64
+ style: z.enum(['jsdoc', 'inline', 'block']).optional().describe('Comment style (default: block)'),
65
+ });
66
+ // Watch mode input schemas
67
+ const InitProjectInput = z.object({
68
+ projectDir: z.string().describe('Root directory for the trace project'),
69
+ producerPath: z.string().describe('Relative path to producer/server code'),
70
+ consumerPath: z.string().describe('Relative path to consumer/client code'),
71
+ producerLanguage: z.enum(['typescript', 'python', 'go', 'rust', 'json_schema']).optional().default('typescript'),
72
+ consumerLanguage: z.enum(['typescript', 'python', 'go', 'rust', 'json_schema']).optional().default('typescript'),
73
+ });
74
+ const WatchInput = z.object({
75
+ projectDir: z.string().describe('Root directory with .trace-mcp config'),
76
+ action: z.enum(['start', 'stop', 'status', 'poll']).default('start').describe('Watch action to perform'),
77
+ });
78
+ const GetProjectStatusInput = z.object({
79
+ projectDir: z.string().describe('Root directory with .trace-mcp config'),
80
+ });
81
+ // Create server
82
+ const server = new Server({
83
+ name: 'trace-mcp',
84
+ version: '1.0.0',
85
+ }, {
86
+ capabilities: {
87
+ tools: {},
88
+ },
89
+ });
90
+ // List available tools
91
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
92
+ return {
93
+ tools: [
94
+ {
95
+ name: 'extract_schemas',
96
+ description: 'Extract MCP tool definitions (ProducerSchemas) from server source code. Scans for server.tool() calls and parses their Zod schemas.',
97
+ inputSchema: {
98
+ type: 'object',
99
+ properties: {
100
+ rootDir: { type: 'string', description: 'Root directory of MCP server source code' },
101
+ include: { type: 'array', items: { type: 'string' }, description: 'Glob patterns to include' },
102
+ exclude: { type: 'array', items: { type: 'string' }, description: 'Glob patterns to exclude' },
103
+ },
104
+ required: ['rootDir'],
105
+ },
106
+ },
107
+ {
108
+ name: 'extract_file',
109
+ description: 'Extract MCP tool definitions from a single TypeScript file.',
110
+ inputSchema: {
111
+ type: 'object',
112
+ properties: {
113
+ filePath: { type: 'string', description: 'Path to a TypeScript file' },
114
+ },
115
+ required: ['filePath'],
116
+ },
117
+ },
118
+ {
119
+ name: 'trace_usage',
120
+ description: 'Trace how client code uses MCP tools. Finds callTool() invocations and tracks which properties are accessed on results.',
121
+ inputSchema: {
122
+ type: 'object',
123
+ properties: {
124
+ rootDir: { type: 'string', description: 'Root directory of consumer source code' },
125
+ include: { type: 'array', items: { type: 'string' }, description: 'Glob patterns to include' },
126
+ exclude: { type: 'array', items: { type: 'string' }, description: 'Glob patterns to exclude' },
127
+ },
128
+ required: ['rootDir'],
129
+ },
130
+ },
131
+ {
132
+ name: 'trace_file',
133
+ description: 'Trace MCP tool usage in a single TypeScript file.',
134
+ inputSchema: {
135
+ type: 'object',
136
+ properties: {
137
+ filePath: { type: 'string', description: 'Path to a TypeScript file' },
138
+ },
139
+ required: ['filePath'],
140
+ },
141
+ },
142
+ {
143
+ name: 'compare',
144
+ description: 'Full analysis pipeline: extract producer schemas, trace consumer usage, and compare them to find mismatches. Returns a detailed report.',
145
+ inputSchema: {
146
+ type: 'object',
147
+ properties: {
148
+ producerDir: { type: 'string', description: 'Path to MCP server source directory' },
149
+ consumerDir: { type: 'string', description: 'Path to consumer/client source directory' },
150
+ format: { type: 'string', enum: ['json', 'markdown', 'summary'], description: 'Output format' },
151
+ strict: { type: 'boolean', description: 'Strict mode for comparison' },
152
+ direction: { type: 'string', enum: ['producer_to_consumer', 'consumer_to_producer', 'bidirectional'], description: 'Data flow direction (default: producer_to_consumer)' },
153
+ },
154
+ required: ['producerDir', 'consumerDir'],
155
+ },
156
+ },
157
+ {
158
+ name: 'scaffold_consumer',
159
+ description: 'Generate consumer code from a producer schema. Creates TypeScript functions, React hooks, or Zustand actions that correctly call MCP tools.',
160
+ inputSchema: {
161
+ type: 'object',
162
+ properties: {
163
+ producerDir: { type: 'string', description: 'Path to MCP server source directory' },
164
+ toolName: { type: 'string', description: 'Name of the tool to scaffold consumer for' },
165
+ target: { type: 'string', enum: ['typescript', 'javascript', 'react-hook', 'zustand-action'], description: 'Output target format' },
166
+ includeErrorHandling: { type: 'boolean', description: 'Include try/catch error handling' },
167
+ includeTypes: { type: 'boolean', description: 'Include TypeScript type definitions' },
168
+ },
169
+ required: ['producerDir', 'toolName'],
170
+ },
171
+ },
172
+ {
173
+ name: 'scaffold_producer',
174
+ description: 'Generate producer schema stub from consumer usage. Creates MCP tool definition based on how client code calls it.',
175
+ inputSchema: {
176
+ type: 'object',
177
+ properties: {
178
+ consumerDir: { type: 'string', description: 'Path to consumer source directory' },
179
+ toolName: { type: 'string', description: 'Name of the tool to scaffold producer for' },
180
+ includeHandler: { type: 'boolean', description: 'Include handler stub' },
181
+ },
182
+ required: ['consumerDir', 'toolName'],
183
+ },
184
+ },
185
+ {
186
+ name: 'comment_contract',
187
+ description: 'Add cross-reference comments to validated producer/consumer pairs. Documents the contract relationship in both files.',
188
+ inputSchema: {
189
+ type: 'object',
190
+ properties: {
191
+ producerDir: { type: 'string', description: 'Path to MCP server source directory' },
192
+ consumerDir: { type: 'string', description: 'Path to consumer source directory' },
193
+ toolName: { type: 'string', description: 'Name of the validated tool' },
194
+ dryRun: { type: 'boolean', description: 'Preview comments without writing to files (default: true)' },
195
+ style: { type: 'string', enum: ['jsdoc', 'inline', 'block'], description: 'Comment style' },
196
+ },
197
+ required: ['producerDir', 'consumerDir', 'toolName'],
198
+ },
199
+ },
200
+ // Watch mode tools
201
+ {
202
+ name: 'init_project',
203
+ description: 'Initialize a trace project with .trace-mcp config directory. Creates project structure for watch mode and caching.',
204
+ inputSchema: {
205
+ type: 'object',
206
+ properties: {
207
+ projectDir: { type: 'string', description: 'Root directory for the trace project' },
208
+ producerPath: { type: 'string', description: 'Relative path to producer/server code' },
209
+ consumerPath: { type: 'string', description: 'Relative path to consumer/client code' },
210
+ producerLanguage: { type: 'string', enum: ['typescript', 'python', 'go', 'rust', 'json_schema'], description: 'Producer language (default: typescript)' },
211
+ consumerLanguage: { type: 'string', enum: ['typescript', 'python', 'go', 'rust', 'json_schema'], description: 'Consumer language (default: typescript)' },
212
+ },
213
+ required: ['projectDir', 'producerPath', 'consumerPath'],
214
+ },
215
+ },
216
+ {
217
+ name: 'watch',
218
+ description: 'Watch project files for changes and auto-revalidate contracts. Actions: start (begin watching), stop (end watching), status (check state), poll (get pending events).',
219
+ inputSchema: {
220
+ type: 'object',
221
+ properties: {
222
+ projectDir: { type: 'string', description: 'Root directory with .trace-mcp config' },
223
+ action: { type: 'string', enum: ['start', 'stop', 'status', 'poll'], description: 'Watch action (default: start)' },
224
+ },
225
+ required: ['projectDir'],
226
+ },
227
+ },
228
+ {
229
+ name: 'get_project_status',
230
+ description: 'Get the status of a trace project including config, cache state, and last validation result.',
231
+ inputSchema: {
232
+ type: 'object',
233
+ properties: {
234
+ projectDir: { type: 'string', description: 'Root directory with .trace-mcp config' },
235
+ },
236
+ required: ['projectDir'],
237
+ },
238
+ },
239
+ ],
240
+ };
241
+ });
242
+ // Handle tool calls
243
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
244
+ const { name, arguments: args } = request.params;
245
+ try {
246
+ switch (name) {
247
+ case 'extract_schemas': {
248
+ const input = ExtractSchemasInput.parse(args);
249
+ log(`Extracting schemas from: ${input.rootDir}`);
250
+ const schemas = await extractProducerSchemas({
251
+ rootDir: input.rootDir,
252
+ include: input.include,
253
+ exclude: input.exclude,
254
+ });
255
+ log(`Found ${schemas.length} tool definitions`);
256
+ return {
257
+ content: [
258
+ {
259
+ type: 'text',
260
+ text: JSON.stringify({
261
+ success: true,
262
+ count: schemas.length,
263
+ schemas,
264
+ }, null, 2),
265
+ },
266
+ ],
267
+ };
268
+ }
269
+ case 'extract_file': {
270
+ const input = ExtractFileInput.parse(args);
271
+ log(`Extracting from file: ${input.filePath}`);
272
+ const schemas = await extractFromFile(input.filePath);
273
+ return {
274
+ content: [
275
+ {
276
+ type: 'text',
277
+ text: JSON.stringify({
278
+ success: true,
279
+ count: schemas.length,
280
+ schemas,
281
+ }, null, 2),
282
+ },
283
+ ],
284
+ };
285
+ }
286
+ case 'trace_usage': {
287
+ const input = TraceUsageInput.parse(args);
288
+ log(`Tracing usage in: ${input.rootDir}`);
289
+ const usage = await traceConsumerUsage({
290
+ rootDir: input.rootDir,
291
+ include: input.include,
292
+ exclude: input.exclude,
293
+ });
294
+ log(`Found ${usage.length} tool calls`);
295
+ return {
296
+ content: [
297
+ {
298
+ type: 'text',
299
+ text: JSON.stringify({
300
+ success: true,
301
+ count: usage.length,
302
+ usage,
303
+ }, null, 2),
304
+ },
305
+ ],
306
+ };
307
+ }
308
+ case 'trace_file': {
309
+ const input = TraceFileInput.parse(args);
310
+ log(`Tracing file: ${input.filePath}`);
311
+ const usage = await traceFromFile(input.filePath);
312
+ return {
313
+ content: [
314
+ {
315
+ type: 'text',
316
+ text: JSON.stringify({
317
+ success: true,
318
+ count: usage.length,
319
+ usage,
320
+ }, null, 2),
321
+ },
322
+ ],
323
+ };
324
+ }
325
+ case 'compare': {
326
+ const input = CompareInput.parse(args);
327
+ log(`Comparing: ${input.producerDir} vs ${input.consumerDir}`);
328
+ const result = await compareDirectories(input.producerDir, input.consumerDir, {
329
+ strict: input.strict,
330
+ direction: input.direction
331
+ });
332
+ const format = (input.format || 'json');
333
+ const output = formatResult(result, format);
334
+ log(`Analysis complete: ${result.summary.matchCount} matches, ${result.summary.mismatchCount} mismatches`);
335
+ return {
336
+ content: [
337
+ {
338
+ type: 'text',
339
+ text: output,
340
+ },
341
+ ],
342
+ };
343
+ }
344
+ case 'scaffold_consumer': {
345
+ const input = ScaffoldConsumerInput.parse(args);
346
+ log(`Scaffolding consumer for tool: ${input.toolName}`);
347
+ // Extract producer schemas to find the requested tool
348
+ const producers = await extractProducerSchemas({ rootDir: input.producerDir });
349
+ const producer = producers.find(p => p.toolName === input.toolName);
350
+ if (!producer) {
351
+ throw new Error(`Tool "${input.toolName}" not found in ${input.producerDir}`);
352
+ }
353
+ const result = scaffoldConsumerFromProducer(producer, {
354
+ target: input.target || 'typescript',
355
+ includeErrorHandling: input.includeErrorHandling ?? true,
356
+ includeTypes: input.includeTypes ?? true,
357
+ includeJSDoc: true,
358
+ });
359
+ log(`Generated ${input.target || 'typescript'} consumer code`);
360
+ return {
361
+ content: [
362
+ {
363
+ type: 'text',
364
+ text: JSON.stringify({
365
+ success: true,
366
+ toolName: input.toolName,
367
+ target: input.target || 'typescript',
368
+ suggestedFilename: result.suggestedFilename,
369
+ code: result.code,
370
+ types: result.types,
371
+ example: result.example,
372
+ }, null, 2),
373
+ },
374
+ ],
375
+ };
376
+ }
377
+ case 'scaffold_producer': {
378
+ const input = ScaffoldProducerInput.parse(args);
379
+ log(`Scaffolding producer for tool: ${input.toolName}`);
380
+ // Trace consumer usage to find the requested tool
381
+ const consumers = await traceConsumerUsage({ rootDir: input.consumerDir });
382
+ const consumer = consumers.find(c => c.toolName === input.toolName);
383
+ if (!consumer) {
384
+ throw new Error(`Tool "${input.toolName}" not found in consumer code at ${input.consumerDir}`);
385
+ }
386
+ const result = scaffoldProducerFromConsumer(consumer, {
387
+ includeHandler: input.includeHandler ?? true,
388
+ });
389
+ log(`Generated producer schema stub`);
390
+ return {
391
+ content: [
392
+ {
393
+ type: 'text',
394
+ text: JSON.stringify({
395
+ success: true,
396
+ toolName: input.toolName,
397
+ suggestedFilename: result.suggestedFilename,
398
+ code: result.code,
399
+ example: result.example,
400
+ }, null, 2),
401
+ },
402
+ ],
403
+ };
404
+ }
405
+ case 'comment_contract': {
406
+ const input = CommentContractInput.parse(args);
407
+ log(`Commenting contract for tool: ${input.toolName}`);
408
+ // Get both producer and consumer
409
+ const producers = await extractProducerSchemas({ rootDir: input.producerDir });
410
+ const consumers = await traceConsumerUsage({ rootDir: input.consumerDir });
411
+ const producer = producers.find(p => p.toolName === input.toolName);
412
+ const consumer = consumers.find(c => c.toolName === input.toolName);
413
+ if (!producer) {
414
+ throw new Error(`Tool "${input.toolName}" not found in producer at ${input.producerDir}`);
415
+ }
416
+ if (!consumer) {
417
+ throw new Error(`Tool "${input.toolName}" not found in consumer at ${input.consumerDir}`);
418
+ }
419
+ const match = {
420
+ toolName: input.toolName,
421
+ producerLocation: producer.location,
422
+ consumerLocation: consumer.callSite,
423
+ };
424
+ const commentOptions = {
425
+ match,
426
+ producer,
427
+ consumer,
428
+ style: input.style || 'block',
429
+ includeTimestamp: true,
430
+ };
431
+ if (input.dryRun !== false) {
432
+ // Preview mode (default)
433
+ const preview = previewContractComments(commentOptions);
434
+ return {
435
+ content: [
436
+ {
437
+ type: 'text',
438
+ text: JSON.stringify({
439
+ success: true,
440
+ mode: 'preview',
441
+ toolName: input.toolName,
442
+ producerPreview: preview.producerPreview,
443
+ consumerPreview: preview.consumerPreview,
444
+ note: 'Set dryRun: false to actually add these comments to files',
445
+ }, null, 2),
446
+ },
447
+ ],
448
+ };
449
+ }
450
+ else {
451
+ // Actually add comments
452
+ const result = await addContractComments(commentOptions);
453
+ return {
454
+ content: [
455
+ {
456
+ type: 'text',
457
+ text: JSON.stringify({
458
+ success: result.success,
459
+ mode: 'applied',
460
+ toolName: input.toolName,
461
+ producerFile: result.producerFile,
462
+ consumerFile: result.consumerFile,
463
+ producerComment: result.producerComment,
464
+ consumerComment: result.consumerComment,
465
+ error: result.error,
466
+ }, null, 2),
467
+ },
468
+ ],
469
+ };
470
+ }
471
+ }
472
+ // Watch mode tools
473
+ case 'init_project': {
474
+ const input = InitProjectInput.parse(args);
475
+ log(`Initializing trace project at: ${input.projectDir}`);
476
+ const project = loadProject(input.projectDir);
477
+ if (project.exists()) {
478
+ return {
479
+ content: [{
480
+ type: 'text',
481
+ text: JSON.stringify({
482
+ success: false,
483
+ error: `Project already exists at ${input.projectDir}. Use get_project_status to view it.`,
484
+ }, null, 2),
485
+ }],
486
+ };
487
+ }
488
+ const config = project.init({
489
+ producer: {
490
+ path: input.producerPath,
491
+ language: input.producerLanguage || 'typescript',
492
+ include: ['**/*.ts'],
493
+ exclude: ['**/*.test.ts', '**/node_modules/**', '**/dist/**'],
494
+ },
495
+ consumer: {
496
+ path: input.consumerPath,
497
+ language: input.consumerLanguage || 'typescript',
498
+ include: ['**/*.ts', '**/*.tsx'],
499
+ exclude: ['**/*.test.ts', '**/node_modules/**', '**/dist/**'],
500
+ },
501
+ });
502
+ log(`Project initialized with config:`, config);
503
+ return {
504
+ content: [{
505
+ type: 'text',
506
+ text: JSON.stringify({
507
+ success: true,
508
+ projectDir: input.projectDir,
509
+ traceDir: project.traceDir,
510
+ config,
511
+ }, null, 2),
512
+ }],
513
+ };
514
+ }
515
+ case 'watch': {
516
+ const input = WatchInput.parse(args);
517
+ const action = input.action || 'start';
518
+ log(`Watch action: ${action} for ${input.projectDir}`);
519
+ const project = loadProject(input.projectDir);
520
+ if (!project.exists()) {
521
+ throw new Error(`No trace project found at ${input.projectDir}. Run init_project first.`);
522
+ }
523
+ const watcher = getWatcher(project);
524
+ switch (action) {
525
+ case 'start': {
526
+ // Collect events during startup
527
+ const events = [];
528
+ const eventHandler = (event) => events.push(event);
529
+ watcher.on('watch-event', eventHandler);
530
+ await watcher.start();
531
+ // Wait a moment for initial validation
532
+ await new Promise(resolve => setTimeout(resolve, 100));
533
+ watcher.off('watch-event', eventHandler);
534
+ return {
535
+ content: [{
536
+ type: 'text',
537
+ text: JSON.stringify({
538
+ success: true,
539
+ action: 'started',
540
+ projectDir: input.projectDir,
541
+ status: watcher.getStatus(),
542
+ events,
543
+ }, null, 2),
544
+ }],
545
+ };
546
+ }
547
+ case 'stop': {
548
+ await stopWatcher(project);
549
+ return {
550
+ content: [{
551
+ type: 'text',
552
+ text: JSON.stringify({
553
+ success: true,
554
+ action: 'stopped',
555
+ projectDir: input.projectDir,
556
+ }, null, 2),
557
+ }],
558
+ };
559
+ }
560
+ case 'status': {
561
+ return {
562
+ content: [{
563
+ type: 'text',
564
+ text: JSON.stringify({
565
+ success: true,
566
+ action: 'status',
567
+ projectDir: input.projectDir,
568
+ status: watcher.getStatus(),
569
+ activeWatchers: listActiveWatchers(),
570
+ }, null, 2),
571
+ }],
572
+ };
573
+ }
574
+ case 'poll': {
575
+ // For polling, collect recent events
576
+ const status = watcher.getStatus();
577
+ return {
578
+ content: [{
579
+ type: 'text',
580
+ text: JSON.stringify({
581
+ success: true,
582
+ action: 'poll',
583
+ projectDir: input.projectDir,
584
+ status,
585
+ lastResult: status.lastResult,
586
+ }, null, 2),
587
+ }],
588
+ };
589
+ }
590
+ default:
591
+ throw new Error(`Unknown watch action: ${action}`);
592
+ }
593
+ }
594
+ case 'get_project_status': {
595
+ const input = GetProjectStatusInput.parse(args);
596
+ log(`Getting project status for: ${input.projectDir}`);
597
+ const project = loadProject(input.projectDir);
598
+ if (!project.exists()) {
599
+ return {
600
+ content: [{
601
+ type: 'text',
602
+ text: JSON.stringify({
603
+ success: false,
604
+ exists: false,
605
+ error: `No trace project found at ${input.projectDir}`,
606
+ }, null, 2),
607
+ }],
608
+ };
609
+ }
610
+ const config = project.config;
611
+ const activeWatchers = listActiveWatchers();
612
+ const isWatching = activeWatchers.includes(project.rootDir);
613
+ let watcherStatus = null;
614
+ if (isWatching) {
615
+ const watcher = getWatcher(project);
616
+ watcherStatus = watcher.getStatus();
617
+ }
618
+ return {
619
+ content: [{
620
+ type: 'text',
621
+ text: JSON.stringify({
622
+ success: true,
623
+ exists: true,
624
+ projectDir: project.rootDir,
625
+ traceDir: project.traceDir,
626
+ config,
627
+ isWatching,
628
+ watcherStatus,
629
+ paths: {
630
+ producer: project.producerPath,
631
+ consumer: project.consumerPath,
632
+ },
633
+ }, null, 2),
634
+ }],
635
+ };
636
+ }
637
+ default:
638
+ throw new Error(`Unknown tool: ${name}`);
639
+ }
640
+ }
641
+ catch (error) {
642
+ const message = error instanceof Error ? error.message : String(error);
643
+ log(`Error in ${name}:`, message);
644
+ return {
645
+ content: [
646
+ {
647
+ type: 'text',
648
+ text: JSON.stringify({
649
+ success: false,
650
+ error: message,
651
+ }),
652
+ },
653
+ ],
654
+ isError: true,
655
+ };
656
+ }
657
+ });
658
+ // Also fix console.log in submodules - redirect to stderr
659
+ const originalLog = console.log;
660
+ console.log = (...args) => {
661
+ console.error(...args);
662
+ };
663
+ // Start server
664
+ async function main() {
665
+ log('Starting trace-mcp server v1.0.0');
666
+ const transport = new StdioServerTransport();
667
+ await server.connect(transport);
668
+ log('Server connected and ready');
669
+ }
670
+ main().catch((error) => {
671
+ console.error('Fatal error:', error);
672
+ process.exit(1);
673
+ });
674
+ //# sourceMappingURL=index.js.map