You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(plugins): add BucketResolverPlugin for multi-bucket dataset queries (#51)
* feat(plugins): add BucketResolverPlugin for multi-bucket dataset queries
Resolves a missing bucket/endpoint per file by matching parsed file paths
against configured dataset prefixes. Runs after QueryParserPlugin so each
file in a query is resolved independently, letting a single query join
across datasets that live in different buckets. Opt-in via the plugins
array, consistent with FSPurgePlugin/StatsPlugin/AvroPlugin.
* fix(s3): avoid day-of-month collision in evictTodayFromListingCache test
The "past day" cache fixture was hardcoded to day=01, colliding with
today's own day-level prefix whenever the suite runs on the 1st of the
month (UTC) and making the "past day entries should remain" assertion
fail. Derive it relative to the actual current day instead.
* feat(plugins): resolve list_files bucket via BucketResolverPlugin
list_files talks to S3 directly and never runs through the query pipeline
that BucketResolverPlugin's processQuery hooks into, so it couldn't
auto-resolve a bucket from datasets. Add a resolveListFiles hook to the
plugin (sharing its prefix-matching logic with processQuery) and have
ListFilesTool reduce over config.plugins to call it — kept local to the
MCP tool rather than lifecycle.js, since that module is scoped to the
s3quoia() query/download pipeline which list_files never touches.
Adding BucketResolverPlugin to config.plugins now covers both the query
and list_files tools with no extra configuration.
When a query references files by relative path (no `{bucket:...}` token) and no `defaultBucket` is set, `BucketResolverPlugin` resolves each file's bucket and endpoint from a list of dataset configs (see [Dataset options](#dataset-options)), matching the file path against each dataset's `prefix`. Resolution runs per file, so a single query can join across datasets in different buckets. Files that don't match any prefix are left unresolved — the existing "no bucket configured" error still applies to them.
query:`SELECT * FROM read_parquet('sales/year={yyyy}/data.parquet')`,
252
+
});
253
+
```
254
+
255
+
When used with `S3QuoiaMCP` (see [Plugins](#plugins-1)), the same `BucketResolverPlugin` instance also resolves the bucket for the `list_files` tool — it calls a second hook, `resolveListFiles`, since `list_files` talks to S3 directly and doesn't go through the query pipeline that `processQuery` hooks into.
256
+
236
257
## MCP Server
237
258
238
259
s3quoia ships a [Model Context Protocol](https://modelcontextprotocol.io/) server that exposes three tools to any MCP-compatible client (Claude Desktop, Claude Code, IBM Bob etc.):
@@ -405,22 +426,25 @@ new S3QuoiaMCP({
405
426
406
427
#### Plugins
407
428
408
-
Pass a `plugins` array to enable `FSPurgePlugin`, `StatsPlugin`, or any custom plugin for every query the server handles:
429
+
Pass a `plugins` array to enable `FSPurgePlugin`, `StatsPlugin`, `BucketResolverPlugin`, or any custom plugin for every query the server handles:
The built-in server (`npx s3quoia`) runs `FSPurgePlugin` and `StatsPlugin` by default. When extending with `S3QuoiaMCP`, plugins are opt-in.
447
+
The built-in server (`npx s3quoia`) runs `FSPurgePlugin` and `StatsPlugin` by default. When extending with `S3QuoiaMCP`, plugins are opt-in — add `BucketResolverPlugin` explicitly if you want both `query` and `list_files` to auto-resolve a bucket per file from your `datasets` config. `list_files` doesn't run through the query pipeline, so the plugin resolves it via a separate `resolveListFiles` hook rather than `processQuery` — no extra config needed, adding the plugin once covers both tools.
0 commit comments