ginny
ginny MCP server
Connect an MCP client to ginny with Streamable HTTP, OAuth, scoped access, and explicit approval for every write.
Endpoint and transport
ginny exposes a single MCP endpoint using Streamable HTTP. Requests are JSON-RPC
2.0 messages over HTTP POST. Clients must also accept text/event-stream because the
server may select an SSE response for a successful request.
- Use HTTPS and send JSON-RPC 2.0 request IDs on calls that expect a response.
- Send both
application/jsonandtext/event-streaminAccept. - Do not open a legacy standalone SSE endpoint; Streamable HTTP uses the MCP URL above.
- Browser clients must send their real
Origin. Unexpected origins are rejected.
OAuth
The MCP endpoint is an OAuth-protected resource. Start without credentials, follow the
401 Unauthorized challenge and protected-resource metadata, then use the advertised
authorization server. Public clients should use an authorization-code flow with PKCE.
- Discover protected-resource metadata from the challenge.
- Request only the scopes needed for the current workflow.
- Complete user authorization and obtain an audience-bound access token.
- Send the token only as
Authorization: Bearer <token>. - On
401, refresh or reauthorize once; never loop indefinitely.
Store refresh tokens in platform-secure storage. Never put an OAuth token in a JSON-RPC parameter, MCP tool argument, URL, log, or model-visible prompt.
Initialize a session
Send initialize first. The example proposes protocol version
2025-06-18; the server response determines the negotiated version. Capture the
MCP-Session-Id response header when present.
export facoolta_mcp_token='oauth-access-token'
curl --include --request POST https://mcp.facoolta.com/mcp \
--header 'Accept: application/json, text/event-stream' \
--header 'Content-Type: application/json' \
--header 'Origin: https://client.example.com' \
--header "Authorization: Bearer $facoolta_mcp_token" \
--data '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {},
"clientInfo": { "name": "campus-client", "version": "1.0.0" }
}
}'
After accepting the server response, send notifications/initialized with the
negotiated protocol version and session ID.
curl --request POST https://mcp.facoolta.com/mcp \
--header 'Accept: application/json, text/event-stream' \
--header 'Content-Type: application/json' \
--header 'Origin: https://client.example.com' \
--header 'MCP-Protocol-Version: 2025-06-18' \
--header "MCP-Session-Id: $facoolta_mcp_session_id" \
--header "Authorization: Bearer $facoolta_mcp_token" \
--data '{"jsonrpc":"2.0","method":"notifications/initialized"}' Required headers
| Header | When | Value |
|---|---|---|
Authorization | Every protected request | Bearer <OAuth access token> |
Content-Type | POST requests | application/json |
Accept | POST and stream-capable requests | application/json, text/event-stream |
Origin | Browser requests | The client’s real, approved HTTPS origin |
MCP-Protocol-Version | After initialization | The negotiated protocol version |
MCP-Session-Id | When issued by the server | The exact opaque response-header value |
Scopes
courses:read- Search and read course context visible to the user.
files:read- Search, inspect, and summarize files the user can access.
calendar:read- Read deadlines and calendar context.
reminders:write- Create, change, or remove reminders after approval.
tasks:write- Create, change, or complete tasks after approval.
messages:write- Post an approved message to facultalk.
doctor:write- Run approved doctor scans and analysis that may persist results.
A granted scope is permission to request an operation, not blanket consent to perform it. Resource-level authorization and write approval are evaluated for every tool call.
Tool surface
Discover exact tool names and input schemas at runtime with tools/list. Do not
hard-code names from screenshots or earlier sessions.
curl --request POST https://mcp.facoolta.com/mcp \
--header 'Accept: application/json, text/event-stream' \
--header 'Content-Type: application/json' \
--header 'Origin: https://client.example.com' \
--header 'MCP-Protocol-Version: 2025-06-18' \
--header "MCP-Session-Id: $facoolta_mcp_session_id" \
--header "Authorization: Bearer $facoolta_mcp_token" \
--data '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' | Capability | Typical scope | Mode |
|---|---|---|
| Course search | courses:read | Read |
| File search and summaries | files:read, sometimes courses:read | Read |
| Deadlines | calendar:read | Read |
| Reminder management | reminders:write | Write + approval |
| Task management | tasks:write | Write + approval |
| doctor scanning and analysis | doctor:write | Write + approval |
| facultalk posting | messages:write | Write + approval |
Human approval for writes
An approval UI should expose:
- the action and destination;
- the exact content, due date, recipients, or affected records;
- whether the action is reversible;
- a clear confirm control and an equally available cancel control.
Approval is single-use. If arguments change, the tool retries after a timeout, or the target is resolved differently, ask again. Never auto-approve a write because a previous, similar action was accepted.
Session lifecycle
- Treat the session ID as opaque and keep it out of model context and logs.
- On an unknown-session response, discard the ID and initialize a new session.
- Reconnect streams with bounded backoff and preserve the negotiated version.
- If the server supports session termination, send HTTP DELETE with the same OAuth, version, and session headers.
- On sign-out or OAuth revocation, close active streams and clear the local session ID.