Skip to content

Commit 7ba2f48

Browse files
committed
feat: add a mcp server to load the different SDK context
1 parent ef2751e commit 7ba2f48

File tree

20 files changed

+1446
-1
lines changed

20 files changed

+1446
-1
lines changed

nx.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,22 @@
367367
],
368368
"cache": true
369369
},
370+
"expose-resources": {
371+
"executor": "nx:run-script",
372+
"options": {
373+
"script": "copy:resources"
374+
},
375+
"dependsOn": [
376+
"compile"
377+
],
378+
"inputs": [
379+
"{projectRoot}/resources/**"
380+
],
381+
"outputs": [
382+
"{projectRoot}/dist/resources/**"
383+
],
384+
"cache": true
385+
},
370386
"expose-schemas": {
371387
"executor": "nx:run-script",
372388
"options": {

packages/@ama-mcp/sdk/README.md

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# @ama-mcp/sdk
2+
3+
MCP module to expose `SDK_CONTEXT.md` from installed packages to AI assistants.
4+
5+
## Purpose
6+
7+
When SDKs are generated using `@ama-sdk/schematics`, they can include an `SDK_CONTEXT.md` file that describes:
8+
- Available API domains and operations
9+
- Models used by each domain
10+
- Guidelines for AI tools to avoid hallucinations
11+
12+
This MCP module automatically discovers and loads these context files from installed packages using Node.js's module resolution, then exposes them to AI assistants.
13+
14+
## Configuration
15+
16+
### Option 1: VS Code `mcp.json` (Recommended)
17+
18+
Configure SDK packages directly in your `.vscode/mcp.json`:
19+
20+
```json
21+
{
22+
"servers": {
23+
"sdk-context": {
24+
"command": "npx",
25+
"args": ["ama-mcp-sdk", "--packages", "@my-scope/my-sdk-package", "@other-scope/other-sdk"]
26+
}
27+
}
28+
}
29+
```
30+
31+
### Option 2: Project `package.json`
32+
33+
Add to your project's `package.json` (used as fallback if no args provided):
34+
35+
```json
36+
{
37+
"sdkContext": {
38+
"packages": [
39+
"@my-scope/my-sdk-package",
40+
"@other-scope/other-sdk"
41+
]
42+
}
43+
}
44+
```
45+
46+
## Usage
47+
48+
### CLI (for mcp.json)
49+
50+
```bash
51+
# Specify packages with --packages flag
52+
ama-mcp-sdk --packages @my-scope/my-sdk @other-scope/other-sdk
53+
54+
# Show help
55+
ama-mcp-sdk --help
56+
```
57+
58+
### Programmatic (in custom MCP server)
59+
60+
```typescript
61+
import { registerSdkContextToolAndResources } from '@ama-mcp/sdk';
62+
63+
// With explicit packages
64+
await registerSdkContextToolAndResources(server, {
65+
sdkPackages: ['@my-scope/my-sdk']
66+
});
67+
68+
// Or reads from package.json sdkContext.packages automatically
69+
await registerSdkContextToolAndResources(server);
70+
```
71+
72+
### Available Tool
73+
74+
**`get_sdk_context`** - Retrieve SDK context for configured packages
75+
76+
```
77+
// List all configured SDKs with context
78+
get_sdk_context()
79+
80+
// Get context for specific package
81+
get_sdk_context({ packageName: "@my-scope/my-sdk-package" })
82+
```
83+
84+
### Available Resources
85+
86+
**`sdk-context://instructions`** - Usage guidelines for AI assistants
87+
88+
This resource provides instructions on how to use SDK context effectively to avoid hallucinations when implementing features. AI assistants should read this resource before using the `get_sdk_context` tool.
89+
90+
**`sdk-context://<package-name>`** - SDK context for each configured package
91+
92+
Each configured SDK package that has an `SDK_CONTEXT.md` file is exposed as a resource.
93+
94+
## How It Works
95+
96+
1. Reads `sdkContext.packages` from project's `package.json` or uses CLI arguments
97+
2. Uses Node.js `require.resolve()` to automatically locate packages
98+
3. Loads `SDK_CONTEXT.md` from each resolved package
99+
4. Registers each as an MCP resource
100+
5. Provides a tool for AI assistants to query SDK information
101+
102+
## Package Resolution
103+
104+
The SDK automatically discovers packages using Node.js's `require.resolve()`. This means:
105+
106+
- **No manual path configuration needed** - packages are found automatically
107+
- **Works with workspaces** - supports npm/yarn/pnpm workspace configurations
108+
- **Flexible installation** - works with local, global, or custom module paths
109+
- **Error handling** - clear error messages when packages aren't found
110+
111+
If a package isn't found, ensure:
112+
1. The package is installed (`npm install <package-name>`)
113+
2. The package name is spelled correctly
114+
3. The package has an `SDK_CONTEXT.md` file in its root
115+
116+
**Security**: The system validates package names to prevent path traversal attacks and only accepts valid npm package name patterns.
117+
118+
## Troubleshooting
119+
120+
### Package Not Found
121+
```
122+
Package "@my-scope/my-sdk" not found. Is it installed?
123+
```
124+
**Solution**: Install the package or verify the name in your configuration.
125+
126+
### No SDK_CONTEXT.md Found
127+
```
128+
No SDK_CONTEXT.md found for @my-scope/my-sdk
129+
```
130+
**Solution**: Generate the context file using the command below.
131+
132+
## Generating SDK Context
133+
134+
SDK maintainers can generate `SDK_CONTEXT.md` using:
135+
136+
```bash
137+
cd /path/to/sdk-project
138+
npx amasdk-update-sdk-context --interactive
139+
```
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import shared from '../../../eslint.shared.config.mjs';
2+
import local from './eslint.local.config.mjs';
3+
4+
export default [
5+
...shared,
6+
...local
7+
];
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import {
2+
dirname,
3+
} from 'node:path';
4+
import {
5+
fileURLToPath,
6+
} from 'node:url';
7+
import globals from 'globals';
8+
9+
const __filename = fileURLToPath(import.meta.url);
10+
// __dirname is not defined in ES module scope
11+
const __dirname = dirname(__filename);
12+
13+
export default [
14+
{
15+
name: '@ama-mcp/sdk/projects',
16+
languageOptions: {
17+
sourceType: 'module',
18+
parserOptions: {
19+
tsconfigRootDir: __dirname,
20+
projectService: true
21+
},
22+
globals: {
23+
...globals.node,
24+
NodeJS: true
25+
}
26+
}
27+
}
28+
];
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const { getJestProjectConfig } = require('@o3r/test-helpers');
2+
3+
/** @type {import('ts-jest/dist/types').JestConfigWithTsJest} */
4+
module.exports = {
5+
...getJestProjectConfig(),
6+
projects: [
7+
'<rootDir>/testing/jest.config.ut.js'
8+
]
9+
};

packages/@ama-mcp/sdk/package.json

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
{
2+
"name": "@ama-mcp/sdk",
3+
"version": "0.0.0-placeholder",
4+
"publishConfig": {
5+
"access": "public"
6+
},
7+
"description": "MCP module to expose SDK_CONTEXT.md from installed packages to AI assistants",
8+
"keywords": [
9+
"mcp",
10+
"sdk",
11+
"ai-context",
12+
"otter-module"
13+
],
14+
"module": "dist/src/public_api.js",
15+
"typings": "dist/src/public_api.d.ts",
16+
"sideEffects": false,
17+
"bin": {
18+
"ama-mcp-sdk": "./dist/src/cli.js"
19+
},
20+
"exports": {
21+
"./package.json": {
22+
"default": "./package.json"
23+
},
24+
".": {
25+
"typings": "./dist/src/public_api.d.ts",
26+
"default": "./dist/src/public_api.js"
27+
}
28+
},
29+
"scripts": {
30+
"nx": "nx",
31+
"ng": "yarn nx",
32+
"build": "yarn nx build ama-mcp-sdk",
33+
"compile": "tsc -b ./tsconfig.build.json && yarn cpy package.json dist && patch-package-json-main",
34+
"copy:resources": "yarn cpy resources dist"
35+
},
36+
"peerDependencies": {
37+
"@ama-mcp/core": "workspace:~",
38+
"@modelcontextprotocol/sdk": "^1.19.0",
39+
"zod": "^3.0.0 || ^4.0.0"
40+
},
41+
"dependencies": {
42+
"@o3r/telemetry": "workspace:~",
43+
"commander": "^14.0.0",
44+
"tslib": "^2.6.2"
45+
},
46+
"devDependencies": {
47+
"@ama-mcp/core": "workspace:~",
48+
"@eslint-community/eslint-plugin-eslint-comments": "^4.4.0",
49+
"@modelcontextprotocol/sdk": "~1.27.0",
50+
"@nx/eslint": "~22.5.3",
51+
"@nx/eslint-plugin": "~22.5.3",
52+
"@nx/jest": "~22.5.3",
53+
"@nx/js": "~22.5.3",
54+
"@o3r/build-helpers": "workspace:^",
55+
"@o3r/eslint-config": "workspace:^",
56+
"@o3r/eslint-plugin": "workspace:^",
57+
"@o3r/test-helpers": "workspace:^",
58+
"@stylistic/eslint-plugin": "~5.7.0",
59+
"@types/jest": "~30.0.0",
60+
"@types/node": "~24.10.0",
61+
"@typescript-eslint/parser": "~8.54.0",
62+
"cpy-cli": "^6.0.0",
63+
"eslint": "~9.39.0",
64+
"eslint-import-resolver-node": "~0.3.9",
65+
"eslint-import-resolver-typescript": "~4.4.0",
66+
"eslint-plugin-import": "~2.32.0",
67+
"eslint-plugin-import-newlines": "~1.4.0",
68+
"eslint-plugin-jest": "~29.12.0",
69+
"eslint-plugin-jsdoc": "~61.7.0",
70+
"eslint-plugin-prefer-arrow": "~1.2.3",
71+
"eslint-plugin-unicorn": "~62.0.0",
72+
"eslint-plugin-unused-imports": "~4.3.0",
73+
"globals": "^16.0.0",
74+
"jest": "~30.2.0",
75+
"jest-junit": "~16.0.0",
76+
"jsonc-eslint-parser": "~2.4.0",
77+
"ts-jest": "~29.4.0",
78+
"typescript": "~5.9.2",
79+
"typescript-eslint": "~8.54.0",
80+
"zod": "~4.3.0"
81+
},
82+
"engines": {
83+
"node": "^22.17.0 || ^24.0.0"
84+
}
85+
}

packages/@ama-mcp/sdk/project.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"name": "ama-mcp-sdk",
3+
"$schema": "https://raw.githubusercontent.com/nrwl/nx/master/packages/nx/schemas/project-schema.json",
4+
"projectType": "library",
5+
"sourceRoot": "packages/@ama-mcp/sdk/src",
6+
"prefix": "o3r",
7+
"targets": {
8+
"build": {
9+
"executor": "nx:noop",
10+
"dependsOn": ["compile", "expose-templates", "expose-resources"]
11+
},
12+
"compile": {
13+
"executor": "nx:run-script",
14+
"options": {
15+
"script": "compile"
16+
},
17+
"dependsOn": ["prepare", "^build"]
18+
},
19+
"expose-resources": {},
20+
"test": {},
21+
"lint": {},
22+
"prepare-publish": {},
23+
"publish": {}
24+
},
25+
"tags": []
26+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# SDK Context Usage Instructions
2+
3+
When implementing features that use installed SDKs, follow these guidelines to avoid hallucinations and ensure accurate code generation.
4+
5+
> **Note**: The SDKs available through this MCP server are those explicitly configured in the server launch parameters (via `--packages` arguments or `sdkContext.packages` in `package.json`). Only these SDKs will have context available through the `get_sdk_context` tool.
6+
7+
## Before Implementing SDK Features
8+
9+
1. **Query available SDK contexts** using the `get_sdk_context` tool without arguments to list all configured SDKs
10+
2. **Read the specific SDK context** by calling `get_sdk_context` with the package name
11+
12+
## Guidelines
13+
14+
### DO
15+
16+
- **Always check SDK context first** - Before suggesting API calls, query the SDK context
17+
- **Explore project structure for endpoints** - If the requested operation is not found in the SDK context, or if no SDK context is available, look for OpenAPI/Swagger specification files (e.g., `openapi.yaml`, `open-api.yaml`, `swagger.json`, `spec.yaml`) in the project to discover available endpoints
18+
- **Inspect the SDK source files** - Browse the SDK's `src/api` or similar directories to find available API classes and their methods
19+
- **Use exact operation IDs** - Only use operations listed in the SDK context or discovered from the specification
20+
- **Reference correct models** - Import models from paths specified in the context or found in the SDK's model directory
21+
- **Follow domain organization** - Use the domain structure described in the context
22+
23+
### DON'T
24+
25+
- **Do not hallucinate operations** - If an operation is not in the context or specification, it doesn't exist
26+
- **Do not invent model properties** - Only use properties defined in the SDK models
27+
- **Do not assume API paths** - Use the exact paths from the SDK context or specification file
28+
29+
## Example Workflow
30+
31+
When a user asks: "How do I fetch a pet by ID?"
32+
33+
1. Call `get_sdk_context()` to list available SDKs
34+
2. Call `get_sdk_context({ packageName: "@my-scope/pet-sdk" })` to get the pet SDK context
35+
3. If the operation is not found in the SDK context, or if no SDK context is available:
36+
- Search for OpenAPI/Swagger specification files (`openapi.yaml`, `open-api.yaml`, `openapi.json`, `open-api.json`, `swagger.json`, `spec.yaml`) in the project
37+
- Browse the SDK's API source files (e.g., `node_modules/@my-scope/pet-sdk/src/api/`) to discover available operations
38+
- Check the SDK's `package.json` for entry points or documentation references
39+
4. Find the relevant domain (e.g., `pet`)
40+
5. Locate the operation (e.g., `getPetById`)
41+
6. Provide implementation using the exact operation ID and model imports from the context or specification
42+
43+
## SDK Context Structure
44+
45+
Each SDK context file contains:
46+
47+
- **SDK Information**: Package name, API version, title
48+
- **Domains**: Logical groupings of API operations
49+
- **Operations**: Available API calls with method, path, and description
50+
- **Models**: Data structures used by each domain
51+
52+
## Troubleshooting
53+
54+
### No SDK contexts found
55+
56+
Ensure the SDK packages are:
57+
1. Listed in `package.json` under `sdkContext.packages`
58+
2. Or provided via CLI arguments: `--packages @scope/sdk-name`
59+
3. Installed in node_modules
60+
4. Have `SDK_CONTEXT.md` generated (use `amasdk-update-sdk-context` in the SDK project)

0 commit comments

Comments
 (0)