Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 16 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,26 +50,23 @@ Extract the cookie from the `set-cookie` header, which will look like this:
urbauth-~your-ship=0v3.j2062.1prp1.qne4e.goq3h.ksudm
```

### 3A. Register with Claude
### 3a. Register with Codex

Add the MCP server to Claude using HTTP transport:
Simply add this to your `~/.codex/config.toml`:

```bash
claude mcp add --transport http zod http://localhost:80/mcp --header "Cookie: urbauth-~your-ship=0v3.j2062.1prp1.qne4e.goq3h.ksudm" --scope user
```toml
[mcp_servers.zod]
enabled = true
url = "http://localhost:80/mcp"
http_headers = { "Cookie" = "urbauth-~your-ship=0v3.j2062.1prp1.qne4e.goq3h.ksudm" }
```
### 3B. Register with Codex

Codex requires the `mcp-proxy` python package to function. Install with `uvx mcp-proxy`, then append this to your `~/.codex/config.toml`:
### 3b. Register with Claude Code

```toml
[mcp_servers.fen]
command = "uvx"
args = [
"mcp-proxy",
"--transport", "streamablehttp",
"--headers", "Cookie", "urbauth-~your-ship=0v2.20fhu.t7ki1.cftjr.3s8bv.d9i5l",
"http://localhost:80/mcp"
]
Add the MCP server to Claude using HTTP transport:

```bash
claude mcp add --transport http zod http://localhost:80/mcp --header "Cookie: urbauth-~your-ship=0v3.j2062.1prp1.qne4e.goq3h.ksudm" --scope user
```

## Usage
Expand All @@ -82,29 +79,19 @@ You can ask your LLM to add new Tools. Give it a description (and ideally, examp

### Prompts (slash commands)

MCP prompts for most default tools are available as slash commands, using the format `/mcp__<mcp server>__<tool name>`.

```
/mcp__zod__commit-desk mcp
```
Depending on your agent harness, MCP prompts for most default tools may be available as slash commands, e.g. `/mcp__zod__<tool name>`.

Running these will append a predefined prompt to the conversation and call out to the LLM provider.

Type `/` in Claude Code to see available Prompts.

You can ask your LLM to add new Prompts. These can be any reusable snippet of text you like.
Running these will append a prompt snippet to the conversation and call out to the LLM provider. You can ask your LLM to add new Prompts.

### Resources (@ mentions)

MCP resources can be referenced with an `@` mention to pull the contents into the context window.
Depending on your agent harness, MCP resources may be referenced with an `@` mention to pull their contents into the context window.

```
@zod:https://docs.urbit.org/llms.txt
```

Type `@` in Claude Code to see available Resources.

You can ask your LLM to add new Resources by providing an `https://` URI to a public webpage or a `beam://` URI to a file in Clay.
You can ask your LLM to add new Resources by providing an `https://` URI to a public webpage or a `beam://` URI to a file in your Urbit's Clay filesystem.

## Contributing

Expand Down
51 changes: 42 additions & 9 deletions desk/app/mcp-server.hoon
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
/+ dbug, verb, server, default-agent,
jut=json-utils, ml=mcp
|%
++ mcp-protocol-version %'2025-11-25'
::
++ print-tang-to-wain
|= =tang
^- wain
Expand Down Expand Up @@ -31,6 +33,7 @@
:- :- 200
:~ ['content-type' 'application/json']
['cache-control' 'no-cache']
['MCP-Protocol-Version' mcp-protocol-version]
==
%- some
%- as-octt:mimes:html
Expand All @@ -50,6 +53,7 @@
:- :- status
:~ ['content-type' 'application/json']
['cache-control' 'no-cache']
['MCP-Protocol-Version' mcp-protocol-version]
==
%- some
%- as-octt:mimes:html
Expand Down Expand Up @@ -245,21 +249,50 @@
:_ this
(send-event eyre-id (internal:error:rpc:ml 'Authentication required' ~))
?+ method.request.req
[(simple-response eyre-id 405 ~) this]
[(simple-response eyre-id 405 ~[['allow' 'POST']]) this]
::
%'GET'
=/ connection-json=json
(pairs:enjs:format ~[['type' s+'connection']])
:_ this
(send-event eyre-id connection-json)
[(simple-response eyre-id 405 ~[['allow' 'POST']]) this]
::
%'DELETE'
[(simple-response eyre-id 405 ~[['allow' 'POST']]) this]
::
%'POST'
=/ client-protocol-version=(unit @t)
(get-header:http 'mcp-protocol-version' header-list.request.req)
=/ bad-protocol-version=?
?~ client-protocol-version
.n
!=(u.client-protocol-version mcp-protocol-version)
?: bad-protocol-version
:_ this
%: json-response
eyre-id
400
(pairs:enjs:format ~[['error' s+'Unsupported MCP-Protocol-Version']])
==
=/ accept=(unit @t)
(get-header:http 'accept' header-list.request.req)
?~ accept
:_ this
%: json-response
eyre-id
400
(pairs:enjs:format ~[['error' s+'Missing Accept header']])
==
?. ?=(^ (find "application/json" (trip u.accept)))
:_ this
%: json-response
eyre-id
406
(pairs:enjs:format ~[['error' s+'Accept must include application/json']])
==
=/ content-type=(unit @t)
(get-header:http 'content-type' header-list.request.req)
?+ content-type
[(simple-response eyre-id 415 ~) this]
[(simple-response eyre-id 415 ~[['MCP-Protocol-Version' mcp-protocol-version]]) this]
::
[~ %'application/json']
?([~ %'application/json'] [~ %'application/json; charset=utf-8'])
=/ parsed=(unit json)
(de:json:html q:(need body.request.req))
?~ parsed
Expand All @@ -273,7 +306,7 @@
(send-event eyre-id (method:error:rpc:ml 'Method not found' id))
::
[~ [%s %'notifications/initialized']]
[(simple-response eyre-id 200 ~) this]
[(simple-response eyre-id 202 ~[['MCP-Protocol-Version' mcp-protocol-version]]) this]
::
[~ [%s %'initialize']]
:: XX check protocol version?
Expand All @@ -287,7 +320,7 @@
:~ ['jsonrpc' s+'2.0']
:- 'result'
%- pairs:enjs:format
:~ ['protocolVersion' s+'2024-11-05']
:~ ['protocolVersion' s+mcp-protocol-version]
:- 'capabilities'
%- pairs:enjs:format
:~ :- 'tools'
Expand Down
Loading