I'm Claude (an AI agent), filing this on behalf of @justin-thurman, who asked me to report it.
Summary
After mcpServerLock limits an MCP server to a package, that package can't call the server when an agent invokes its export from execute. The package is denied the same way ad hoc execute code is. As far as I can tell, the documented loop in guide:locked_mcp_server can't work for the main way agents call packages.
Steps to reproduce
mcpServerAdd({ name: 'notion', url: 'https://mcp.notion.com/mcp' }), then authorize. mcpServerList shows state: "ready", 44 tools.
- Publish a thin wrapper package (
@justin-thurman/notion-read) whose exports call kody.mcp["notion"].notion_search_<hash>(...) and similar. From execute, import smokeTest from 'kody:@justin-thurman/notion-read/smoke-test' works.
mcpServerLock({ server: 'notion', package_id: '<notion-read package id>' }). mcpServerList now shows usageMode: "packages" and allowedPackageIds: ["<notion-read package id>"].
- From
execute, call the same export again, as the guide's step 5 says ("Smoke-test from the package, not execute").
Expected
The package export succeeds. A direct kody.mcp["notion"] call from execute fails with the account URL.
Actual
Both fail with:
Unknown MCP server "notion". Available MCP servers: none.
Same result with:
- a static import:
import x from 'kody:@scope/pkg/export'
- a computed import:
await import('kody:@scope/pkg/export')
- a republish of the package after the lock (new
published_commit)
Switching Usage back to "any context" on the website fixes it right away.
Likely cause
assertCanUseMcpServer / filterEnabledMcpServerRefsForCaller (packages/worker/src/mcp-client/package-access.ts) allow a call only when it has a packageId. mcp-server/index.ts reads that from ctx.callerContext.storageContext?.packageId. Package code imported into an execute module seems to run with execute's caller context, so packageId is empty and the server is filtered out. Package-run surfaces such as jobs, webhooks, and apps may work. I didn't test them.
A smaller related problem: since the server is filtered out of the listing before the assert runs, execute gets Unknown MCP server rather than the friendlier createMcpServerExecuteAccessDeniedMessage text with the usage URL that the guide describes.
The same pattern probably affects integrationLock (integrations/package-access.ts looks similar) and so the locked_gmail_drafts loop, but I haven't verified that.
Separate: @kody/notion-mcp can't find any Notion tools
@kody/notion-mcp (src/mcp.ts callNotionMcp) looks up tools by bare names (search, notion-search, API-post-search). Connected servers expose tools as <snake_name>_<8-hex hash>, e.g. notion_search_9cd52b13. kody.mcp["notion"]["notion-search"] throws Unknown MCP tool "notion-search", so the package's search and smoke-test can't find a tool even with a working connection. (guide:provider_notion doesn't mention the MCP lane at all, although that package's README calls it the preferred one-click path.)
Summary
After
mcpServerLocklimits an MCP server to a package, that package can't call the server when an agent invokes its export fromexecute. The package is denied the same way ad hocexecutecode is. As far as I can tell, the documented loop inguide:locked_mcp_servercan't work for the main way agents call packages.Steps to reproduce
mcpServerAdd({ name: 'notion', url: 'https://mcp.notion.com/mcp' }), then authorize.mcpServerListshowsstate: "ready", 44 tools.@justin-thurman/notion-read) whose exports callkody.mcp["notion"].notion_search_<hash>(...)and similar. Fromexecute,import smokeTest from 'kody:@justin-thurman/notion-read/smoke-test'works.mcpServerLock({ server: 'notion', package_id: '<notion-read package id>' }).mcpServerListnow showsusageMode: "packages"andallowedPackageIds: ["<notion-read package id>"].execute, call the same export again, as the guide's step 5 says ("Smoke-test from the package, not execute").Expected
The package export succeeds. A direct
kody.mcp["notion"]call fromexecutefails with the account URL.Actual
Both fail with:
Same result with:
import x from 'kody:@scope/pkg/export'await import('kody:@scope/pkg/export')published_commit)Switching Usage back to "any context" on the website fixes it right away.
Likely cause
assertCanUseMcpServer/filterEnabledMcpServerRefsForCaller(packages/worker/src/mcp-client/package-access.ts) allow a call only when it has apackageId.mcp-server/index.tsreads that fromctx.callerContext.storageContext?.packageId. Package code imported into anexecutemodule seems to run with execute's caller context, sopackageIdis empty and the server is filtered out. Package-run surfaces such as jobs, webhooks, and apps may work. I didn't test them.A smaller related problem: since the server is filtered out of the listing before the assert runs,
executegetsUnknown MCP serverrather than the friendliercreateMcpServerExecuteAccessDeniedMessagetext with the usage URL that the guide describes.The same pattern probably affects
integrationLock(integrations/package-access.tslooks similar) and so thelocked_gmail_draftsloop, but I haven't verified that.Separate:
@kody/notion-mcpcan't find any Notion tools@kody/notion-mcp(src/mcp.tscallNotionMcp) looks up tools by bare names (search,notion-search,API-post-search). Connected servers expose tools as<snake_name>_<8-hex hash>, e.g.notion_search_9cd52b13.kody.mcp["notion"]["notion-search"]throwsUnknown MCP tool "notion-search", so the package'ssearchandsmoke-testcan't find a tool even with a working connection. (guide:provider_notiondoesn't mention the MCP lane at all, although that package's README calls it the preferred one-click path.)