|
| 1 | +# Schools TypeScript MCP Server |
| 2 | + |
| 3 | +It is generated with [Stainless](https://www.stainless.com/). |
| 4 | + |
| 5 | +## Installation |
| 6 | + |
| 7 | +### Building |
| 8 | + |
| 9 | +Because it's not published yet, clone the repo and build it: |
| 10 | + |
| 11 | +```sh |
| 12 | +git clone git@github.com:et0and/schools-sdk-typescript.git |
| 13 | +cd schools-sdk-typescript |
| 14 | +./scripts/bootstrap |
| 15 | +./scripts/build |
| 16 | +``` |
| 17 | + |
| 18 | +### Running |
| 19 | + |
| 20 | +```sh |
| 21 | +# set env vars as needed |
| 22 | +export SCHOOLS_API_KEY="My API Key" |
| 23 | +export SCHOOLS_ENVIRONMENT="production" |
| 24 | +node ./packages/mcp-server/dist/index.js |
| 25 | +``` |
| 26 | + |
| 27 | +> [!NOTE] |
| 28 | +> Once this package is [published to npm](https://www.stainless.com/docs/guides/publish), this will become: `npx -y schools-sdk-mcp` |
| 29 | +
|
| 30 | +### Via MCP Client |
| 31 | + |
| 32 | +[Build the project](#building) as mentioned above. |
| 33 | + |
| 34 | +There is a partial list of existing clients at [modelcontextprotocol.io](https://modelcontextprotocol.io/clients). If you already |
| 35 | +have a client, consult their documentation to install the MCP server. |
| 36 | + |
| 37 | +For clients with a configuration JSON, it might look something like this: |
| 38 | + |
| 39 | +```json |
| 40 | +{ |
| 41 | + "mcpServers": { |
| 42 | + "schools_sdk_api": { |
| 43 | + "command": "node", |
| 44 | + "args": ["/path/to/local/schools-sdk-typescript/packages/mcp-server", "--client=claude", "--tools=all"], |
| 45 | + "env": { |
| 46 | + "SCHOOLS_API_KEY": "My API Key", |
| 47 | + "SCHOOLS_ENVIRONMENT": "production" |
| 48 | + } |
| 49 | + } |
| 50 | + } |
| 51 | +} |
| 52 | +``` |
| 53 | + |
| 54 | +## Exposing endpoints to your MCP Client |
| 55 | + |
| 56 | +There are two ways to expose endpoints as tools in the MCP server: |
| 57 | + |
| 58 | +1. Exposing one tool per endpoint, and filtering as necessary |
| 59 | +2. Exposing a set of tools to dynamically discover and invoke endpoints from the API |
| 60 | + |
| 61 | +### Filtering endpoints and tools |
| 62 | + |
| 63 | +You can run the package on the command line to discover and filter the set of tools that are exposed by the |
| 64 | +MCP Server. This can be helpful for large APIs where including all endpoints at once is too much for your AI's |
| 65 | +context window. |
| 66 | + |
| 67 | +You can filter by multiple aspects: |
| 68 | + |
| 69 | +- `--tool` includes a specific tool by name |
| 70 | +- `--resource` includes all tools under a specific resource, and can have wildcards, e.g. `my.resource*` |
| 71 | +- `--operation` includes just read (get/list) or just write operations |
| 72 | + |
| 73 | +### Dynamic tools |
| 74 | + |
| 75 | +If you specify `--tools=dynamic` to the MCP server, instead of exposing one tool per endpoint in the API, it will |
| 76 | +expose the following tools: |
| 77 | + |
| 78 | +1. `list_api_endpoints` - Discovers available endpoints, with optional filtering by search query |
| 79 | +2. `get_api_endpoint_schema` - Gets detailed schema information for a specific endpoint |
| 80 | +3. `invoke_api_endpoint` - Executes any endpoint with the appropriate parameters |
| 81 | + |
| 82 | +This allows you to have the full set of API endpoints available to your MCP Client, while not requiring that all |
| 83 | +of their schemas be loaded into context at once. Instead, the LLM will automatically use these tools together to |
| 84 | +search for, look up, and invoke endpoints dynamically. However, due to the indirect nature of the schemas, it |
| 85 | +can struggle to provide the correct properties a bit more than when tools are imported explicitly. Therefore, |
| 86 | +you can opt-in to explicit tools, the dynamic tools, or both. |
| 87 | + |
| 88 | +See more information with `--help`. |
| 89 | + |
| 90 | +All of these command-line options can be repeated, combined together, and have corresponding exclusion versions (e.g. `--no-tool`). |
| 91 | + |
| 92 | +Use `--list` to see the list of available tools, or see below. |
| 93 | + |
| 94 | +### Specifying the MCP Client |
| 95 | + |
| 96 | +Different clients have varying abilities to handle arbitrary tools and schemas. |
| 97 | + |
| 98 | +You can specify the client you are using with the `--client` argument, and the MCP server will automatically |
| 99 | +serve tools and schemas that are more compatible with that client. |
| 100 | + |
| 101 | +- `--client=<type>`: Set all capabilities based on a known MCP client |
| 102 | + |
| 103 | + - Valid values: `openai-agents`, `claude`, `claude-code`, `cursor` |
| 104 | + - Example: `--client=cursor` |
| 105 | + |
| 106 | +Additionally, if you have a client not on the above list, or the client has gotten better |
| 107 | +over time, you can manually enable or disable certain capabilities: |
| 108 | + |
| 109 | +- `--capability=<name>`: Specify individual client capabilities |
| 110 | + - Available capabilities: |
| 111 | + - `top-level-unions`: Enable support for top-level unions in tool schemas |
| 112 | + - `valid-json`: Enable JSON string parsing for arguments |
| 113 | + - `refs`: Enable support for $ref pointers in schemas |
| 114 | + - `unions`: Enable support for union types (anyOf) in schemas |
| 115 | + - `formats`: Enable support for format validations in schemas (e.g. date-time, email) |
| 116 | + - `tool-name-length=N`: Set maximum tool name length to N characters |
| 117 | + - Example: `--capability=top-level-unions --capability=tool-name-length=40` |
| 118 | + - Example: `--capability=top-level-unions,tool-name-length=40` |
| 119 | + |
| 120 | +### Examples |
| 121 | + |
| 122 | +1. Filter for read operations on cards: |
| 123 | + |
| 124 | +```bash |
| 125 | +--resource=cards --operation=read |
| 126 | +``` |
| 127 | + |
| 128 | +2. Exclude specific tools while including others: |
| 129 | + |
| 130 | +```bash |
| 131 | +--resource=cards --no-tool=create_cards |
| 132 | +``` |
| 133 | + |
| 134 | +3. Configure for Cursor client with custom max tool name length: |
| 135 | + |
| 136 | +```bash |
| 137 | +--client=cursor --capability=tool-name-length=40 |
| 138 | +``` |
| 139 | + |
| 140 | +4. Complex filtering with multiple criteria: |
| 141 | + |
| 142 | +```bash |
| 143 | +--resource=cards,accounts --operation=read --tag=kyc --no-tool=create_cards |
| 144 | +``` |
| 145 | + |
| 146 | +## Running remotely |
| 147 | + |
| 148 | +Launching the client with `--transport=http` launches the server as a remote server using Streamable HTTP transport. The `--port` setting can choose the port it will run on, and the `--socket` setting allows it to run on a Unix socket. |
| 149 | + |
| 150 | +Authorization can be provided via the `Authorization` header using the Bearer scheme. |
| 151 | + |
| 152 | +Additionally, authorization can be provided via the following headers: |
| 153 | +| Header | Equivalent client option | Security scheme | |
| 154 | +| ------------------- | ------------------------ | --------------- | |
| 155 | +| `x-schools-api-key` | `apiKey` | bearerAuth | |
| 156 | + |
| 157 | +A configuration JSON for this server might look like this, assuming the server is hosted at `http://localhost:3000`: |
| 158 | + |
| 159 | +```json |
| 160 | +{ |
| 161 | + "mcpServers": { |
| 162 | + "schools_sdk_api": { |
| 163 | + "url": "http://localhost:3000", |
| 164 | + "headers": { |
| 165 | + "Authorization": "Bearer <auth value>" |
| 166 | + } |
| 167 | + } |
| 168 | + } |
| 169 | +} |
| 170 | +``` |
| 171 | + |
| 172 | +The command-line arguments for filtering tools and specifying clients can also be used as query parameters in the URL. |
| 173 | +For example, to exclude specific tools while including others, use the URL: |
| 174 | + |
| 175 | +``` |
| 176 | +http://localhost:3000?resource=cards&resource=accounts&no_tool=create_cards |
| 177 | +``` |
| 178 | + |
| 179 | +Or, to configure for the Cursor client, with a custom max tool name length, use the URL: |
| 180 | + |
| 181 | +``` |
| 182 | +http://localhost:3000?client=cursor&capability=tool-name-length%3D40 |
| 183 | +``` |
| 184 | + |
| 185 | +## Importing the tools and server individually |
| 186 | + |
| 187 | +```js |
| 188 | +// Import the server, generated endpoints, or the init function |
| 189 | +import { server, endpoints, init } from "schools-sdk-mcp/server"; |
| 190 | + |
| 191 | +// import a specific tool |
| 192 | +import checkHealth from "schools-sdk-mcp/tools/health/check-health"; |
| 193 | + |
| 194 | +// initialize the server and all endpoints |
| 195 | +init({ server, endpoints }); |
| 196 | + |
| 197 | +// manually start server |
| 198 | +const transport = new StdioServerTransport(); |
| 199 | +await server.connect(transport); |
| 200 | + |
| 201 | +// or initialize your own server with specific tools |
| 202 | +const myServer = new McpServer(...); |
| 203 | + |
| 204 | +// define your own endpoint |
| 205 | +const myCustomEndpoint = { |
| 206 | + tool: { |
| 207 | + name: 'my_custom_tool', |
| 208 | + description: 'My custom tool', |
| 209 | + inputSchema: zodToJsonSchema(z.object({ a_property: z.string() })), |
| 210 | + }, |
| 211 | + handler: async (client: client, args: any) => { |
| 212 | + return { myResponse: 'Hello world!' }; |
| 213 | + }) |
| 214 | +}; |
| 215 | + |
| 216 | +// initialize the server with your custom endpoints |
| 217 | +init({ server: myServer, endpoints: [checkHealth, myCustomEndpoint] }); |
| 218 | +``` |
| 219 | + |
| 220 | +## Available Tools |
| 221 | + |
| 222 | +The following tools are available in this MCP server. |
| 223 | + |
| 224 | +### Resource `health`: |
| 225 | + |
| 226 | +- `check_health` (`read`): API health check |
| 227 | + |
| 228 | +### Resource `root`: |
| 229 | + |
| 230 | +- `retrieve_root` (`read`): API root information |
| 231 | + |
| 232 | +### Resource `schools`: |
| 233 | + |
| 234 | +- `retrieve_schools` (`read`): Get school by School ID |
| 235 | +- `list_schools` (`read`): Get all schools with filtering |
| 236 | +- `by_authority_schools` (`read`): Get schools by authority |
| 237 | +- `by_city_schools` (`read`): Get schools by city |
| 238 | +- `by_status_schools` (`read`): Get schools by status |
| 239 | +- `by_suburb_schools` (`read`): Get schools by suburb |
| 240 | +- `search_schools` (`read`): Full-text search schools by name |
| 241 | + |
| 242 | +### Resource `sync`: |
| 243 | + |
| 244 | +- `get_status_sync` (`read`): Get sync status |
| 245 | +- `trigger_sync` (`write`): Trigger manual data sync |
0 commit comments