Skip to content

Commit 646e717

Browse files
authored
Merge pull request #8 from context-dot-dev/release-please--branches--main--changes--next--components--context.dev
release: 1.1.0
2 parents 9f38a69 + 0b12591 commit 646e717

18 files changed

Lines changed: 784 additions & 33 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.CONTEXT_DEV_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-
".": "1.0.1"
2+
".": "1.1.0"
33
}

.stats.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
configured_endpoints: 20
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev%2Fcontext.dev-ea89aeedfdd75f71542bcbb53880ecbc07f2656945d9ac8dce55d7bdabc5f8cc.yml
3-
openapi_spec_hash: c4dd62c3a3dc8c59a050fb6a76ab5f1b
4-
config_hash: df40ba3de7dbee2faf0315c5fbd001dc
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev%2Fcontext.dev-2ddb6d73ec8831eee4cb4352b85843a1f6f444e48d8be837cfcd118eddd2a63e.yml
3+
openapi_spec_hash: 1163122fba27e56fa5879bc98d32ee14
4+
config_hash: 38268bb88fc4dcbb8f2f94dd138b5910

CHANGELOG.md

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

3+
## 1.1.0 (2026-03-28)
4+
5+
Full Changelog: [v1.0.1...v1.1.0](https://github.com/context-dot-dev/context-typescript-sdk/compare/v1.0.1...v1.1.0)
6+
7+
### Features
8+
9+
* **api:** api update ([a2de140](https://github.com/context-dot-dev/context-typescript-sdk/commit/a2de140e3c6fc84fc1ac6ba0687791ebd240442a))
10+
* **api:** api update ([5a78e41](https://github.com/context-dot-dev/context-typescript-sdk/commit/5a78e4152accbe64cb41dbc43f057132fd651b44))
11+
12+
13+
### Chores
14+
15+
* **ci:** escape input path in publish-npm workflow ([bb90d39](https://github.com/context-dot-dev/context-typescript-sdk/commit/bb90d39c47c8eb13a337507ffc03ccef93db197b))
16+
* **internal:** codegen related update ([c658fd1](https://github.com/context-dot-dev/context-typescript-sdk/commit/c658fd1b8f7270e2d54c9aed39b59b67b165c496))
17+
* **internal:** support custom-instructions-path flag in MCP servers ([34b0150](https://github.com/context-dot-dev/context-typescript-sdk/commit/34b0150e4887578596139019d36b045a6b09cc88))
18+
* **internal:** support local docs search in MCP servers ([118d95d](https://github.com/context-dot-dev/context-typescript-sdk/commit/118d95dc88b884f3210f5be2c36335eb2f728a49))
19+
320
## 1.0.1 (2026-03-25)
421

522
Full Changelog: [v1.0.0...v1.0.1](https://github.com/context-dot-dev/context-typescript-sdk/compare/v1.0.0...v1.0.1)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "context.dev",
3-
"version": "1.0.1",
3+
"version": "1.1.0",
44
"description": "The official TypeScript library for the Context Dev API",
55
"author": "Context Dev <hello@context.dev>",
66
"types": "dist/index.d.ts",

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": "context.dev-mcp",
4-
"version": "1.0.1",
4+
"version": "1.1.0",
55
"description": "The official MCP Server for the Context Dev API",
66
"author": {
77
"name": "Context Dev",

packages/mcp-server/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "context.dev-mcp",
3-
"version": "1.0.1",
3+
"version": "1.1.0",
44
"description": "The official MCP Server for the Context Dev API",
55
"author": "Context Dev <hello@context.dev>",
66
"types": "dist/index.d.ts",
@@ -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/docs-search-tool.ts

Lines changed: 56 additions & 10 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,49 @@ export const tool: Tool = {
4344
const docsSearchURL =
4445
process.env['DOCS_SEARCH_URL'] || 'https://api.stainless.com/api/projects/context.dev/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+
const SUPPORTED_LANGUAGES = new Set(['http', 'typescript', 'javascript']);
54+
55+
async function searchLocal(args: Record<string, unknown>): Promise<unknown> {
56+
if (!_localSearch) {
57+
throw new Error('Local search not initialized');
58+
}
59+
60+
const query = (args['query'] as string) ?? '';
61+
const language = (args['language'] as string) ?? 'typescript';
62+
const detail = (args['detail'] as string) ?? 'verbose';
63+
64+
if (!SUPPORTED_LANGUAGES.has(language)) {
65+
throw new Error(
66+
`Local docs search only supports HTTP, TypeScript, and JavaScript. Got language="${language}". ` +
67+
`Use --docs-search-mode stainless-api for other languages, or set language to "http", "typescript", or "javascript".`,
68+
);
69+
}
70+
71+
return _localSearch.search({
72+
query,
73+
language,
74+
detail,
75+
maxResults: 10,
76+
}).results;
77+
}
78+
79+
async function searchRemote(
80+
args: Record<string, unknown>,
81+
stainlessApiKey: string | undefined,
82+
): Promise<unknown> {
5383
const body = args as any;
5484
const query = new URLSearchParams(body).toString();
5585

5686
const startTime = Date.now();
5787
const result = await fetch(`${docsSearchURL}?${query}`, {
5888
headers: {
59-
...(reqContext.stainlessApiKey && { Authorization: reqContext.stainlessApiKey }),
89+
...(stainlessApiKey && { Authorization: stainlessApiKey }),
6090
},
6191
});
6292

@@ -75,7 +105,7 @@ export const handler = async ({
75105
'Got error response from docs search tool',
76106
);
77107

78-
if (result.status === 404 && !reqContext.stainlessApiKey) {
108+
if (result.status === 404 && !stainlessApiKey) {
79109
throw new Error(
80110
'Could not find docs for this project. You may need to provide a Stainless API key via the STAINLESS_API_KEY environment variable, the --stainless-api-key flag, or the x-stainless-api-key HTTP header.',
81111
);
@@ -94,7 +124,23 @@ export const handler = async ({
94124
},
95125
'Got docs search result',
96126
);
97-
return asTextContentResult(resultBody);
127+
return resultBody;
128+
}
129+
130+
export const handler = async ({
131+
reqContext,
132+
args,
133+
}: {
134+
reqContext: McpRequestContext;
135+
args: Record<string, unknown> | undefined;
136+
}) => {
137+
const body = args ?? {};
138+
139+
if (_localSearch) {
140+
return asTextContentResult(await searchLocal(body));
141+
}
142+
143+
return asTextContentResult(await searchRemote(body, reqContext.stainlessApiKey));
98144
};
99145

100146
export default { metadata, tool, handler };

packages/mcp-server/src/http.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ const newServer = async ({
2323
res: express.Response;
2424
}): Promise<McpServer | null> => {
2525
const stainlessApiKey = getStainlessApiKey(req, mcpOptions);
26-
const server = await newMcpServer(stainlessApiKey);
26+
const customInstructionsPath = mcpOptions.customInstructionsPath;
27+
const server = await newMcpServer({ stainlessApiKey, customInstructionsPath });
2728

2829
const authOptions = parseClientAuthHeaders(req, false);
2930

packages/mcp-server/src/instructions.ts

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

3+
import fs from 'fs/promises';
34
import { readEnv } from './util';
45
import { getLogger } from './logger';
56

@@ -12,9 +13,15 @@ interface InstructionsCacheEntry {
1213

1314
const instructionsCache = new Map<string, InstructionsCacheEntry>();
1415

15-
export async function getInstructions(stainlessApiKey: string | undefined): Promise<string> {
16+
export async function getInstructions({
17+
stainlessApiKey,
18+
customInstructionsPath,
19+
}: {
20+
stainlessApiKey?: string | undefined;
21+
customInstructionsPath?: string | undefined;
22+
}): Promise<string> {
1623
const now = Date.now();
17-
const cacheKey = stainlessApiKey ?? '';
24+
const cacheKey = customInstructionsPath ?? stainlessApiKey ?? '';
1825
const cached = instructionsCache.get(cacheKey);
1926

2027
if (cached && now - cached.fetchedAt <= INSTRUCTIONS_CACHE_TTL_MS) {
@@ -28,12 +35,28 @@ export async function getInstructions(stainlessApiKey: string | undefined): Prom
2835
}
2936
}
3037

31-
const fetchedInstructions = await fetchLatestInstructions(stainlessApiKey);
38+
let fetchedInstructions: string;
39+
40+
if (customInstructionsPath) {
41+
fetchedInstructions = await fetchLatestInstructionsFromFile(customInstructionsPath);
42+
} else {
43+
fetchedInstructions = await fetchLatestInstructionsFromApi(stainlessApiKey);
44+
}
45+
3246
instructionsCache.set(cacheKey, { fetchedInstructions, fetchedAt: now });
3347
return fetchedInstructions;
3448
}
3549

36-
async function fetchLatestInstructions(stainlessApiKey: string | undefined): Promise<string> {
50+
async function fetchLatestInstructionsFromFile(path: string): Promise<string> {
51+
try {
52+
return await fs.readFile(path, 'utf-8');
53+
} catch (error) {
54+
getLogger().error({ error, path }, 'Error fetching instructions from file');
55+
throw error;
56+
}
57+
}
58+
59+
async function fetchLatestInstructionsFromApi(stainlessApiKey: string | undefined): Promise<string> {
3760
// Setting the stainless API key is optional, but may be required
3861
// to authenticate requests to the Stainless API.
3962
const response = await fetch(

0 commit comments

Comments
 (0)