Skip to content

Commit e719b4c

Browse files
release: 9.4.1 (#650)
* chore(internal): support local docs search in MCP servers * chore(ci): escape input path in publish-npm workflow * chore(mcp-server): add support for session id, forward client info * chore(internal): improve local docs search for MCP servers * chore(tests): bump steady to v0.20.1 * chore(internal): improve local docs search for MCP servers * chore(tests): bump steady to v0.20.2 * chore(internal): support type annotations when running MCP in local execution mode * chore(mcp-server): log client info * chore(internal): use link instead of file in MCP server package.json files * chore(internal): fix MCP docker image builds in yarn projects * chore(internal): fix MCP server import ordering * release: 9.4.1 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com>
1 parent 39e79d7 commit e719b4c

18 files changed

Lines changed: 2954 additions & 25 deletions

.github/workflows/publish-npm.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,14 @@ jobs:
3333
3434
- name: Publish to NPM
3535
run: |
36-
if [ -n "${{ github.event.inputs.path }}" ]; then
37-
PATHS_RELEASED='[\"${{ github.event.inputs.path }}\"]'
36+
if [ -n "$INPUT_PATH" ]; then
37+
PATHS_RELEASED="[\"$INPUT_PATH\"]"
3838
else
3939
PATHS_RELEASED='[\".\", \"packages/mcp-server\"]'
4040
fi
4141
yarn tsn scripts/publish-packages.ts "{ \"paths_released\": \"$PATHS_RELEASED\" }"
4242
env:
43+
INPUT_PATH: ${{ github.event.inputs.path }}
4344
NPM_TOKEN: ${{ secrets.FINCH_NPM_TOKEN || secrets.NPM_TOKEN }}
4445

4546
- name: Upload MCP Server DXT GitHub release asset

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "9.4.0"
2+
".": "9.4.1"
33
}

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,24 @@
11
# Changelog
22

3+
## 9.4.1 (2026-04-06)
4+
5+
Full Changelog: [v9.4.0...v9.4.1](https://github.com/Finch-API/finch-api-node/compare/v9.4.0...v9.4.1)
6+
7+
### Chores
8+
9+
* **ci:** escape input path in publish-npm workflow ([937becb](https://github.com/Finch-API/finch-api-node/commit/937becb997cb913a0328004f30e659267b4e6408))
10+
* **internal:** fix MCP docker image builds in yarn projects ([82c9ea5](https://github.com/Finch-API/finch-api-node/commit/82c9ea5c80252c99b5a6f5454341e77c36b5bf27))
11+
* **internal:** fix MCP server import ordering ([cebd49f](https://github.com/Finch-API/finch-api-node/commit/cebd49f12cc7ce3055fb2bc48c89c8c029b27cc8))
12+
* **internal:** improve local docs search for MCP servers ([996bc5f](https://github.com/Finch-API/finch-api-node/commit/996bc5f36e0c86bdc9af549e70f3f4edaebb5d3c))
13+
* **internal:** improve local docs search for MCP servers ([718d076](https://github.com/Finch-API/finch-api-node/commit/718d076ca4e7646b354ddb90bd481d870afcfff0))
14+
* **internal:** support local docs search in MCP servers ([c1b4351](https://github.com/Finch-API/finch-api-node/commit/c1b4351dfc3afdf78cb3b05303da95b38f7f063d))
15+
* **internal:** support type annotations when running MCP in local execution mode ([dee433e](https://github.com/Finch-API/finch-api-node/commit/dee433e64a5b46bb3cdfcdae22f0e7e3bf0cf624))
16+
* **internal:** use link instead of file in MCP server package.json files ([93c6720](https://github.com/Finch-API/finch-api-node/commit/93c6720c745b801c0740737164bd316f185d20df))
17+
* **mcp-server:** add support for session id, forward client info ([c4e007e](https://github.com/Finch-API/finch-api-node/commit/c4e007e78562fdab27d1dfba7be94cf1b03a57a4))
18+
* **mcp-server:** log client info ([9a5e04e](https://github.com/Finch-API/finch-api-node/commit/9a5e04ebe0ab27ee31ddf23fcca0cd7256b729ca))
19+
* **tests:** bump steady to v0.20.1 ([d50d641](https://github.com/Finch-API/finch-api-node/commit/d50d641be70b27821146bad6c1d708919954765c))
20+
* **tests:** bump steady to v0.20.2 ([034ea66](https://github.com/Finch-API/finch-api-node/commit/034ea662efe9f95db50f2dca215f54e63ff96009))
21+
322
## 9.4.0 (2026-03-27)
423

524
Full Changelog: [v9.3.0...v9.4.0](https://github.com/Finch-API/finch-api-node/compare/v9.3.0...v9.4.0)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@tryfinch/finch-api",
3-
"version": "9.4.0",
3+
"version": "9.4.1",
44
"description": "The official TypeScript library for the Finch API",
55
"author": "Finch <founders@tryfinch.com>",
66
"types": "dist/index.d.ts",

packages/mcp-server/Dockerfile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ COPY . .
3535

3636
# Install all dependencies and build everything
3737
RUN yarn install --frozen-lockfile && \
38-
yarn build
38+
yarn build && \
39+
# Remove the symlink to the SDK so it doesn't interfere with the explicit COPY below
40+
rm -Rf packages/mcp-server/node_modules/@tryfinch/finch-api
3941

4042
FROM denoland/deno:alpine-2.7.1
4143

packages/mcp-server/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"dxt_version": "0.2",
33
"name": "@tryfinch/finch-api-mcp",
4-
"version": "9.4.0",
4+
"version": "9.4.1",
55
"description": "The official MCP Server for the Finch API",
66
"author": {
77
"name": "Finch",

packages/mcp-server/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@tryfinch/finch-api-mcp",
3-
"version": "9.4.0",
3+
"version": "9.4.1",
44
"description": "The official MCP Server for the Finch API",
55
"author": "Finch <founders@tryfinch.com>",
66
"types": "dist/index.d.ts",
@@ -30,7 +30,7 @@
3030
"fix": "eslint --fix ."
3131
},
3232
"dependencies": {
33-
"@tryfinch/finch-api": "file:../../dist/",
33+
"@tryfinch/finch-api": "link:../../dist/",
3434
"ajv": "^8.18.0",
3535
"@cloudflare/cabidela": "^0.2.4",
3636
"@hono/node-server": "^1.19.10",
@@ -41,6 +41,7 @@
4141
"cors": "^2.8.5",
4242
"express": "^5.1.0",
4343
"fuse.js": "^7.1.0",
44+
"minisearch": "^7.2.0",
4445
"jq-web": "https://github.com/stainless-api/jq-web/releases/download/v0.8.8/jq-web.tar.gz",
4546
"pino": "^10.3.1",
4647
"pino-http": "^11.0.0",

packages/mcp-server/src/code-tool-worker.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ import ts from 'typescript';
77
import { WorkerOutput } from './code-tool-types';
88
import { Finch, ClientOptions } from '@tryfinch/finch-api';
99

10+
async function tseval(code: string) {
11+
return import('data:application/typescript;charset=utf-8;base64,' + Buffer.from(code).toString('base64'));
12+
}
13+
1014
function getRunFunctionSource(code: string): {
1115
type: 'declaration' | 'expression';
1216
client: string | undefined;
@@ -283,7 +287,9 @@ const fetch = async (req: Request): Promise<Response> => {
283287

284288
const log_lines: string[] = [];
285289
const err_lines: string[] = [];
286-
const console = {
290+
const originalConsole = globalThis.console;
291+
globalThis.console = {
292+
...originalConsole,
287293
log: (...args: unknown[]) => {
288294
log_lines.push(util.format(...args));
289295
},
@@ -293,7 +299,7 @@ const fetch = async (req: Request): Promise<Response> => {
293299
};
294300
try {
295301
let run_ = async (client: any) => {};
296-
eval(`${code}\nrun_ = run;`);
302+
run_ = (await tseval(`${code}\nexport default run;`)).default;
297303
const result = await run_(makeSdkProxy(client, { path: ['client'] }));
298304
return Response.json({
299305
is_error: false,
@@ -311,6 +317,8 @@ const fetch = async (req: Request): Promise<Response> => {
311317
} satisfies WorkerOutput,
312318
{ status: 400, statusText: 'Code execution error' },
313319
);
320+
} finally {
321+
globalThis.console = originalConsole;
314322
}
315323
};
316324

packages/mcp-server/src/docs-search-tool.ts

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import { Tool } from '@modelcontextprotocol/sdk/types.js';
44
import { Metadata, McpRequestContext, asTextContentResult } from './types';
55
import { getLogger } from './logger';
6+
import type { LocalDocsSearch } from './local-docs-search';
67

78
export const metadata: Metadata = {
89
resource: 'all',
@@ -43,20 +44,41 @@ export const tool: Tool = {
4344
const docsSearchURL =
4445
process.env['DOCS_SEARCH_URL'] || 'https://api.stainless.com/api/projects/finch/docs/search';
4546

46-
export const handler = async ({
47-
reqContext,
48-
args,
49-
}: {
50-
reqContext: McpRequestContext;
51-
args: Record<string, unknown> | undefined;
52-
}) => {
47+
let _localSearch: LocalDocsSearch | undefined;
48+
49+
export function setLocalSearch(search: LocalDocsSearch): void {
50+
_localSearch = search;
51+
}
52+
53+
async function searchLocal(args: Record<string, unknown>): Promise<unknown> {
54+
if (!_localSearch) {
55+
throw new Error('Local search not initialized');
56+
}
57+
58+
const query = (args['query'] as string) ?? '';
59+
const language = (args['language'] as string) ?? 'typescript';
60+
const detail = (args['detail'] as string) ?? 'default';
61+
62+
return _localSearch.search({
63+
query,
64+
language,
65+
detail,
66+
maxResults: 5,
67+
}).results;
68+
}
69+
70+
async function searchRemote(args: Record<string, unknown>, reqContext: McpRequestContext): Promise<unknown> {
5371
const body = args as any;
5472
const query = new URLSearchParams(body).toString();
5573

5674
const startTime = Date.now();
5775
const result = await fetch(`${docsSearchURL}?${query}`, {
5876
headers: {
5977
...(reqContext.stainlessApiKey && { Authorization: reqContext.stainlessApiKey }),
78+
...(reqContext.mcpSessionId && { 'x-stainless-mcp-session-id': reqContext.mcpSessionId }),
79+
...(reqContext.mcpClientInfo && {
80+
'x-stainless-mcp-client-info': JSON.stringify(reqContext.mcpClientInfo),
81+
}),
6082
},
6183
});
6284

@@ -94,7 +116,23 @@ export const handler = async ({
94116
},
95117
'Got docs search result',
96118
);
97-
return asTextContentResult(resultBody);
119+
return resultBody;
120+
}
121+
122+
export const handler = async ({
123+
reqContext,
124+
args,
125+
}: {
126+
reqContext: McpRequestContext;
127+
args: Record<string, unknown> | undefined;
128+
}) => {
129+
const body = args ?? {};
130+
131+
if (_localSearch) {
132+
return asTextContentResult(await searchLocal(body));
133+
}
134+
135+
return asTextContentResult(await searchRemote(body, reqContext));
98136
};
99137

100138
export default { metadata, tool, handler };

packages/mcp-server/src/http.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ const newServer = async ({
6969
}
7070
}
7171

72+
const mcpClientInfo =
73+
typeof req.body?.params?.clientInfo?.name === 'string' ?
74+
{ name: req.body.params.clientInfo.name, version: String(req.body.params.clientInfo.version ?? '') }
75+
: undefined;
76+
7277
await initMcpServer({
7378
server: server,
7479
mcpOptions: effectiveMcpOptions,
@@ -78,8 +83,14 @@ const newServer = async ({
7883
},
7984
stainlessApiKey: stainlessApiKey,
8085
upstreamClientEnvs,
86+
mcpSessionId: (req as any).mcpSessionId,
87+
mcpClientInfo,
8188
});
8289

90+
if (mcpClientInfo) {
91+
getLogger().info({ mcpSessionId: (req as any).mcpSessionId, mcpClientInfo }, 'MCP client connected');
92+
}
93+
8394
return server;
8495
};
8596

@@ -135,9 +146,23 @@ export const streamableHTTPApp = ({
135146
const app = express();
136147
app.set('query parser', 'extended');
137148
app.use(express.json());
149+
app.use((req: express.Request, res: express.Response, next: express.NextFunction) => {
150+
const existing = req.headers['mcp-session-id'];
151+
const sessionId = (Array.isArray(existing) ? existing[0] : existing) || crypto.randomUUID();
152+
(req as any).mcpSessionId = sessionId;
153+
const origWriteHead = res.writeHead.bind(res);
154+
res.writeHead = function (statusCode: number, ...rest: any[]) {
155+
res.setHeader('mcp-session-id', sessionId);
156+
return origWriteHead(statusCode, ...rest);
157+
} as typeof res.writeHead;
158+
next();
159+
});
138160
app.use(
139161
pinoHttp({
140162
logger: getLogger(),
163+
customProps: (req) => ({
164+
mcpSessionId: (req as any).mcpSessionId,
165+
}),
141166
customLogLevel: (req, res) => {
142167
if (res.statusCode >= 500) {
143168
return 'error';

0 commit comments

Comments
 (0)