Skip to content

feat(mcp): add custom tool profile config models - #676

Draft
vishal-bala wants to merge 1 commit into
feat/mcp-locked-filter-mergefrom
feat/mcp-profile-config
Draft

feat(mcp): add custom tool profile config models#676
vishal-bala wants to merge 1 commit into
feat/mcp-locked-filter-mergefrom
feat/mcp-profile-config

Conversation

@vishal-bala

Copy link
Copy Markdown
Collaborator

Stack position: 2 of 3. Base is #675.

The declarative surface for custom tool profiles: what an author may put in a custom_tools: YAML entry, and every way that entry can be wrong.

A profile is search-records with some arguments frozen by the author and the rest still exposed. lock holds what the author decides; params holds the exposure and cap policy for what the model may still pass. Anything unlisted stays exposed, so a profile that only locks a filter keeps the rest of the built-in's contract. A locked projection is the one implicit case: locking it means the model cannot also choose one.

Read this before approving: it must not reach main alone

Nothing consumes these models yet — registration and execution land in #676. That ordering is deliberate, because this is the complete authoring contract and is fully testable on its own, so it reads before the machine that honors it.

But this must not be merged to main by itself. A custom_tools: block would validate here and then register nothing, with no warning and no error — exactly the silent-misconfiguration failure these models otherwise exist to prevent. That is the whole reason the stack targets an integration branch instead of main.

Validation

Front-loaded to config load wherever the information exists there, since the alternative is a tool that looks locked and enforces nothing. Covered:

  • a name that collides with a built-in, uses a reserved redisvl-/redisvl_ prefix (both separators, since the name pattern permits either), or falls outside the character set MCP hosts commonly accept
  • a duplicate tool name
  • a missing index when several bindings exist, or one naming an unknown binding
  • a params key that is not a real argument
  • max on anything but limit
  • a cap above the bound index's own runtime.max_limit, which could never be satisfied
  • hiding query, which a search profile needs
  • locking return_fields while also exposing them

Field checks that need the inspected schema stay at startup, in #676.

All three models set extra="forbid". A misspelled key would otherwise be dropped in silence, which is the worst outcome available here: lock: {return_field: [...]} would read as a locked projection while enforcing nothing at all.

Verification

  • MCP unit tests: 304 passing
  • make check-types: clean

The declarative surface for custom tool profiles: what an author may put
in a `custom_tools:` YAML entry, and every way that entry can be wrong.

A profile is `search-records` with some arguments frozen by the author and
the rest still exposed. `lock` holds what the author decides;`params`
holds the exposure and cap policy for what the model may still pass.
Anything unlisted stays exposed, so a profile that only locks a filter
keeps the rest of the built-in's contract. A locked projection is the one
implicit case: locking it means the model cannot also choose one.

Nothing consumes these models yet -- registration and execution land in
the next commit in this stack. That ordering is deliberate: this is the
complete authoring contract and it is fully testable on its own, so it
reads before the machine that honors it. It must not reach main by itself,
though. A `custom_tools:` block would validate here and then register
nothing, with no warning -- exactly the silent-misconfiguration failure
these models otherwise guard against.

Validation is front-loaded to config load wherever the information exists
there, since the alternative is a tool that looks locked and enforces
nothing. Covered: a name that collides with a built-in, uses a reserved
`redisvl-`/`redisvl_` prefix (both separators, since the pattern permits
either), or falls outside the character set MCP hosts commonly accept; a
duplicate name; a missing `index` when several bindings exist, or one
naming an unknown binding; a `params` key that is not a real argument;
`max` on anything but `limit`; a cap above the bound index's own
`runtime.max_limit`, which could never be satisfied; hiding `query`, which
a search profile needs; and locking `return_fields` while also exposing
them. Field checks that need the inspected schema stay at startup.

All three models set `extra="forbid"`. A misspelled key would otherwise be
dropped in silence, which is the worst outcome available here: `lock:
{return_field: [...]}` would read as a locked projection while enforcing
nothing at all.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant