TeaNode · Documentation · Source
The Model Context Protocol is how programs tell each other "here are the things I can do, call them by name". TeaNode is on both ends of it, and the two directions share a wire format and almost nothing else.
Outward, your agent connects to servers you have, so their tools become its tools. Inward, TeaNode answers the protocol itself, so a coding harness, an editor, or a chat assistant such as ChatGPT or Grok can use your agent's tools, and can put a question to your agent in words.
POST /api/v1/mcp
Every request carries a token. The one thing kept between requests is the rest of a long answer (see below), in memory, so a restart loses only that. There are three ways to give a program one.
# point it at the address, then approve it in your browser
claude mcp add --transport http teanode https://mail.example.com/api/v1/mcp
# on a machine your command line is signed in on
claude mcp add teanode -- teanode agent mcp serve
# or hand it an API token yourself
claude mcp add --transport http teanode \
https://mail.example.com/api/v1/mcp \
--header "Authorization: Bearer tnt_..."
The first needs nothing copied anywhere. Refused without a token, the program is told where to register and where to send you; you sign in to the dashboard if you are not already, see which program is asking, and allow it. It registers without a secret, because a program on somebody's machine cannot keep one, and proves it is the program that asked when it collects the token.
The token it gets is narrower than an API token: it is good for the agent
tools and refused by the GraphQL API and everything else. It is replaced every
time it is refreshed, so these tokens are listed by program rather than beside
your API tokens. Settings, then Apps, renames a program or disconnects it,
which revokes every token it holds, and so does teanode app.
Some hosted assistants do not register themselves and ask you for a client identifier instead. Register one for that assistant's own callback address. It has to be that exact address: an approval is only ever sent to an address the program registered.
The second is a pipe rather than a second implementation. teanode agent mcp serve posts each message to the same endpoint with the profile you are
already signed in with, so whatever the server offers it offers.
The third is for a program that does neither. An API token carries its account's whole permissions, so it is the operator's to hand out and yours to keep.
What programs did through the agent tools is on the agent's Activity tab,
each tool called and each question asked, under the kind mcp.
Your whole catalogue, filtered the way a conversation's is: what your permissions allow, less whatever the operator switched off, plus the tools of the servers you have connected and the skills the operator installed. Somebody who may not read mail is not offered the mail search, because it is not in their catalogue to begin with. Every tool comes with its annotations, read-only or destructive, so the program can tell a look from a change the way the agent does.
None of this grants anything the token did not already allow. A program approved in the browser is held to the agent tools; one given an API token could already reach every operation that account's permissions allow through the GraphQL API beside this endpoint. What changes is the shape of the request, not what may be asked.
A tools/call runs the tool. It does not start a conversation in which a
model decides to run it. You already knew what you wanted, and a model in
the middle would cost money, take seconds, and answer differently each time.
Every call is executed and audited as you.
Calls arrive marked as confirmed. Your harness asks you before it runs a tool, and there is no card this server could show that would reach you; the credential you handed the harness is what says you meant it. Anything a tool marks untrusted is wrapped before it goes back, the same way the agent's own loop wraps it, because the harness hands it to a model of its own, which needs telling as much as ours does.
teanode_ask takes a question in words and returns your agent's answer, with
the whole of its kit and its memory of you behind it. A harness that would
otherwise orchestrate six calls asks once.
It is bounded by what a harness will wait for rather than by what a turn takes. Most give a tool call about a minute. After 55 seconds this one returns whatever has been said so far and names the conversation; the turn carries on, and calling again with that conversation and no question collects the rest. A turn that finished in the meantime is handed back and replays what it said, so coming back late still hears the answer. Ten minutes after a run ends the conversation itself is where the answer is.
A turn that stops to raise a confirmation card cannot be answered from a harness. The answer says so, and says the card is waiting in the dashboard, rather than looking like an answer that simply stopped.
Clients cut a long tool answer themselves, somewhere past twelve thousand
characters and without saying where, so the model on the other end cannot
read on. A tool called over MCP is given a smaller budget, so the tools that
page themselves (a search, a file read) fit. Anything still longer is sent a
part at a time: the first part ends with a line naming result_more and
where to go on from, and calling it returns the next part. The rest is held
for thirty minutes.
Connect a chat assistant that speaks MCP (ChatGPT, Grok, and others) to the same address, approve it in your browser, and your mail, calendar, memory and finances are reachable from that assistant's app, by voice if it has a voice mode. So are the coding sessions on your computers: ask what each one is doing, answer the one that is waiting, tell another what to do next. The tool that reaches them tells these clients it is read-only, at your word, so they run it without asking each time.
ask_user exists to put a question in front of somebody who is watching.
There is a person at the far end of a call, but they are looking at their
harness, and this server cannot draw on it. A tool that reaches for it gets
an error saying so rather than a guessed answer.
tool_search exists to keep a long catalogue out of a model's request until
it is wanted. A harness lists the tools once and keeps the list, so it is
better served by the list.
The other direction. An operator declares a server: a name, an address, and how people authenticate with it: nothing, a shared credential, each person's own, or OAuth. You then connect your own credential, or authorize in a browser for a server using OAuth. Credentials are sealed with the server secret before they are stored.
teanode agent mcp list
teanode agent mcp connect tracker --credential -
teanode agent mcp disconnect tracker
What comes back is namespaced by the server's name and joined into your catalogue. Each server's tool list is held for five minutes, and three failures in a row withdraw a server's tools until the next interval, so one service being down does not take your agent's whole kit with it.
Each tool arrives with the annotations its server gave it, such as read-only or destructive. A read-only tool runs without asking, and so does one the operator listed as read-only; a destructive one asks. Every other call is judged by the fast model and asks only where it acts for you toward other people, moves money, places or cancels an order, or deletes something. A card for every look at an account teaches people to approve without reading, which is worse than no card. Everything such a server returns is data. It never instructs.
Some services send an authorization only to a loopback address, the way meant for a program on your own machine. A server declared that way is authorized through your attached computer instead: finish it in a browser on that computer and the dashboard completes the connection.
Nothing stops an operator declaring this server's own endpoint as one of the
agent's connected servers, which would give the agent a namespaced copy of
its own catalogue and a call that comes straight back out. The handshake
refuses a client that says it is TeaNode, which is what our own client says,
and teanode_ask is never in the agent's own catalogue, so even a loop past
the first guard cannot recurse through it.
teanode_ask.teanode agent mcp and the rest.Every document is also plain markdown, listed in /llms.txt.