Skip to content

Commit 5bae442

Browse files
release: 9.1.0 (#644)
* chore(internal): codegen related update * fix(mcp): allow falling back for required env variables * fix(docs): fix mcp installation instructions for remote servers * chore(mcp): up tsconfig lib version to es2022 * fix(client): avoid memory leak with abort signals * chore(client): do not parse responses with empty content-length * chore(internal): support oauth authorization code flow for MCP servers * chore(client): restructure abort controller binding * chore(internal): refactor flag parsing for MCP servers and add debug flag * feat(mcp): add initial server instructions Adds generated MCP server instructions, to help agents get easy tasks on the first try. * fix(client): avoid removing abort listener too early * chore(internal): fix pagination internals not accepting option promises * chore(internal): add health check to MCP server when running in HTTP mode * chore(internal): always generate MCP server dockerfiles and upgrade associated dependencies * chore(internal): allow basic filtering of methods allowed for MCP code mode * chore(internal): avoid type checking errors with ts-reset * chore(mcp): forward STAINLESS_API_KEY to docs search endpoint * chore(internal): improve layout of generated MCP server files * chore(internal/client): fix form-urlencoded requests * chore(internal): allow setting x-stainless-api-key header on mcp server requests * release: 9.1.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com>
1 parent 753228c commit 5bae442

23 files changed

+861
-103
lines changed

.dockerignore

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Dependencies
2+
node_modules/
3+
**/node_modules/
4+
5+
# Build outputs
6+
dist/
7+
**/dist/
8+
9+
# Git
10+
.git/
11+
.gitignore
12+
13+
# CI/CD
14+
.github/
15+
.gitlab-ci.yml
16+
.travis.yml
17+
18+
# IDE
19+
.vscode/
20+
.idea/
21+
*.swp
22+
*.swo
23+
*~
24+
25+
# OS
26+
.DS_Store
27+
Thumbs.db
28+
29+
# Testing
30+
test/
31+
tests/
32+
__tests__/
33+
*.test.js
34+
*.spec.js
35+
coverage/
36+
.nyc_output/
37+
38+
# Logs
39+
*.log
40+
npm-debug.log*
41+
yarn-debug.log*
42+
yarn-error.log*
43+
44+
# Environment
45+
.env
46+
.env.*
47+
48+
# Temporary files
49+
*.tmp
50+
*.temp
51+
.cache/
52+
53+
# Examples and scripts
54+
examples/
55+
bin/
56+
57+
# Other packages (we only need mcp-server)
58+
packages/*/
59+
!packages/mcp-server/

.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.0.0"
2+
".": "9.1.0"
33
}

CHANGELOG.md

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

3+
## 9.1.0 (2026-02-17)
4+
5+
Full Changelog: [v9.0.0...v9.1.0](https://github.com/Finch-API/finch-api-node/compare/v9.0.0...v9.1.0)
6+
7+
### Features
8+
9+
* **mcp:** add initial server instructions ([41a62e7](https://github.com/Finch-API/finch-api-node/commit/41a62e7da2c6f6fe1b59afe8d87066489d707bc4))
10+
11+
12+
### Bug Fixes
13+
14+
* **client:** avoid memory leak with abort signals ([e6cbcb4](https://github.com/Finch-API/finch-api-node/commit/e6cbcb4c380d391797875514114fbd870e680aa9))
15+
* **client:** avoid removing abort listener too early ([834599b](https://github.com/Finch-API/finch-api-node/commit/834599b8d10c0cc7858861504ebbc6142d28768d))
16+
* **docs:** fix mcp installation instructions for remote servers ([2346e45](https://github.com/Finch-API/finch-api-node/commit/2346e45e51546112f96d29f89904a499c66c61d2))
17+
* **mcp:** allow falling back for required env variables ([e2285bf](https://github.com/Finch-API/finch-api-node/commit/e2285bffd1403ecbb223daf47f7e1eda40033d54))
18+
19+
20+
### Chores
21+
22+
* **client:** do not parse responses with empty content-length ([9168b0e](https://github.com/Finch-API/finch-api-node/commit/9168b0e266bb4babc638698f27c166d282c5f346))
23+
* **client:** restructure abort controller binding ([03776eb](https://github.com/Finch-API/finch-api-node/commit/03776eb5c0329b6580fb3c2e58ce4d811fbde635))
24+
* **internal/client:** fix form-urlencoded requests ([1ac688c](https://github.com/Finch-API/finch-api-node/commit/1ac688c453fda8fb75435c7640baee617ebe2391))
25+
* **internal:** add health check to MCP server when running in HTTP mode ([c6b1999](https://github.com/Finch-API/finch-api-node/commit/c6b1999a1895466414ad1c3975b27ee317faa473))
26+
* **internal:** allow basic filtering of methods allowed for MCP code mode ([c6921b7](https://github.com/Finch-API/finch-api-node/commit/c6921b76e9db6ddd6019353a6da69c12a43f8570))
27+
* **internal:** allow setting x-stainless-api-key header on mcp server requests ([b54dd75](https://github.com/Finch-API/finch-api-node/commit/b54dd7599a900f5a37968d409581aa09092389e4))
28+
* **internal:** always generate MCP server dockerfiles and upgrade associated dependencies ([d786340](https://github.com/Finch-API/finch-api-node/commit/d7863401c96e70f832d74a7eca4b7ef0850791e2))
29+
* **internal:** avoid type checking errors with ts-reset ([ec27092](https://github.com/Finch-API/finch-api-node/commit/ec270924322d2fbb055eb36ae6b8b75c2102f89a))
30+
* **internal:** codegen related update ([b3f5e09](https://github.com/Finch-API/finch-api-node/commit/b3f5e099f190c0dcdd648262398d4629fac02671))
31+
* **internal:** fix pagination internals not accepting option promises ([6b75209](https://github.com/Finch-API/finch-api-node/commit/6b7520906d83f1ebeaf76c2b827f34f8ebeeeca2))
32+
* **internal:** improve layout of generated MCP server files ([efb8e62](https://github.com/Finch-API/finch-api-node/commit/efb8e625da8e577178a22350215ef3931ad657db))
33+
* **internal:** refactor flag parsing for MCP servers and add debug flag ([c3685d5](https://github.com/Finch-API/finch-api-node/commit/c3685d56e5988db461e09f3ec90e693dbec3bdfa))
34+
* **internal:** support oauth authorization code flow for MCP servers ([ed2565a](https://github.com/Finch-API/finch-api-node/commit/ed2565a0da646b78e0f3d74bbe7d2f7c8c4c46bb))
35+
* **mcp:** forward STAINLESS_API_KEY to docs search endpoint ([e307e2e](https://github.com/Finch-API/finch-api-node/commit/e307e2e1c806385c6aa5a3bdea69e690fde06d73))
36+
* **mcp:** up tsconfig lib version to es2022 ([b96b21e](https://github.com/Finch-API/finch-api-node/commit/b96b21eccc21170a8c655ac8de964723952e9f93))
37+
338
## 9.0.0 (2026-01-27)
439

540
Full Changelog: [v8.2.1...v9.0.0](https://github.com/Finch-API/finch-api-node/compare/v8.2.1...v9.0.0)

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ It is generated with [Stainless](https://www.stainless.com/).
1212

1313
Use the Finch MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.
1414

15-
[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=%40tryfinch%2Ffinch-api-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkB0cnlmaW5jaC9maW5jaC1hcGktbWNwIl19)
16-
[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40tryfinch%2Ffinch-api-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40tryfinch%2Ffinch-api-mcp%22%5D%7D)
15+
[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=%40tryfinch%2Ffinch-api-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkB0cnlmaW5jaC9maW5jaC1hcGktbWNwIl0sImVudiI6eyJGSU5DSF9BQ0NFU1NfVE9LRU4iOiJNeSBBY2Nlc3MgVG9rZW4iLCJGSU5DSF9DTElFTlRfSUQiOiI0YWIxNWU1MS0xMWFkLTQ5ZjQtYWNhZS1mMzQzYjc3OTQzNzUiLCJGSU5DSF9DTElFTlRfU0VDUkVUIjoiTXkgQ2xpZW50IFNlY3JldCIsIkZJTkNIX1dFQkhPT0tfU0VDUkVUIjoiTXkgV2ViaG9vayBTZWNyZXQifX0)
16+
[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40tryfinch%2Ffinch-api-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40tryfinch%2Ffinch-api-mcp%22%5D%2C%22env%22%3A%7B%22FINCH_ACCESS_TOKEN%22%3A%22My%20Access%20Token%22%2C%22FINCH_CLIENT_ID%22%3A%224ab15e51-11ad-49f4-acae-f343b7794375%22%2C%22FINCH_CLIENT_SECRET%22%3A%22My%20Client%20Secret%22%2C%22FINCH_WEBHOOK_SECRET%22%3A%22My%20Webhook%20Secret%22%7D%7D)
1717

1818
> Note: You may need to set environment variables in your MCP client.
1919

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.0.0",
3+
"version": "9.1.0",
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: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Dockerfile for Finch MCP Server
2+
#
3+
# This Dockerfile builds a Docker image for the MCP Server.
4+
#
5+
# To build the image locally:
6+
# docker build -f packages/mcp-server/Dockerfile -t @tryfinch/finch-api-mcp:local .
7+
#
8+
# To run the image:
9+
# docker run -i @tryfinch/finch-api-mcp:local [OPTIONS]
10+
#
11+
# Common options:
12+
# --tool=<name> Include specific tools
13+
# --resource=<name> Include tools for specific resources
14+
# --operation=read|write Filter by operation type
15+
# --client=<type> Set client compatibility (e.g., claude, cursor)
16+
# --transport=<type> Set transport type (stdio or http)
17+
#
18+
# For a full list of options:
19+
# docker run -i @tryfinch/finch-api-mcp:local --help
20+
#
21+
# Note: The MCP server uses stdio transport by default. Docker's -i flag
22+
# enables interactive mode, allowing the container to communicate over stdin/stdout.
23+
24+
# Build stage
25+
FROM node:24-alpine AS builder
26+
27+
# Install bash for build script
28+
RUN apk add --no-cache bash openssl
29+
30+
# Set working directory
31+
WORKDIR /build
32+
33+
# Copy entire repository
34+
COPY . .
35+
36+
# Install all dependencies and build everything
37+
RUN yarn install --frozen-lockfile && \
38+
yarn build
39+
40+
# Production stage
41+
FROM node:24-alpine
42+
43+
# Add non-root user
44+
RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001
45+
46+
# Set working directory
47+
WORKDIR /app
48+
49+
# Copy the built mcp-server dist directory
50+
COPY --from=builder /build/packages/mcp-server/dist ./
51+
52+
# Copy node_modules from mcp-server (includes all production deps)
53+
COPY --from=builder /build/packages/mcp-server/node_modules ./node_modules
54+
55+
# Copy the built @tryfinch/finch-api into node_modules
56+
COPY --from=builder /build/dist ./node_modules/@tryfinch/finch-api
57+
58+
# Change ownership to nodejs user
59+
RUN chown -R nodejs:nodejs /app
60+
61+
# Switch to non-root user
62+
USER nodejs
63+
64+
# The MCP server uses stdio transport by default
65+
# No exposed ports needed for stdio communication
66+
67+
# Set the entrypoint to the MCP server
68+
ENTRYPOINT ["node", "index.js"]
69+
70+
# Allow passing arguments to the MCP server
71+
CMD []

packages/mcp-server/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,22 +45,22 @@ For clients with a configuration JSON, it might look something like this:
4545
If you use Cursor, you can install the MCP server by using the button below. You will need to set your environment variables
4646
in Cursor's `mcp.json`, which can be found in Cursor Settings > Tools & MCP > New MCP Server.
4747

48-
[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=%40tryfinch%2Ffinch-api-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkB0cnlmaW5jaC9maW5jaC1hcGktbWNwIl0sImVudiI6eyJGSU5DSF9BQ0NFU1NfVE9LRU4iOiJTZXQgeW91ciBGSU5DSF9BQ0NFU1NfVE9LRU4gaGVyZS4iLCJGSU5DSF9DTElFTlRfSUQiOiJTZXQgeW91ciBGSU5DSF9DTElFTlRfSUQgaGVyZS4iLCJGSU5DSF9DTElFTlRfU0VDUkVUIjoiU2V0IHlvdXIgRklOQ0hfQ0xJRU5UX1NFQ1JFVCBoZXJlLiIsIkZJTkNIX1dFQkhPT0tfU0VDUkVUIjoiU2V0IHlvdXIgRklOQ0hfV0VCSE9PS19TRUNSRVQgaGVyZS4ifX0)
48+
[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=%40tryfinch%2Ffinch-api-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkB0cnlmaW5jaC9maW5jaC1hcGktbWNwIl0sImVudiI6eyJGSU5DSF9BQ0NFU1NfVE9LRU4iOiJNeSBBY2Nlc3MgVG9rZW4iLCJGSU5DSF9DTElFTlRfSUQiOiI0YWIxNWU1MS0xMWFkLTQ5ZjQtYWNhZS1mMzQzYjc3OTQzNzUiLCJGSU5DSF9DTElFTlRfU0VDUkVUIjoiTXkgQ2xpZW50IFNlY3JldCIsIkZJTkNIX1dFQkhPT0tfU0VDUkVUIjoiTXkgV2ViaG9vayBTZWNyZXQifX0)
4949

5050
### VS Code
5151

5252
If you use MCP, you can install the MCP server by clicking the link below. You will need to set your environment variables
5353
in VS Code's `mcp.json`, which can be found via Command Palette > MCP: Open User Configuration.
5454

55-
[Open VS Code](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40tryfinch%2Ffinch-api-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40tryfinch%2Ffinch-api-mcp%22%5D%2C%22env%22%3A%7B%22FINCH_ACCESS_TOKEN%22%3A%22Set%20your%20FINCH_ACCESS_TOKEN%20here.%22%2C%22FINCH_CLIENT_ID%22%3A%22Set%20your%20FINCH_CLIENT_ID%20here.%22%2C%22FINCH_CLIENT_SECRET%22%3A%22Set%20your%20FINCH_CLIENT_SECRET%20here.%22%2C%22FINCH_WEBHOOK_SECRET%22%3A%22Set%20your%20FINCH_WEBHOOK_SECRET%20here.%22%7D%7D)
55+
[Open VS Code](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40tryfinch%2Ffinch-api-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40tryfinch%2Ffinch-api-mcp%22%5D%2C%22env%22%3A%7B%22FINCH_ACCESS_TOKEN%22%3A%22My%20Access%20Token%22%2C%22FINCH_CLIENT_ID%22%3A%224ab15e51-11ad-49f4-acae-f343b7794375%22%2C%22FINCH_CLIENT_SECRET%22%3A%22My%20Client%20Secret%22%2C%22FINCH_WEBHOOK_SECRET%22%3A%22My%20Webhook%20Secret%22%7D%7D)
5656

5757
### Claude Code
5858

5959
If you use Claude Code, you can install the MCP server by running the command below in your terminal. You will need to set your
6060
environment variables in Claude Code's `.claude.json`, which can be found in your home directory.
6161

6262
```
63-
claude mcp add tryfinch_finch_api_mcp_api --env FINCH_ACCESS_TOKEN="Your FINCH_ACCESS_TOKEN here." FINCH_CLIENT_ID="Your FINCH_CLIENT_ID here." FINCH_CLIENT_SECRET="Your FINCH_CLIENT_SECRET here." FINCH_WEBHOOK_SECRET="Your FINCH_WEBHOOK_SECRET here." -- npx -y @tryfinch/finch-api-mcp
63+
claude mcp add tryfinch_finch_api_mcp_api --env FINCH_ACCESS_TOKEN="My Access Token" FINCH_CLIENT_ID="4ab15e51-11ad-49f4-acae-f343b7794375" FINCH_CLIENT_SECRET="My Client Secret" FINCH_WEBHOOK_SECRET="My Webhook Secret" -- npx -y @tryfinch/finch-api-mcp
6464
```
6565

6666
## Code Mode

packages/mcp-server/package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@tryfinch/finch-api-mcp",
3-
"version": "9.0.0",
3+
"version": "9.1.0",
44
"description": "The official MCP Server for the Finch API",
55
"author": "Finch <founders@tryfinch.com>",
66
"types": "dist/index.d.ts",
@@ -34,10 +34,13 @@
3434
"@cloudflare/cabidela": "^0.2.4",
3535
"@modelcontextprotocol/sdk": "^1.25.2",
3636
"@valtown/deno-http-worker": "^0.0.21",
37+
"cookie-parser": "^1.4.6",
3738
"cors": "^2.8.5",
3839
"express": "^5.1.0",
3940
"fuse.js": "^7.1.0",
4041
"jq-web": "https://github.com/stainless-api/jq-web/releases/download/v0.8.8/jq-web.tar.gz",
42+
"morgan": "^1.10.0",
43+
"morgan-body": "^2.6.9",
4144
"qs": "^6.14.1",
4245
"typescript": "5.8.3",
4346
"yargs": "^17.7.2",
@@ -50,9 +53,11 @@
5053
},
5154
"devDependencies": {
5255
"@anthropic-ai/mcpb": "^2.1.2",
56+
"@types/cookie-parser": "^1.4.10",
5357
"@types/cors": "^2.8.19",
5458
"@types/express": "^5.0.3",
5559
"@types/jest": "^29.4.0",
60+
"@types/morgan": "^1.9.10",
5661
"@types/qs": "^6.14.0",
5762
"@types/yargs": "^17.0.8",
5863
"@typescript-eslint/eslint-plugin": "8.31.1",
Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
import { IncomingMessage } from 'node:http';
44
import { ClientOptions } from '@tryfinch/finch-api';
5+
import { McpOptions } from './options';
56

6-
export const parseAuthHeaders = (req: IncomingMessage): Partial<ClientOptions> => {
7+
export const parseClientAuthHeaders = (req: IncomingMessage, required?: boolean): Partial<ClientOptions> => {
78
if (req.headers.authorization) {
89
const scheme = req.headers.authorization.split(' ')[0]!;
910
const value = req.headers.authorization.slice(scheme.length + 1);
@@ -21,6 +22,8 @@ export const parseAuthHeaders = (req: IncomingMessage): Partial<ClientOptions> =
2122
'Unsupported authorization scheme. Expected the "Authorization" header to be a supported scheme (Bearer, Basic).',
2223
);
2324
}
25+
} else if (required) {
26+
throw new Error('Missing required Authorization header; see WWW-Authenticate header for details.');
2427
}
2528

2629
const clientID =
@@ -33,3 +36,17 @@ export const parseAuthHeaders = (req: IncomingMessage): Partial<ClientOptions> =
3336
: req.headers['x-finch-client-secret'];
3437
return { clientID, clientSecret };
3538
};
39+
40+
export const getStainlessApiKey = (req: IncomingMessage, mcpOptions: McpOptions): string | undefined => {
41+
// Try to get the key from the x-stainless-api-key header
42+
const headerKey =
43+
Array.isArray(req.headers['x-stainless-api-key']) ?
44+
req.headers['x-stainless-api-key'][0]
45+
: req.headers['x-stainless-api-key'];
46+
if (headerKey && typeof headerKey === 'string') {
47+
return headerKey;
48+
}
49+
50+
// Fall back to value set in the mcpOptions (e.g. from environment variable), if provided
51+
return mcpOptions.stainlessApiKey;
52+
};

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

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
22

3-
import { McpTool, Metadata, ToolCallResult, asErrorResult, asTextContentResult } from './types';
3+
import {
4+
McpRequestContext,
5+
McpTool,
6+
Metadata,
7+
ToolCallResult,
8+
asErrorResult,
9+
asTextContentResult,
10+
} from './types';
411
import { Tool } from '@modelcontextprotocol/sdk/types.js';
5-
import { readEnv } from './server';
12+
import { readEnv } from './util';
613
import { WorkerInput, WorkerOutput } from './code-tool-types';
14+
import { SdkMethod } from './methods';
715

816
const prompt = `Runs JavaScript code to interact with the Finch API.
917
@@ -35,7 +43,7 @@ Variables will not persist between calls, so make sure to return or log any data
3543
*
3644
* @param endpoints - The endpoints to include in the list.
3745
*/
38-
export function codeTool(): McpTool {
46+
export function codeTool({ blockedMethods }: { blockedMethods: SdkMethod[] | undefined }): McpTool {
3947
const metadata: Metadata = { resource: 'all', operation: 'write', tags: [] };
4048
const tool: Tool = {
4149
name: 'execute',
@@ -55,26 +63,47 @@ export function codeTool(): McpTool {
5563
required: ['code'],
5664
},
5765
};
58-
const handler = async (_: unknown, args: any): Promise<ToolCallResult> => {
66+
const handler = async ({
67+
reqContext,
68+
args,
69+
}: {
70+
reqContext: McpRequestContext;
71+
args: any;
72+
}): Promise<ToolCallResult> => {
5973
const code = args.code as string;
6074
const intent = args.intent as string | undefined;
75+
const client = reqContext.client;
76+
77+
// Do very basic blocking of code that includes forbidden method names.
78+
//
79+
// WARNING: This is not secure against obfuscation and other evasion methods. If
80+
// stronger security blocks are required, then these should be enforced in the downstream
81+
// API (e.g., by having users call the MCP server with API keys with limited permissions).
82+
if (blockedMethods) {
83+
const blockedMatches = blockedMethods.filter((method) => code.includes(method.fullyQualifiedName));
84+
if (blockedMatches.length > 0) {
85+
return asErrorResult(
86+
`The following methods have been blocked by the MCP server and cannot be used in code execution: ${blockedMatches
87+
.map((m) => m.fullyQualifiedName)
88+
.join(', ')}`,
89+
);
90+
}
91+
}
6192

62-
// this is not required, but passing a Stainless API key for the matching project_name
63-
// will allow you to run code-mode queries against non-published versions of your SDK.
64-
const stainlessAPIKey = readEnv('STAINLESS_API_KEY');
6593
const codeModeEndpoint =
6694
readEnv('CODE_MODE_ENDPOINT_URL') ?? 'https://api.stainless.com/api/ai/code-tool';
6795

96+
// Setting a Stainless API key authenticates requests to the code tool endpoint.
6897
const res = await fetch(codeModeEndpoint, {
6998
method: 'POST',
7099
headers: {
71-
...(stainlessAPIKey && { Authorization: stainlessAPIKey }),
100+
...(reqContext.stainlessApiKey && { Authorization: reqContext.stainlessApiKey }),
72101
'Content-Type': 'application/json',
73102
client_envs: JSON.stringify({
74-
FINCH_CLIENT_ID: readEnv('FINCH_CLIENT_ID'),
75-
FINCH_CLIENT_SECRET: readEnv('FINCH_CLIENT_SECRET'),
76-
FINCH_WEBHOOK_SECRET: readEnv('FINCH_WEBHOOK_SECRET'),
77-
FINCH_BASE_URL: readEnv('FINCH_BASE_URL'),
103+
FINCH_CLIENT_ID: readEnv('FINCH_CLIENT_ID') ?? client.clientID ?? undefined,
104+
FINCH_CLIENT_SECRET: readEnv('FINCH_CLIENT_SECRET') ?? client.clientSecret ?? undefined,
105+
FINCH_WEBHOOK_SECRET: readEnv('FINCH_WEBHOOK_SECRET') ?? client.webhookSecret ?? undefined,
106+
FINCH_BASE_URL: readEnv('FINCH_BASE_URL') ?? client.baseURL ?? undefined,
78107
}),
79108
},
80109
body: JSON.stringify({

0 commit comments

Comments
 (0)