feat!: consolidate MCP tool surface (27 → 15) behind backward-compatible aliases#62
Conversation
Adds src/tool-aliases.ts (resolveToolAlias + empty TOOL_ALIASES map) and wires it into the CallTool dispatcher ahead of Zod validation, plus an EVERNOTE_LEGACY_TOOLS ListTools branch (off by default) and a warn-once deprecation notice. Empty map means every call resolves to itself, so there is no behavior change. Groundwork for the 27->15 tool-surface consolidation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rojection
Replace get_resource_text, get_resource_recognition, and list_note_resources
with a projected get_resource({guid, as: text|binary|recognition|metadata})
plus the unchanged add_resource_to_note. Default as:"text".
- text/recognition/binary reached through the `as` discriminator; metadata adds
hasRecognition + fileName (getResource gains an optional withAttributes flag,
default false so text-extraction paths are unchanged).
- Retired names stay callable via TOOL_ALIASES (get_resource_text->as:text,
get_resource_recognition->as:recognition, list_note_resources->get_note
resources[]); re-advertised only under EVERNOTE_LEGACY_TOOLS.
- Dead code removed: EvernoteAPI.listNoteResources + ResourceInfo import.
Default advertised surface 27->24. Verified live against Evernote.
BREAKING CHANGE: get_resource now defaults to text extraction, not binary
download; pass as:"binary" (or deprecated includeData:true) for base64.
evernote_get_resource_text, evernote_get_resource_recognition, and
evernote_list_note_resources are removed from the default surface (still
callable as deprecated aliases; EVERNOTE_LEGACY_TOOLS=true re-lists them).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…{action})
Collapse start_polling/stop_polling/poll_now/polling_status into
evernote_polling({ action: "start"|"stop"|"poll"|"status" }). Handler logic and
response text are unchanged; the four retired names route through TOOL_ALIASES
and re-list only under EVERNOTE_LEGACY_TOOLS.
Default advertised surface 24->21. Verified live (canonical == alias output).
BREAKING CHANGE: evernote_start_polling, evernote_stop_polling,
evernote_poll_now, and evernote_polling_status are removed from the default
tool surface; use evernote_polling({action}). Old names remain callable as
deprecated aliases; EVERNOTE_LEGACY_TOOLS=true re-lists them.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ction({action})
Fold health_check, get_user_info, reconnect, and revoke_auth into
evernote_connection({ action: "status"|"user"|"reconnect"|"revoke", verbose? }).
Handler logic and response shapes are unchanged: revoke/reconnect run pre-API,
status/user keep the old ensureAPI gating. Retired names route via TOOL_ALIASES
and re-list only under EVERNOTE_LEGACY_TOOLS. Removes the now-dead
HealthCheckSchema (health_check is aliased away).
Default advertised surface 21->18. Verified live (canonical == alias output).
BREAKING CHANGE: evernote_health_check, evernote_get_user_info,
evernote_reconnect, and evernote_revoke_auth are removed from the default tool
surface; use evernote_connection({action}). Old names remain callable as
deprecated aliases; EVERNOTE_LEGACY_TOOLS=true re-lists them.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
list_notebooks and list_tags now return a single entity (fresh, full detail) when given a name or guid, or the full cached list otherwise — absorbing the retired get_notebook/get_tag. Retired names route via TOOL_ALIASES and re-list only under EVERNOTE_LEGACY_TOOLS. Removes the now-dead GetNotebookSchema/ GetTagSchema. Default advertised surface 18->16. Verified live (alias == single-lookup). BREAKING CHANGE: evernote_get_notebook and evernote_get_tag are removed from the default tool surface; call evernote_list_notebooks / evernote_list_tags with a name or guid instead. Old names remain callable as deprecated aliases; EVERNOTE_LEGACY_TOOLS=true re-lists them. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ements[]) update_note gains an optional replacements[] input: when present it applies the targeted find-and-replace patch (preserving title/tags/notebook/attachments) and is mutually exclusive with title/content/tags/notebookName (enforced by superRefine). Absent, it behaves as the existing full-field update. patch_note is retired to a TOOL_ALIASES entry (re-listed only under EVERNOTE_LEGACY_TOOLS); PatchNoteSchema is removed. Completes the consolidation: default advertised surface is now 15 tools (was 27). BREAKING CHANGE: evernote_patch_note is removed from the default tool surface; call evernote_update_note with replacements[] instead. The old name remains callable as a deprecated alias; EVERNOTE_LEGACY_TOOLS=true re-lists it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rewrite the MCP Tools section (27 -> 15): document the get_resource `as` projection, list-absorbs-get for notebooks/tags, update_note patch mode, and the polling/connection action tools. Add MIGRATION.md mapping every retired tool to its canonical form + args, and note the EVERNOTE_LEGACY_TOOLS grace window. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 60fedd3eb4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…re-auth
- validateToolArgs coerces omitted `arguments` to {} so the zero-arg list-all
form of list_notebooks/list_tags works (object schemas no longer reject
undefined); required-arg tools still error properly.
- evernote_connection({action:"status"}) (and the health_check alias) now run
before ensureAPI(), so the diagnostic reports needs_auth/needs_setup for an
unauthenticated server instead of surfacing a generic auth error.
The Codex finding on the list_note_resources alias was verified false live: the
get_note path returns resources[] metadata even with withResourcesData=false.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2bb9cd3347
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…/forceUpdate
- list_note_resources is no longer aliased to get_note (which changed the
response from a top-level array to a nested object and dropped
hash/hasRecognition). It keeps a dedicated hidden handler returning the exact
original array [{guid,filename,mimeType,size,hash,hasRecognition}], still off
the default surface (EVERNOTE_LEGACY_TOOLS re-lists it).
- update_note rejects replacements combined with forceUpdate (patch mode never
reaches the edit-lock fallback) instead of silently ignoring the request.
Verified live; MIGRATION.md updated; tests added.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d6ed445225
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…get_tag guard
- server.json (MCP registry manifest) now advertises the 15 canonical tools
(dropped retired get_user_info; added connection/polling/get_resource/
add_resource_to_note/update_notebook/update_tag) so registry clients discover
the consolidated surface.
- get_notebook/get_tag aliases carry requireOneOf:["name","guid"]; the
dispatcher rejects an empty legacy lookup (preserving the old "requires one
of" error) while list_notebooks/list_tags still accept {} as list-all.
Verified live; tests added.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cb6b456475
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ookups
- patch_note alias carries requireOneOf:["replacements"] so a legacy call
without replacements errors instead of falling through to a no-op full update.
- list_notebooks/list_tags require non-empty name/guid when present, so an
empty-string lookup errors instead of silently listing all (list-all stays {}).
Verified live; tests added.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. Swish! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Consolidates the MCP tool surface from 27 tools to 15 with zero capability
loss, behind a non-breaking alias shim. Fewer tools means less context loaded on
every turn and more reliable tool selection (27 was ~2× the 10–15 comfort ceiling).
Folds into the standing 2.0.0 release (already breaking on the Node 20.16 bump).
Changes (one commit per bucket)
resolveToolAlias+TOOL_ALIASES+EVERNOTE_LEGACY_TOOLS(no behavior change)get_resource({guid, as: text|binary|recognition|metadata}); droplist_note_resourcespolling({action: start|stop|poll|status})connection({action: status|user|reconnect|revoke})(foldsget_user_info)list_notebooks/list_tagsabsorbget_notebook/get_tagvia optionalname/guidpatch_notefolds intoupdate_notepatch mode (replacements[])Only safe consolidation mechanisms were used — projection, list-absorbs-get, and
admin action-unions. No action-unions on note/notebook/tag write verbs.
Backward compatibility
All 14 retired tool names stay callable: a
TOOL_ALIASESmap (src/tool-aliases.ts)rewrites each to its canonical tool + args before validation, logging a one-time
deprecation notice. Retired names are hidden from
ListToolsby default; setEVERNOTE_LEGACY_TOOLS=trueto re-advertise them during a migration window.Full old→new mapping in
MIGRATION.md.Verification
__tests__/unit/tool-aliases.test.ts: proves the resolution mechanism andenforces two invariants over every alias (canonical exists;
mapArgsoutputvalidates against the canonical Zod schema).
every bucket:
get_resourceasprojections + OCR, alias routing,pollingand
connection(canonical output == alias output), notebook/tag list vssingle-lookup, and a self-cleaning create→patch→verify→delete for
update_notepatch mode (via both the canonical tool and the
patch_notealias).EVERNOTE_LEGACY_TOOLS; every retired call logsexactly one deprecation notice.
BREAKING CHANGES
from
ListTools(still callable as deprecated aliases;EVERNOTE_LEGACY_TOOLS=truere-lists them).
evernote_get_resourcenow defaults to text extraction, not binarydownload. Pass
as:"binary"(or the deprecatedincludeData:true) for base64.🤖 Generated with Claude Code