@nimbus-dev/connectors 0.1.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 (301) hide show
  1. package/LICENSE +662 -0
  2. package/NOTICE +40 -0
  3. package/README.md +111 -0
  4. package/connectors/airflow/nimbus.extension.json +16 -0
  5. package/connectors/airflow/src/search-filter.ts +38 -0
  6. package/connectors/airflow/src/server.ts +91 -0
  7. package/connectors/apple/nimbus.extension.json +40 -0
  8. package/connectors/apple/src/apple-mail-core.ts +43 -0
  9. package/connectors/apple/src/caldav-core.ts +116 -0
  10. package/connectors/apple/src/calendar-tools.ts +278 -0
  11. package/connectors/apple/src/server.ts +541 -0
  12. package/connectors/apple/src/tools.ts +138 -0
  13. package/connectors/argocd/nimbus.extension.json +16 -0
  14. package/connectors/argocd/src/search-filter.ts +24 -0
  15. package/connectors/argocd/src/server.ts +158 -0
  16. package/connectors/athena/nimbus.extension.json +15 -0
  17. package/connectors/athena/src/server.ts +6 -0
  18. package/connectors/athena/src/tools.ts +181 -0
  19. package/connectors/aws/nimbus.extension.json +21 -0
  20. package/connectors/aws/src/server.ts +191 -0
  21. package/connectors/azure/nimbus.extension.json +15 -0
  22. package/connectors/azure/src/server.ts +139 -0
  23. package/connectors/bigeye/nimbus.extension.json +16 -0
  24. package/connectors/bigeye/src/search-filter.ts +22 -0
  25. package/connectors/bigeye/src/server.ts +161 -0
  26. package/connectors/bigquery/nimbus.extension.json +15 -0
  27. package/connectors/bigquery/src/server.ts +6 -0
  28. package/connectors/bigquery/src/tools.ts +175 -0
  29. package/connectors/bitbucket/nimbus.extension.json +15 -0
  30. package/connectors/bitbucket/src/server.ts +252 -0
  31. package/connectors/bitrise/nimbus.extension.json +15 -0
  32. package/connectors/bitrise/src/search-filter.ts +11 -0
  33. package/connectors/bitrise/src/server.ts +83 -0
  34. package/connectors/canva/nimbus.extension.json +15 -0
  35. package/connectors/canva/src/search-filter.ts +23 -0
  36. package/connectors/canva/src/server.ts +77 -0
  37. package/connectors/circleci/nimbus.extension.json +15 -0
  38. package/connectors/circleci/src/server.ts +184 -0
  39. package/connectors/cloud-logging/nimbus.extension.json +15 -0
  40. package/connectors/cloud-logging/src/server.ts +6 -0
  41. package/connectors/cloud-logging/src/tools.ts +115 -0
  42. package/connectors/cloudwatch/nimbus.extension.json +15 -0
  43. package/connectors/cloudwatch/src/server.ts +6 -0
  44. package/connectors/cloudwatch/src/tools.ts +144 -0
  45. package/connectors/codemagic/nimbus.extension.json +15 -0
  46. package/connectors/codemagic/src/search-filter.ts +11 -0
  47. package/connectors/codemagic/src/server.ts +74 -0
  48. package/connectors/confluence/nimbus.extension.json +15 -0
  49. package/connectors/confluence/src/kb-append.ts +25 -0
  50. package/connectors/confluence/src/server.ts +309 -0
  51. package/connectors/dagster/nimbus.extension.json +16 -0
  52. package/connectors/dagster/src/search-filter.ts +53 -0
  53. package/connectors/dagster/src/server.ts +218 -0
  54. package/connectors/databricks/nimbus.extension.json +16 -0
  55. package/connectors/databricks/src/search-filter.ts +28 -0
  56. package/connectors/databricks/src/server.ts +81 -0
  57. package/connectors/datadog/nimbus.extension.json +15 -0
  58. package/connectors/datadog/src/server.ts +56 -0
  59. package/connectors/dataprofile/nimbus.extension.json +16 -0
  60. package/connectors/dataprofile/src/profile.ts +298 -0
  61. package/connectors/dataprofile/src/server.ts +6 -0
  62. package/connectors/dataprofile/src/tools.ts +69 -0
  63. package/connectors/dbt/nimbus.extension.json +16 -0
  64. package/connectors/dbt/src/search-filter.ts +28 -0
  65. package/connectors/dbt/src/server.ts +96 -0
  66. package/connectors/dependencytrack/nimbus.extension.json +16 -0
  67. package/connectors/dependencytrack/src/search-filter.ts +24 -0
  68. package/connectors/dependencytrack/src/server.ts +80 -0
  69. package/connectors/discord/nimbus.extension.json +15 -0
  70. package/connectors/discord/src/server.ts +93 -0
  71. package/connectors/elasticsearch/nimbus.extension.json +16 -0
  72. package/connectors/elasticsearch/src/server.ts +6 -0
  73. package/connectors/elasticsearch/src/tools.ts +110 -0
  74. package/connectors/fastmail/nimbus.extension.json +16 -0
  75. package/connectors/fastmail/src/jmap-core.ts +86 -0
  76. package/connectors/fastmail/src/server.ts +194 -0
  77. package/connectors/fastmail/src/tools.ts +143 -0
  78. package/connectors/figma/nimbus.extension.json +15 -0
  79. package/connectors/figma/src/search-filter.ts +24 -0
  80. package/connectors/figma/src/server.ts +117 -0
  81. package/connectors/firebase/nimbus.extension.json +15 -0
  82. package/connectors/firebase/src/search-filter.ts +30 -0
  83. package/connectors/firebase/src/server.ts +94 -0
  84. package/connectors/firebase/src/token.ts +41 -0
  85. package/connectors/flagsmith/nimbus.extension.json +15 -0
  86. package/connectors/flagsmith/src/search-filter.ts +29 -0
  87. package/connectors/flagsmith/src/server.ts +102 -0
  88. package/connectors/flux/nimbus.extension.json +16 -0
  89. package/connectors/flux/src/search-filter.ts +42 -0
  90. package/connectors/flux/src/server.ts +182 -0
  91. package/connectors/gcp/nimbus.extension.json +15 -0
  92. package/connectors/gcp/src/server.ts +140 -0
  93. package/connectors/github/nimbus.extension.json +15 -0
  94. package/connectors/github/src/server.ts +347 -0
  95. package/connectors/github-actions/nimbus.extension.json +15 -0
  96. package/connectors/github-actions/src/server.ts +213 -0
  97. package/connectors/gitlab/nimbus.extension.json +15 -0
  98. package/connectors/gitlab/src/server.ts +392 -0
  99. package/connectors/gmail/nimbus.extension.json +15 -0
  100. package/connectors/gmail/src/server.ts +277 -0
  101. package/connectors/google-drive/nimbus.extension.json +15 -0
  102. package/connectors/google-drive/src/drive-query.ts +3 -0
  103. package/connectors/google-drive/src/server.ts +531 -0
  104. package/connectors/google-meet/nimbus.extension.json +15 -0
  105. package/connectors/google-meet/src/server.ts +89 -0
  106. package/connectors/google-photos/nimbus.extension.json +15 -0
  107. package/connectors/google-photos/src/server.ts +139 -0
  108. package/connectors/grafana/nimbus.extension.json +15 -0
  109. package/connectors/grafana/src/server.ts +61 -0
  110. package/connectors/great-expectations/nimbus.extension.json +16 -0
  111. package/connectors/great-expectations/src/gx-parse.ts +292 -0
  112. package/connectors/great-expectations/src/server.ts +6 -0
  113. package/connectors/great-expectations/src/tools.ts +91 -0
  114. package/connectors/greenhouse/nimbus.extension.json +15 -0
  115. package/connectors/greenhouse/src/search-filter.ts +65 -0
  116. package/connectors/greenhouse/src/server.ts +67 -0
  117. package/connectors/hubspot/nimbus.extension.json +15 -0
  118. package/connectors/hubspot/src/search-filter.ts +28 -0
  119. package/connectors/hubspot/src/server.ts +81 -0
  120. package/connectors/iac/nimbus.extension.json +14 -0
  121. package/connectors/iac/src/server.ts +145 -0
  122. package/connectors/imap/nimbus.extension.json +16 -0
  123. package/connectors/imap/src/imap-core.ts +110 -0
  124. package/connectors/imap/src/server.ts +232 -0
  125. package/connectors/imap/src/tools.ts +40 -0
  126. package/connectors/intercom/nimbus.extension.json +15 -0
  127. package/connectors/intercom/src/search-filter.ts +46 -0
  128. package/connectors/intercom/src/server.ts +65 -0
  129. package/connectors/jenkins/nimbus.extension.json +15 -0
  130. package/connectors/jenkins/src/jenkins-api.ts +156 -0
  131. package/connectors/jenkins/src/server.ts +223 -0
  132. package/connectors/jira/nimbus.extension.json +15 -0
  133. package/connectors/jira/src/server.ts +309 -0
  134. package/connectors/kubernetes/nimbus.extension.json +15 -0
  135. package/connectors/kubernetes/src/server.ts +163 -0
  136. package/connectors/launchdarkly/nimbus.extension.json +15 -0
  137. package/connectors/launchdarkly/src/search-filter.ts +31 -0
  138. package/connectors/launchdarkly/src/server.ts +79 -0
  139. package/connectors/lever/nimbus.extension.json +15 -0
  140. package/connectors/lever/src/search-filter.ts +35 -0
  141. package/connectors/lever/src/server.ts +64 -0
  142. package/connectors/linear/nimbus.extension.json +15 -0
  143. package/connectors/linear/src/server.ts +467 -0
  144. package/connectors/localdb/nimbus.extension.json +16 -0
  145. package/connectors/localdb/src/server.ts +6 -0
  146. package/connectors/localdb/src/sql-scan.ts +158 -0
  147. package/connectors/localdb/src/tools.ts +67 -0
  148. package/connectors/looker/nimbus.extension.json +16 -0
  149. package/connectors/looker/src/search-filter.ts +22 -0
  150. package/connectors/looker/src/server.ts +254 -0
  151. package/connectors/mendeley/nimbus.extension.json +15 -0
  152. package/connectors/mendeley/src/search-filter.ts +68 -0
  153. package/connectors/mendeley/src/server.ts +59 -0
  154. package/connectors/mercury/nimbus.extension.json +15 -0
  155. package/connectors/mercury/src/search-filter.ts +11 -0
  156. package/connectors/mercury/src/server.ts +61 -0
  157. package/connectors/metabase/nimbus.extension.json +16 -0
  158. package/connectors/metabase/src/search-filter.ts +22 -0
  159. package/connectors/metabase/src/server.ts +83 -0
  160. package/connectors/miro/nimbus.extension.json +15 -0
  161. package/connectors/miro/src/search-filter.ts +24 -0
  162. package/connectors/miro/src/server.ts +76 -0
  163. package/connectors/mlflow/nimbus.extension.json +16 -0
  164. package/connectors/mlflow/src/search-filter.ts +38 -0
  165. package/connectors/mlflow/src/server.ts +167 -0
  166. package/connectors/monte-carlo/nimbus.extension.json +16 -0
  167. package/connectors/monte-carlo/src/search-filter.ts +11 -0
  168. package/connectors/monte-carlo/src/server.ts +241 -0
  169. package/connectors/netlify/nimbus.extension.json +15 -0
  170. package/connectors/netlify/src/search-filter.ts +37 -0
  171. package/connectors/netlify/src/server.ts +64 -0
  172. package/connectors/newrelic/nimbus.extension.json +15 -0
  173. package/connectors/newrelic/src/server.ts +48 -0
  174. package/connectors/notion/nimbus.extension.json +15 -0
  175. package/connectors/notion/src/kb-append.ts +23 -0
  176. package/connectors/notion/src/server.ts +343 -0
  177. package/connectors/obsidian/nimbus.extension.json +19 -0
  178. package/connectors/obsidian/src/server.ts +433 -0
  179. package/connectors/onedrive/nimbus.extension.json +15 -0
  180. package/connectors/onedrive/src/server.ts +256 -0
  181. package/connectors/outlook/nimbus.extension.json +15 -0
  182. package/connectors/outlook/src/server.ts +358 -0
  183. package/connectors/outlook/src/tool-scope-policy.ts +53 -0
  184. package/connectors/pagerduty/nimbus.extension.json +15 -0
  185. package/connectors/pagerduty/src/server.ts +140 -0
  186. package/connectors/pipedrive/nimbus.extension.json +15 -0
  187. package/connectors/pipedrive/src/search-filter.ts +11 -0
  188. package/connectors/pipedrive/src/server.ts +62 -0
  189. package/connectors/powerbi/nimbus.extension.json +16 -0
  190. package/connectors/powerbi/src/search-filter.ts +22 -0
  191. package/connectors/powerbi/src/server.ts +249 -0
  192. package/connectors/prefect/nimbus.extension.json +16 -0
  193. package/connectors/prefect/src/search-filter.ts +40 -0
  194. package/connectors/prefect/src/server.ts +94 -0
  195. package/connectors/protonmail/nimbus.extension.json +16 -0
  196. package/connectors/protonmail/src/mail-core.ts +96 -0
  197. package/connectors/protonmail/src/server.ts +231 -0
  198. package/connectors/protonmail/src/tools.ts +45 -0
  199. package/connectors/raindrop/nimbus.extension.json +15 -0
  200. package/connectors/raindrop/src/search-filter.ts +20 -0
  201. package/connectors/raindrop/src/server.ts +107 -0
  202. package/connectors/ramp/nimbus.extension.json +15 -0
  203. package/connectors/ramp/src/search-filter.ts +37 -0
  204. package/connectors/ramp/src/server.ts +109 -0
  205. package/connectors/readwise/nimbus.extension.json +15 -0
  206. package/connectors/readwise/src/search-filter.ts +64 -0
  207. package/connectors/readwise/src/server.ts +92 -0
  208. package/connectors/sagemaker/nimbus.extension.json +15 -0
  209. package/connectors/sagemaker/src/server.ts +6 -0
  210. package/connectors/sagemaker/src/tools.ts +121 -0
  211. package/connectors/salesforce/nimbus.extension.json +15 -0
  212. package/connectors/salesforce/src/search-filter.ts +23 -0
  213. package/connectors/salesforce/src/server.ts +94 -0
  214. package/connectors/semgrep/nimbus.extension.json +15 -0
  215. package/connectors/semgrep/src/search-filter.ts +31 -0
  216. package/connectors/semgrep/src/server.ts +108 -0
  217. package/connectors/sentry/nimbus.extension.json +15 -0
  218. package/connectors/sentry/src/server.ts +66 -0
  219. package/connectors/slack/nimbus.extension.json +15 -0
  220. package/connectors/slack/src/server.ts +360 -0
  221. package/connectors/snowflake/nimbus.extension.json +16 -0
  222. package/connectors/snowflake/src/search-filter.ts +26 -0
  223. package/connectors/snowflake/src/server.ts +236 -0
  224. package/connectors/snyk/nimbus.extension.json +15 -0
  225. package/connectors/snyk/src/search-filter.ts +28 -0
  226. package/connectors/snyk/src/server.ts +144 -0
  227. package/connectors/sonarqube/nimbus.extension.json +15 -0
  228. package/connectors/sonarqube/src/search-filter.ts +28 -0
  229. package/connectors/sonarqube/src/server.ts +115 -0
  230. package/connectors/stackoverflow/nimbus.extension.json +15 -0
  231. package/connectors/stackoverflow/src/search-filter.ts +52 -0
  232. package/connectors/stackoverflow/src/server.ts +81 -0
  233. package/connectors/storybook/nimbus.extension.json +16 -0
  234. package/connectors/storybook/src/server.ts +6 -0
  235. package/connectors/storybook/src/storybook-parse.ts +67 -0
  236. package/connectors/storybook/src/tools.ts +68 -0
  237. package/connectors/stripe/nimbus.extension.json +15 -0
  238. package/connectors/stripe/src/search-filter.ts +19 -0
  239. package/connectors/stripe/src/server.ts +65 -0
  240. package/connectors/superset/nimbus.extension.json +16 -0
  241. package/connectors/superset/src/search-filter.ts +22 -0
  242. package/connectors/superset/src/server.ts +119 -0
  243. package/connectors/tableau/nimbus.extension.json +16 -0
  244. package/connectors/tableau/src/search-filter.ts +22 -0
  245. package/connectors/tableau/src/server.ts +248 -0
  246. package/connectors/teams/nimbus.extension.json +20 -0
  247. package/connectors/teams/src/bot-send.ts +72 -0
  248. package/connectors/teams/src/server.ts +257 -0
  249. package/connectors/testflight/nimbus.extension.json +15 -0
  250. package/connectors/testflight/src/jwt.ts +27 -0
  251. package/connectors/testflight/src/search-filter.ts +30 -0
  252. package/connectors/testflight/src/server.ts +74 -0
  253. package/connectors/vercel/nimbus.extension.json +15 -0
  254. package/connectors/vercel/src/search-filter.ts +34 -0
  255. package/connectors/vercel/src/server.ts +79 -0
  256. package/connectors/vertex-ai/nimbus.extension.json +15 -0
  257. package/connectors/vertex-ai/src/server.ts +6 -0
  258. package/connectors/vertex-ai/src/tools.ts +145 -0
  259. package/connectors/wiz/nimbus.extension.json +15 -0
  260. package/connectors/wiz/src/search-filter.ts +50 -0
  261. package/connectors/wiz/src/server.ts +192 -0
  262. package/connectors/workday/nimbus.extension.json +19 -0
  263. package/connectors/workday/src/search-filter.ts +5 -0
  264. package/connectors/workday/src/server.ts +78 -0
  265. package/connectors/workday/src/tools.ts +1 -0
  266. package/connectors/zendesk/nimbus.extension.json +16 -0
  267. package/connectors/zendesk/src/search-filter.ts +11 -0
  268. package/connectors/zendesk/src/server.ts +77 -0
  269. package/connectors/zoom/nimbus.extension.json +15 -0
  270. package/connectors/zoom/src/encode-meeting-path.ts +5 -0
  271. package/connectors/zoom/src/recordings-window.ts +34 -0
  272. package/connectors/zoom/src/search-filter.ts +42 -0
  273. package/connectors/zoom/src/server.ts +98 -0
  274. package/connectors/zotero/nimbus.extension.json +15 -0
  275. package/connectors/zotero/src/search-filter.ts +81 -0
  276. package/connectors/zotero/src/server.ts +82 -0
  277. package/package.json +152 -0
  278. package/shared/atlassian-json-fetch.ts +42 -0
  279. package/shared/audit-chain.ts +133 -0
  280. package/shared/connector-mode.ts +60 -0
  281. package/shared/consent-kit.ts +323 -0
  282. package/shared/fetch-bearer-json.ts +18 -0
  283. package/shared/header-safe.ts +28 -0
  284. package/shared/imap-bodystructure.ts +113 -0
  285. package/shared/imap-mail-core.ts +57 -0
  286. package/shared/imap-tool-kit.ts +293 -0
  287. package/shared/join-api-path.ts +18 -0
  288. package/shared/kb-markdown.ts +142 -0
  289. package/shared/mcp-search-tool.ts +37 -0
  290. package/shared/mcp-tool-kit.ts +35 -0
  291. package/shared/nimbus-spawn.ts +128 -0
  292. package/shared/rest-tool-kit.ts +18 -0
  293. package/shared/run-cli-json.ts +55 -0
  294. package/shared/run-read-only-mcp-connector.ts +59 -0
  295. package/shared/safe-cli-arg.ts +55 -0
  296. package/shared/search-filter.ts +140 -0
  297. package/shared/strip-trailing-slashes.ts +7 -0
  298. package/shared/write-scope.ts +58 -0
  299. package/standalone/src/bin.ts +19 -0
  300. package/standalone/src/launcher.ts +186 -0
  301. package/standalone/tsconfig.json +8 -0
@@ -0,0 +1,67 @@
1
+ import { z } from "zod";
2
+ import { mcpJsonResult as jsonResult } from "../../../shared/mcp-tool-kit.ts";
3
+ import type { ZodToolRegistrar } from "../../../shared/run-read-only-mcp-connector.ts";
4
+ import {
5
+ filterSavedQueries,
6
+ getSavedQuery,
7
+ type SavedQuery,
8
+ scanSavedQueries,
9
+ } from "./sql-scan.ts";
10
+
11
+ /**
12
+ * Local DB Schema Indexing MCP tool surface. Reads saved `.sql` queries from the
13
+ * configured local DB-tool scripts dir — a pure filesystem read. No database is
14
+ * connected to and no query is executed; the SQL TEXT is returned for recall.
15
+ */
16
+ export const LOCALDB_TOOL_NAMES = ["localdb_list", "localdb_get", "localdb_search"] as const;
17
+
18
+ function toEnvelope(q: SavedQuery): Record<string, unknown> {
19
+ return {
20
+ relativePath: q.relativePath,
21
+ title: q.title,
22
+ sizeBytes: q.sizeBytes,
23
+ lineCount: q.lineCount,
24
+ sql: q.preview,
25
+ };
26
+ }
27
+
28
+ /**
29
+ * Register the read-only local-DB saved-query tools onto the given registrar.
30
+ * Shared between `server.ts` (live) and the contract test (introspection).
31
+ */
32
+ export function registerLocaldbTools(reg: ZodToolRegistrar): void {
33
+ reg(
34
+ "localdb_list",
35
+ "List saved SQL queries read from the configured local DB-tool scripts directory (DBeaver/DataGrip/pgAdmin). Returns each query's relative path, title, size, line count, and SQL text. A pure filesystem read — no database is connected to and no query is executed.",
36
+ z.object({ limit: z.number().int().min(1).max(500).optional() }),
37
+ async (p) => {
38
+ const all = await scanSavedQueries();
39
+ const limit = p.limit ?? 100;
40
+ return jsonResult({ items: all.slice(0, limit).map(toEnvelope) });
41
+ },
42
+ );
43
+
44
+ reg(
45
+ "localdb_get",
46
+ "Fetch one saved SQL query by its relative path (within the configured scripts dir). Returns the SQL text + metadata. Never connects to a database.",
47
+ z.object({ relativePath: z.string().min(1).max(1024) }),
48
+ async (p) => {
49
+ const q = await getSavedQuery(p.relativePath);
50
+ return jsonResult(q === null ? { item: null } : { item: toEnvelope(q) });
51
+ },
52
+ );
53
+
54
+ reg(
55
+ "localdb_search",
56
+ "Substring search over saved SQL queries (matches the title, relative path, and SQL text). Returns the same view as localdb_list. Searches local files only.",
57
+ z.object({
58
+ query: z.string().min(1).max(500),
59
+ limit: z.number().int().min(1).max(500).optional(),
60
+ }),
61
+ async (p) => {
62
+ const all = await scanSavedQueries();
63
+ const matches = filterSavedQueries(all, p.query).slice(0, p.limit ?? 100);
64
+ return jsonResult({ matches: matches.map(toEnvelope) });
65
+ },
66
+ );
67
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "id": "com.nimbus.looker",
3
+ "displayName": "Looker",
4
+ "version": "0.1.0",
5
+ "description": "Looker connector. Indexes Looker dashboards and LookML views as `looker:dashboard` and `looker:data_model` items in the local index and exposes read tools (`looker_list`, `looker_get`, `looker_search`) plus HITL-gated write tools (`looker_datagroup_trigger`, `looker_schedule_run_once`). Uses the Looker API 4.0 with OAuth2 client-credentials auth (POST /api/4.0/login). The per-tenant base URL is supplied via the `looker.base_url` vault key and its hostname is added to the sandbox network list at spawn time by `phase3AddLookerMcp`, so the static manifest network list is intentionally empty. LookML view sql_table_name fields are normalized via normalizeDataModelKey to produce cross-connector lineage edges (Looker→dbt).",
6
+ "author": "Nimbus",
7
+ "entrypoint": "dist/server.js",
8
+ "runtime": "bun",
9
+ "permissions": {
10
+ "network": [],
11
+ "filesystem": { "read": [], "write": [] }
12
+ },
13
+ "hitlRequired": ["write"],
14
+ "syncInterval": 600,
15
+ "minNimbusVersion": "0.5.0"
16
+ }
@@ -0,0 +1,22 @@
1
+ import {
2
+ asRecord,
3
+ makeQueryFilter,
4
+ type SearchMatchOptions,
5
+ } from "../../../shared/search-filter.ts";
6
+
7
+ export type LookerSearchMatchOptions = SearchMatchOptions;
8
+
9
+ function stringAt(row: Record<string, unknown>, key: string): string {
10
+ const v = row[key];
11
+ return typeof v === "string" ? v : "";
12
+ }
13
+
14
+ function fieldsOf(item: unknown): readonly string[] | null {
15
+ const row = asRecord(item);
16
+ if (row === undefined) {
17
+ return null;
18
+ }
19
+ return [stringAt(row, "title"), stringAt(row, "id")];
20
+ }
21
+
22
+ export const filterLookerDashboards = makeQueryFilter(fieldsOf);
@@ -0,0 +1,254 @@
1
+ import { z } from "zod";
2
+ import { type ConsentServer, createWriteToolRegistrar } from "../../../shared/consent-kit.ts";
3
+ import { searchToolInputSchema } from "../../../shared/mcp-search-tool.ts";
4
+ import { fetchWithTimeout, mcpJsonResult as jsonResult } from "../../../shared/mcp-tool-kit.ts";
5
+ import {
6
+ runReadOnlyMcpConnector,
7
+ type ZodToolRegistrar,
8
+ } from "../../../shared/run-read-only-mcp-connector.ts";
9
+ import { filterLookerDashboards } from "./search-filter.ts";
10
+
11
+ function trimTrailingSlash(s: string): string {
12
+ return s.endsWith("/") ? s.slice(0, -1) : s;
13
+ }
14
+
15
+ function apiBase(): string {
16
+ const v = process.env["LOOKER_BASE_URL"]?.trim();
17
+ if (v === undefined || v === "") {
18
+ throw new Error("LOOKER_BASE_URL is not set");
19
+ }
20
+ return trimTrailingSlash(v);
21
+ }
22
+
23
+ function clientId(): string {
24
+ const v = process.env["LOOKER_CLIENT_ID"]?.trim();
25
+ if (v === undefined || v === "") {
26
+ throw new Error("LOOKER_CLIENT_ID is not set");
27
+ }
28
+ return v;
29
+ }
30
+
31
+ function clientSecret(): string {
32
+ const v = process.env["LOOKER_CLIENT_SECRET"]?.trim();
33
+ if (v === undefined || v === "") {
34
+ throw new Error("LOOKER_CLIENT_SECRET is not set");
35
+ }
36
+ return v;
37
+ }
38
+
39
+ async function lookerLogin(): Promise<string> {
40
+ const base = apiBase();
41
+ const body = `client_id=${encodeURIComponent(clientId())}&client_secret=${encodeURIComponent(clientSecret())}`;
42
+ const res = await fetchWithTimeout(`${base}/api/4.0/login`, {
43
+ method: "POST",
44
+ headers: {
45
+ "Content-Type": "application/x-www-form-urlencoded",
46
+ Accept: "application/json",
47
+ },
48
+ body,
49
+ });
50
+ const text = await res.text();
51
+ if (!res.ok) {
52
+ throw new Error(`Looker login ${String(res.status)}: ${text.slice(0, 400)}`);
53
+ }
54
+ const parsed = JSON.parse(text) as unknown;
55
+ const root =
56
+ parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)
57
+ ? (parsed as Record<string, unknown>)
58
+ : null;
59
+ const token = typeof root?.["access_token"] === "string" ? root["access_token"] : null;
60
+ if (token === null || token === "") {
61
+ throw new Error("Looker login response missing access_token");
62
+ }
63
+ return token;
64
+ }
65
+
66
+ /** GET a Looker collection as a bare array. With a `page`, adds `?limit&offset`; else the default page. */
67
+ async function getArray(
68
+ token: string,
69
+ path: string,
70
+ page?: { limit: number; offset: number },
71
+ ): Promise<unknown[]> {
72
+ const base = apiBase();
73
+ const qs = page === undefined ? "" : `?limit=${page.limit}&offset=${page.offset}`;
74
+ const res = await fetchWithTimeout(`${base}${path}${qs}`, {
75
+ headers: { Authorization: `Bearer ${token}`, Accept: "application/json" },
76
+ });
77
+ const text = await res.text();
78
+ if (!res.ok) {
79
+ throw new Error(`Looker ${path} ${String(res.status)}: ${text.slice(0, 400)}`);
80
+ }
81
+ const parsed = JSON.parse(text) as unknown;
82
+ return Array.isArray(parsed) ? parsed : [];
83
+ }
84
+
85
+ async function listDashboards(token: string): Promise<unknown[]> {
86
+ return getArray(token, "/api/4.0/dashboards");
87
+ }
88
+
89
+ /** Resolve an opaque offset cursor; null / "" / undefined → 0. */
90
+ function offsetCursor(cursor: string | null | undefined): number {
91
+ return cursor === null || cursor === undefined || cursor === ""
92
+ ? 0
93
+ : Math.max(0, Number.parseInt(cursor, 10) || 0);
94
+ }
95
+
96
+ export function registerLookerTools(reg: ZodToolRegistrar, server: unknown): void {
97
+ // Despite the read-only helper's name, this connector exposes write tools. The consent
98
+ // kit needs the real server, which the helper now passes through as its second argument.
99
+ const registerWriteTool = createWriteToolRegistrar(server as ConsentServer, {
100
+ connector: "looker",
101
+ scopeEnv: "NIMBUS_MCP_LOOKER_WRITE_SCOPE",
102
+ scopeKinds: ["resource"],
103
+ });
104
+
105
+ reg(
106
+ "looker_list",
107
+ "List Looker dashboards (`GET /api/4.0/dashboards`). Requires a client-credentials login first. Paginated: `cursor` (opaque offset) + `limit` (default 200, max 500) → `{ items, nextCursor }`.",
108
+ z.object({
109
+ cursor: z.string().nullable().optional(),
110
+ limit: z.number().int().min(1).max(500).optional(),
111
+ }),
112
+ async (p) => {
113
+ const limit = p.limit ?? 200;
114
+ const offset = offsetCursor(p.cursor);
115
+ const token = await lookerLogin();
116
+ const items = await getArray(token, "/api/4.0/dashboards", { limit, offset });
117
+ return jsonResult({
118
+ items,
119
+ nextCursor: items.length === limit ? String(offset + limit) : null,
120
+ });
121
+ },
122
+ );
123
+
124
+ reg(
125
+ "looker_models_list",
126
+ "List LookML models (`GET /api/4.0/lookml_models`) for dashboard→table lineage. Paginated: `cursor` (opaque offset) + `limit` (default 200, max 500) → `{ items, nextCursor }`. Returns raw models (explores/views nested); the gateway flattens them.",
127
+ z.object({
128
+ cursor: z.string().nullable().optional(),
129
+ limit: z.number().int().min(1).max(500).optional(),
130
+ }),
131
+ async (p) => {
132
+ const limit = p.limit ?? 200;
133
+ const offset = offsetCursor(p.cursor);
134
+ const token = await lookerLogin();
135
+ const items = await getArray(token, "/api/4.0/lookml_models", { limit, offset });
136
+ return jsonResult({
137
+ items,
138
+ nextCursor: items.length === limit ? String(offset + limit) : null,
139
+ });
140
+ },
141
+ );
142
+
143
+ reg(
144
+ "looker_get",
145
+ "Fetch one Looker dashboard by its id. Throws when no dashboard with that id exists.",
146
+ z.object({
147
+ id: z.string().min(1),
148
+ }),
149
+ async (p) => {
150
+ const token = await lookerLogin();
151
+ const dashboards = await listDashboards(token);
152
+ const found = dashboards.find((d) => {
153
+ const obj =
154
+ d !== null && typeof d === "object" && !Array.isArray(d)
155
+ ? (d as Record<string, unknown>)
156
+ : null;
157
+ return obj?.["id"] === p.id;
158
+ });
159
+ if (found === undefined) {
160
+ throw new Error(`Looker dashboard not found: ${p.id}`);
161
+ }
162
+ return jsonResult(found);
163
+ },
164
+ );
165
+
166
+ reg(
167
+ "looker_search",
168
+ "Substring search across Looker dashboards. Matches the query (case-insensitive) against dashboard title and id. Returns a `{ matches: [...] }` envelope.",
169
+ searchToolInputSchema(200),
170
+ async (p) => {
171
+ const token = await lookerLogin();
172
+ const dashboards = await listDashboards(token);
173
+ const matches = filterLookerDashboards(dashboards, { query: p.query, limit: p.limit });
174
+ return jsonResult({ matches });
175
+ },
176
+ );
177
+
178
+ registerWriteTool(
179
+ "looker_datagroup_trigger",
180
+ {
181
+ mutates: "looker.datagroup.trigger",
182
+ recoverable: true,
183
+ scopeTargetOf: (p) => ({ kind: "resource", value: p.datagroupId }),
184
+ },
185
+ "Invalidate a Looker datagroup to force a PDT/cache rebuild (`PATCH /api/4.0/datagroups/{datagroupId}`). Sets `stale_before` to the current epoch so all cached results are considered stale. Requires HITL approval.",
186
+ z.object({
187
+ datagroupId: z.string().min(1),
188
+ }),
189
+ async (p) => {
190
+ const token = await lookerLogin();
191
+ const base = apiBase();
192
+ const epochSeconds = Math.floor(Date.now() / 1000);
193
+ const res = await fetchWithTimeout(
194
+ `${base}/api/4.0/datagroups/${encodeURIComponent(p.datagroupId)}`,
195
+ {
196
+ method: "PATCH",
197
+ headers: {
198
+ Authorization: `Bearer ${token}`,
199
+ "Content-Type": "application/json",
200
+ Accept: "application/json",
201
+ },
202
+ body: JSON.stringify({ stale_before: epochSeconds }),
203
+ },
204
+ );
205
+ const text = await res.text();
206
+ if (!res.ok) {
207
+ throw new Error(`Looker datagroup trigger ${res.status}: ${text.slice(0, 400)}`);
208
+ }
209
+ return jsonResult({ status: "ok", datagroupId: p.datagroupId });
210
+ },
211
+ );
212
+
213
+ registerWriteTool(
214
+ "looker_schedule_run_once",
215
+ {
216
+ mutates: "looker.schedule.run_once",
217
+ recoverable: true,
218
+ scopeTargetOf: (p) => ({ kind: "resource", value: p.scheduledPlanId }),
219
+ },
220
+ "Run a Looker scheduled plan immediately (`POST /api/4.0/scheduled_plans/{scheduledPlanId}/run_once`). Triggers a one-off execution of the plan outside its normal schedule. Requires HITL approval.",
221
+ z.object({
222
+ scheduledPlanId: z.string().min(1),
223
+ }),
224
+ async (p) => {
225
+ const token = await lookerLogin();
226
+ const base = apiBase();
227
+ const res = await fetchWithTimeout(
228
+ `${base}/api/4.0/scheduled_plans/${encodeURIComponent(p.scheduledPlanId)}/run_once`,
229
+ {
230
+ method: "POST",
231
+ headers: {
232
+ Authorization: `Bearer ${token}`,
233
+ "Content-Type": "application/json",
234
+ Accept: "application/json",
235
+ },
236
+ body: JSON.stringify({}),
237
+ },
238
+ );
239
+ const text = await res.text();
240
+ if (!res.ok) {
241
+ throw new Error(`Looker schedule run_once ${res.status}: ${text.slice(0, 400)}`);
242
+ }
243
+ return jsonResult({ status: "queued", scheduledPlanId: p.scheduledPlanId });
244
+ },
245
+ );
246
+ }
247
+
248
+ // Exported so the bundled-connector registry can start this server explicitly: `import.meta.main`
249
+ // is false under an import, and the module must stay importable by tests without connecting stdio.
250
+ export async function startConnector(): Promise<void> {
251
+ await runReadOnlyMcpConnector("nimbus-looker", registerLookerTools);
252
+ }
253
+
254
+ if (import.meta.main) await startConnector();
@@ -0,0 +1,15 @@
1
+ {
2
+ "id": "com.nimbus.mendeley",
3
+ "displayName": "Mendeley",
4
+ "version": "0.1.0",
5
+ "description": "Mendeley connector (read-only). Surfaces the metadata of the user's Mendeley reference library as `mendeley:reference` items in the local index — the title, the author list, the publication year, the source/publication, the document type, keywords, the DOI/identifiers, the source URL, and a truncated abstract. Binary PDF attachments are never fetched or parsed. Useful for research questions (\"what did I save about retrieval-augmented generation?\") without leaving Nimbus. Authenticates via the Elsevier OAuth2 authorization-code flow (confidential client); the user supplies their own NIMBUS_OAUTH_MENDELEY_CLIENT_ID / _SECRET. The SaaS host (api.mendeley.com) is fixed. The /documents endpoint paginates via RFC 5988 Link headers (rel=\"next\"); the connector walks a single page-capped forward pass per cycle and supports modified_since incremental pulls.",
6
+ "author": "Nimbus",
7
+ "entrypoint": "dist/server.js",
8
+ "runtime": "bun",
9
+ "permissions": {
10
+ "network": ["api.mendeley.com"]
11
+ },
12
+ "hitlRequired": [],
13
+ "syncInterval": 600,
14
+ "minNimbusVersion": "0.2.0"
15
+ }
@@ -0,0 +1,68 @@
1
+ import {
2
+ asObjectish,
3
+ makeQueryFilter,
4
+ type SearchMatchOptions,
5
+ stringField,
6
+ } from "../../../shared/search-filter.ts";
7
+
8
+ export type MendeleySearchMatchOptions = SearchMatchOptions;
9
+
10
+ function nonEmptyString(v: unknown): string | null {
11
+ return typeof v === "string" && v !== "" ? v : null;
12
+ }
13
+
14
+ function authorName(a: unknown): string | null {
15
+ if (a === null || typeof a !== "object") {
16
+ return null;
17
+ }
18
+ const row = a as Record<string, unknown>;
19
+ const parts = [nonEmptyString(row["first_name"]), nonEmptyString(row["last_name"])].filter(
20
+ (p): p is string => p !== null,
21
+ );
22
+ return parts.length > 0 ? parts.join(" ") : null;
23
+ }
24
+
25
+ function authorNames(doc: Record<string, unknown>): string {
26
+ const authors = doc["authors"];
27
+ if (!Array.isArray(authors)) {
28
+ return "";
29
+ }
30
+ const names: string[] = [];
31
+ for (const a of authors) {
32
+ const name = authorName(a);
33
+ if (name !== null) {
34
+ names.push(name);
35
+ }
36
+ }
37
+ return names.join(" ");
38
+ }
39
+
40
+ function keywordNames(doc: Record<string, unknown>): string {
41
+ const keywords = doc["keywords"];
42
+ return Array.isArray(keywords)
43
+ ? keywords.filter((k): k is string => typeof k === "string").join(" ")
44
+ : "";
45
+ }
46
+
47
+ function doi(doc: Record<string, unknown>): string {
48
+ const ids = asObjectish(doc["identifiers"]);
49
+ return ids === undefined ? "" : stringField(ids, "doi");
50
+ }
51
+
52
+ function fieldsOf(item: unknown): readonly string[] | null {
53
+ const doc = asObjectish(item);
54
+ if (doc === undefined) {
55
+ return null;
56
+ }
57
+ return [
58
+ stringField(doc, "title"),
59
+ stringField(doc, "type"),
60
+ stringField(doc, "abstract"),
61
+ stringField(doc, "source"),
62
+ doi(doc),
63
+ authorNames(doc),
64
+ keywordNames(doc),
65
+ ];
66
+ }
67
+
68
+ export const filterMendeleyDocuments = makeQueryFilter(fieldsOf);
@@ -0,0 +1,59 @@
1
+ import { z } from "zod";
2
+ import { matchesResult } from "../../../shared/mcp-search-tool.ts";
3
+ import { mcpJsonResult as jsonResult } from "../../../shared/mcp-tool-kit.ts";
4
+ import { runReadOnlyMcpConnector } from "../../../shared/run-read-only-mcp-connector.ts";
5
+ import { filterMendeleyDocuments } from "./search-filter.ts";
6
+
7
+ const BASE = "https://api.mendeley.com";
8
+ const DOC_ACCEPT = "application/vnd.mendeley-document.1+json";
9
+
10
+ function accessToken(): string {
11
+ const t = process.env["MENDELEY_ACCESS_TOKEN"]?.trim();
12
+ if (t === undefined || t === "") {
13
+ throw new Error("MENDELEY_ACCESS_TOKEN is not set");
14
+ }
15
+ return t;
16
+ }
17
+
18
+ async function mendeleyGet(path: string): Promise<unknown> {
19
+ const res = await fetch(`${BASE}${path}`, {
20
+ headers: { Authorization: `Bearer ${accessToken()}`, Accept: DOC_ACCEPT },
21
+ });
22
+ const text = await res.text();
23
+ if (!res.ok) {
24
+ // Include the HTTP status so an expired token (401) surfaces explicitly to the
25
+ // gateway client; matches the zotero server's error shape.
26
+ throw new Error(`Mendeley ${String(res.status)}: ${text.slice(0, 400)}`);
27
+ }
28
+ return JSON.parse(text) as unknown;
29
+ }
30
+
31
+ await runReadOnlyMcpConnector("nimbus-mendeley", (reg) => {
32
+ reg(
33
+ "mendeley_list",
34
+ "List the user's Mendeley library documents (`GET /documents?view=all&limit=100`). Returns the raw JSON array of document objects — each is `{ id, title, type, authors, year, source, identifiers: { doi, ... }, keywords, abstract, last_modified, websites, ... }`.",
35
+ z.object({}),
36
+ async () => {
37
+ return jsonResult(await mendeleyGet(`/documents?view=all&limit=100`));
38
+ },
39
+ );
40
+
41
+ reg(
42
+ "mendeley_get",
43
+ "Fetch one Mendeley document by its id (`GET /documents/{id}?view=all`). Returns the document object directly (NOT wrapped in an array). Throws when no match is found.",
44
+ z.object({ id: z.string().min(1) }),
45
+ async (p) => {
46
+ return jsonResult(await mendeleyGet(`/documents/${encodeURIComponent(p.id)}?view=all`));
47
+ },
48
+ );
49
+
50
+ reg(
51
+ "mendeley_search",
52
+ "Substring search across the first page of the user's library documents. Matches the query against the title, document type, abstract, source, DOI, formatted author names, and keywords (case-insensitive). Returns a `{ matches: [...] }` envelope.",
53
+ z.object({ query: z.string().min(1), limit: z.number().int().min(1).max(100).optional() }),
54
+ async (p) => {
55
+ const root = await mendeleyGet(`/documents?view=all&limit=100`);
56
+ return matchesResult(root, filterMendeleyDocuments, p);
57
+ },
58
+ );
59
+ });
@@ -0,0 +1,15 @@
1
+ {
2
+ "id": "com.nimbus.mercury",
3
+ "displayName": "Mercury",
4
+ "version": "0.1.0",
5
+ "description": "Mercury business-banking connector (read-only). Surfaces the user's bank accounts as `mercury:account` items in the local index — account name, status (active/archived), type/kind (checking/savings), the last 4 digits of the account number (the full number is never stored), routing number, available + current USD balances, the legal business name, and the open date. Useful for answering banking questions (\"what's my checking balance?\", \"which accounts are archived?\") without leaving Nimbus. Bearer API-token auth. The SaaS host (api.mercury.com) is fixed. Mercury balances are USD major units (dollars, not cents) and `createdAt` is ISO-8601 (converted to epoch-ms on index). Transactions / bills / statements and the wire / ACH (HITL) writes are deferred follow-ups.",
6
+ "author": "Nimbus",
7
+ "entrypoint": "dist/server.js",
8
+ "runtime": "bun",
9
+ "permissions": {
10
+ "network": ["api.mercury.com"]
11
+ },
12
+ "hitlRequired": [],
13
+ "syncInterval": 600,
14
+ "minNimbusVersion": "0.2.0"
15
+ }
@@ -0,0 +1,11 @@
1
+ import {
2
+ fieldsFromKeys,
3
+ makeQueryFilter,
4
+ type SearchMatchOptions,
5
+ } from "../../../shared/search-filter.ts";
6
+
7
+ export type MercurySearchMatchOptions = SearchMatchOptions;
8
+
9
+ export const filterMercuryAccounts = makeQueryFilter(
10
+ fieldsFromKeys(["id", "name", "status", "type", "kind", "legalBusinessName"]),
11
+ );
@@ -0,0 +1,61 @@
1
+ import { z } from "zod";
2
+ import { matchesResult, searchToolInputSchema } from "../../../shared/mcp-search-tool.ts";
3
+ import { mcpJsonResult as jsonResult } from "../../../shared/mcp-tool-kit.ts";
4
+ import { runReadOnlyMcpConnector } from "../../../shared/run-read-only-mcp-connector.ts";
5
+ import { filterMercuryAccounts } from "./search-filter.ts";
6
+
7
+ const BASE = "https://api.mercury.com";
8
+
9
+ function apiToken(): string {
10
+ const t = process.env["MERCURY_TOKEN"]?.trim();
11
+ if (t === undefined || t === "") {
12
+ throw new Error("MERCURY_TOKEN is not set");
13
+ }
14
+ return t;
15
+ }
16
+
17
+ function authHeader(): Record<string, string> {
18
+ return { Authorization: `Bearer ${apiToken()}`, Accept: "application/json" };
19
+ }
20
+
21
+ async function mercuryGet(path: string): Promise<unknown> {
22
+ const res = await fetch(`${BASE}${path}`, { headers: authHeader() });
23
+ const text = await res.text();
24
+ if (!res.ok) {
25
+ throw new Error(`Mercury ${String(res.status)}: ${text.slice(0, 400)}`);
26
+ }
27
+ return JSON.parse(text) as unknown;
28
+ }
29
+
30
+ await runReadOnlyMcpConnector("nimbus-mercury", (reg) => {
31
+ reg(
32
+ "mercury_list",
33
+ "List the user's Mercury bank accounts (`GET /api/v1/accounts`). Returns the `{ accounts: [...] }` envelope. There is no pagination — Mercury returns the full account list in one call.",
34
+ z.object({}),
35
+ async () => {
36
+ return jsonResult(await mercuryGet(`/api/v1/accounts`));
37
+ },
38
+ );
39
+
40
+ reg(
41
+ "mercury_get",
42
+ "Fetch one Mercury account by its id (`GET /api/v1/account/{id}`, note the singular `account` in the path). Returns the account object directly. Throws when no match is found.",
43
+ z.object({
44
+ id: z.string().min(1),
45
+ }),
46
+ async (p) => {
47
+ return jsonResult(await mercuryGet(`/api/v1/account/${encodeURIComponent(p.id)}`));
48
+ },
49
+ );
50
+
51
+ reg(
52
+ "mercury_search",
53
+ "Substring search across the user's Mercury accounts. Matches the query against id, name, status, type, kind, and the legal business name (case-insensitive). Returns a `{ matches: [...] }` envelope.",
54
+ searchToolInputSchema(100),
55
+ async (p) => {
56
+ const root = await mercuryGet(`/api/v1/accounts`);
57
+ const accounts = (root as { accounts?: unknown[] } | null)?.accounts;
58
+ return matchesResult(accounts, filterMercuryAccounts, p);
59
+ },
60
+ );
61
+ });
@@ -0,0 +1,16 @@
1
+ {
2
+ "id": "com.nimbus.metabase",
3
+ "displayName": "Metabase",
4
+ "version": "0.1.0",
5
+ "description": "Metabase connector (read-only). Surfaces Metabase dashboards — name, description, collection, creator, archived flag, card count, created/updated timestamps — into the local index as `metabase:dashboard` items, with the dashboard's collection name resolved from a single `GET /api/collection` call. Metabase API-key auth (sent as the `x-api-key` request header, NOT `Authorization`). Metabase has no universal SaaS host: the server host is supplied via the `metabase.url` vault key and added to the sandbox network list at spawn time by `phase3AddMetabaseMcp`, so the static manifest network list is intentionally empty. v1 indexes dashboards only — saved questions (cards) and collections-as-items are a deferred follow-up. No write tools.",
6
+ "author": "Nimbus",
7
+ "entrypoint": "dist/server.js",
8
+ "runtime": "bun",
9
+ "permissions": {
10
+ "network": [],
11
+ "filesystem": { "read": [], "write": [] }
12
+ },
13
+ "hitlRequired": [],
14
+ "syncInterval": 600,
15
+ "minNimbusVersion": "0.2.0"
16
+ }
@@ -0,0 +1,22 @@
1
+ import {
2
+ asRecord,
3
+ makeQueryFilter,
4
+ type SearchMatchOptions,
5
+ } from "../../../shared/search-filter.ts";
6
+
7
+ export type MetabaseSearchMatchOptions = SearchMatchOptions;
8
+
9
+ function stringAt(row: Record<string, unknown>, key: string): string {
10
+ const v = row[key];
11
+ return typeof v === "string" ? v : "";
12
+ }
13
+
14
+ function fieldsOf(item: unknown): readonly string[] | null {
15
+ const row = asRecord(item);
16
+ if (row === undefined) {
17
+ return null;
18
+ }
19
+ return [stringAt(row, "name"), stringAt(row, "description")];
20
+ }
21
+
22
+ export const filterMetabaseDashboards = makeQueryFilter(fieldsOf);