203 lines
5.8 KiB
Markdown
203 lines
5.8 KiB
Markdown
|
|
# Example MCP Server — Build & Test Skill
|
||
|
|
|
||
|
|
This skill explains how to build, run, and test the example MCP server that
|
||
|
|
demonstrates the `mcp` Haskell library.
|
||
|
|
|
||
|
|
## Prerequisites
|
||
|
|
|
||
|
|
- GHC 9.12.2 and cabal-install
|
||
|
|
- The project root is at the repository root (where `cabal.project` lives)
|
||
|
|
|
||
|
|
## Build
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cabal build mcp-example
|
||
|
|
```
|
||
|
|
|
||
|
|
This compiles the example server along with its dependencies (`mcp-types` and
|
||
|
|
`mcp`).
|
||
|
|
|
||
|
|
## Run
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cabal run mcp-example
|
||
|
|
```
|
||
|
|
|
||
|
|
The server starts on **http://localhost:8080/mcp** and prints a JWT bearer token
|
||
|
|
to stdout. Copy this token — you need it for all requests.
|
||
|
|
|
||
|
|
## Test with curl
|
||
|
|
|
||
|
|
Replace `$TOKEN` with the token printed by the server.
|
||
|
|
|
||
|
|
### 1. Initialize the session
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -s -X POST http://localhost:8080/mcp \
|
||
|
|
-H 'Content-Type: application/json' \
|
||
|
|
-H "Authorization: Bearer $TOKEN" \
|
||
|
|
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}'
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Send initialized notification
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -s -X POST http://localhost:8080/mcp \
|
||
|
|
-H 'Content-Type: application/json' \
|
||
|
|
-H "Authorization: Bearer $TOKEN" \
|
||
|
|
-d '{"jsonrpc":"2.0","method":"notifications/initialized","params":null}'
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. List tools
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -s -X POST http://localhost:8080/mcp \
|
||
|
|
-H 'Content-Type: application/json' \
|
||
|
|
-H "Authorization: Bearer $TOKEN" \
|
||
|
|
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4. Call the echo tool
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -s -X POST http://localhost:8080/mcp \
|
||
|
|
-H 'Content-Type: application/json' \
|
||
|
|
-H "Authorization: Bearer $TOKEN" \
|
||
|
|
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"echo","arguments":{"message":"Hello from MCP!"}}}'
|
||
|
|
```
|
||
|
|
|
||
|
|
### 5. Call the add tool
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -s -X POST http://localhost:8080/mcp \
|
||
|
|
-H 'Content-Type: application/json' \
|
||
|
|
-H "Authorization: Bearer $TOKEN" \
|
||
|
|
-d '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"add","arguments":{"a":17,"b":25}}}'
|
||
|
|
```
|
||
|
|
|
||
|
|
### 6. Call the current-time tool
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -s -X POST http://localhost:8080/mcp \
|
||
|
|
-H 'Content-Type: application/json' \
|
||
|
|
-H "Authorization: Bearer $TOKEN" \
|
||
|
|
-d '{"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"current-time","arguments":{}}}'
|
||
|
|
```
|
||
|
|
|
||
|
|
### 7. List resources
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -s -X POST http://localhost:8080/mcp \
|
||
|
|
-H 'Content-Type: application/json' \
|
||
|
|
-H "Authorization: Bearer $TOKEN" \
|
||
|
|
-d '{"jsonrpc":"2.0","id":6,"method":"resources/list","params":{}}'
|
||
|
|
```
|
||
|
|
|
||
|
|
### 8. Read a resource
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -s -X POST http://localhost:8080/mcp \
|
||
|
|
-H 'Content-Type: application/json' \
|
||
|
|
-H "Authorization: Bearer $TOKEN" \
|
||
|
|
-d '{"jsonrpc":"2.0","id":7,"method":"resources/read","params":{"uri":"resource://example/readme"}}'
|
||
|
|
```
|
||
|
|
|
||
|
|
### 9. List resource templates
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -s -X POST http://localhost:8080/mcp \
|
||
|
|
-H 'Content-Type: application/json' \
|
||
|
|
-H "Authorization: Bearer $TOKEN" \
|
||
|
|
-d '{"jsonrpc":"2.0","id":8,"method":"resources/templates/list","params":{}}'
|
||
|
|
```
|
||
|
|
|
||
|
|
### 10. Read a templated resource
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -s -X POST http://localhost:8080/mcp \
|
||
|
|
-H 'Content-Type: application/json' \
|
||
|
|
-H "Authorization: Bearer $TOKEN" \
|
||
|
|
-d '{"jsonrpc":"2.0","id":9,"method":"resources/read","params":{"uri":"resource://example/users/42"}}'
|
||
|
|
```
|
||
|
|
|
||
|
|
### 11. List prompts
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -s -X POST http://localhost:8080/mcp \
|
||
|
|
-H 'Content-Type: application/json' \
|
||
|
|
-H "Authorization: Bearer $TOKEN" \
|
||
|
|
-d '{"jsonrpc":"2.0","id":10,"method":"prompts/list","params":{}}'
|
||
|
|
```
|
||
|
|
|
||
|
|
### 12. Get a prompt
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -s -X POST http://localhost:8080/mcp \
|
||
|
|
-H 'Content-Type: application/json' \
|
||
|
|
-H "Authorization: Bearer $TOKEN" \
|
||
|
|
-d '{"jsonrpc":"2.0","id":11,"method":"prompts/get","params":{"name":"summarize","arguments":{"text":"The MCP protocol enables AI models to interact with external tools."}}}'
|
||
|
|
```
|
||
|
|
|
||
|
|
### 13. Request completions
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -s -X POST http://localhost:8080/mcp \
|
||
|
|
-H 'Content-Type: application/json' \
|
||
|
|
-H "Authorization: Bearer $TOKEN" \
|
||
|
|
-d '{"jsonrpc":"2.0","id":12,"method":"completion/complete","params":{"ref":{"type":"ref/prompt","name":"summarize"},"argument":{"name":"text","value":"Hel"}}}'
|
||
|
|
```
|
||
|
|
|
||
|
|
### 14. Set log level
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -s -X POST http://localhost:8080/mcp \
|
||
|
|
-H 'Content-Type: application/json' \
|
||
|
|
-H "Authorization: Bearer $TOKEN" \
|
||
|
|
-d '{"jsonrpc":"2.0","id":13,"method":"logging/setLevel","params":{"level":"debug"}}'
|
||
|
|
```
|
||
|
|
|
||
|
|
### 15. Ping
|
||
|
|
|
||
|
|
```bash
|
||
|
|
curl -s -X POST http://localhost:8080/mcp \
|
||
|
|
-H 'Content-Type: application/json' \
|
||
|
|
-H "Authorization: Bearer $TOKEN" \
|
||
|
|
-d '{"jsonrpc":"2.0","id":14,"method":"ping","params":{}}'
|
||
|
|
```
|
||
|
|
|
||
|
|
## Available Features
|
||
|
|
|
||
|
|
| Feature | Methods |
|
||
|
|
|----------------------|----------------------------------------------|
|
||
|
|
| Tools | `tools/list`, `tools/call` |
|
||
|
|
| Resources | `resources/list`, `resources/read` |
|
||
|
|
| Resource Templates | `resources/templates/list` |
|
||
|
|
| Prompts | `prompts/list`, `prompts/get` |
|
||
|
|
| Completions | `completion/complete` |
|
||
|
|
| Logging | `logging/setLevel` |
|
||
|
|
| Lifecycle | `initialize`, `notifications/initialized` |
|
||
|
|
| Health | `ping` |
|
||
|
|
|
||
|
|
## Run the agent test (Claude Agent SDK)
|
||
|
|
|
||
|
|
A Node.js test in `test/` uses the Claude Agent SDK to start the server and
|
||
|
|
exercise every tool endpoint through a Claude agent.
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd mcp-server/example/test
|
||
|
|
pnpm install
|
||
|
|
pnpm test # requires ANTHROPIC_API_KEY
|
||
|
|
```
|
||
|
|
|
||
|
|
The script starts the server, captures its JWT token, connects a Claude agent,
|
||
|
|
and verifies that all 3 tool checks pass (echo, add, current-time).
|
||
|
|
See `test/README.md` for details.
|
||
|
|
|
||
|
|
## Run the library tests
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cabal test all
|
||
|
|
```
|
||
|
|
|
||
|
|
This runs the full integration test suite (42 tests) for the `mcp` library.
|