@@ -108,28 +108,31 @@ function errorTool(parts: SessionV1.Part[]) {
108108 return part ?. state . status === "error" ? ( part as ErrorToolPart ) : undefined
109109}
110110
111- const mcp = Layer . succeed (
112- MCP . Service ,
113- MCP . Service . of ( {
114- status : ( ) => Effect . succeed ( { } ) ,
115- clients : ( ) => Effect . succeed ( { } ) ,
116- tools : ( ) => Effect . succeed ( { } ) ,
117- prompts : ( ) => Effect . succeed ( { } ) ,
118- resources : ( ) => Effect . succeed ( { } ) ,
119- add : ( ) => Effect . succeed ( { status : { status : "disabled" as const } } ) ,
120- connect : ( ) => Effect . void ,
121- disconnect : ( ) => Effect . void ,
122- getPrompt : ( ) => Effect . succeed ( undefined ) ,
123- readResource : ( ) => Effect . succeed ( undefined ) ,
124- startAuth : ( ) => Effect . die ( "unexpected MCP auth in prompt-effect tests" ) ,
125- authenticate : ( ) => Effect . die ( "unexpected MCP auth in prompt-effect tests" ) ,
126- finishAuth : ( ) => Effect . die ( "unexpected MCP auth in prompt-effect tests" ) ,
127- removeAuth : ( ) => Effect . void ,
128- supportsOAuth : ( ) => Effect . succeed ( false ) ,
129- hasStoredTokens : ( ) => Effect . succeed ( false ) ,
130- getAuthStatus : ( ) => Effect . succeed ( "not_authenticated" as const ) ,
131- } ) ,
132- )
111+ function makeMcp ( instructions : string [ ] = [ ] ) {
112+ return Layer . succeed (
113+ MCP . Service ,
114+ MCP . Service . of ( {
115+ status : ( ) => Effect . succeed ( { } ) ,
116+ clients : ( ) => Effect . succeed ( { } ) ,
117+ instructions : ( ) => Effect . succeed ( instructions ) ,
118+ tools : ( ) => Effect . succeed ( { } ) ,
119+ prompts : ( ) => Effect . succeed ( { } ) ,
120+ resources : ( ) => Effect . succeed ( { } ) ,
121+ add : ( ) => Effect . succeed ( { status : { status : "disabled" as const } } ) ,
122+ connect : ( ) => Effect . void ,
123+ disconnect : ( ) => Effect . void ,
124+ getPrompt : ( ) => Effect . succeed ( undefined ) ,
125+ readResource : ( ) => Effect . succeed ( undefined ) ,
126+ startAuth : ( ) => Effect . die ( "unexpected MCP auth in prompt-effect tests" ) ,
127+ authenticate : ( ) => Effect . die ( "unexpected MCP auth in prompt-effect tests" ) ,
128+ finishAuth : ( ) => Effect . die ( "unexpected MCP auth in prompt-effect tests" ) ,
129+ removeAuth : ( ) => Effect . void ,
130+ supportsOAuth : ( ) => Effect . succeed ( false ) ,
131+ hasStoredTokens : ( ) => Effect . succeed ( false ) ,
132+ getAuthStatus : ( ) => Effect . succeed ( "not_authenticated" as const ) ,
133+ } ) ,
134+ )
135+ }
133136
134137const lsp = Layer . succeed (
135138 LSP . Service ,
@@ -163,7 +166,7 @@ const blockingProcessor = Layer.succeed(
163166 } ) ,
164167)
165168
166- function makePrompt ( input ?: { processor ?: "blocking" } ) {
169+ function makePrompt ( input ?: { mcpInstructions ?: string [ ] ; processor ?: "blocking" } ) {
167170 const deps = Layer . mergeAll (
168171 Session . defaultLayer ,
169172 Snapshot . defaultLayer ,
@@ -176,7 +179,7 @@ function makePrompt(input?: { processor?: "blocking" }) {
176179 Config . defaultLayer ,
177180 ProviderSvc . defaultLayer ,
178181 lsp ,
179- mcp ,
182+ makeMcp ( input ?. mcpInstructions ) ,
180183 FSUtil . defaultLayer ,
181184 BackgroundJob . defaultLayer ,
182185 status ,
@@ -229,17 +232,29 @@ function makePrompt(input?: { processor?: "blocking" }) {
229232 )
230233}
231234
232- function makeHttp ( input ?: { processor ?: "blocking" } ) {
235+ function makeHttp ( input ?: { mcpInstructions ?: string [ ] ; processor ?: "blocking" } ) {
233236 return Layer . mergeAll ( TestLLMServer . layer , makePrompt ( input ) )
234237}
235238
236- function makeHttpNoLLMServer ( input ?: { processor ?: "blocking" } ) {
239+ function makeHttpNoLLMServer ( input ?: { mcpInstructions ?: string [ ] ; processor ?: "blocking" } ) {
237240 return makePrompt ( input )
238241}
239242
240243const it = testEffect ( makeHttp ( ) )
241244const noLLMServer = testEffect ( makeHttpNoLLMServer ( ) )
242245const raceNoLLMServer = testEffect ( makeHttpNoLLMServer ( { processor : "blocking" } ) )
246+ const withMcpInstructions = testEffect (
247+ makeHttp ( {
248+ mcpInstructions : [
249+ [
250+ "Instructions from: MCP server guide-server" ,
251+ "These instructions apply to MCP tools whose names start with `guide-server_`, and to prompts/resources from this MCP server." ,
252+ "" ,
253+ "Use lookup before mutate." ,
254+ ] . join ( "\n" ) ,
255+ ] ,
256+ } ) ,
257+ )
243258const unix = process . platform !== "win32" ? it . instance : it . instance . skip
244259const unixNoLLMServer = process . platform !== "win32" ? noLLMServer . instance : noLLMServer . instance . skip
245260
@@ -506,6 +521,31 @@ it.instance("loop calls LLM and returns assistant message", () =>
506521 } ) ,
507522)
508523
524+ withMcpInstructions . instance ( "loop includes MCP instructions in model system context" , ( ) =>
525+ Effect . gen ( function * ( ) {
526+ const { llm } = yield * useServerConfig ( providerCfg )
527+ const prompt = yield * SessionPrompt . Service
528+ const sessions = yield * Session . Service
529+ const chat = yield * sessions . create ( {
530+ title : "Pinned" ,
531+ permission : [ { permission : "*" , pattern : "*" , action : "allow" } ] ,
532+ } )
533+ yield * llm . hang
534+ yield * user ( chat . id , "hello" )
535+
536+ const fiber = yield * prompt . loop ( { sessionID : chat . id } ) . pipe ( Effect . forkChild )
537+ yield * awaitWithTimeout ( llm . wait ( 1 ) , "timed out waiting for MCP instruction request" , "10 seconds" )
538+
539+ const hits = yield * llm . hits
540+ const body = JSON . stringify ( hits [ 0 ] ?. body )
541+ expect ( body ) . toContain ( "Instructions from: MCP server guide-server" )
542+ expect ( body ) . toContain ( "guide-server_" )
543+ expect ( body ) . toContain ( "Use lookup before mutate." )
544+ yield * Fiber . interrupt ( fiber )
545+ } ) ,
546+ 15_000 ,
547+ )
548+
509549it . instance ( "loop surfaces content-filter finishes as session errors" , ( ) =>
510550 Effect . gen ( function * ( ) {
511551 const { llm } = yield * useServerConfig ( providerCfg )
0 commit comments